|
Hobbyist Programmer
Join Date: Nov 2004
Location: 1691 miles East of L.A.
Posts: 159
Rep Power: 4 
|
test
.686 .model flat, stdcall option casemap :none include \masm32\include\windows.inc include \masm32\macros\macros.asm include \masm32\include\masm32.inc include \masm32\include\kernel32.inc include \masm32\include\user32.inc includelib \masm32\lib\user32.lib includelib \masm32\lib\masm32.lib includelib \masm32\lib\kernel32.lib .data ; strings -n- things cmp_win db 'The computer has won.',0Dh,0Ah,0 plr_win db 'The player has won.',0Dh,0Ah,0 itsa_tie db 'You have battled to a tie.',0Dh,0Ah,0 s_about db 0Dh,0Ah,' |== TIC/TAC/TOE in assembler by lostcauz ==|',0 s_format db ' ',0 board_view db '---------',0 two_newlines db 0Dh,0Ah,0Dh,0Ah,0 one_newline db 0Dh,0Ah,0 buffer db 'EEE',0 ; counter num_moves db 0 num_wins db 0h,0h,0h ; dword variables board_state dd 00000000h game_over_bit dd 00040000h turn_bit dd 00080000h ; =============================================== TABLES =================================================== ; win tables represent board states that cause victory cmp_win_table dd 00000015h,00000540h,00001041h,00001110h,00004104h,00010101h,00010410h,00015000h plr_win_table dd 0000002Ah,00000A80h,00002082h,00002220h,00008208h,00020202h,00020820h,0002A000h ; value tables represent squares being occupied comptr_values dd 00000001h,00000004h,00000010h,00000040h,00000100h,00000400h,00001000h,00004000h,00010000h player_values dd 00000002h,00000008h,00000020h,00000080h,00000200h,00000800h,00002000h,00008000h,00020000h ; Artificial Intelligence table (I chose a playable level of difficulty) ai_comp_moves dd 00000014h,00001040h,00010100h,00000028h,00002080h,00020200h dd 00000011h,00004100h,00000022h,00008200h dd 00000005h,00010400h,00001100h,0000000Ah,00020800h,00002200h dd 00000500h,00001001h,00000A00h,00002002h dd 00000440h,00004004h,00010001h,00001010h,00000880h,00008008h,00020002h,00002020h dd 00000140h,00010010h,00000280h,00020020h dd 00014000h,00000041h,00000110h,00028000h,00000082h,00000220h dd 00011000h,00000104h,00022000h,00000208h dd 00005000h,00000410h,00000101h,0000A000h,00000820h,00000202h ; =========================================================================================================== .code start: print addr s_about xor eax,eax ; start new game mov board_state,eax ; clear board_state mov num_moves,al ; clear num_moves game_loop: call get_move ; get next move call show_board ; show board... mov eax,board_state ; load current board state and eax,game_over_bit ; and to see if game is over cmp eax,game_over_bit ; if bit is set, game over jne game_loop ; continue mov eax,sval(input("Press <enter> to continue, any letter first to quit. ")) or eax,eax ; quit? jnz byby ; yep... time ta jet. mov ecx,board_state and ecx,turn_bit cmp ecx,turn_bit jne start xor ecx,ecx ; clear current state of board mov num_moves,cl xor ecx,turn_bit ; toggle turn switch mov board_state,ecx ; save state jmp game_loop ; play it again. byby: exit ; i'm outta here.... ; ============================= get_move ==================================== get_move: mov ecx,board_state ; load current state of board add num_moves,1 ; increment move counter xor ecx,turn_bit ; toggle turn switch mov board_state,ecx ; save state and ecx,turn_bit ; gotta take turns cmp ecx,turn_bit ; ... je cmp_turn ; computer turn jmp plr_turn ; player turn mov_ret: cmp num_moves,9 ; 9 total moves in this game jb @f ; continue playing mov eax,game_over_bit ; 9 moves reached mov ecx,board_state ; load current state and ecx,eax ; see if game_over_bit is set yet cmp ecx,eax ; ... je c_up ; get out, the win came on move 9 add board_state,eax ; set the game_over_bit @@: cmp num_moves,5 ; 5 moves before we need to test for win jb c_up ; just leave call test_win ; better see if there's a winner c_up: ret ; return to caller ; ========================= players turn ================================ plr_turn: print addr two_newlines ; couple newlines @@: xor eax,eax ; zero the register, prolly not necessary mov eax,sval(input("Enter your move 1-9 : ")) or eax,eax ; did the dummy enter '0' anyhow? jz @b ; yep... mov ecx,board_state ; load current state sub eax,1 ; adjust per array cmp eax,8 ; did the waferhead enter > 9? ja @b ; yep... mov ebx,ecx ; need to make sure nobody owns this square and ebx,[player_values+eax*4] ; and board state with table position value cmp ebx,[player_values+eax*4] ; determine if it is set je @b ; player owns the square mov ebx,ecx ; load board state and ebx,[comptr_values+eax*4] ; and with table position value cmp ebx,[comptr_values+eax*4] ; determine if it is set je @b ; computer owns the square add ecx,[player_values+eax*4] ; update state with new move mov board_state,ecx ; save new board state jmp mov_ret ; ======================== computers turn =============================== cmp_turn: print addr two_newlines ; couple newlines mov ebx,-4 ; prepare for loop try_cmp: add ebx,4 ; increment computer value table position mov eax,board_state ; load board state... yawn... and eax,[comptr_values+ebx] ; and state with comptr_values table pointer cmp eax,[comptr_values+ebx] ; test if bit was set je try_cmp ; computer already owns this square mov eax,board_state ; reload board state and eax,[player_values+ebx] ; and with player value table cmp eax,[player_values+ebx] ; bit set? je try_cmp ; player owns this square ; ========================== AI begins ========================= mov eax,board_state ; The square is empty cmp ebx,0 jne @f and eax,[ai_comp_moves] ; check winning combinations cmp eax,[ai_comp_moves] je ai_move ; is this a winning move? or the best move? mov eax,board_state and eax,[ai_comp_moves+04h] cmp eax,[ai_comp_moves+04h] je ai_move mov eax,board_state and eax,[ai_comp_moves+08h] cmp eax,[ai_comp_moves+08h] je ai_move ; made it this far, it's not a win to move here. mov eax,board_state ; look for a block now. and eax,[ai_comp_moves+0Ch] ; We must block or player can win cmp eax,[ai_comp_moves+0Ch] je ai_move mov eax,board_state and eax,[ai_comp_moves+010h] cmp eax,[ai_comp_moves+010h] je ai_move mov eax,board_state and eax,[ai_comp_moves+014h] cmp eax,[ai_comp_moves+014h] je ai_move jmp try_cmp ; try another more interesting square @@: cmp ebx,4 jne @f mov eax,board_state and eax,[ai_comp_moves+018h] ; check winning combinations cmp eax,[ai_comp_moves+018h] je ai_move ; is this a winning move? or the best move? mov eax,board_state and eax,[ai_comp_moves+01Ch] cmp eax,[ai_comp_moves+01Ch] je ai_move ; blocking code mov eax,board_state ; load board state and eax,[ai_comp_moves+020h] ; and with player aggression cmp eax,[ai_comp_moves+020h] ; determine if player is in a '1 move to win' situation je ai_move ; We must block or player can win mov eax,board_state ; ... and eax,[ai_comp_moves+024h] ; another '1 move to win' situation for the player cmp eax,[ai_comp_moves+024h] ; hopefully it's not set... je ai_move ; it's set, play the block. jmp try_cmp ; try another more interesting square @@: cmp ebx,8 jne @f mov eax,board_state and eax,[ai_comp_moves+028h] ; check winning combinations cmp eax,[ai_comp_moves+028h] je ai_move ; is this a winning move? mov eax,board_state and eax,[ai_comp_moves+02Ch] cmp eax,[ai_comp_moves+02Ch] je ai_move mov eax,board_state and eax,[ai_comp_moves+030h] cmp eax,[ai_comp_moves+030h] je ai_move ; blocking code mov eax,board_state ; load board state and eax,[ai_comp_moves+034h] ; and with player aggression cmp eax,[ai_comp_moves+034h] ; determine if player is in a '1 move to win' situation je ai_move ; We must block or player can win mov eax,board_state ; ... and eax,[ai_comp_moves+038h] ; another '1 move to win' situation for the player cmp eax,[ai_comp_moves+038h] ; hopefully it's not set... je ai_move ; it's set, play the block. mov eax,board_state ; ... and eax,[ai_comp_moves+03Ch] cmp eax,[ai_comp_moves+03Ch] ; hopefully it's not set... je ai_move ; it's set, play the block. jmp try_cmp ; try another more interesting square @@: cmp ebx,12 jne @f mov eax,board_state and eax,[ai_comp_moves+040h] ; check winning combinations cmp eax,[ai_comp_moves+040h] je ai_move ; is this a winning move? or the best move? mov eax,board_state and eax,[ai_comp_moves+044h] cmp eax,[ai_comp_moves+044h] je ai_move ; blocking code mov eax,board_state ; load board state and eax,[ai_comp_moves+048h] cmp eax,[ai_comp_moves+048h] je ai_move ; We must block or player can win mov eax,board_state ; ... and eax,[ai_comp_moves+04Ch] ; another '1 move to win' situation for the player cmp eax,[ai_comp_moves+04Ch] ; hopefully it's not set... je ai_move ; it's set, play the block. jmp try_cmp ; try another more interesting square @@: cmp ebx,16 jne @f mov eax,board_state and eax,[ai_comp_moves+050h] ; check winning combinations cmp eax,[ai_comp_moves+050h] je ai_move ; is this a winning move? mov eax,board_state and eax,[ai_comp_moves+054h] cmp eax,[ai_comp_moves+054h] je ai_move mov eax,board_state and eax,[ai_comp_moves+058h] cmp eax,[ai_comp_moves+058h] je ai_move mov eax,board_state and eax,[ai_comp_moves+05Ch] cmp eax,[ai_comp_moves+05Ch] je ai_move ; blocking code mov eax,board_state ; load board state and eax,[ai_comp_moves+060h] ; and with player aggression cmp eax,[ai_comp_moves+060h] ; determine if player is in a '1 move to win' situation je ai_move ; We must block or player can win mov eax,board_state ; ... and eax,[ai_comp_moves+064h] cmp eax,[ai_comp_moves+064h] je ai_move ; it's set, play the block. mov eax,board_state ; ... and eax,[ai_comp_moves+068h] ; another '1 move to win' situation for the player cmp eax,[ai_comp_moves+068h] ; hopefully it's not set... je ai_move ; it's set, play the block. mov eax,board_state ; ... and eax,[ai_comp_moves+06Ch] ; another '1 move to win' situation for the player cmp eax,[ai_comp_moves+06Ch] ; hopefully it's not set... je ai_move ; it's set, play the block. jmp try_cmp ; try another more interesting square @@: cmp ebx,20 jne @f mov eax,board_state and eax,[ai_comp_moves+070h] ; check winning combinations cmp eax,[ai_comp_moves+070h] je ai_move mov eax,board_state and eax,[ai_comp_moves+074h] cmp eax,[ai_comp_moves+074h] je ai_move mov eax,board_state ; ... and eax,[ai_comp_moves+078h] cmp eax,[ai_comp_moves+078h] ; hopefully it's not set... je ai_move ; it's set, play the block. mov eax,board_state and eax,[ai_comp_moves+07Ch] cmp eax,[ai_comp_moves+07Ch] je ai_move ; it's set, play the block. jmp try_cmp ; try another more interesting square @@: cmp ebx,24 jne @f mov eax,board_state and eax,[ai_comp_moves+080h] ; check winning combinations cmp eax,[ai_comp_moves+080h] je ai_move mov eax,board_state and eax,[ai_comp_moves+084h] cmp eax,[ai_comp_moves+084h] je ai_move mov eax,board_state and eax,[ai_comp_moves+088h] cmp eax,[ai_comp_moves+088h] je ai_move ; blocking code mov eax,board_state ; load board state and eax,[ai_comp_moves+08Ch] ; and with player aggression cmp eax,[ai_comp_moves+08Ch] je ai_move ; We must block or player can win mov eax,board_state and eax,[ai_comp_moves+090h] cmp eax,[ai_comp_moves+090h] ; hopefully it's not set... je ai_move ; it's set, play the block. mov eax,board_state and eax,[ai_comp_moves+094h] cmp eax,[ai_comp_moves+094h] ; hopefully it's not set... je ai_move ; it's set, play the block. jmp try_cmp ; try another interesting square @@: cmp ebx,28 jne @f mov eax,board_state and eax,[ai_comp_moves+098h] ; check winning combinations cmp eax,[ai_comp_moves+098h] je ai_move ; is this a winning move? or the best move? mov eax,board_state and eax,[ai_comp_moves+09Ch] cmp eax,[ai_comp_moves+09Ch] je ai_move mov eax,board_state ; ... and eax,[ai_comp_moves+0A0h] ; another '1 move to win' situation for the player cmp eax,[ai_comp_moves+0A0h] ; hopefully it's not set... je ai_move ; it's set, play the block. mov eax,board_state ; ... and eax,[ai_comp_moves+0A4h] cmp eax,[ai_comp_moves+0A4h] ; hopefully it's not set... je ai_move ; it's set, play the block. jmp try_cmp ; try another more interesting square ; (final square), try an advantageous sequence here after testing wins/blocks @@: cmp ebx,32 jne @f mov eax,board_state and eax,[ai_comp_moves+0A8h] ; check winning combinations cmp eax,[ai_comp_moves+0A8h] je ai_move mov eax,board_state and eax,[ai_comp_moves+0ACh] cmp eax,[ai_comp_moves+0ACh] je ai_move mov eax,board_state and eax,[ai_comp_moves+0B0h] cmp eax,[ai_comp_moves+0B0h] je ai_move ; blocking code mov eax,board_state ; load board state and eax,[ai_comp_moves+0B4h] cmp eax,[ai_comp_moves+0B4h] ; determine if player is in a '1 move to win' situation je ai_move ; We must block or player can win mov eax,board_state ; ... and eax,[ai_comp_moves+0B8h] cmp eax,[ai_comp_moves+0B8h] je ai_move ; it's set, play the block. mov eax,board_state ; ... and eax,[ai_comp_moves+0BCh] cmp eax,[ai_comp_moves+0BCh] ; hopefully it's not set... je ai_move ; it's set, play the block. ; now just make a move in a decent sequence - 4,0,5,6,1,8,3,2,7 mov eax,board_state ; load board state.. and eax,[comptr_values+010h] ; center square cmp eax,[comptr_values+010h] ; test if bit was set je @f ; computer already owns this square mov eax,board_state ; reload board state and eax,[player_values+010h] ; and with player value table cmp eax,[player_values+010h] ; bit set? je @f ; player owns this square mov ebx,010h jmp ai_move @@: mov eax,board_state ; load board state.. and eax,[comptr_values] ; upper-left square cmp eax,[comptr_values] ; test if bit was set je @f ; computer already owns this square mov eax,board_state ; reload board state and eax,[player_values] ; and with player value table cmp eax,[player_values] ; bit set? je @f ; player owns this square xor ebx,ebx jmp ai_move @@: mov eax,board_state ; load board state.. and eax,[comptr_values+014h] ; middle-right square cmp eax,[comptr_values+014h] ; test if bit was set je @f ; computer already owns this square mov eax,board_state ; reload board state and eax,[player_values+014h] ; and with player value table cmp eax,[player_values+014h] ; bit set? je @f ; player owns this square mov ebx,014h jmp ai_move @@: mov eax,board_state ; load board state.. and eax,[comptr_values+018h] ; lower-left square cmp eax,[comptr_values+018h] ; test if bit was set je @f ; computer already owns this square mov eax,board_state ; reload board state and eax,[player_values+018h] ; and with player value table cmp eax,[player_values+018h] ; bit set? je @f ; player owns this square mov ebx,018h jmp ai_move @@: mov eax,board_state ; load board state.. and eax,[comptr_values+04h] ; upper-center square cmp eax,[comptr_values+04h] ; test if bit was set je @f ; computer already owns this square mov eax,board_state ; reload board state and eax,[player_values+04h] ; and with player value table cmp eax,[player_values+04h] ; bit set? je @f ; player owns this square mov ebx,04h jmp ai_move @@: mov eax,board_state ; load board state.. and eax,[comptr_values+020h] ; lower-right square cmp eax,[comptr_values+020h] ; test if bit was set je @f ; computer already owns this square mov eax,board_state ; reload board state and eax,[player_values+020h] cmp eax,[player_values+020h] ; bit set? je @f ; player owns this square mov ebx,020h jmp ai_move @@: mov eax,board_state ; load board state.. and eax,[comptr_values+0Ch] ; middle-left square cmp eax,[comptr_values+0Ch] ; test if bit was set je @f ; computer already owns this square mov eax,board_state ; reload board state and eax,[player_values+0Ch] cmp eax,[player_values+0Ch] ; bit set? je @f ; player owns this square mov ebx,0Ch jmp ai_move @@: mov eax,board_state ; load board state.. and eax,[comptr_values+08h] ; upper-right square cmp eax,[comptr_values+08h] ; test if bit was set je @f ; computer already owns this square mov eax,board_state ; reload board state and eax,[player_values+08h] cmp eax,[player_values+08h] ; bit set? je @f ; player owns this square mov ebx,08h jmp ai_move @@: mov ebx,01Ch ; lower-left square ai_move: mov eax,board_state add eax,[comptr_values+ebx] ; set the bit mov board_state,eax ; save new board state ;print str$([comptr_values+ebx]) ; debugging... jmp mov_ret ; cruise... ; =============================== test_win ===================================== test_win: push ebx ; preserve registers mov ecx,board_state ; load current state of board xor edx,edx ; counter for table traversal traverse: mov ebx,ecx ; load for manipulation mov eax,ecx ; load for manipulation and ebx,[cmp_win_table+edx] ; and cmp_win_table for computer win and eax,[plr_win_table+edx] ; and plr_win_table for player win cmp ebx,[cmp_win_table+edx] ; test result with cmp_win_table je computa ; equal, computer wins cmp eax,[plr_win_table+edx] ; test result with plr_win_table je playa ; equal, player wins add edx,4 ; increment counter cmp edx,32 jb traverse ; continue and ecx,game_over_bit ; determine if all moves are exhausted cmp ecx,game_over_bit ; ... jne clean ; nope, next move print addr itsa_tie ; must be a tie.. print addr two_newlines ; couple newlines add byte ptr[num_wins+2],1 score: print chr$(" Computer: ") ; print scores xor eax,eax mov al,byte ptr[num_wins] print str$(eax) print chr$(" Player: ") xor eax,eax mov al,byte ptr[num_wins+1] print str$(eax) print chr$(" Ties: ") xor eax,eax mov al,byte ptr[num_wins+2] print str$(eax) clean: print addr one_newline pop ebx ; clean up ret ; return computa: print addr cmp_win ; computer wins print addr two_newlines ; couple newlines mov eax,game_over_bit ; game over add board_state,eax ; update board state add byte ptr[num_wins],1 jmp score ; clean up playa: print addr plr_win ; player wins print addr two_newlines ; couple newlines mov eax,game_over_bit ; game over add board_state,eax ; update board state add byte ptr[num_wins+1],1 jmp score ; =============================== show_board ================================== show_board: push ebx ; preserve registers push esi ; continue housekeeping push edi ; ... mov ecx,board_state ; load current state lea esi,comptr_values ; address computer values lea edi,player_values ; address player values xor ebx,ebx ; counter for table traversal sub esi,4 ; prepare fer computer_value table cipherin' sub edi,4 ; prepare fer player_value table cipherin' l1: mov eax,ecx ; load board state for testing add esi,4 ; update pointer to computer values table mov edx,ecx ; load board state for testing against player add edi,4 ; update pointer to player values table and eax,[esi] ; computer == 'O' and edx,[edi] ; player == 'X' cmp eax,[esi] ; computer owns the square je c_square ; ... cmp edx,[edi] ; player owns the square je p_square ; ... mov byte ptr[board_view+ebx],'-' ; unoccupied square pr_ret: add ebx,1 ; increment base index for board_view cmp ebx,9 ; last one? jnz l1 ; continue print addr one_newline ; newline lea edi,buffer ; buffer helps break down board_view for print lea esi,board_view ; load effective address board_view mov ax,[esi] ; load first word stosw ; store word mov al,[esi+2] ; load next byte stosb ; store byte print addr s_format ; formatting print addr buffer ; print 1 word and 1 byte print addr one_newline ; newline lea edi,buffer ; reload buffer mov ax,[esi+3] ; load word stosw ; store word mov al,[esi+5] ; load byte stosb ; store byte print addr s_format ; formatting print addr buffer ; print the 3 characters in buffer print addr one_newline ; newline lea edi,buffer ; reload mov ax,[esi+6] ; load word stosw ; store it mov al,[esi+8] ; load byte stosb ; store byte print addr s_format ; formatting print addr buffer ; print 3 characters print addr one_newline ; newline pop edi ; sweep... pop esi ; mop... pop ebx ; and wax... ret ; return to caller p_square: mov byte ptr[board_view+ebx],'X' ; set players square jmp pr_ret ; return c_square: mov byte ptr[board_view+ebx],'O' ; set computers square jmp pr_ret ; return end start
|