.TITLE LIVE -- A LIFE PROGRAM FOR VT52'S .SBTTL PHIL BUDNE@DEC, DECEMBER 1982 ; ************* STAND ALONE DEFINITIONS TKS==177560 TKB==TKS+2 TPS==TKS+4 TPB==TKS+6 R0=%0 R1=%1 R2=%2 R3=%3 R4=%4 R5=%5 SP=%6 PC=%7 .=1000 ; ************ END STAND ALONE DEFS STAR='* SPACE=<' > ; CELL STATE BITS DEAD=0 ;* DEAD, STABLE (MUST BE ZERO) ALIVE=1 ;* LIVE, STABLE CHANGE=2 BIRTH=DEAD+CHANGE ;* DEAD -> LIVE SOON DEATH=ALIVE+CHANGE ;* LIVE -> DEAD SOON SCRWID=70. ;DISPLAY WIDTH 1..SCRWID SCRLEN=24. ;DISPLAY LENGTH 1..SCRLEN SCRPAD=10. ;AMOUNT TO PAD SCREEN BY ON EACH SIDE SCRPDW=SCRPAD ;WIDTH PADDING SCRPDL=SCRPAD*2 ;LENGTH PADDING FLDWID=SCRWID+<2*SCRPDW> ;ACTUAL CELL FIELD WIDTH FLDLEN=SCRLEN+<2*SCRPDL> ;ACTUAL CELL FIELD LENGTH WIDTH=FLDWID+2 ;WIDTH W/ BUFFER CELLS LENGTH=FLDLEN+2 ;LENGTH W/ BUFFER ROWS TOP=WIDTH+1 ;FIRST ACTIVE CELL BOT=*WIDTH-2 ;LAST ACTIVE CELL VTOP=TOP++SCRPDW ;FIRST DISPLAYED CELL XTOP=1 ;X CURSOR POS FOR VTOP YTOP=1 ;Y CURSOR POS FOR VTOP ; 000000000000000000 ; 0xXXXXXXXXXXXXXXX0 ; 0XXXXXXXXXXXXXXXX0 ; 0XX,...........XX0 ; 0XX............XX0 ; 0XX............XX0 ; 0XX............XX0 ; 0XX............XX0 ; 0XXXXXXXXXXXXXXXX0 ; 0XXXXXXXXXXXXXXXX0 ; 000000000000000000 ; ; . CELLS IN BOARD, FLD, SCR ,=VTOP ; X CELLS IN BOARD, FLD x=TOP ; 0 CELLS IN BOARD UP=-WIDTH ;OFFSET TO GO UP 1 ROW DOWN=WIDTH ;DOWN 1 RON RIGHT=1 ;RIGHT 1 CELL LEFT=-1 ;LEFT 1 CELL ; LEFT RIGHT ; ------------------------- ; UP ! . ! . ! . ! ; ! . ! . ! . ! ; DOWN ! . ! . ! . ! ; ------------------------- ; SUML SUMC SUMR SUML: .BLKW 1 ;SUM OF CELLS IN LEFT COLM SUMC: .BLKW 1 ;SUM OF CELLS IN CENTER COLM SUMR: .BLKW 1 ;SUM OF CELLS IN RIGHT COLM STATES: .BLKW 4 ;SUM OF CELLS IN EACH STATE XPOS: .BLKW 1 ;EDITING X POSN YPOS: .BLKW 1 ;EDITING Y POSN CELPOS: .BLKW 1 ;EDITING POINTER INTO CELLS XTEMP: .BLKW 1 YTEMP: .BLKW 1 BRDSIZ=WIDTH*LENGTH BOARD: .BLKB BRDSIZ .EVEN .SBTTL PROGRAM STARTS HERE START: MOV #1000, SP ;GIVE US A STACK *** STAND ALONE *** BEGIN: JSR PC, CM.CLR ;CLEAR SCREEN TOPLVL: JSR PC, GETC ; HERE WITH CMD CHAR IN R0 1$: MOV #COMTBL, R1 2$: CMP (R1)+, R0 ;THIS IT? BEQ 3$ ;YEP! TST (R1)+ ;NO, DISCARD ADDR BNE 2$ ;END? MOV #'G-100, R0 ;FLEEP JSR PC, PUTC BR TOPLVL 3$: JSR PC, @(R1) ;GO!!, RETURN WITH CARRY SET IF ERROR BR TOPLVL ;GET ANOTHER CMD COMTBL: .WORD SPACE, CM.SPA ;SPACE - ERASE + EAST .WORD STAR, CM.NEW ;STAR - NEW CELL + EAST .WORD '., CM.NEW ;DOT - NEW CELL + EAST .WORD '?, CM.HLP ;? - BE HELPFUL .WORD 'S, CM.TOG ;S - TOGGLE .WORD 'W, CM.N ;W - NORTH .WORD 'X, CM.S ;X - SOUTH .WORD 'D, CM.E ;D - EAST .WORD 'A, CM.W ;A - WEST .WORD 'E, CM.NE ;E - NORTH EAST .WORD 'Q, CM.NW ;Q - NORTH WEST .WORD 'C, CM.SE ;C - SOUTH EAST .WORD 'Z, CM.SW ;Z - SOUTH WEST .WORD '5, CM.TOG ;5 - TOGGLE .WORD '8, CM.N ;8 - NORTH .WORD '2, CM.S ;2 - SOUTH .WORD '6, CM.E ;6 - EAST .WORD '4, CM.W ;4 - WEST .WORD '9, CM.NE ;9 - NORTH EAST .WORD '7, CM.NW ;7 - NORTH WEST .WORD '3, CM.SE ;3 - SOUTH EAST .WORD '1, CM.SW ;1 - SOUTH WEST .WORD '0, CM.SPA ;0 - CLEAR, ADVANCE .WORD 'G, CM.RUN ;G - GO! .WORD 'K, CM.CLR ;K - CLEAR SCREEN .WORD 'H, CM.HLP ;H - HELP!! .WORD 'R, CM.REF ;R - REFRESH .WORD 33, CM.ESC ;ESC - DO ESCAPE PROCESSING .WORD 'B-100, CM.W ;^B - WEST (ALA EMACS) .WORD 'D-100, CM.KILL ;^D - ERASE .WORD 'F-100, CM.E ;^F - EAST (ALA EMACS) .WORD 'H-100, CM.W ;^H - WEST .WORD 'J-100, CM.S ;^J - SOUTH .WORD 'L-100, CM.REF ;^L - REFRESH .WORD 'N-100, CM.S ;^N - SOUTH (ALA EMACS) .WORD 'P-100, CM.N ;^P - NORTH (ALA EMACS) .WORD 'Z-100, CM.QUIT ;^Z - QUIT .WORD 177, CM.DEL ;DEL - RUBOUT .WORD -1, 0 CM.HLP: JSR PC, CLRSCR ;CLEAR THE SCREEN MOV #HLPMES, R1 ;POINT TO TEXT JSR PC, PUTS ;OUTPUT IT JSR PC, GETC ;GET A CHAR JMP CM.REF ;RETURN, REFRESH CM.ESC: ;;; JSR PC, CHKC ;GET ESCAPE DISPATCH CHAR ;;; BCS 2$ ;WELL, MAYBE NOT JSR PC, GETC ;ALWAYS GET CHAR IN R0 MOV #ESCTBL, R1 ;POINT TO TABLE 1$: CMP (R1)+, R0 ;THIS IT? BEQ 3$ ;YEP! TST (R1)+ ;NO, DISCARD ADDR BNE 1$ ;END? 2$: JMP FLEEP ;YES, WE'VE BEEN HAD!! 3$: JMP @(R1) ;GO!!, RETURN STATUS TO TOP ESCTBL: .WORD 'A, CM.N ;A - NORTH ON VT52 KEYPAD .WORD 'B, CM.S ;B - SOUTH ON VT52 KEYPAD .WORD 'C, CM.E ;C - EAST ON VT52 KEYPAD .WORD 'D, CM.W ;D - WEST ON VT52 KEYPAD .WORD 'P, CM.RUN ;P - BLU ON VT52 KEYPAD == RUN .WORD 'Q, CM.CLR ;Q - RED ON VT52 KEYPAD == CLEAR .WORD 'R, RETT ;R - GRY ON VT52 KEYPAD == NO-OP .WORD 0, 0 CM.RUN: JSR PC, DOGEN ;DO IT!! JSR PC, FIXSCR ;FIX UP SCREEN TST STATES+ ;ANY LIVING CELLS BEQ 3$ ;NO!! MOV STATES+, R0 ADD STATES+, R0 BEQ 2$ ;STABLE 1$: JSR PC, CHKC ;ANY INPUT? BCC 4$ ;YES, RETURN ; MOV R1, SLPSEC ;SECONDS TO SLEEP ; BEQ CM.RUN ;NONE ; JSR PC, SLEEP ;DOZE BR CM.RUN ;LOOP 2$: ; "STABLE" 3$: ; "ALL DEAD" 4$: ; "HALTED" JMP CM.HOM ;HOME THE CURSOR, RETURN TRUE FIXSCR: JMP UPDATE CM.DEL: JSR PC, CM.W ;GO WEST.. BCC CM.KIL ;OK?, NOW KILL RTS PC CM.KIL: JSR PC, GO.ERA ;ERASE A CELL MOV #SPACE, R0 JSR PC, PUTC JSR PC, CURLFT CM.RTT: JMP RETT CM.TOG: JSR PC, GO.TOG ;TOGGLE A CELL BR CM.RTT CM.NEW: JSR PC, GO.DEP ;DEPOSIT A CELL CM.DEP: MOV #STAR, R0 BR CM.ER2 CM.REF: JSR PC, FRESH BR CM.RTT CM.N: JSR PC, GO.UP ;TRY TO GO UP BCS FLEEP ;NO GO JSR PC, CURUP ;MOVE CURSOR BR RETT CM.S: JSR PC, GO.DWN ;TRY TO GO DOWN BCS FLEEP ;SORRY! JSR PC, CURDWN ;MOVE CURSOR BR RETT CM.SPA: JSR PC, GO.ERA ;ERASE CM.ERA: MOV #SPACE, R0 ;SPACE CM.ER2: JSR PC, PUTC JSR PC, CURLFT ;GO BACK LEFT CM.E: JSR PC, GO.RGH ;TRY TO GO RIGHT BCS FLEEP ;FRAID NOT JSR PC, CURRGT ;MOVE CURSOR BR RETT CM.W: JSR PC, GO.LFT ;TRY TO GO LEFT BCS FLEEP ;SORRY CHARLIE JSR PC, CURLFT ;MOVE CURSOR BR RETT CM.NE: JSR PC, CM.N ;NORTH BCS FLEEP ;NO JSR PC, CM.E ;EAST BCC RETT ;OK JSR PC, CM.S ;EAST LOST, FIX UP BR FLEEP CM.NW: JSR PC, CM.N ;NORTH BCS FLEEP ;NO JSR PC, CM.W ;WEST BCC RETT ;OK JSR PC, CM.S ;WEST LOST, FIX UP BR FLEEP CM.SE: JSR PC, CM.S ;SOUTH BCS FLEEP ;NO JSR PC, CM.E ;EAST BCC RETT ;OK JSR PC, CM.N ;EAST LOST, FIX UP BR FLEEP CM.SW: JSR PC, CM.S ;SOUTH BCS FLEEP ;NO JSR PC, CM.W ;WEST BCC RETT ;OK JSR PC, CM.N ;WEST LOST, FIX UP BR FLEEP FLEEP: MOV #'G-100, R0 ;CTRL-G JSR PC, PUTC ;SAY IT BR RETF ;SAY YOU ARE SORRY CM.CLR: MOV #BOARD+TOP, R0 ;START OF ACTIVE BOARD 1$: MOVB #DEAD, (R0)+ ;MAKE DEAD CMP R0, #BOARD+BOT ;DONE? BLT 1$ ;NOPE JSR PC, CLRSCR ;ZAP SCREEN CM.HOM: JSR PC, CURHOM ;HOME CURSOR JSR PC, GO.HOM ;HOME EDIT POINTERS BR RETT CM.QUI: JSR PC, DOQUIT ;ENVIRONMENT DEPENDANT BR RETT .SBTTL CELL MANIPULATION GO.HOM: MOV #1, XPOS MOV #1, YPOS MOV #BOARD+VTOP, CELPOS RTS PC GO.DEP: MOVB #ALIVE, @CELPOS ;LIVE CELL RTS PC GO.TOG: TSTB @CELPOS ;DEAD CELL? BEQ GO.DEP ;YES, MAKE LIVE GO.ERA: MOVB #DEAD, @CELPOS ;DEAD CELL RTS PC GO.UP: DEC YPOS ;GO UP 1 LINE BEQ 1$ ;TOO FAR? ADD #UP, CELPOS ;MOVE CELL POINTER UP BR RETT 1$: INC YPOS ;FIX POSN RETF: SEC ;SET CARRY RTS PC GO.DWN: CMP YPOS, #SCRLEN ;COMPARE POSN TO SCREEN LENGTH BEQ RETF ;ON THE EDGE NOW INC YPOS ;ELSE, DOWN A LINE ADD #DOWN, CELPOS ;AND UPDATE CELL POINTER RETT: CLC ;HAPPY RETURN RTS PC GO.LFT: DEC XPOS ;OVER ONE ON X AXIS BEQ 1$ ;OOOPS! ADD #LEFT, CELPOS ;FIX CELL POINTER TOO BR RETT ;GOOD RETURN 1$: INC XPOS ;FIXUP POSN BR RETF ;FAIL GO.RGH: CMP XPOS, #SCRWID ;ON THE EDGE BEQ RETF ;YES, GO NO FURTHER INC XPOS ;SLIDE OVER ONE ADD #RIGHT, CELPOS ;SHIFT CELL POINTER BR RETT .SBTTL DOGEN - DO NEXT GENERATION ;CALL: ; JSR PC, DOGEN ;RETURNS: ; CHANGE BITS SET IN BOARD DOGEN: MOV #BOARD+TOP, R0 CLR STATES+ ;CLEAR DEAD COUNT CLR STATES+ ;CLEAR ALIVE COUNT CLR STATES+ ;CLEAR BIRTH COUNT CLR STATES+ ;CLEAR DEATH TOLL BEGROW: MOV #FLDWID, R1 ;LIVE CELLS IN A ROW CLR SUML ;NO LIVE CELLS TO THE LEFT CLR SUMC ;ACCUMULATE CENTER SUM BITB #ALIVE, UP(R0) ;ABOVE MAY HAVE CHANGE BIT SET BEQ 1$ ;ALIVE? INC SUMC ;IT WAS! 1$: TSTB DOWN(R0) ;BOTTOM CELL NOT CHANGED BEQ 2$ ;ALIVE? INC SUMC ;BUMP 2$: TSTB (R0) ;NOR CURRENT CELL BEQ DORGHT ;ALIVE? INC SUMC ;YES BR DORGHT ;JOIN THE 'HUMAN' RACE NXTCEL: INC R0 ;BUMP UP ONE CELL MOV SUMC, SUML ;CENTER COLM BECOMES LEFT MOV SUMR, SUMC ;AND RIGHT BECOMES CENTER DORGHT: CLR R2 ;CALCULATE RIGHT SUM BITB #ALIVE, UP+RIGHT(R0) ;UPPER RIGHT MIGHT BE CHANGED BEQ 1$ ;ALIVE? INC R2 ;YEP! 1$: BITB #ALIVE, RIGHT(R0) ;RIGHT, MAY HAVE CHANGED BEQ 2$ ;ALIVE? INC R2 ;BUMP COUNT 2$: TSTB RIGHT+DOWN(R0) ;BOTTOM RIGHT BEQ 3$ ;ALIVE? INC R2 3$: MOV R2, SUMR ;SAVE AS RIGHT SUM ADD SUMC, R2 ;ADD IN CENTER COLM ADD SUML, R2 ;AND LEFT COLM TSTB (R0) ;LOOK AT CURRENT CELL BNE 4$ ;LIVE? MOVB DEDTAB(R2), R2 ;GET NEW STATUS FOR DEAD CELL BR GONEXT 4$: MOVB LIVTAB-1(R2), R2 ;GET NEW STATUS FOR LIVE CELL GONEXT: MOVB R2, (R0) ;STORE NEW CELL STATE ASL R2 ;MAKE WORD OFFSET INC STATES(R2) ;TALLY STATES SOB R1, NXTCEL ;TICK OFF THIS CELL CMP #BOT+BOARD, R0 ;DONE WITH BOTTOM ROW? BLE DONE ADD #WIDTH-FLDWID+1, R0 ;GO TO FRONT OF NEXT ROW BR BEGROW ;AND START THE NEW ROW! .POPJ: DONE: RTS PC ; NEIGHBORS= 0 1 2 3 4 5 6 7 8 LIVTAB: .BYTE DEATH, DEATH, ALIVE, ALIVE, DEATH, DEATH, DEATH, DEATH, DEATH DEDTAB: .BYTE DEAD, DEAD, DEAD, BIRTH, DEAD, DEAD, DEAD, DEAD, DEAD .SBTTL FRESH - REPAINT SCREEN FRESH: JSR PC, CLRSCR ;CLEAR THE SCREEN MOV #BOARD+VTOP, R4 ;BOARD POINTER MOV #1, R1 ;CURSOR NOW AT X=1 MOV R1, R2 ;AND Y=1 MOV #YTOP, YTEMP ;STARTING ROW MOV #SCRLEN+1, R5 ;LINE COUNT BR FR.ROW ;START A ROW FR.NXT: INC XTEMP ;NEXT CELL IN A ROW INC R4 ;UPDATE CELL PTR FR.1ST: MOVB (R4), R0 ;GET CELL CONTENTS BEQ FR.GO ;EMPTY, KEEP GOING MOVB FR.TAB(R0), (R4) ;GET NEW STATE BEQ FR.GO ;QUIT IF NOW DEAD CMP R1, XTEMP ;IS X CORRECT? BNE 1$ ;NO, USE CURSOR FUNCTIONS CMP R2, YTEMP ;AND Y? BEQ 2$ ;YES, JUST TYPE * 1$: MOV XTEMP, R1 MOV YTEMP, R2 JSR PC, GOPOS 2$: MOV #STAR, R0 JSR PC, PUTC ;PRINT LIVE CELL INC R1 ;ADD 1 TO X FR.GO: SOB R3, FR.NXT ;TICK OFF THIS CELL DEC R5 ;TICK OFF THIS ROW BEQ FR.RET ;DONE INC YTEMP ;NO, START FRESH ROW ADD #WIDTH-SCRWID+1, R4 ;GO TO FRONT OF NEXT ROW FR.ROW: MOV #XTOP, XTEMP ;CURSOR SHOULD BE HERE MOV #SCRWID, R3 ;WIDTH OF A LINE BR FR.1ST FR.RET: RTS PC ; DEAD, ALIVE, BIRTH, DEATH FR.TAB: .BYTE DEAD, ALIVE, ALIVE, DEAD .SBTTL UPDATE - CHANGE SCREEN UPDATE: MOV #BOARD+VTOP, R4 ;BOARD POINTER CLR R1 ;UNKNOWN CURSOR POSN CLR R2 ;DITTO MOV #YTOP, YTEMP ;ROW=1 MOV #SCRLEN+1, R5 ;LINES+1 TO UPDATE BR UP.ROW ;START A ROW UP.NXT: INC XTEMP ;NEXT CELL IN A ROW INC R4 ;UPDATE CELL PTR UP.1ST: MOVB (R4), R0 ;GET CELL CONTENTS BEQ UP.GO ;EMPTY, KEEP GOING MOVB UP.TAB(R0), (R4) ;GET NEW STATE MOVB UP.CHR(R0), R0 ;GET NEW CHAR BEQ UP.GO ;QUIT IF NO CHANGE CMP R1, XTEMP ;IS X CORRECT? BNE 1$ ;NO, USE CURSOR FUNCTIONS CMP R2, YTEMP ;AND Y? BEQ 2$ ;YES, JUST TYPE CHAR 1$: MOV XTEMP, R1 ;LOAD NEW XTEMP MOV YTEMP, R2 ;AND YTEMP MOV R0, -(SP) ;SAVE R0 JSR PC, GOPOS ;CURSOR ADDRESSING MOV (SP)+, R0 ;RESTORE R0 2$: JSR PC, PUTC ;PRINT LIVE CELL (CHAR IN R0) INC R1 ;ADD 1 TO X UP.GO: SOB R3, UP.NXT ;TICK OFF THIS CELL DEC R5 ;TICK OFF THIS LINE BEQ UP.RET ;ALL DONE? INC YTEMP ;START FRESH ROW ADD #3, R4 ;GO TO FRONT OF NEXT ROW UP.ROW: MOV #XTOP, XTEMP MOV #FLDWID, R3 ;WIDTH OF A LINE BR UP.1ST UP.RET: RTS PC ; DEAD, ALIVE, BIRTH, DEATH UP.TAB: .BYTE DEAD, ALIVE, ALIVE, DEAD UP.CHR: .BYTE 0, 0, STAR, SPACE .SBTTL CURSOR PRIMATIVES - VT52 ONLY CLRSCR: MOV #CLRSTR, R1 JMP PUTS ; R1=X, R2=Y, 1 BASED GOPOS: MOV #33, R0 ;ESC JSR PC, PUTC MOV #'Y, R0 ;Y JSR PC, PUTC MOV R2, R0 ADD #31., R0 JSR PC, PUTC ;Y POSN MOV R1, R0 ADD #31., R0 BR PUTC ;X POSN CLRSTR: .BYTE 33, 'H, 33, 'J, 0 .EVEN CURUP: MOV #'A, R1 BR PUTESC CURDWN: MOV #'B, R1 BR PUTESC CURLFT: MOV #'D, R1 BR PUTESC CURRGT: MOV #'C, R1 BR PUTESC CURHOM: MOV #'H, R1 BR PUTESC PUTESC: MOV #33, R0 JSR PC, PUTC MOV R1, R0 BR PUTC ; ********* STAND ALONE GOODIES ********* PUTS: MOVB (R1)+, R0 BEQ 1$ JSR PC, PUTC BR PUTS 1$: RTS PC PUTC: TSTB @#TPS ;WAIT FOR PRINTER NOT BUSY BPL PUTC MOVB R0,@#TPB ;PRINT RTS PC GETC: TSTB @#TKS ;WAIT FOR A CHAR BPL GETC MOVB @#TKB,R0 ;INPUT RTS PC CHKC: TSTB @#TKS ;A CHAR? BPL 1$ ;NOPE MOVB @#TKB,R0 ;INPUT CLC ;HAPPY RET RTS PC 1$: SEC ;SAD RETURN RTS PC DOQUIT: HALT RTS PC .SBTTL HELP TEXT CR='M-100 LF='J-100 .MACRO LINE STR .ASCII \STR\ .ENDM HLPMES: LINE LINE <> LINE LINE LINE LINE LINE <> LINE LINE <============ ======> LINE <.* Create cell> LINE LINE LINE <0,SPACE Clear cell> LINE LINE LINE LINE <^J Down line> LINE <^H Move Left> LINE <^D Clear cell> LINE <^Z Exit> LINE LINE <> .ASCIZ /(type any key to return)/ .END START