title Game of life name ('GAMELIFE') ; The GAME OF LIFE ; Extracted from the JOYCE tool MAIL232 entry $memry OS equ 0000h BDOS equ 0005h .condir equ 6 .get equ 0ffh lf equ 0ah cr equ 0dh esc equ 1bh ; ; Movement selection for board setting ; MoveLft equ 'A'-'@' ; Move left MoveRgt equ 'F'-'@' ; Move right MoveDwn equ '^'-'@' ; Move down MoveUp equ '_'-'@' ; Move up VidCol equ 90 VidLine equ 30 ld sp,(BDOS+1) ; Get our stack ld hl,($memry) ; Get top of memory ld (Board1),hl ; Set for 1st board ld de,VidCol*(VidLine+1) add hl,de ld (Board2),hl ; Set for 2nd board call clrscr ; Clear screen call ExecGame ; Execute the game jp OS ; ; Clear screen ; clrscr: ld a,'E' call prESC ; Give clear screen ; ; Home cursor ; goto00: ld a,'H' jr prESC ; Give home cursor ; ; Make cursor visible ; visib: ld a,'e' jr prESC ; Make cursor visible ; ; Make cursor invisible ; invisib: ld a,'f' ; Make cursor invisible ; ; Give escape character ; ENTRY Reg E holds escape sequence character ; prESC: push af ld a,esc call conout ; Give real ESCape pop af ; Then character call conout ret ; ; Print piece ; ENTRY Accu reflects state: 00 is piece set ; FF is not prPiece: or a ; Test state ld e,'O' ; Indicate set jr z,conput ; It is set ld e,' ' ; Blank on reset jr conput ; ; Put character to console ; conout: ld e,a jr conput ; Just put it ; ; Get character from console ; conin: ld e,.get conput: ld c,.condir call BDOS ; Just get it ret ; ; Get upper case character from console ; uppin: call conin ; Get character cp 'a' ; Test range ret c cp 'z'+1 ret nc add a,'A'-'a' ; Make upper case ret ; ; The GAME OF LIFE starts ; ExecGame: xor a ld hl,(Board1) ld bc,2*VidCol*(VidLine+1) ld e,l ld d,h inc de ld (hl),a ; Clear both game boards ldir ld (BoardSel),a ; Set current board call goto00 ; Home cursor ld a,lf call conout ; Give new line call visib ; Make cursor visible ld bc,VidCol ld hl,(Board1) add hl,bc ; Point to 2nd line SetLoop: push hl call uppin ; Get character from console pop hl or a jr z,SetLoop ; Wait for any ld (CurLoc),hl ; Save board pointer cp ' ' ; Test input jr z,StartGame cp MoveUp jr z,LineUp cp MoveDwn jr z,LineDown cp MoveLft jr z,LineLeft cp MoveRgt jr z,LineRight cp cr jr nz,SetLoop ; ; Input: ENTER ; ld a,(hl) ; Get cell content xor 1 ; Toggle it ld (hl),a dec a push hl call prPiece ; Print piece ld a,'D' jr SetCurs ; Move cursor left a column ; ; Input: Cursor up ; LineUp: ld de,VidCol or a sbc hl,de ; Calculate previous line call ChkLoc ; Check within range push hl ld a,'A' ; Move cursor up a row SetCurs: call prESC ; Set cursor movement pop hl jr SetLoop ; ; Input: Cursor down ; LineDown: ld de,VidCol add hl,de ; Calculate next line call ChkLoc ; Check within range push hl ld a,'B' ; Move cursor down a row jr SetCurs ; ; Input: Cursor left ; LineLeft: dec hl ; Calculate previous column call ChkLoc ; Check within range push hl ld a,'D' jr SetCurs ; Move cursor left a column ; ; Input: Cursor right ; LineRight: inc hl ; Calculate next column call ChkLoc ; Check within range push hl ld a,'C' jr SetCurs ; Move cursor right a column ; ; Check board pointer within range ; ENTRY Reg HL points to board location ; EXIT Reg HL points to board location ; ChkLoc: push hl ld de,(Board1) ; Point to first board or a sbc hl,de ; Test location within first board jr nc,RngOk? ; Maybe OutRng: pop hl ; Clean stack pop hl ; And level of call ld hl,(CurLoc) ; Reset board pointer jr SetLoop ; Reenter input RngOk?: add hl,de ; Reset location push hl ld hl,(Board1) ld de,VidCol*VidLine add hl,de ex de,hl pop hl or a sbc hl,de ; Test within first board jr nc,OutRng ; Nope pop hl ret ; ; Input: Blank - Start the "Game of Life" ; StartGame: call invisib ; Make cursor invisible GameLoop: call SelBoard ; Set current board ld bc,VidLine*VidCol ScanBoard: push hl pop ix ; Copy board call CountPop ; Calculate population cp 1 ; Test death jr z,Dead cp 2 jr z,Survive ; Test survival cp 3 jr z,Birth ; Test birth Dead: xor a StSec: ld (de),a ; Set unoccupied inc hl ; Advance pointers inc de dec bc ld a,b ; Test all locations scanned or c jr nz,ScanBoard ; Nope call prBoard ; Print board ld a,(BoardSel) cpl ; Toggle current board ld (BoardSel),a call conin ; Test character from console or a jr z,GameLoop ; Nope, so loop call goto00 ; Home cursor call visib ; Make cursor visible ret ; And stop the game Survive: ld a,(hl) ; Copy for survival jr StSec Birth: ld a,1 ; Set new piece jr StSec ; ; Calculate neighbours ; (Pieces that touch horizontally, vertically ; or diagonally are said to be neighboring pieces) ; CountPop: xor a ; Reset sum add a,(ix-VidCol-1) ; Add the eight neighbours add a,(ix-VidCol) add a,(ix-VidCol+1) add a,(ix-1) add a,(ix+1) add a,(ix+VidCol-1) add a,(ix+VidCol) add a,(ix+VidCol+1) ret ; ; Set current board ; EXIT Reg HL holds primary board ; Reg DE holds secondary board ; SelBoard: ld hl,(Board1) ; Set primary board ld de,(Board2) ; And secondary ld a,(BoardSel) ; Get current board or a ; Test selection jr z,Sel1 ex de,hl Sel1: ld (Primary),hl ; Save pointer ld (Secondary),de ret ; ; Print board ; prBoard: call goto00 ; Home cursor ld de,(Primary) ; Get primray ld b,VidLine ld hl,(Secondary) ; Get secondary LinLoop: push bc ld b,VidCol ColLoop: push bc ld a,(hl) ; Get from secondary inc hl inc de push hl push de dec a call prPiece ; Print piece pop de pop hl pop bc djnz ColLoop ; Get thru colums push hl pop hl pop bc djnz LinLoop ; Get thru lines ret dseg BoardSel: db 0 Primary: dw 0 Secondary: dw 0 CurLoc: dw 0 $memry: dw 0 Board1: dw 0 Board2: dw 0 end