home *** CD-ROM | disk | FTP | other *** search
- COMMENT $
-
- FILE NAME GAM_LIFE.ASM
- TITLE THE GAME OF LIFE ON THE IBM-PC
- SOURCE DR. DOBB'S JOURNAL,#80,JUNE 1983
- AUTHOR SIMSON L. GARFINKEL
-
- *****************************
- * *
- * THE GAME OF LIFE *
- * *
- *****************************
-
- John Conway's mathematical game of life, implemented on
- the IBM/PC, by Simson L. Garfinkel.
-
- Written in 8088 assembly language using the Microsoft
- Macro Assembler.
-
- Notes on running the program:
-
- When program is run:
-
- 1. Screen clears.
- 2. User enters first generation from keyboard.
- Arrow keys move the cursor. INS key deposits
- a live cell, DEL removes a live cell, (in case
- the user makes a mistake.)
- 3. Pressing ESC starts program.
- 4. For each generation, cells which will have life
- on the next turn are inverted.
- 5. Screen is updated to next generation.
- 6. Keyboard is interrogated for command.
- 7. If ESC is pressed, program terminates.
- 8. If a number 0-9 is pressed, speed is selected.
- At speed 0, approx. 2.7 generations/sec are performed.
- At speed 9, each generation takes 3.5 sec.
- 9. program loops to #4.
-
- $
-
- ;global definitions
-
- LIVE EQU 02 ;CHARACTER FOR A LIVE CELL
- DEAD EQU 00 ;CHARACTER FOR A DEAD CELL
-
- REV EQU 70H ;REVERSE VIDEO (MARKS CELL TO LIVE)
- DARK EQU 2 ;NORMAL VIDEO (MARKS CELL TO DIE )
-
- TIME EQU 300 ;TIME DELAY BASE
-
- TERM EQU 27 ;CHARACTER TO EXIT MODE
-
- CSEG SEGMENT PARA PUBLIC 'CODE'
- START PROC FAR
- ASSUME CS:CSEG,DS:NOTHING,SS:NOTHING,ES:NOTHING
-
- ;SET UP RETURN LOCATION
- PUSH DS
- SUB AX,AX ;NOT I CAN GO HAME WHEN I'M FINISHED
- PUSH AX
-
- CALL ENTER ;ENTER BOARD
- MOV CX,0 ;INITIAL DELAY, 0
- MAIN:
- PUSH CX ;SAVE DELAY VARIABLE
- CMP CX,0
- JZ S13
-
- S1: PUSH CX
- MOV CX,TIME
- S11: PUSH CX
- MOV CX,TIME
- LOOP S12
- S12: POP CX
- LOOP S11
- POP CX
- LOOP S1 ;WHAT A TIME DELAY!
-
- S13: CALL COUNT ;COUNT UP EVERY CELL'S NEIGHBOURS,
- CALL UPDATE ;UPDATE SCREEN
- POP CX ;GET BACK THE TIME DELAY
-
- MOV AH,1 ;SEE IF USER HAS PUSHED A KEY
- INT 16H
- JZ MAIN ;NOPE - LOOP BACK
-
- MOV AH,0 ;GET THE CHARACTER OUT OF THE BUFFER
- INT 16H
-
- CMP AL,TERM
- JNZ S2
- RET ;FINISHED - GO BACK TO MS/DOS
-
- S2: CMP AL,'0' ;SEE IF IT IS A SPEED COMMAND
- JB MAIN
- CMP AL,'9'
- JNBE MAIN
- ;IT'S A NUMBER
- SUB AL,'0' ;NOW IT GOES FROM 0 TO 9
- MOV AH,0
- MOV CX,AX ;PUT IT IN CX
- JMP MAIN
- START ENDP
-
-
- ENTER PROC NEAR ;SUBROUTINE TO ENTER BOARD
- ;DEFINE SCAN-CODES:
- LEFT EQU 75
- RIGHT EQU 77
- UP EQU 72
- DOWN EQU 80
- POINT EQU 82
- DEL EQU 83
- ESC EQU 1
-
- CALL CLS ;CLEAR THE SCREEN
-
- ;REGISTERS ARE USED AS FOLLOWS:
- ;DH - Y POSITION
- ;DL - X POSITION
-
- MOV AH,12
- MOV DL,40
-
- E1: MOV BH,0 ;MOVE THE CURSOR TO X,Y POSITION
- MOV AH,2 ;CODE THE CURSOR MOVE
- INT 10H ;INTERRUPT FOR CURSOR MOVE
-
- MOV AH,0 ;SET UP TO READ THE NEXT KEYPRESS
- INT 16H ;KEYPRESS READ
-
- CMP AH,LEFT ;MAKE A RATIONAL DECISION ABOUT THE USERS
- JZ GO_LEFT ;ENTRY
- CMP AH,RIGHT
- JZ GO_RIGHT
- CMP AH,UP
- JZ GO_UP
- CMP AH,DOWN
- JZ GO_DOWN
- CMP AH,POINT
- JZ GO_POINT
- CMP AH,DEL
- JZ GO_DEL
-
- CMP AH,ESC
- JNZ E1 ;LOOP BACK - UNKNOWN COMMAND
- MOV DX,23*256 ;PUT THE CURSOR AT LOWER-LEFT HAND CORNER
- MOV AH,2
- INT 10H
- RET ;GO BACK TO CALLER
-
- GO_LEFT: ;MOVE LEFT IF I CAN
- CMP DL,0 ;IN LEFTMOST COLLUMN?
- JZ E1 ;YES - GO BACK
- SUB DL,1 ;NO - SUBTRACK ONE
- JMP E1 ;GO BACK
-
- GO_RIGHT: ;MOVE RIGHT IF I CAN
- CMP DL,79
- JZ E1
- ADD DL,1
- JMP E1
-
- GO_UP: ;GO UP IF I CAN
- CMP DH,0
- JZ E1
- SUB DH,1
- JMP E1
-
- GO_DOWN: ;GO DOWN IF I CAN
- CMP DH,24
- JZ E1
- ADD DH,1
- JMP E1
-
- GO_POINT: ;PUT A LIVE DOT WHERE THE CURSOR IS -- DON'T MOVE IT
- MOV AL,LIVE ;IT'S THE LIVE CHARACTER
- GP2: MOV CX,1 ;ONE CHARACTER TO WRITE
- MOV AH,10 ;CODE TO WRITE CHARACTER
- INT 10H ;DO IT
- JMP E1 ;GET NEXT COMMAND
-
- GO_DEL: ;DELETE CHARACTER AT CURSOR
- MOV AL,DEAD
- JMP GP2 ;LET GO_POINT DO THE REST
- ENTER ENDP
-
-
- CLS PROC NEAR ;SUBROUTINE TO CLEAR THE SCREEN
- MOV AX,6*256
- MOV CX,0
- MOV DX,24*256+79
- MOV BH,2
- INT 10H
- RET
- CLS ENDP
-
-
- COUNT PROC NEAR ;SUBROUTINE TO COUNT UP EVERY CELL'S NEIGHBOURS
- ;REGISTERS USED:
- ;DH,DL: Y,X OF SURRENT CELL BEING INTERROGATED
- ;DS : BASE OFFSET - INTO SCREEN MEMORY
- ;DI : OFFSET FOR CHARACTER PRESENTLY BEING LOOKED AT
- ;
- ;OUTLINE FOR EACH CHARACTER
- ; 1. COUNT UP NUMBER OF NEIGHBOURS
- ; 2. IF THREE NEIGHBOURS, OR IF TWO AND CELL IS LIVE, PUT
- ; A REV ON THE SCREEN AT THE ATTRIBUTE PASITION, ELSE
- ; PUT A DARK
- ; 3. GO TO NEXT CHARACTER
-
- CHK MACRO YY,XX
- LOCAL CH1,OFFS
- OFFS EQU (XX+YY*80)*2
- MOV CX,[DI+OFFS] ;GET BYTE TO CHECK
- CMP CL,LIVE ;CHECK TO SEE IF THIS CELL IS ALIVE
- JNZ CH1 ;NOPE
- ADD AL,1 ;YES - INCREASE NEIGHBOUR COUNT
- CH1:
- ENDM
- MOV AX,0Bb00H
- MOV DS,AX ;OFFSET VALUE FOR MONOCHROME DISPLAY
-
- MOV DH,1 ;START AT 1,1 AND GO TO 23,78
- MOV DL,1 ;TO PREVENT WRAP-ARROUND
-
- C1: MOV AX,160 ;GET TRUE OFFSET FROM DS INTO SCREEN MEMORY
- MUL DH
-
- MOV CX,DX
- MOV CH,00 ;JUST GET DL
- ADD AX,CX
- ADD AX,CX ;AX:=(DH*80+DL)*2
-
- MOV DI,AX ;DI:=AX
- MOV AX,0 ;AX WILL BE USED FOR NEIGHBOUR COUNTING
-
- CHK -1,-1 ;COUNT NUMBER OF NEIGHBOURS
- CHK -1, 0
- CHK -1,+1
- CHK 0,-1
- CHK 0,+1
- CHK +1,-1
- CHK +1, 0
- CHK +1,+1 ;TEST ALL OF THE NEIGHBOURS
-
- MOV CX,[DI] ;GET BYTE TO CHECK
- CMP AL,3
- JZ GIVE_LIFE ;LIFE IF HAS 3 NEIGHBOURS
- CMP CL,LIVE ;IS IT ALIVE?
- JNZ GIVE_DEATH ;NO
- CMP AL,2 ;HE LIVES IF HE HAS 2 NEIGHBOURS AND HE IS
- ;ALREADY ALIVE
- JNZ GIVE_DEATH ;NOPE
-
- GIVE_LIFE: ;MAKE THIS ONE ALIVE
- MOV CH,REV
- JMP C2
-
- GIVE_DEATH:
- MOV CH,DARK
- C2: MOV [DI],CX ;PUT BACK ON THE SCREEN
-
- NEXT_CELL:
- CMP DL,78 ;AM I AT THE END OF THE X LINE?
- JZ C3 ;YES
- ADD DL,1 ;NOPE
- JMP C1
- C3: MOV DL,1
- CMP DH,23 ;AM I AT THE END OF THE Y LINE?
- JZ C4 ;YES
- ADD DH,1 ;NOPE
- JMP C1
- C4: RET ;YES - GO HOME
- COUNT ENDP
-
- UPDATE PROC NEAR ;THIS UPDATES THE GENERATION ON THE SCREEN
- MOV AX,0Bb00H ;GET SCREEN OFFSET
- MOV DS,AX
-
- MOV BX,24*80*2-2 ;LOOP THROUGH ALL OF THE SCREEN BUT LAST LINE
- U1: MOV CX,[BX] ;LINE
- CMP CH,REV ;IS IT LIVE?
- JNZ U2 ;NO
- MOV CL,LIVE ;YES
- JMP U3
- U2: MOV CL,DEAD ;NO
- U3: MOV CH,DARK ;TURN OFF REVERSE
- MOV [BX],CX ;PUT IT BACK ON THE SCREEN
- SUB BX,2 ;LOOP BACK UNTIL DONE WITH THE SCREEN
- JG U1
- RET ;GO BACK TO CALLER
- UPDATE ENDP
- CSEG ENDS
-
- STACK SEGMENT PARA STACK 'STACK'
- DB 30 DUP('STACK ')
- STACK ENDS
-
- END
-