Flipping bits game: Difference between revisions
Content added Content deleted
m (→{{header|Red}}) |
Not a robot (talk | contribs) (Add 8080 assembly version) |
||
Line 22: | Line 22: | ||
Show an example of a short game here, on this page, for a 3 by 3 array of bits. |
Show an example of a short game here, on this page, for a 3 by 3 array of bits. |
||
<br><br> |
<br><br> |
||
=={{header|8080 Assembly}}== |
|||
This program runs under CP/M and takes the board size from the command line. |
|||
<lang 8080asm> ;;; Flip the Bits game, CP/M version. |
|||
;;; CP/M zero page locations |
|||
cmdln: equ 80h |
|||
;;; CP/M system calls |
|||
getch: equ 1h |
|||
putch: equ 2h |
|||
rawio: equ 6h |
|||
puts: equ 9h |
|||
org 100h |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Retrieve command line input. If it is not correct, end. |
|||
lxi d,usage ; Usage string |
|||
mvi c,puts ; Print that string when we need to |
|||
lxi h,cmdln ; Pointer to command line |
|||
mov a,m ; Get length |
|||
ana a ; Zero? |
|||
jc 5 ; Then print and stop |
|||
inx h ; Advance to first non-space element |
|||
inx h |
|||
mov a,m ; Get first character |
|||
sui '3' ; Minimum number |
|||
jc 5 ; If input was less than that, print and stop |
|||
adi 3 ; Add 3 back, giving the board size |
|||
cpi 9 ; Is it higher than 8 now? |
|||
jnc 5 ; Then print usage and stop |
|||
sta boardsz ; Store the board size |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Because there's no standard way in CP/M to get at any |
|||
;;; entropy (not even a clock), ask the user to supply some |
|||
;;; by pressing the keys on the keyboard. |
|||
lxi d,presskeys |
|||
call outs |
|||
mvi b,8 ; we want to do this 8 times, for 24 keys total |
|||
randouter: mvi c,3 ; there are 3 bytes of state for the RNG |
|||
lxi h,xabcdat+1 |
|||
randinner: push h ; keep the pointer and counters |
|||
push b |
|||
waitkey: mvi c,rawio |
|||
mvi e,0FFh |
|||
call 5 |
|||
ana a |
|||
jz waitkey |
|||
pop b ; restore the pointer and counters |
|||
pop h |
|||
xra m ; XOR key with data |
|||
mov m,a |
|||
inx h |
|||
dcr c ; Have we had 3 bytes yet? |
|||
jnz randinner |
|||
dcr b ; Have we done it 8 times yet? |
|||
jnz randouter |
|||
lxi d,welcome |
|||
call outs |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Generate a random board |
|||
lxi h,board |
|||
lxi b,4001h ; B=81, C=1 |
|||
genrand: call xabcrand |
|||
ana c |
|||
mov m,a |
|||
inx h |
|||
dcr b |
|||
jnz genrand |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Copy board into goal |
|||
lxi h,board |
|||
lxi d,goal |
|||
mvi b,64 |
|||
copygoal: mov a,m |
|||
stax d |
|||
inx h |
|||
inx d |
|||
dcr b |
|||
jnz copygoal |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Do a bunch of random flips on the board (5-20) |
|||
call xabcrand |
|||
ani 0Fh ; 0..15 flips |
|||
adi 5 ; 5..20 flips |
|||
sta sysflips |
|||
mov b,a ; Do that many flips |
|||
randflip: call xabcrand |
|||
call flip ; Unused bits in the random number are ignored |
|||
dcr b |
|||
jnz randflip |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Print the current state |
|||
gamestate: lxi d,smoves |
|||
call outs |
|||
lda usrflips |
|||
call outanum |
|||
lxi d,sgoal |
|||
call outs |
|||
lda sysflips |
|||
call outanum |
|||
lxi d,newline |
|||
call outs |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Print the current board and the goal |
|||
;;; Print the header first |
|||
lxi d,sboardhdr |
|||
call outs |
|||
lda boardsz |
|||
lxi d,2041h ; E=letter (A), D=space |
|||
add e ; Last letter |
|||
mov b,a ; B = last letter |
|||
mvi l,2 ; Print two headers |
|||
header: mvi e,'A' |
|||
mov a,d |
|||
call outaspace |
|||
headerpart: mov a,e |
|||
cmp b |
|||
jc headerltr |
|||
mov a,d ; Print spaces for invalid positions |
|||
headerltr: call outaspace |
|||
mov a,e |
|||
inr a |
|||
mov e,a |
|||
cpi 'A'+8 |
|||
jc headerpart |
|||
mvi a,9 |
|||
call outa |
|||
dcr l ; Print two headers (for two boards) |
|||
jnz header |
|||
lxi d,newline |
|||
call outs |
|||
;;; Then print each line of the board |
|||
mvi c,0 ; Start with line 0 |
|||
printline: lxi h,board ; Get position on board |
|||
mvi d,2 ; Run twice - print board and goal |
|||
prbrdline: mvi a,'1' ; Print line number |
|||
add c |
|||
call outaspace |
|||
push d |
|||
mov a,c ; Line offset in board |
|||
rlc |
|||
rlc |
|||
rlc |
|||
mov e,a |
|||
mvi d,0 |
|||
dad d ; Add line offset |
|||
pop d ; Restore board counter |
|||
mvi b,0 ; Start with column 0 |
|||
printcol: lda boardsz ; Valid position? |
|||
dcr a |
|||
cmp b |
|||
jnc printbit |
|||
mvi a,' ' ; No - print space |
|||
jmp printpos |
|||
printbit: mov a,m ; Yes - print 0 or 1 |
|||
adi '0' |
|||
printpos: call outaspace |
|||
inx h ; Next board pos |
|||
inr b |
|||
mov a,b ; Done yet? |
|||
cpi 8 |
|||
jnz printcol ; If not, print next column |
|||
mvi a,9 |
|||
call outa |
|||
lxi h,goal ; Print goal line next |
|||
dcr d |
|||
jnz prbrdline |
|||
mvi a,13 ; Print newline |
|||
call outa |
|||
mvi a,10 |
|||
call outa |
|||
inr c ; Next line |
|||
lda boardsz ; Valid line? |
|||
dcr a |
|||
cmp c |
|||
jnc printline |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Prompt the user for a move |
|||
lxi d,prompt ; Print prompt |
|||
call outs |
|||
readinput: mvi c,getch ; Read character |
|||
call 5 |
|||
ori 32 ; Make letters lowercase |
|||
cpi 'q' ; Quit? |
|||
rz |
|||
cpi '9'+1 ; 9 or lower? assume number |
|||
jc nummove |
|||
sui 'a' ; Otherwise, assume letter |
|||
jc invalid ; So <'a' is invalid input |
|||
call checkmove ; See if the move is valid |
|||
jc invalid ; If not, wrong input |
|||
ori 128 ; Set high bit for column flip |
|||
call flip ; Do the flip |
|||
jmp checkboard ; See if the game is won |
|||
nummove: sui '1' ; Board array is 0-based of course |
|||
jc invalid ; Not on board = invalid input |
|||
call checkmove ; See if the move is vali |
|||
jc invalid |
|||
call flip ; Do the move (high bit clear for row) |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; See if the user has won |
|||
checkboard: lda boardsz |
|||
dcr a |
|||
mov b,a ; B = line |
|||
checkrow: lda boardsz |
|||
dcr a |
|||
mov c,a ; C = column |
|||
checkcol: mov a,b |
|||
rlc ; Line * 8 |
|||
rlc |
|||
rlc |
|||
add c ; + column = offset |
|||
push b ; Store line/column |
|||
mvi h,0 ; Position offset |
|||
mov l,a |
|||
lxi d,board ; Get board |
|||
dad d |
|||
mov b,m ; B = board position |
|||
lxi d,64 ; Goal = board+64 |
|||
dad d |
|||
mov a,m ; A = goal position |
|||
cmp b ; Are they the same? |
|||
pop b ; Restore line/column |
|||
jnz nowin ; If not, the user hasn't won |
|||
dcr c ; If so, try next column position |
|||
jp checkcol |
|||
dcr b ; If column done, try next row |
|||
jp checkrow |
|||
;;; If we get here, the user has won |
|||
lxi d,win |
|||
jmp outs |
|||
;;; The user hasn't won yet, get another move |
|||
nowin: lxi h,usrflips ; Increment the user flips |
|||
inr m |
|||
jmp gamestate ; Print new game state, get new move |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Invalid input: erase it, beep, and get another character |
|||
invalid: lxi d,nope |
|||
call outs |
|||
jmp readinput |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Check if the move in A is valid. Set carry if not. |
|||
checkmove: mov b,a |
|||
lda boardsz |
|||
dcr a |
|||
cmp b |
|||
mov a,b |
|||
ret |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Flip row or column A & 7 (zero-indexed) on the board. |
|||
;;; Bit 7 set = column, else row. |
|||
flip: rlc ; Test bit 7 (and A*2) |
|||
jc flipcol |
|||
;;; Flip row |
|||
push b ; Keep registers |
|||
push h |
|||
ani 0Eh ; Get row number |
|||
rlc ; Calculate offset, A*4 |
|||
rlc ; A*8 |
|||
mvi b,0 ; BC = A |
|||
mov c,a |
|||
lxi h,board ; Get board pointer |
|||
dad b ; Add row offset |
|||
lxi b,0801h ; Max. 8 bits, and C=1 (to flip) |
|||
fliprowbit: mov a,m ; Get position |
|||
xra c ; Flip position |
|||
mov m,a ; Store position |
|||
inx h ; Increment pointer |
|||
dcr b ; Done yet? |
|||
jnz fliprowbit |
|||
pop h ; Restore registers |
|||
pop b |
|||
ret |
|||
;;; Flip column |
|||
flipcol: push b ; Keep registers |
|||
push d |
|||
push h |
|||
rrc ; Rotate A back |
|||
ani 7 ; Get column number |
|||
mvi d,0 ; Column offset |
|||
mov e,a |
|||
lxi h,board ; Get board pointer |
|||
dad d ; Add column offset |
|||
mvi e,8 ; Advance by 8 each time through the loop |
|||
lxi b,0801h ; Max. 8 bits, and C=1 (to flip) |
|||
flipcolbit: mov a,m ; Get position |
|||
xra c ; Flip position |
|||
mov m,a ; Store position |
|||
dad d ; Next row |
|||
dcr b ; Done yet? |
|||
jnz flipcolbit |
|||
pop h ; Restore registers |
|||
pop d |
|||
pop b |
|||
ret |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; The "X ABC" 8-bit random number generator |
|||
xabcrand: push h |
|||
lxi h,xabcdat |
|||
inr m ; X++ |
|||
mov a,m ; X, |
|||
inx h ; |
|||
xra m ; ^ C, |
|||
inx h ; |
|||
xra m ; ^ A, |
|||
mov m,a ; -> A |
|||
inx h |
|||
add m ; + B, |
|||
mov m,a ; -> B |
|||
rar ; >>1 |
|||
dcx h |
|||
xra m ; ^ A, |
|||
dcx h |
|||
add m ; + C |
|||
mov m,a ; -> C |
|||
pop h |
|||
ret |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Print the string in DE. This saves one byte per call. |
|||
outs: mvi c,puts |
|||
jmp 5 |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Print the number in A in decimal, preserving registers |
|||
outanum: push psw |
|||
push b |
|||
push d |
|||
push h |
|||
lxi d,outabuf+3 |
|||
outadgt: mvi b,-1 |
|||
outdivmod: inr b |
|||
sui 10 |
|||
jnc outdivmod |
|||
adi 10+'0' |
|||
dcx d |
|||
stax d |
|||
mov a,b |
|||
ana a |
|||
jnz outadgt |
|||
call outs |
|||
jmp regrestore |
|||
outabuf: db '***$' ; Room for ASCII number |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Print the character in A followed by a space, preserving |
|||
;;; registers. |
|||
outaspace: call outa |
|||
push psw |
|||
mvi a,' ' |
|||
call outa |
|||
pop psw |
|||
ret |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Print the character in A, preserving all registers. |
|||
outa: push psw |
|||
push b |
|||
push d |
|||
push h |
|||
mov e,a |
|||
mvi c,putch |
|||
call 5 |
|||
regrestore: pop h |
|||
pop d |
|||
pop b |
|||
pop psw |
|||
ret |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Strings |
|||
usage: db 'Usage: FLIP [3..8], number is board size.$' |
|||
presskeys: db 'Please press some keys to generate a random state...$' |
|||
welcome: db 'done.',13,10,13,10 |
|||
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 '--Board------------',9,'--Goal-------------',13,10,'$' |
|||
prompt: db '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!$' |
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|||
;;; Data |
|||
boardsz: ds 1 ; This will hold the board size |
|||
sysflips: ds 1 ; How many flips the system did |
|||
usrflips: ds 1 ; How many flips the user did |
|||
xabcdat: ds 4 ; RNG state |
|||
board: equ $ |
|||
goal: equ board + 64 ; Max. 8*8 board</lang> |
|||
{{out}} |
|||
Example game: |
|||
<pre>A>flip 3 |
|||
Please press some keys to generate a random state...done. |
|||
*** FLIP THE BITS *** |
|||
--------------------- |
|||
Your flips: 0 Goal: 20 |
|||
--Board------------ --Goal------------- |
|||
A B C A B C |
|||
1 0 0 0 1 0 1 1 |
|||
2 0 0 0 2 1 0 0 |
|||
3 1 1 1 3 0 1 1 |
|||
Press line or column to flip, or Q to quit: a |
|||
Your flips: 1 Goal: 20 |
|||
--Board------------ --Goal------------- |
|||
A B C A B C |
|||
1 1 0 0 1 0 1 1 |
|||
2 1 0 0 2 1 0 0 |
|||
3 0 1 1 3 0 1 1 |
|||
Press line or column to flip, or Q to quit: 1 |
|||
You win! |
|||
A></pre> |
|||
=={{header|Ada}}== |
=={{header|Ada}}== |