Files
asm_game/game.s
2025-02-05 22:28:50 +00:00

315 lines
7.2 KiB
ArmAsm

; TODO out of moves check
global _start
section .text
checkVictory:
mov rax, 0
mov cl, [fieldBuffer + 12]
and cl, [fieldBuffer + 14]
and cl, [fieldBuffer + 16]
cmp cl, dil
je .returnTrue
mov cl, [fieldBuffer + 22]
and cl, [fieldBuffer + 24]
and cl, [fieldBuffer + 26]
cmp cl, dil
je .returnTrue
mov cl, [fieldBuffer + 32]
and cl, [fieldBuffer + 34]
and cl, [fieldBuffer + 36]
cmp cl, dil
je .returnTrue
mov cl, [fieldBuffer + 12]
and cl, [fieldBuffer + 22]
and cl, [fieldBuffer + 32]
cmp cl, dil
je .returnTrue
mov cl, [fieldBuffer + 14]
and cl, [fieldBuffer + 24]
and cl, [fieldBuffer + 34]
cmp cl, dil
je .returnTrue
mov cl, [fieldBuffer + 16]
and cl, [fieldBuffer + 26]
and cl, [fieldBuffer + 36]
cmp cl, dil
je .returnTrue
mov cl, [fieldBuffer + 12]
and cl, [fieldBuffer + 24]
and cl, [fieldBuffer + 36]
cmp cl, dil
je .returnTrue
mov cl, [fieldBuffer + 16]
and cl, [fieldBuffer + 24]
and cl, [fieldBuffer + 32]
cmp cl, dil
je .returnTrue
mov rax, 0
ret
.returnTrue:
mov rax, 1
ret
makeAIMove:
rdtsc
mov rbx, rax
.loop:
; RAND from wiki https://en.wikipedia.org/wiki/Linear_congruential_generator. Numerical Recipes ranqd1, Chapter 7.1, §An Even Quicker Generator, Eq. 7.1.6 parameters from Knuth and H. W. Lewis
mov rdx, 1664525
mul rdx
add rax, 1013904223
mov rbx, rax
; clamping to 1-3 range and moving to rdi
mov rsi, 3
mov rax, 0
mov ah, bh
mov dx, 0
div si ;TODO for some reason div sil causes division by zero
inc dx
mov di, dx
shl di, 8
mov rax, 0
mov ah, bl
mov dx, 0
div si
inc dx
mov dil, dl
mov rsi, 'o'
call placeChar
cmp rax, 0
je .return
mov rax, rbx
jmp .loop
.return:
ret
drawField:
mov rax, 1 ; sys_write
mov rdi, 1 ; out
mov rsi, fieldBuffer ; str
mov rdx, fieldBufferLen ; size
syscall ;
ret
placeChar:
;computing pos in string
mov dx, di
mov rcx, 0
; cl = dh * 10
mov cl, dh
shl cl, 3
add cl, dh
add cl, dh
; cl += dl * 2
shl dl, 1
add cl, dl
;checking if it was occupied char to the string
mov rax, 0
mov byte al, [fieldBuffer + rcx]
sub al, ' '
jne .return
;placing char to the string
mov byte [fieldBuffer + rcx], sil
.return:
ret
readXY:
; clearing input buffer
mov dword [userInputBuffer], 0
mov rax, 0 ; sys_read
mov rdi, 0 ; in
mov rsi, userInputBuffer ; str
mov rdx, 256 ; size
syscall ;
; only accept strings with length of 4 (reading more to skip some invalid inputs)
cmp rax, 4
jne .return
mov ax, 0
cmp byte [userInputBuffer+1], ' ' ; second should be whitespace
jne .return
cmp byte [userInputBuffer+3], 0xA ; fourth should be \n
jne .return
mov al, [userInputBuffer] ; x
sub al, '0'
mov ah, [userInputBuffer + 2] ; y
sub ah, '0'
.return:
ret
_start:
; call drawField
mov rax, 1 ; sys_write
mov rdi, 1 ; out
mov rsi, greetingsMessage ; str
mov rdx, greetingsMessageLen ; size
syscall ;
call drawField
mov rax, 1 ; sys_write
mov rdi, 1 ; out
mov rsi, readInputsMessage ; str
mov rdx, readInputsMessageLen ; size
syscall ;
.loop:
;reading input
call readXY
;reading check x,y range
cmp al, 1
jl .printInputError
cmp al, 3
jg .printInputError
cmp ah, 1
jl .printInputError
cmp ah, 3
jg .printInputError
mov rdi, rax ; passing xy to placeChar function
mov sil, 'x' ; passing char to placeChar function
call placeChar
; failed to place a char
jne .printOccupiedError
;check win condition
mov rdi, 'x'
call checkVictory
cmp rax, 0
jne .printYouWon
;drawing field again
call drawField
;ai thinking...
mov rax, 1 ; sys_write
mov rdi, 1 ; out
mov rsi, aiThinkingMessage ; str
mov rdx, aiThinkingMessageLen ; size
syscall ;
mov rbx, 10
.thinkingReallyHardLoop:
mov rax, 1000000000
.thinkingReallyHardInnerLoop:
dec rax
jne .thinkingReallyHardInnerLoop
mov rax, 1 ; sys_write
mov rdi, 1 ; out
mov rsi, aiThinkingDotMessage ; str
mov rdx, aiThinkingDotMessageLen ; size
syscall ;
dec rbx
jne .thinkingReallyHardLoop
mov rax, 1 ; sys_write
mov rdi, 1 ; out
mov rsi, endlnMessage ; str
mov rdx, endlnMessageLen ; size
syscall ;
call makeAIMove
call drawField
mov rdi, 'o'
call checkVictory
cmp rax, 0
jne .printYouLost
;printing input message again
mov rax, 1 ; sys_write
mov rdi, 1 ; out
mov rsi, readInputsMessage ; str
mov rdx, readInputsMessageLen ; size
syscall ;
jmp .loop
.printInputError:
mov rax, 1 ; sys_write
mov rdi, 1 ; out
mov rsi, wrongValuesMessage ; str
mov rdx, wrongValuesMessageLen ; size
syscall ;
jmp .loop
.printOccupiedError:
mov rax, 1 ; sys_write
mov rdi, 1 ; out
mov rsi, occupiedMessage ; str
mov rdx, occupiedMessageLen ; size
syscall ;
jmp .loop
.printYouWon:
call drawField
mov rax, 1 ; sys_write
mov rdi, 1 ; out
mov rsi, youWonMessage ; str
mov rdx, youWonMessageLen ; size
syscall ;
jmp .exit
.printYouLost:
call drawField
mov rax, 1 ; sys_write
mov rdi, 1 ; out
mov rsi, youLostMessage ; str
mov rdx, youLostMessageLen ; size
syscall ;
.exit:
; exiting program
mov rax, 60 ; sys_exit
mov rdi, 0 ; code
syscall ;
section .rodata
greetingsMessage: db "Welcome to tic-tac-toe!", 0xA
greetingsMessageLen: equ $ - greetingsMessage
readInputsMessage: db "Type [x y] to place a cross:", 0xA
readInputsMessageLen: equ $ - readInputsMessage
wrongValuesMessage: db "Unexpected x or y value. Could be 1,2 or 3 in [x y] format. Try again:", 0xA
wrongValuesMessageLen: equ $ - wrongValuesMessage
occupiedMessage: db "Cell is already occupied. Try again:", 0xA
occupiedMessageLen: equ $ - occupiedMessage
youWonMessage: db "YOU WON!!!", 0xA
youWonMessageLen: equ $ - youWonMessage
youLostMessage: db "you lost T_T", 0xA
youLostMessageLen: equ $ - youLostMessage
aiThinkingMessage: db "AI thinking"
aiThinkingMessageLen: equ $ - aiThinkingMessage
aiThinkingDotMessage: db "."
aiThinkingDotMessageLen: equ $ - aiThinkingDotMessage
endlnMessage: db 0xA
endlnMessageLen: equ $ - endlnMessage
section .bss
userInputBuffer resb 256
section .data
fieldBuffer: db "#########", 0xA, "# #", 0xA, "# #", 0xA, "# #", 0xA, "#########", 0xA
fieldBufferLen: equ $ - fieldBuffer