Programming

;-----------------------------------------------------------------------------
;
; [] TET - 256 byte Tetris [][][]
; [][] []
; [] by []
; [] [] []
; [][][] [][] James David Chapman [][] [][] []
; [][][][] [] [] [] [][] []
;-----------------------------------------------------------------------------
;
; Here is a 256 byte version of of the all time classic game Tetris...
;
; To play, use the left and right SHIFT keys to move the current block, and
; the ALT key to rotate it. Press CONTROL to exit.
;
; I have not had the amount of time that I would have liked to write this
;program, so am sure that there is some optimization still left to be done. If
;you find a saving somewhere along the line, do let me know.
;
; Another idea for a 256 compo? - 256 scramble. Could be fun.
;
; James David Chapman 1999.
;-----------------------------------------------------------------------------
;Features:
; Cool looking blocks Almost as good as graphics mode ones.
; Random shape Taken from the timer.
; Random colours Also taken from timer.
; Rotatable shape I hated writing this bit, as expected.
; Block stop check Stops blocks when they hit another one
; Solidity Prevent sideways crashing into blocks.
; Dual loop timing Allows for multiple input per advance.
; End of game effect More of a useful side effect really!
; Full lines removed A quickly cobbled together routine.
; Frame Sets a maximum 10 block width for game.
; End program key Better than using Control-C etc.
;No space for:
; Scoring +2 for a line, +4 if the bottom line..
; Beeps a simple beep on line removal...
; Speedup should increase in speed over time...
; Graphics mode I had a lovely graphics version, and
; Nice enlarge effect a cool block effect which was too big.
;-----------------------------------------------------------------------------
;assembler startup ;assembled with:
.MODEL TINY ;TASM TET.ASM /m2 /uM520 /t >errors
MASM51 ;TLINK TET.OBJ /3 /x /t
QUIRKS
.386 ;uses pusha/popa (286+)
.CODE ;uses fs segment register (386+)
.STARTUP
;-----------------------------------------------------------------------------
;setup segs and vars
MOV AX,1 ;set colour screen mode 40 cols
INT 10H ;call BIOS
PUSH 040H ;set segment for keyboard flags
POP FS
PUSH 0B800H ;colour text segment
POP ES ;set ES to colour text segment
PUSH DS ;store data segment
PUSH ES
POP DS ;set DS to colour text segment
;-----------------------------------------------------------------------------
;get a new random coloured tile
NEWBLOCK:
XOR AX,AX ;clear AX
IN AL,40H ;get a random number from timer
MOV BP,AX ;use top bits to select block shape
SHR BP,5
JZ NEWBLOCK ;only 7 shapes so redo if 0
MOV BP,[BP+OFFSET SHAPETABLE-1] ;BP assumes SS, which saves segment
SHL BP,4 ; override here.
AND BP,0FF0H ;convert data byte into word
AND AL,0111B ;use bottom bits for colour
OR AL,1000B ;make colours bright
MOV AH,AL ;store colour
MOV DI,-60 ;set inital print position
;-----------------------------------------------------------------------------
;increase current block's row position
@@:
ADD DI,80 ;advance block down screen
;do mainloop
MOV BX,4 ;do main game loop 4 times per
MAINLOOP: ; block advance, to allow for more
DEC BX ; than one rotation/move per advance
JZ @B
;-----------------------------------------------------------------------------
;print game board frame, and clear any full lines
PUSHA ;store all general purpose registers
MOV SI,80*25+2 ;set SI/DI to bottom left of board
MOV DI,SI
BOARDLOOP:
XOR DX,DX ;zero block counter
MOV CL,10 ;each line is 10 blocks wide
CHECKLINE:
LODSW
CMP AH,7 ;check attribute of character to copy
JBE @F
INC DX ;count the number of consecutive blox
@@:
STOSW ;print the character/attribute
LOOP CHECKLINE
LODSW ;smaller form of add si,2
MOV AX,09B1H ;print right hand column
STOSW
CMP DX,10 ;check to see if there was a row of 10
JB @F
ADD DI,80 ;if there was, force di to skip a row
@@:
SUB DI,80+24 ;update di for next row
SUB SI,80+24 ;update si for next row
STOSW ;print left hand column
LODSW ;smaller form of add si,2
JNC BOARDLOOP ;if sub causes si to cross 0 then end
POPA ;restore general purpose registers
;-----------------------------------------------------------------------------
;get keyboard input
XOR CX,CX ;clear cx - allows cl usage*3 later
MOV SI,DI ;store old position - possible restore
PUSH BP ;store old rotation - possible restore
MOV CL,FS:[17H] ;get keyboard flags
RCR CL,1 ;split on set bits
JNC @F ;right shift-move block right
INC DI ;add 2 to position variable
INC DI
@@:
RCR CL,1
JNC @F ;left shift-move block left
DEC DI ;sub 2 from position variable
DEC DI
@@:
RCR CL,1
JNC @F ;control-escape
POP BP ;reset stack
POP DS ;restore data segment
RET ;end program
@@:
RCR CL,1
JNC @F ;alt-rotate block
;-----------------------------------------------------------------------------
;90 degree rotate function:
;
;ABCD EFGH IJKL MNOP ABCD => DHLP CGKO BFJN AEIM DHLP
; EFGH CGKO
; --> Displayed as: IJKL -> Displayed as: BFJN
; MNOP AEIM
;
;-----------------------------------------------------------------------------
MOV CL,16 ;create 16 bits in DX output
MOV DX,0EEEEH ;set bits where no ROR is to be done
RLOOP:
ROL BP,4 ;rotate bp, carry=last bit rotated
RCL DX,1 ;carry into dx, high dx into carry
JC SKIPROR ;skip ROR for preset bits in dx
ROR BP,1 ;adjust bp back 1 every 4 bits
SKIPROR:
LOOP RLOOP
MOV BP,DX ;store rotated value back into bp
@@:
;-----------------------------------------------------------------------------
;check plot
XOR DX,DX ;zero dl to supress ploting
CALL PLOTBLOCK ;check if plot would cover a block
JZ @F
POP BP ;use old value for rotate
MOV DI,SI ;use old value for position
PUSH DX ;set stack so reset is ok
@@:
POP DX ;reset stack
;plot the current block
MOV DX,BX ;set flag for normal plot block
CALL PLOTBLOCK ;bx just used as a non zero number
;should block stop?
JNZ NEWBLOCK ;there is a block below so do newblock
;-----------------------------------------------------------------------------
;wait for vertical retrace
PUSH AX
MOV CL,4 ;do vertwait 6 times per gameloop
VERTWAIT: ;this slows down the keyboard entry
MOV DX,3DAH ;VGA status register
@@:
IN AL,DX
TEST AL,8
JZ @B ;wait for vertical retrace to start
@@:
IN AL,DX
TEST AL,8
JNZ @B ;wait for vertical retrace to end
LOOP VERTWAIT ;loop 6 times
;-----------------------------------------------------------------------------
;erase block
XOR AX,AX ;clear colour
CALL PLOTBLOCK ;print block again, this time with
POP AX ;zero (black) attribute.
JMP MAINLOOP ;restart game loop
;-----------------------------------------------------------------------------
PLOTBLOCK:
;write a 4*4 block to the screen
PUSHA ;store registers
MOV CX,16 ;4*4=16
MOV AL,8 ;ascii 8 is the block we use, it
PLOTLOOP: ;is also used for test below.
TEST CX,11B ;every 4 prints...
JNZ @F
ADD DI,72 ;change print position to next line
@@:
ROL BP,1 ;test bp bits without disturbing bp
JC @F ;if no carry, then no block is to
SKIP: ;be printed here so skip over it.
INC DI
INC DI
JMP SHORT NEXTPLOT
@@:
;check overwrite
OR DL,DL ;if in overwrite checking mode,
JNZ @F ;do not print, report back on
OR DH,[DI+1] ;what you will be printing over,
JMP SHORT SKIP ;and skip printing.
@@:
;check below block ;if there is a block below this one
OR DH,[DI+81] ;then newblock will need to be run
CMP DI,80*24 ;check for end of screen
JB NOSTOP
OR DH,AL ;force newblock if end of screen
NOSTOP:
STOSW ;print part of the block here
NEXTPLOT:
LOOP PLOTLOOP ;do 16 of these
TEST DH,AL ;pass result of checks as zero flag
POPA ;for gameloop to interpret
RET
;-----------------------------------------------------------------------------
;data
;OOO. OO. .OO .O.. OOOO .OO. OOO.
;..O. .OO. OO. OOO. .... .OO. O...
SHAPETABLE LABEL BYTE ;the 7 tetris shapes used in the game
DB 11100010B ;setbit=print a block at this position
DB 11000110B ;loaded as words, cleared back to
DB 01101100B ;bytes and then shifted by a 4 bits to
DB 01001110B ;create blank top and bottom rows.
DB 11110000B ;..as it turns out not much of a
DB 01100110B ;saving.
DB 11101000B
;-----------------------------------------------------------------------------
END ;end of tetris game, phew.
;-----------------------------------------------------------------------------
;(c) JDC 1999.
;jchap@globalnet.co.uk
;http://www.users.globalnet.co.uk/~jchap/
;-----------------------------------------------------------------------------
|
A page from James David Chapman's website.
Located at: http://www.users.globalnet.co.uk/~jchap/ Site mirrored here at: http://www.j.chap.btinternet.co.uk |
|
|
This page last updated:
My rating for the page:
|