Code archives/Algorithms/Binary Tetris
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
You'll have to hum the tune I'm afraid - however, it's much better if you have some progressively nicer wavs to play depending on the number of lines that the player got - bit of a parp for one line, and something cute for 4 etc. Plus a land sound. I've commented-out the loadsound, playsound commands where you should put them - just do a search for playsound - but they're all in the move_down() function. Loadsound is at the top natch. line1.wav - 1 line line2.wav - 2 lines line3.wav - 3 lines line4.wav - 4 lines land.wav - sound of brick landing I removed the error-checking for loading sounds from the init() function though. | |||||
;3FF - Harlequin Software 2002 - 2007 ;Updated version 30 January 2007 AppTitle "3FF - Harlequin Software" Graphics 320,360,0,2 Const ESCAPE=1, ENTER=28, SPACEBAR=57 Const UPARROW=200, DOWNARROW=208, LEFTARROW=203, RIGHTARROW=205, LEFTCONTROL=29 ;bit values for action Const PLAY=$1, QUITTED=$2, REDRAW=$4, LANDED=$8, GAMEOVER=$10, ESCAPED=$20 Const BITSUSED=$3F Const DRAWN=BITSUSED Xor REDRAW, NOTLANDED=BITSUSED Xor LANDED Const GAMEOVER_OR_ESCAPED=GAMEOVER Or ESCAPED ; Const EMPTYROW=$801, FULLROW=$FFF, FULLVISIBLE=$7FE, HIDDENROW=$7FE Const EAST=-1: WEST=1: CLOCKWISE=1: ANTICLOCKWISE=-1 ;East and West are inverted because - erm - read the guide :) Global currentrow, shifter, rotation, numlines, startrow Global speed, time, action Global tiles=CreateImage(16,16,4) ;Global line1snd=LoadSound("sound\line1.wav") ;Global line2snd=LoadSound("sound\line2.wav") ;Global line3snd=LoadSound("sound\line3.wav") ;Global line4snd=LoadSound("sound\line4.wav") ;Global landsnd=LoadSound("sound\land.wav") Dim leveldata(23) Dim levelpaused(21) Dim currentbrick(3,3) Dim nextbrick(3,3) Dim lines(3) SeedRnd MilliSecs() init() ;################################ M A I N L O O P ############################# Repeat draw_title() draw_next_brick() draw_score() Flip False action=0 Repeat Delay 1 If KeyHit(ENTER) Then action=PLAY If KeyHit(ESCAPE) Then action=QUITTED Until action If action=PLAY FlushKeys() action=REDRAW speed=1000 clear_arrays(True) get_a_brick() get_a_brick() ;to get "next brick" as well numlines=0 draw_score() time=MilliSecs() Repeat If action And LANDED get_a_brick() Else If MilliSecs()-time > speed move_down() time=MilliSecs() Else If KeyDown(DOWNARROW) And (MilliSecs()-time > 40) move_down() time=MilliSecs() Else If KeyHit(LEFTARROW) move_brick(WEST) Else If KeyHit(RIGHTARROW) move_brick(EAST) Else If KeyHit(UPARROW) rotate_brick(CLOCKWISE) Else If KeyHit(LEFTCONTROL) rotate_brick(ANTICLOCKWISE) EndIf EndIf EndIf EndIf EndIf EndIf EndIf If action And REDRAW If Not(action And LANDED) Then xor_brick() draw_play_area() Flip False action=action And DRAWN Else Delay 1 ;keep cpu usage down EndIf If KeyHit(SPACEBAR) Then pause() If KeyHit(ESCAPE) Then action=action Or ESCAPED Until action And GAMEOVER_OR_ESCAPED If action And GAMEOVER Then game_over_man() clear_arrays(False) EndIf Until action = QUITTED End ;############################################################# Function clear_arrays(clearlevel) Local rownumber If clearlevel For rownumber=0 To 21 leveldata(rownumber)=EMPTYROW Next leveldata(22)=HIDDENROW EndIf For rotation=0 To 3 For rownumber=0 To 3 nextbrick(rotation,rownumber)=0 Next Next Return End Function ;----------------------------------- Function collided(xadd) Local x, y, collision=False shifter=shifter + xadd If shifter>-1 ;shifting left or right? For y=currentrow To currentrow+3 If (currentbrick(rotation,y-currentrow) Shl shifter) And leveldata(y) Then collision=True Next Else For y=currentrow To currentrow+3 If (currentbrick(rotation,y-currentrow) Shr (shifter*-1)) And leveldata(y) Then collision=True Next EndIf If collision Then shifter=shifter + (xadd * -1) Return collision End Function ;----------------------------------- Function draw_next_brick() Local x, y For y=0 To 3 For x=0 To 3 DrawBlock tiles,284-(x Shl 4),20+(y Shl 4),((nextbrick(0,y) Shr (x+4)) And 1)+2 Next Next action=action Or REDRAW Return End Function ;----------------------------------- Function draw_play_area() Local row, column For row=2 To 21 For column=1 To 10 DrawBlock tiles,192-(column Shl 4),(row-2) Shl 4,(leveldata(row) Shr column) And 1 Next Next Return End Function ;----------------------------------- Function draw_score() Local x ;this function assumes no one will ever score more than 255 lines For x=0 To 7 DrawBlock tiles, 176-(x Shl 4), 340, ((numlines Shr x) And 1) + 2 Next Return End Function ;----------------------------------- Function draw_title() Local rownumber Restore title3ff For rownumber=2 To 21 Read leveldata(rownumber) Next draw_play_area() Return End Function ;----------------------------------- Function game_over_man() Color 0,0,0 Rect 48,136,128,32,True Color 255,255,255 Text 112,146,"GAME OVER!",True Rect 47,135,130,34,False Flip False Repeat Delay 1 Until KeyHit(ENTER) Or KeyHit(ESCAPE) FlushKeys() Return End Function ;----------------------------------- Function get_a_brick() Local randbrick, rownumber currentrow=startrow ;startrow is next brick's start row randbrick=Rand(0,6) Select randbrick Case 0 Restore column Case 1 Restore L Case 2 Restore r Case 3 Restore cube Case 4 Restore T Case 5 Restore Z Case 6 Restore S End Select startrow=(randbrick > 2) ;startrow depends on height of brick For rownumber=0 To 3 For rotation=0 To 3 currentbrick(rotation,rownumber)=nextbrick(rotation,rownumber) Read nextbrick(rotation,rownumber) Next Next rotation=0 action=action And NOTLANDED shifter=0 If collided(0) Then action=action Or GAMEOVER Else draw_next_brick() Return End Function ;----------------------------------- Function init() Local tilenumber, y, help$, error, r, g, b Restore initdata For tilenumber=0 To 3 Read r,g,b SetBuffer ImageBuffer(tiles,tilenumber) ClsColor r,g,b Cls Color r Shl 1, g Shl 1, b Shl 1 Text 4,1,tilenumber And 1 Next SetBuffer BackBuffer() Color 192,164,0 Text 16,342,"Lines:" For y=0 To 5 Read help$ Text 210,100+(26 * y),help$ Next Color 128,96,0 For y=0 To 5 Read help$ Text 220,113+(26 * y),help$ Next Return End Function ;----------------------------------- Function move_brick(xadd) xor_brick() If collided(xadd) xor_brick() Else action=action Or REDRAW EndIf Return End Function ;----------------------------------- Function move_down() Local newlines, rownumber, scrolloff, emptyrows, n xor_brick() currentrow=currentrow+1 If collided(0) newlines=0 action=action Or LANDED currentrow=currentrow-1 xor_brick() For rownumber=currentrow To currentrow+3 If leveldata(rownumber)=FULLROW newlines=newlines+1 lines(rownumber-currentrow)=rownumber currentbrick(rotation,rownumber-currentrow)=0 leveldata(rownumber)=FULLVISIBLE ;ready to scroll off EndIf Next If newlines ; Select newlines ; Case 1 PlaySound(line1snd) ; Case 2 PlaySound(line2snd) ; Case 3 PlaySound(line3snd) ; Case 4 PlaySound(line4snd) ; End Select For scrolloff=0 To 9 For rownumber=0 To 3 If lines(rownumber) If (rownumber And 1) leveldata(lines(rownumber))=leveldata(lines(rownumber)) Shr 1 Else leveldata(lines(rownumber))=leveldata(lines(rownumber)) Shl 1 EndIf EndIf Next draw_play_area() Delay 30: Flip False Next Delay 50 For rownumber=0 To 3 If lines(rownumber) Then leveldata(lines(rownumber))=EMPTYROW lines(rownumber)=0 Next For emptyrows=0 To newlines For rownumber=currentrow+3 To 1 Step-1 If leveldata(rownumber)=EMPTYROW And leveldata(rownumber-1)>EMPTYROW leveldata(rownumber)=leveldata(rownumber-1) leveldata(rownumber-1)=EMPTYROW EndIf Next draw_play_area() Delay 30: Flip False Next n=numlines+newlines If (n -(n Mod 10)) > (numlines-(numlines Mod 10)) Then speed=speed-(speed * 0.1) ;speed + 10% every 10 lines numlines=numlines+newlines draw_score() ; Else ; PlaySound(landsnd) EndIf Else action=action Or REDRAW EndIf Return End Function ;----------------------------------- Function pause() Local oldtime, rownumber oldtime=MilliSecs()-time Restore pauseddata For rownumber=2 To 21 levelpaused(rownumber)=leveldata(rownumber) Read leveldata(rownumber) Next draw_play_area() Flip False Repeat Delay 1 If KeyHit(ESCAPE) Then action=action Or ESCAPED Until KeyHit(SPACEBAR) Or (action And ESCAPED) FlushKeys() If Not(action And ESCAPED) For rownumber=2 To 21 leveldata(rownumber)=levelpaused(rownumber) Next draw_play_area() Flip False time=MilliSecs()-oldtime EndIf Return End Function ;----------------------------------- Function rotate_brick(modifier) Local oldrotation xor_brick() oldrotation=rotation rotation=rotation + modifier If rotation > 3 Then rotation=0 ElseIf rotation < 0 Then rotation=3 If collided(0) If shift_collided() rotation=oldrotation xor_brick() Else action=action Or REDRAW EndIf Else action=action Or REDRAW EndIf Return End Function ;----------------------------------- Function shift_collided() ;rotation caused a collision - can we shift brick sideways? If collided(-1) If collided(1) If collided(-2) Return collided(2) EndIf EndIf EndIf Return False End Function ;----------------------------------- Function xor_brick() Local y If shifter>-1 For y=currentrow To currentrow+3 leveldata(y) = (leveldata(y)) Xor currentbrick(rotation,y-currentrow) Shl shifter Next Else For y=currentrow To currentrow+3 leveldata(y) = (leveldata(y)) Xor currentbrick(rotation,y-currentrow) Shr (shifter*-1) Next EndIf Return End Function ;----------------------------------- .initdata Data 32,32,32 ;Grey 0 Data 127,127,127 ;Grey 1 Data 48,32,64 ;Purple 0 Data 96,64,127 ;Purple 1 Data "Play:","Move:","Rotate right:","Rotate left:","Pause:","Quit:" Data "Enter","Cursor keys","Up-arrow","L-Ctrl","Spacebar","Escape" .title3ff Data 0,0,0,0,$7FE,0,$36C,$148,$36C,$148,$348,0,$7FE,0,0,0,0,0,0,0,0,$7FE ;brickpatterns .column Data $40,$00,$40,$00, $40,$00,$40,$00, $40,$F0,$40,$F0, $40,$00,$40,$00 .T Data $00,$00,$00,$00, $40,$40,$00,$40, $E0,$60,$E0,$C0, $00,$40,$40,$40 .cube Data $00,$00,$00,$00, $60,$60,$60,$60, $60,$60,$60,$60, $00,$00,$00,$00 .r Data $00,$00,$00,$00,$20,$40,$30,$00,$20,$70,$20,$70,$60,$00,$20,$10 .L Data $00,$00,$00,$00,$40,$00,$C0,$20,$40,$E0,$40,$E0,$60,$80,$40,$00 .Z Data $00,$00,$00,$00, $C0,$20,$C0,$20, $60,$60,$60,$60, $00,$40,$00,$40 .S Data $00,$00,$00,$00, $60,$40,$60,$40, $C0,$60,$C0,$60, $00,$20,$00,$20 .pauseddata Data $FFE,$FFE,$FFE,$60E,$666,$666,$666,$666,$666,$60E,$67E,$67E,$67E,$67E Data $67E,$67E,$67E,$FFE,$FFE,$FFE |
Comments
| ||
Note - due to the discovery of a bug in BlitzPlus's Random Number Generator after posting the above code, you should add a Default to the Select clause that picks a random brick - something along the lines of: RunTimeError "Random number generated outside specified range" Problem current as of 07 February 2007 I suppose that good programming practice demands that you should always have a default clause to trap errors, but who knew. |
| ||
If..EndIf's nested 7 deep? You're doing it wrong ;) |
| ||
I don't think it's that bad. I woud do it like this though: If action And LANDED get_a_brick() ElseIf MilliSecs()-time > speed move_down() time=MilliSecs() ElseIf KeyDown(DOWNARROW) And (MilliSecs()-time > 40) move_down() time=MilliSecs() ElseIf KeyHit(LEFTARROW) move_brick(WEST) ElseIf KeyHit(RIGHTARROW) move_brick(EAST) ElseIf KeyHit(UPARROW) rotate_brick(CLOCKWISE) ElseIf KeyHit(LEFTCONTROL) rotate_brick(ANTICLOCKWISE) EndIf |
Code Archives Forum