Flipping bits game: Difference between revisions
Content added Content deleted
Not a robot (talk | contribs) (Add 8080 assembly version) |
Not a robot (talk | contribs) (Add 8086 assembly version) |
||
Line 436: | Line 436: | ||
You win! |
You win! |
||
A></pre> |
A></pre> |
||
=={{header|8086 Assembly}}== |
|||
This program runs under MS-DOS and takes the board size from the command line. |
|||
<lang asm> bits 16 |
|||
cpu 8086 |
|||
;;; MS-DOS PSP locations |
|||
arglen: equ 80h |
|||
argstart: equ 82h |
|||
;;; MS-DOS system calls |
|||
getch: equ 1h |
|||
putch: equ 2h |
|||
puts: equ 9h |
|||
time: equ 2Ch |
|||
section .text |
|||
org 100h |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Read board size from command line |
|||
cmp byte [arglen],0 ; Command line empty? |
|||
je printusage ; Then print usage and stop |
|||
mov al,[argstart] ; Get first byte on command line |
|||
cmp al,'3' ; <3? |
|||
jb printusage ; Then print usage and stop |
|||
cmp al,'8' ; >8? |
|||
ja printusage ; Then print usage and stop |
|||
sub al,'0' ; Make number from ASCII |
|||
mov [boardsz],al ; Store the board size |
|||
mov ah,puts ; If we made it here, print the |
|||
mov dx,welcome ; welcome banner. |
|||
int 21h |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Generate random board |
|||
call xabcinit ; Initialize the RNG with system time |
|||
mov si,board |
|||
xor bx,bx |
|||
genboard: call xabcrand ; Get random byte |
|||
mov ah,al |
|||
call xabcrand ; Get another |
|||
and ax,0101h ; Keep only the low bit of each byte |
|||
mov [si+bx],ax ; And store them |
|||
inc bx ; Two bytes onward |
|||
inc bx |
|||
cmp bl,64 ; Are we done? |
|||
jne genboard |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Copy the board into the goal |
|||
mov si,board ; Source is board |
|||
mov di,goal ; Destination is goal |
|||
mov bx,0 ; Start at the beginning |
|||
copyboard: mov ax,[si+bx] ; Load word from board |
|||
mov [di+bx],ax ; Store word in goal |
|||
inc bx ; We've copied two bytes |
|||
inc bx |
|||
cmp bl,64 ; Are we done yet? |
|||
jne copyboard |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Make an amount of random flips |
|||
call xabcrand ; Random number |
|||
and al,15 ; [0..15] |
|||
add al,5 ; [5..20] |
|||
mov [sysflips],al ; Store in memory |
|||
mov cl,al ; Flip doesn't touch CL |
|||
xor ch,ch ; Set high byte zero |
|||
randflips: call xabcrand ; Random number |
|||
call flip ; Do a flip (unused bits are ignored) |
|||
loop randflips |
|||
mov byte [usrflips],0 ; Initialize user flips to 0 |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Print game status (moves, goal moves) |
|||
status: mov ah,puts |
|||
mov dx,smoves |
|||
int 21h |
|||
mov al,[usrflips] |
|||
call printal |
|||
mov ah,puts |
|||
mov dx,sgoal |
|||
int 21h |
|||
mov al,[sysflips] |
|||
call printal |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Print the game board and goal board |
|||
mov ah,puts ; Print the header |
|||
mov dx,sboardhdr |
|||
int 21h |
|||
mov cl,2 ; Print two headers |
|||
mov ah,putch ; Indent columns |
|||
;;; Print column headers |
|||
colheader: mov dl,' ' |
|||
int 21h |
|||
int 21h |
|||
mov bh,0 ; Offset |
|||
mov bl,'A' ; First letter |
|||
.curcol: cmp bh,[boardsz] |
|||
mov dl,bl ; Print letter |
|||
jb .printcol |
|||
mov dl,' ' ; Print space if column not used |
|||
.printcol: call dlspace ; Print DL + separator space |
|||
inc bl |
|||
inc bh |
|||
cmp bh,8 ; Done yet? |
|||
jb .curcol |
|||
mov dl,9 ; Separate the boards with a TAB |
|||
int 21h |
|||
dec cl ; We need two headers (board and goal) |
|||
jnz colheader |
|||
mov ah,puts ; Print a newline afterwards |
|||
mov dx,newline |
|||
int 21h |
|||
;;; Print the rows of the boards |
|||
xor bh,bh ; Zero high byte of BX |
|||
xor cl,cl ; Row index |
|||
boardrow: mov ch,2 ; Two rows, board and goal |
|||
mov si,board ; Start by printing the game board |
|||
.oneboard: xor dh,dh ; Column index |
|||
mov dl,cl ; Print row number |
|||
add dl,'1' |
|||
call dlspace |
|||
.curpos: cmp dh,[boardsz] ; Column in use? |
|||
mov dl,' ' ; If not, print a space |
|||
jae .printpos |
|||
mov bl,cl ; Row index |
|||
shl bl,1 ; * 8 |
|||
shl bl,1 |
|||
shl bl,1 |
|||
add bl,dh ; Add column index |
|||
mov dl,[bx+si] ; Get position from board |
|||
add dl,'0' ; Print as ASCII 0 or 1 |
|||
.printpos: call dlspace |
|||
inc dh ; Increment column index |
|||
cmp dh,8 ; Are we there yet? |
|||
jb .curpos ; If not, print next position |
|||
mov dl,9 ; Separate the boards with a TAB |
|||
int 21h |
|||
dec ch ; Have we printed the goal yet? |
|||
mov si,goal ; If not, print the goal next |
|||
jnz .oneboard |
|||
mov ah,puts ; Print a newline |
|||
mov dx,newline |
|||
int 21h |
|||
inc cl ; Next row |
|||
cmp cl,[boardsz] ; Are we there yet? |
|||
jb boardrow ; If not, print the next row. |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Ask the user for a move |
|||
mov ah,puts ; Write the prompt |
|||
mov dx,prompt |
|||
int 21h |
|||
readmove: mov ah,getch ; Read a character |
|||
int 21h |
|||
or al,32 ; Make letters lowercase |
|||
cmp al,'q' ; Quit? |
|||
je quit |
|||
cmp al,'9' ; Numeric (row) input? |
|||
jbe .nummove ; If not, alphabetic (column) input |
|||
;;; Letter input (column) |
|||
sub al,'a' ; Subtract 'a' |
|||
jc invalid ; If it was <'a', invalid input |
|||
cmp al,[boardsz] ; Is it on the board? |
|||
jae invalid |
|||
or al,128 ; Set high bit, for column flip |
|||
call flip ; Flip the column |
|||
jmp checkwin ; See if the user has won |
|||
;;; Number input (row) |
|||
.nummove: sub al,'1' ; Rows start at 1. |
|||
jc invalid ; If <'1', then invalid |
|||
cmp al,[boardsz] ; Is it on the board? |
|||
jae invalid |
|||
call flip ; Flip the row |
|||
;;; Check if the user has won the game |
|||
checkwin: xor bh,bh ; Zero high byte of array index |
|||
mov dl,[boardsz] |
|||
xor ch,ch ; Row coordinate |
|||
.row: xor cl,cl ; Column coordinate |
|||
.pos: mov bl,ch ; BL = row*8 + col |
|||
shl bl,1 |
|||
shl bl,1 |
|||
shl bl,1 |
|||
add bl,cl |
|||
mov al,[board+bx] ; Get position from board |
|||
cmp al,[goal+bx] ; Compare with corresponding goal pos |
|||
jne .nowin ; Not equal: the user hasn't won |
|||
inc cl |
|||
cmp cl,dl ; Done all positions on row? |
|||
jb .pos ; If not, do next. |
|||
inc ch |
|||
cmp ch,dl ; Done all rows? |
|||
jb .row ; If not, do next. |
|||
;;; If we get here, the user has won |
|||
mov ah,puts |
|||
mov dx,win |
|||
int 21h |
|||
ret |
|||
;;; The user hasn't won |
|||
.nowin: inc byte [usrflips] ; Record that the user has made a move |
|||
jmp status ; Print status and board, get new move |
|||
;;; Invalid input |
|||
invalid: mov ah,puts |
|||
mov dx,nope |
|||
int 21h |
|||
jmp readmove |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Flip the line or column in AL. If bit 7 set, flip column. |
|||
flip: mov si,board ; SI = board |
|||
test al,al ; This sets sign flag if bit 7 set |
|||
js .column ; If so, flip column. |
|||
and al,7 ; We only need the first 3 bits |
|||
shl al,1 ; Multiply by 8 |
|||
shl al,1 ; 8086 does not support 'shl al,3' |
|||
shl al,1 |
|||
xor ah,ah ; High byte 0 |
|||
mov bx,ax ; BX = offset |
|||
mov ah,4 ; 4 words |
|||
.rowloop xor word [si+bx],0101h ; Flip two bytes at once |
|||
inc bx |
|||
inc bx |
|||
dec ah |
|||
jnz .rowloop |
|||
ret |
|||
.column: and al,7 ; Flip a column. |
|||
xor ah,ah |
|||
mov bx,ax ; BX = row offset |
|||
mov ah,8 ; 8 bytes (need to do it byte by byte) |
|||
.colloop: xor byte [si+bx],01h ; Flip position |
|||
add bx,8 |
|||
dec ah |
|||
jnz .colloop |
|||
quit: ret |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Print usage and stop |
|||
printusage: mov ah,puts |
|||
mov dx,usage |
|||
int 21h |
|||
ret |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Print the character in DL followed by a space |
|||
dlspace: mov ah,putch |
|||
int 21h |
|||
mov dl,' ' |
|||
int 21h |
|||
ret |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Initialize the random number generator using the system |
|||
;;; time. |
|||
xabcinit: mov ah,time |
|||
int 21h |
|||
mov bx,xabcdat |
|||
xor [bx],cx |
|||
xor [bx+2],dx |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; The "X ABC" random number generator |
|||
;;; Return random byte in AL |
|||
xabcrand: push bx ; Save registers |
|||
push cx |
|||
push dx |
|||
mov bx,xabcdat ; RNG state pointer |
|||
mov cx,[bx] ; CL=x CH=a |
|||
mov dx,[bx+2] ; DL=b DH=c |
|||
inc cl ; X++ |
|||
xor ch,dh ; A^=C |
|||
xor ch,cl ; A^=X |
|||
add dl,ch ; B+=A |
|||
mov al,dl |
|||
shr al,1 ; B>>1 |
|||
xor al,ch ; ^A |
|||
add al,dh ; +C |
|||
mov dh,al ; ->C |
|||
mov [bx],cx ; Store new RNG state |
|||
mov [bx+2],dx |
|||
pop dx ; Restore registers |
|||
pop cx |
|||
pop bx |
|||
ret |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Print the byte in AL as a decimal number |
|||
printal: mov di,decnum + 3 ; Room in memory for decimal number |
|||
mov dl,10 ; Divide by 10 |
|||
.loop: xor ah,ah ; Zero remainder |
|||
div dl ; Divide by 10 |
|||
add ah,'0' ; Add ASCII 0 to remainder |
|||
dec di |
|||
mov [di],ah ; Store digit in memory |
|||
and al,al ; Done yet? |
|||
jnz .loop ; If not, next digit |
|||
mov dx,di ; DX = number string |
|||
mov ah,puts ; Print the string |
|||
int 21h |
|||
ret |
|||
section .data |
|||
decnum: db '***$' ; Decimal number placeholder |
|||
usage: db 'Usage: FLIP [3..8], number is board size.$' |
|||
welcome: db '*** FLIP THE BITS *** ',13,10 |
|||
db '--------------------- ', |
|||
newline: db 13,10,'$' |
|||
smoves: db 13,10,13,10,'Your flips: $' |
|||
sgoal: db 9,'Goal: $' |
|||
sboardhdr: db 13,10,10,'--Board------------' |
|||
db 9,'--Goal-------------',13,10,'$' |
|||
prompt: db 13,10,'Press line or column to flip, or Q to quit: $' |
|||
nope: db 8,32,8,7,'$' ; Beep and erase input |
|||
win: db 13,10,7,7,7,'You win!$' |
|||
section .bss |
|||
boardsz: resb 1 ; Board size |
|||
sysflips: resb 1 ; Amount of flips that the system does |
|||
usrflips: resb 1 ; Amount of flips that the user does |
|||
xabcdat: resb 4 ; Four byte RNG state |
|||
board: resb 64 ; 8*8 board |
|||
goal: resb 64 ; 8*8 goal</lang> |
|||
=={{header|Ada}}== |
=={{header|Ada}}== |