home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
assemblr
/
library
/
sampler0
/
life.asm
< prev
next >
Wrap
Assembly Source File
|
1986-03-01
|
7KB
|
303 lines
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