flat assembler
Message board for the users of flat assembler.
Index
> Assembly > New version of TetrOS |
Author |
|
Tomasz Grysztar 03 Nov 2019, 17:49
While preparing to organize a 512-byte coding contest for the 20th anniversary of fasm, I decided to revisit my own old piece. Obviously, as an organizer I'm not going to participate in the new contest myself, but perhaps an example from me could serve as an inspiration for potential contestants.
TetrOS is a boot sector game I wrote in 2004 for a 512-byte OS contest we had at the time. It did not attempt to be anything more than a game, but I thought that the fact that it is bootable (plus the pun in the name) should be enough for it to qualify. I did submit it in a bit of a hurry, though, and it was a bit unpolished - as I admitted in the comment to my submission. It did not win any notable place in the actual contest, but is had been appreciated nonetheless. Some kind soul has even given it a page on MobyGames with nice little description and several screenshots. It is worth noting that many of game design choices, like the width of well (12 columns instead of standard 10), were made to replicate the feel of my personal favorite, a Tetris built into DOS Navigator (which I used to play for hours to clear my mind while coding in the DOS days). The main reason why I defined all the pieces directly through data (instead of attempting to generate them with some trick) was that I wanted all of them to behave the same as I was used to. A feature that did not make the cut was the scoring system - Tetris in DOS Navigator gave you more points for clearing the lines higher in the well, and that encouraged more risky play patterns. I liked that approach, but then I decided to remove it from TetrOS before submission, because I thought that it might appear random at first and give impression of something that had to be done because of the space constraints (while it was in fact the opposite of that). Now, as I went back to this old code and started cleaning it up, I found out that in many places it could be optimized better, some of the instructions were in fact completely redundant. I realized I may be able to reclaim enough space to fit some additional features. So I did my best and I managed to add what felt like the most missing one - a preview of the forthcoming block. And here it comes, a shiny new version: Code: ; TetrOS version 1.02 ; by Tomasz Grysztar ; Requires VGA and 80386 CPU or higher. ; Version 1.01 was submitted in 2004 for a 512-byte OS contest. ; For your playing pleasure, it's a boot-sector Tetris game. ; Keys: ; Left - move left ; Right - move right ; Up - rotate ; Down - drop ; Esc - new game at any time format binary as 'img' org 7C00h ROWS = 23 COLUMNS = 12 DELAY = 4 virtual at 46Ch clock dw ? end virtual virtual at bp current dw ? current_column db ? current_row dw ? next dw ? score dw ? last_tick dw ? random dw ? end virtual label well at 9000h label pics at well-2*64 xor ax,ax mov sp,8000h mov ss,ax mov ds,ax mov es,ax push ax push start retf start: mov bp,sp mov al,13h int 10h mov di,3*4 mov ax,int_3 stosw xor ax,ax stosw lea di,[next] stosw ; [next] stosw ; [score] mov ax,[clock] stosw ; [last_tick] stosw ; [random] mov di,pics mov cx,64 mov al,1 ; remove this instruction to get randomized background rep stosb mov ah,15 mov dx,7 @@: mov al,15 stosb mov al,ah mov cl,6 rep stosb mov ax,0708h stosb dec dx jnz @b mov cl,8 rep stosb or ax,-1 stosw stosw stosw mov cl,ROWS+4 mov ax,11b + (-1) shl (COLUMNS+2) rep stosw new_piece: mov bx,[random] mov ax,257 mul bx inc ax mov cx,43243 div cx mov [random],dx and bx,7 jz new_piece shl bx,1 mov ax,[pieces+bx-2] xchg ax,[next] or ax,ax jz new_piece lea di,[current] stosw ; [current] mov al,COLUMNS/2 stosb ; [current_column] mov ax,well + (3+ROWS-4)*2 stosw ; [current_row] mov si,no_move call first_move jz update_screen inc bp ; game over process_key: xor ah,ah int 16h mov al,ah dec ah jz start test bp,bp jnp process_key mov si,rotate cmp al,48h je action mov si,left cmp al,4Bh je action mov si,right cmp al,4Dh je action cmp al,50h jne main_loop drop_down: call do_move_down jz drop_down action: call do_move update_screen: mov bx,7 mov dx,12h mov ah,2 int 10h mov cl,12 print_score: mov ax,[score] shr ax,cl and al,0Fh cmp al,10 sbb al,69h das mov ah,0Eh int 10h sub cl,4 jnc print_score push es push 0A000h pop es mov si,well+3*2 mov di,320*184+160-(COLUMNS*8)/2 draw_well: lodsw push si mov dl,COLUMNS xchg bx,ax shr bx,2 call draw_row pop si cmp si,well+(3+ROWS)*2 jb draw_well mov di,320*100+250 mov bx,[next] draw_preview: mov dl,4 call draw_row cmp di,320*68 ja draw_preview pop es main_loop: mov ah,1 int 16h jnz process_key mov ax,[clock] sub ax,[last_tick] cmp al,DELAY jb main_loop add [last_tick],ax call do_move_down jz update_screen mov dx,1 mov si,well+3*2 mov di,si check_row: lodsw inc ax jz remove_row dec ax stosw jmp check_next_row remove_row: shl dx,1 check_next_row: cmp di,well+(3+ROWS)*2 jb check_row add [score],dx jmp new_piece draw_row: push di blit_row: shr bx,1 mov si,pics jnc blit_block add si,64 blit_block: mov cx,8 rep movsb add di,320-8 test si,111111b jnz blit_block sub di,320*8-8 dec dx jnz blit_row pop di sub di,320*8 ret do_move_down: mov si,down do_move: mov ax,clear_piece int3 first_move: push dword [current] call si xor ch,ch mov ax,test_piece int3 mov al,draw_piece and 0FFh pop edx or ch,ch jz @f mov dword [current],edx @@: int3 no_move: ret down: sub byte [current_row],2 ret left: dec [current_column] ret right: inc [current_column] ret rotate: mov cx,3 @@: bt [current],cx rcl dx,1 add cl,4 cmp cl,16 jb @b sub cl,17 jnc @b mov [current],dx ret int_3: mov di,[current_row] mov bx,4 on_piece_row: mov dx,[current] mov cl,bh shr dx,cl and dx,1111b mov cl,[current_column] add cl,4 shl edx,cl shr edx,4 call ax add bh,4 scasw dec bl jnz on_piece_row iret clear_piece: not dx and [di],dx ret test_piece: test [di],dx jz @f inc ch @@: ret draw_piece: or [di],dx ret pieces dw 0010001000100010b dw 0010011000100000b dw 0010001001100000b dw 0100010001100000b dw 0000011001100000b dw 0100011000100000b dw 0010011001000000b rb 7C00h+510-$ dw 0AA55h You may notice a comment that encourages to remove one of the instructions - this change makes the background color be chosen randomly every time the game is restarted. It is fun, but also some of the color combinations look horrible (a perk of the randomness), so I decided to not enable this by default and keep the original look, even though this change also makes the code even smaller. One of the tricks in TetrOS is to hook the interrupt 3 to make a function callable with just a single byte (INT3 instruction). Converting the function to an interrupt also makes it automatically preserve flags - which is actually relevant here and allows to save on PUSHF/POPF that would be otherwise needed. Nonetheless, in the new version the INT3 function is only called three times and the trick no longer gains anything. It breaks even, though, so I decided to keep it - as I consider it a kind of a trademark of TetrOS that I should not remove without a really good reason. Because I deemed the addition of a piece preview the most important one, I did not manage to bring back the height-dependent scoring system this time. Perhaps this is something I may still work towards in the future.
|
||||||||||||||||||||
03 Nov 2019, 17:49 |
|
Mike Gonta 04 Nov 2019, 09:11
Tomasz Grysztar wrote: While preparing to organize a 512-byte coding contest for the 20th anniversary of fasm, ... *Of course, there is always emulation, which is the sincerest form of flattery. |
|||
04 Nov 2019, 09:11 |
|
Tomasz Grysztar 04 Nov 2019, 11:49
Mike Gonta wrote: It seems quite fitting (in an historical context) that such a contest (that is dependent on the BIOS)* coincides with Intel saying "Bye to BIOS" by 2020. Back to the new TetrOS: I made another kind of screenshot, this is my old DOS PC running it. Note that it's a variant that has instruction responsible for background color commented out to enable random coloring.
|
||||||||||
04 Nov 2019, 11:49 |
|
Tomasz Grysztar 04 Nov 2019, 12:59
Another previously overlooked (and substantial) optimization allowed me to implement a height-dependent scoring system that I wanted. Please welcome version 1.03:
Code: ; TetrOS version 1.03 ; by Tomasz Grysztar ; Requires VGA and 80386 CPU or higher. ; Version 1.01 was submitted in 2004 for a 512-byte OS contest. ; For your playing pleasure, it's a boot-sector Tetris game. ; Keys: ; Left - move left ; Right - move right ; Up - rotate ; Down - drop ; Esc - new game at any time format binary as 'img' org 7C00h ROWS = 23 COLUMNS = 12 DELAY = 4 virtual at 46Ch clock dw ? end virtual virtual at bp current dw ? current_column db ? current_row dw ? next dw ? score dw ? last_tick dw ? random dw ? end virtual label well at 9000h label pics at well-2*64 xor ax,ax mov sp,8000h mov ss,ax mov ds,ax mov es,ax push ax push start retf start: mov bp,sp mov al,13h int 10h mov di,3*4 mov ax,int_3 stosw xor ax,ax stosw lea di,[next] stosw ; [next] stosw ; [score] mov ax,[clock] stosw ; [last_tick] stosw ; [random] mov di,pics mov cx,64 mov al,1 ; remove this instruction to get randomized background rep stosb mov ah,15 mov dx,7 @@: mov al,15 stosb mov al,ah mov cl,6 rep stosb mov ax,0708h stosb dec dx jnz @b mov cl,8 rep stosb or ax,-1 stosw stosw stosw mov cl,ROWS+4 mov ax,not ( (1 shl COLUMNS - 1) shl ((16-COLUMNS)/2) ) rep stosw new_piece: mov bx,[random] mov ax,257 mul bx inc ax mov cx,43243 div cx mov [random],dx and bx,7 jz new_piece shl bx,1 mov ax,[pieces+bx-2] xchg ax,[next] or ax,ax jz new_piece lea di,[current] stosw ; [current] mov al,6 stosb ; [current_column] mov ax,well + (3+ROWS-4)*2 stosw ; [current_row] mov si,no_move call first_move jz update_screen inc bp ; game over process_key: xor ah,ah int 16h mov al,ah dec ah jz start test bp,bp jnp process_key mov si,rotate cmp al,48h je action mov si,left cmp al,4Bh je action mov si,right cmp al,4Dh je action cmp al,50h jne main_loop drop_down: call do_move_down jz drop_down action: call do_move update_screen: mov bx,7 mov dx,12h mov ah,2 int 10h mov cl,12 print_score: mov ax,[score] shr ax,cl and al,0Fh cmp al,10 sbb al,69h das mov ah,0Eh int 10h sub cl,4 jnc print_score push es push 0A000h pop es mov si,well+3*2 mov di,320*184+160-(COLUMNS*8)/2 draw_well: lodsw push si mov dl,COLUMNS xchg bx,ax shr bx,(16-COLUMNS)/2 call draw_row pop si cmp si,well+(3+ROWS)*2 jb draw_well mov di,320*100+250 mov bx,[next] draw_preview: mov dl,4 call draw_row cmp di,320*68 ja draw_preview pop es main_loop: mov ah,1 int 16h jnz process_key mov ax,[clock] sub ax,[last_tick] cmp al,DELAY jb main_loop add [last_tick],ax call do_move_down jz update_screen movzx dx,byte [current_row] shr dx,2 mov si,well+3*2 mov di,si check_row: lodsw inc ax jz remove_row dec ax stosw jmp check_next_row remove_row: shl dx,1 check_next_row: cmp di,well+(3+ROWS)*2 jb check_row add [score],dx jmp new_piece draw_row: push di blit_row: shr bx,1 mov si,pics jnc blit_block add si,64 blit_block: mov cx,8 rep movsb add di,320-8 test si,111111b jnz blit_block sub di,320*8-8 dec dx jnz blit_row pop di sub di,320*8 ret do_move_down: mov si,down do_move: mov al,1 int3 first_move: push dword [current] call si xor ax,ax int3 inc ax pop edx test ah,ah jz @f mov dword [current],edx @@: int3 no_move: ret down: sub byte [current_row],2 ret left: dec [current_column] ret right: inc [current_column] ret rotate: mov cx,3 @@: bt [current],cx rcl dx,1 add cl,4 cmp cl,16 jb @b sub cl,17 jnc @b mov [current],dx ret int_3: mov di,[current_row] mov bx,4 on_piece_row: mov dx,[current] mov cl,bh shr dx,cl and dx,1111b mov cl,[current_column] add cl,4 shl edx,cl shr edx,4 test al,al jz @f xor [di],dx @@: test [di],dx jz @f inc ah @@: add bh,4 scasw dec bl jnz on_piece_row iret pieces dw 0010001000100010b dw 0010011000100000b dw 0010001001100000b dw 0100010001100000b dw 0000011001100000b dw 0100011000100000b dw 0010011001000000b rb 7C00h+510-$ dw 0AA55h Code: ; TetrOS version 1.04 ; by Tomasz Grysztar ; Requires VGA and 80386 CPU or higher. ; Version 1.01 was submitted in 2004 for a 512-byte OS contest. ; For your playing pleasure, it's a boot-sector Tetris game. ; Keys: ; Left - move left ; Right - move right ; Up - rotate ; Down - drop ; Esc - new game at any time format binary as 'img' org 7C00h ROWS = 23 COLUMNS = 12 BACKGROUND = 0 ; background color, 0 for randomized virtual at 46Ch clock dw ? end virtual virtual at bp current dw ? current_column db ? current_row dw ? next dw ? score dw ? last_tick dw ? random dw ? end virtual label well at 9000h label pics at well-2*64 xor ax,ax mov sp,8000h mov ss,ax mov ds,ax mov es,ax push ax push start retf start: mov bp,sp mov al,13h int 10h mov di,3*4 mov ax,int_3 stosw xor ax,ax stosw lea di,[next] stosw ; [next] stosw ; [score] mov ax,[clock] stosw ; [last_tick] stosw ; [random] mov di,pics mov cx,64 if BACKGROUND mov ax,0F00h + BACKGROUND else mov ah,15 end if rep stosb mov dx,7 @@: mov al,15 stosb mov al,ah mov cl,6 rep stosb mov ax,0708h stosb dec dx jnz @b mov cl,8 rep stosb or ax,-1 stosw stosw stosw mov cl,ROWS+4 mov ax,not ( (1 shl COLUMNS - 1) shl ((16-COLUMNS)/2) ) rep stosw new_piece: mov bx,[random] mov ax,257 mul bx inc ax mov cx,43243 div cx mov [random],dx and bx,7 jz new_piece shl bx,1 mov ax,[pieces+bx-2] xchg ax,[next] or ax,ax jz new_piece lea di,[current] stosw ; [current] mov al,6 stosb ; [current_column] mov ax,well+(3+ROWS-4)*2 stosw ; [current_row] mov si,no_move call first_move jz update_screen inc bp ; game over process_key: xor ah,ah int 16h mov al,ah dec ah jz start test bp,bp jnp process_key mov si,rotate cmp al,48h je action mov si,left cmp al,4Bh je action mov si,right cmp al,4Dh je action cmp al,50h jne main_loop drop_down: call do_move_down jz drop_down action: call do_move update_screen: mov bx,7 mov dx,12h mov ah,2 int 10h mov cl,12 print_score: mov ax,[score] shr ax,cl and al,0Fh cmp al,10 sbb al,69h das mov ah,0Eh int 10h sub cl,4 jnc print_score push es push 0A000h pop es mov si,well+3*2 mov di,320*184+160-(COLUMNS*8)/2 draw_well: lodsw push si mov dl,COLUMNS xchg bx,ax shr bx,(16-COLUMNS)/2 call draw_row pop si cmp si,well+(3+ROWS)*2 jb draw_well mov di,320*100+250 mov bx,[next] draw_preview: mov dl,4 call draw_row cmp di,320*68 ja draw_preview pop es main_loop: mov ah,1 int 16h jnz process_key mov al,-1 xor al,byte [score+1] and al,11b mov cx,[clock] sub cx,[last_tick] cmp cl,al jbe main_loop add [last_tick],cx call do_move_down jz update_screen movzx dx,byte [current_row] shr dx,2 mov si,well+3*2 mov di,si check_row: lodsw inc ax jz remove_row dec ax stosw jmp check_next_row remove_row: shl dx,1 check_next_row: cmp di,well+(3+ROWS)*2 jb check_row add [score],dx jmp new_piece draw_row: push di blit_row: shr bx,1 mov si,pics jnc blit_block add si,64 blit_block: mov cx,8 rep movsb add di,320-8 test si,111111b jnz blit_block sub di,320*8-8 dec dx jnz blit_row pop di sub di,320*8 ret do_move_down: mov si,down do_move: mov al,1 int3 first_move: push dword [current] call si xor ax,ax int3 inc ax pop edx test ah,ah jz @f mov dword [current],edx @@: int3 no_move: ret down: sub byte [current_row],2 ret left: dec [current_column] ret right: inc [current_column] ret rotate: mov cx,3 @@: bt [current],cx rcl dx,1 add cl,4 cmp cl,16 jb @b sub cl,17 jnc @b mov [current],dx ret int_3: mov di,[current_row] mov bx,4 on_piece_row: mov dx,[current] mov cl,bh shr dx,cl and dx,1111b mov cl,[current_column] add cl,4 shl edx,cl shr edx,4 test al,al jz @f xor [di],dx @@: test [di],dx jz @f inc ah @@: add bh,4 scasw dec bl jnz on_piece_row iret pieces dw 0010001000100010b dw 0010011000100000b dw 0010001001100000b dw 0100010001100000b dw 0000011001100000b dw 0100011000100000b dw 0010011001000000b rb 7C00h+510-$ dw 0AA55h
Last edited by Tomasz Grysztar on 05 Dec 2019, 15:51; edited 1 time in total |
|||||||||||||||||||||
04 Nov 2019, 12:59 |
|
Tomasz Grysztar 23 Nov 2019, 14:05
By finally letting go of the INT3 trick I could strip off a couple more bytes. I have no good use for them, so this is still the same as 1.04 functionally. But this is yet another testament to how ridiculously under-optimized the initial version was.
Code: ; TetrOS version 1.04a ; by Tomasz Grysztar ; Requires VGA and 80386 CPU or higher. ; Version 1.01 was submitted in 2004 for a 512-byte OS contest. ; For your playing pleasure, it's a boot-sector Tetris game. ; Keys: ; Left - move left ; Right - move right ; Up - rotate ; Down - drop ; Esc - new game at any time format binary as 'img' org 7C00h ROWS = 23 COLUMNS = 12 BACKGROUND = 0 ; background color, 0 for randomized virtual at 46Ch clock dw ? end virtual virtual at bp current dw ? current_column db ? current_row dw ? next dw ? score dw ? last_tick dw ? random dw ? end virtual label well at 9000h label pics at well-2*64 xor ax,ax mov sp,8000h mov ss,ax mov ds,ax mov es,ax push ax push start retf start: mov bp,sp mov al,13h int 10h xor ax,ax lea di,[next] stosw ; [next] stosw ; [score] mov ax,[clock] stosw ; [last_tick] stosw ; [random] mov di,pics mov cx,64 if BACKGROUND mov ax,0F00h + BACKGROUND else mov ah,15 end if rep stosb mov dx,7 @@: mov al,15 stosb mov al,ah mov cl,6 rep stosb mov ax,0708h stosb dec dx jnz @b mov cl,8 rep stosb or ax,-1 stosw stosw stosw mov cl,ROWS+4 mov ax,not ( (1 shl COLUMNS - 1) shl ((16-COLUMNS)/2) ) rep stosw new_piece: mov bx,[random] mov ax,257 mul bx inc ax mov cx,43243 div cx mov [random],dx and bx,7 jz new_piece shl bx,1 mov ax,[pieces+bx-2] xchg ax,[next] or ax,ax jz new_piece lea di,[current] stosw ; [current] mov al,6 stosb ; [current_column] mov ax,well+(3+ROWS-4)*2 stosw ; [current_row] mov si,no_move call first_move jz update_screen inc bp ; game over process_key: xor ah,ah int 16h mov al,ah dec ah jz start test bp,bp jnp process_key mov si,rotate cmp al,48h je action mov si,left cmp al,4Bh je action mov si,right cmp al,4Dh je action cmp al,50h jne main_loop drop_down: call do_move_down jz drop_down action: call do_move update_screen: mov bx,7 mov dx,12h mov ah,2 int 10h mov cl,12 print_score: mov ax,[score] shr ax,cl and al,0Fh cmp al,10 sbb al,69h das mov ah,0Eh int 10h sub cl,4 jnc print_score push es push 0A000h pop es mov si,well+3*2 mov di,320*184+160-(COLUMNS*8)/2 draw_well: lodsw push si mov dl,COLUMNS xchg bx,ax shr bx,(16-COLUMNS)/2 call draw_row pop si cmp si,well+(3+ROWS)*2 jb draw_well mov di,320*100+250 mov bx,[next] draw_preview: mov dl,4 call draw_row cmp di,320*68 ja draw_preview pop es main_loop: mov ah,1 int 16h jnz process_key mov al,-1 xor al,byte [score+1] and al,11b mov cx,[clock] sub cx,[last_tick] cmp cl,al jbe main_loop add [last_tick],cx call do_move_down jz update_screen movzx dx,byte [current_row] shr dx,2 mov si,well+3*2 mov di,si check_row: lodsw inc ax jz remove_row dec ax stosw jmp check_next_row remove_row: shl dx,1 check_next_row: cmp di,well+(3+ROWS)*2 jb check_row add [score],dx jmp new_piece draw_row: push di blit_row: shr bx,1 mov si,pics jnc blit_block add si,64 blit_block: mov cx,8 rep movsb add di,320-8 test si,111111b jnz blit_block sub di,320*8-8 dec dx jnz blit_row pop di sub di,320*8 ret do_move_down: mov si,down do_move: mov al,1 call on_piece first_move: push dword [current] call si xor ax,ax call on_piece inc ax pop edx test ah,ah jz @f mov dword [current],edx @@: jmp on_piece down: sub byte [current_row],2 ret left: dec [current_column] ret right: inc [current_column] no_move: ret rotate: mov cx,3 @@: bt [current],cx rcl dx,1 add cl,4 cmp cl,16 jb @b sub cl,17 jnc @b mov [current],dx ret on_piece: pushf mov di,[current_row] mov bx,4 on_piece_row: mov dx,[current] mov cl,bh shr dx,cl and dx,1111b mov cl,[current_column] add cl,4 shl edx,cl shr edx,4 test al,al jz @f xor [di],dx @@: test [di],dx jz @f inc ah @@: add bh,4 scasw dec bl jnz on_piece_row popf ret pieces dw 0010001000100010b dw 0010011000100000b dw 0010001001100000b dw 0100010001100000b dw 0000011001100000b dw 0100011000100000b dw 0010011001000000b rb 7C00h+510-$ dw 0AA55h Last edited by Tomasz Grysztar on 05 Dec 2019, 15:51; edited 1 time in total |
|||
23 Nov 2019, 14:05 |
|
Tomasz Grysztar 23 Nov 2019, 18:09
I saved a couple more bytes by putting all the data next to each other and I came up with something to do with the remaining bytes. I've changed the color of the upper digits of the score - the ones that affect the speed of the game (note that speed reaches its maximum at 3 and then rolls over back to being slower). I'm not sure if I like the look of it, but still: this is yet another "feature" I managed to fit in there.
Code: ; TetrOS version 1.05 ; by Tomasz Grysztar ; Requires VGA and 80386 CPU or higher. ; Version 1.01 was submitted in 2004 for a 512-byte OS contest. ; For your playing pleasure, it's a boot-sector Tetris game. ; Keys: ; Left - move left ; Right - move right ; Up - rotate ; Down - drop ; Esc - new game at any time format binary as 'img' org 7C00h ROWS = 23 COLUMNS = 12 BACKGROUND = 0 ; background color, 0 for randomized virtual at 46Ch clock dw ? end virtual virtual at bp current dw ? current_column db ? current_row dw ? filler db ? next dw ? score dw ? last_tick dw ? random dw ? pics_wrt_bp: end virtual label well at 8000h label pics at well-2*64 label origin at pics-(pics_wrt_bp-bp) ORIGIN_PARITY = origin and 0FFh while ORIGIN_PARITY and not 1 ORIGIN_PARITY = (ORIGIN_PARITY shr 1) xor (ORIGIN_PARITY and 1) end while xor ax,ax mov sp,origin mov ss,ax mov ds,ax mov es,ax push ax push start retf start: mov al,13h int 10h restart: mov bp,sp xor ax,ax lea di,[next] stosw ; [next] stosw ; [score] mov ax,[clock] stosw ; [last_tick] stosw ; [random] mov cx,64 if BACKGROUND mov ax,0F00h + BACKGROUND else mov ah,15 end if rep stosb mov dx,7 @@: mov al,15 stosb mov al,ah mov cl,6 rep stosb mov ax,0708h stosb dec dx jnz @b mov cl,8 rep stosb or ax,-1 stosw stosw stosw mov cl,ROWS+4 mov ax,not ( (1 shl COLUMNS - 1) shl ((16-COLUMNS)/2) ) rep stosw new_piece: mov bx,[random] mov ax,257 mul bx inc ax mov cx,43243 div cx mov [random],dx and bx,7 jz new_piece shl bx,1 mov ax,[pieces+bx-2] xchg ax,[next] or ax,ax jz new_piece lea di,[current] stosw ; [current] mov al,6 stosb ; [current_column] mov ax,well+(3+ROWS-4)*2 stosw ; [current_row] mov si,no_move call first_move jz update_screen inc bp ; game over process_key: xor ah,ah int 16h mov al,ah dec ah jz restart test bp,bp if ORIGIN_PARITY jp process_key else jnp process_key end if mov si,rotate cmp al,48h je action mov si,left cmp al,4Bh je action mov si,right cmp al,4Dh je action cmp al,50h jne main_loop drop_down: call do_move_down jz drop_down action: call do_move update_screen: mov bx,15 mov dx,12h mov ah,2 int 10h mov cl,84h print_score: mov ax,[score] rol ax,cl and al,0Fh cmp al,10 sbb al,69h das mov ah,0Eh int 10h add cl,84h jns print_score xor bl,15 xor 7 jnp print_score push es push 0A000h pop es mov si,well+3*2 mov di,320*184+160-(COLUMNS*8)/2 draw_well: lodsw push si mov dl,COLUMNS xchg bx,ax shr bx,(16-COLUMNS)/2 call draw_row pop si cmp si,well+(3+ROWS)*2 jb draw_well mov di,320*100+250 mov bx,[next] draw_preview: mov dl,4 call draw_row cmp di,320*68 ja draw_preview pop es main_loop: mov ah,1 int 16h jnz process_key mov al,-1 xor al,byte [score+1] and al,11b mov cx,[clock] sub cx,[last_tick] cmp cl,al jbe main_loop add [last_tick],cx call do_move_down jz update_screen movzx dx,byte [current_row] shr dx,2 mov si,well+3*2 mov di,si check_row: lodsw inc ax jz remove_row dec ax stosw jmp check_next_row remove_row: shl dx,1 check_next_row: cmp di,well+(3+ROWS)*2 jb check_row add [score],dx jmp new_piece draw_row: push di blit_row: shr bx,1 mov si,pics jnc blit_block add si,64 blit_block: mov cx,8 rep movsb add di,320-8 test si,111111b jnz blit_block sub di,320*8-8 dec dx jnz blit_row pop di sub di,320*8 ret do_move_down: mov si,down do_move: mov al,1 call on_piece first_move: push dword [current] call si xor ax,ax call on_piece inc ax pop edx test ah,ah jz @f mov dword [current],edx @@: jmp on_piece down: sub byte [current_row],2 ret left: dec [current_column] ret right: inc [current_column] no_move: ret rotate: mov cx,3 @@: bt [current],cx rcl dx,1 add cl,4 cmp cl,16 jb @b sub cl,17 jnc @b mov [current],dx ret on_piece: pushf mov di,[current_row] mov bx,4 on_piece_row: mov dx,[current] mov cl,bh shr dx,cl and dx,1111b mov cl,[current_column] add cl,4 shl edx,cl shr edx,4 test al,al jz @f xor [di],dx @@: test [di],dx jz @f inc ah @@: add bh,4 scasw dec bl jnz on_piece_row popf ret pieces dw 0010001000100010b dw 0010011000100000b dw 0010001001100000b dw 0100010001100000b dw 0000011001100000b dw 0100011000100000b dw 0010011001000000b rb 7C00h+510-$ dw 0AA55h
Last edited by Tomasz Grysztar on 17 Dec 2019, 07:03; edited 2 times in total |
||||||||||||||||||||
23 Nov 2019, 18:09 |
|
edfed 25 Nov 2019, 09:16
funny trick to know how many bytes are available instead of rb 7C00h+510+$
Code: repeat 7C00h+510-$ display "0" db 0 end repeat also, can save many more byte by using bytes to encode pieces. but it needs to recode the piece computations also... Code: pieces: db 1111'0000b ;I db 1110'0100b ;T db 1110'0010b ;J db 1110'1000b ;L db 0110'0110b ;O db 0110'1100b ;S db 1100'0110b ;Z where and how?? there is a lot of code to modify i guess. Code: new_piece: mov bx,[random] mov ax,257 mul bx inc ax mov cx,43243 div cx mov [random],dx and bx,7 jz new_piece ; shl bx,1 movzx ax,byte[pieces+bx-1] ;shl ax,4 xchg ax,[next] or ax,ax jz new_piece lea di,[current] stosw ; [current] mov al,6 stosb ; [current_column] mov ax,well+(3+ROWS-4)*2 stosw ; [current_row] mov si,no_move call first_move jz update_screen inc bp ; game over Code: pieces: db 1111'0000b ;I db 1110'0100b ;T db 1110'0010b ;J db 1110'1000b ;L db 0110'0110b ;O db 0110'1100b ;S db 1100'0110b ;Z ; dw 0010'0010'0010'0010b ; dw 0010'0110'0010'0000b ; dw 0010'0010'0110'0000b ; dw 0100'0100'0110'0000b ; dw 0000'0110'0110'0000b ; dw 0100'0110'0010'0000b ; dw 0010'0110'0100'0000b n = 0 repeat 7C00h+510-$ display n+30h n=n+1 if n=10 n=0 display 13,10 end if db 0 end repeat dw 0AA55h |
|||
25 Nov 2019, 09:16 |
|
Tomasz Grysztar 25 Nov 2019, 20:49
edfed wrote: also, can save many more byte by using bytes to encode pieces. However, you made me realize that I could skip an SHL instruction by making the piece selection look like this: Code: and bx,7 shl 1 jz new_piece mov ax,[pieces+bx-2] |
|||
25 Nov 2019, 20:49 |
|
edfed 26 Nov 2019, 11:57
i've got 13 free bytes now
enough to add the random rotation for new pieces. i think also, it can be possible to use the video segment for data and stack as there are 5536 bytes not used at the end of the video mem (to try)... it can save the push es, push 0a000h, pop es, pop es bytes |
|||
26 Nov 2019, 11:57 |
|
Tomasz Grysztar 26 Nov 2019, 12:14
edfed wrote: i think also, it can be possible to use the video segment for data and stack as there are 5536 bytes not used at the end of the video mem (to try)... it can save the push es, push 0a000h, pop es, pop es bytes |
|||
26 Nov 2019, 12:14 |
|
edfed 28 Nov 2019, 09:10
i find this tetros size optimisation very exiting.
i think we can fit tetros "as it is" in less than 450 bytes. that will let us add cool features. |
|||
28 Nov 2019, 09:10 |
|
Tomasz Grysztar 28 Nov 2019, 09:52
I already have the features and behavior that I wanted. See my remark in the initial post, that I intentionally disregarded some of the possible optimizations that would not allow to get exactly the playing experience that I prefer.
Anyway, it is up to you if you want to try optimizing it more. Perhaps you could even make a DN-like Pentix? But I should add, just in case: please do not make a TetrOS-based project your submission in the upcoming contest. |
|||
28 Nov 2019, 09:52 |
|
edfed 28 Nov 2019, 09:57
of course not, i have another project for the contest .
tetros optimising is just a game here with setalc, i can save one byte per mov al,-1 but it needs carry flag set somewhere... then, hohoho, lets bend the code |
|||
28 Nov 2019, 09:57 |
|
Tomasz Grysztar 05 Dec 2019, 16:07
While testing on a real hardware I noticed that I made a wrong assumption about INT 16h. I have therefore updated versions 1.04-1.05 above with a fix.
|
|||
05 Dec 2019, 16:07 |
|
Flat12 06 Dec 2024, 13:03
Yea, I use TetrOS as ISA Option ROM and PCI Option ROM. Works on the AWARD Bios and on Coreboot+Seabios - tested on Abit BF6 motherboard.
Using this tutorial: Building a "Kernel" in PCI Expansion ROM I added ISA Option ROM support - isa_exp_rom_os.tar.gz: https://board.flatassembler.net/topic.php?p=165451#165451 If no any drive (HDD, FDD or CD-ROM) is connected to the motherboard, TetrOS starts automatically https://www.youtube.com/watch?v=NJLx2fUZc-c |
|||
06 Dec 2024, 13:03 |
|
< Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.