; 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