331 lines
7.6 KiB
ArmAsm
331 lines
7.6 KiB
ArmAsm
global _start
|
|
|
|
section .text
|
|
|
|
checkVictory:
|
|
mov eax, 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 r8, 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 r8, rax
|
|
|
|
; clamping to 1-3 range and moving to rdi
|
|
mov rsi, 3
|
|
mov rax, 0
|
|
mov al, r8b
|
|
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 ax, r8w
|
|
shr ax, 8
|
|
mov dx, 0
|
|
div si
|
|
inc dx
|
|
mov dil, dl
|
|
mov rsi, 'o'
|
|
call placeChar
|
|
cmp rax, 0
|
|
je .return
|
|
mov rax, r8
|
|
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 ;
|
|
|
|
mov rbp, 0 ; number of moves done
|
|
.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
|
|
|
|
inc rbp
|
|
|
|
;check win condition
|
|
mov rdi, 'x'
|
|
call checkVictory
|
|
cmp rax, 0
|
|
jne .printYouWon
|
|
|
|
cmp rbp, 5 ; player did 5 moves, time to go
|
|
je .printDraw
|
|
|
|
;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
|
|
|
|
.printDraw:
|
|
call drawField
|
|
mov rax, 1 ; sys_write
|
|
mov rdi, 1 ; out
|
|
mov rsi, drawMessage ; str
|
|
mov rdx, drawMessageLen ; 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
|
|
drawMessage: db "it's a draw", 0xA
|
|
drawMessageLen: equ $ - drawMessage
|
|
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 |