.global _start _start: BL _printboard _inputloop: BL _getdigit LDR R1, =firstmove STRB R0, [R1] BL _getdigit LDR R2, =firstmove LDRB R1, [R2] BL _isvalidmove CMP R2, #1 BEQ _inputloop @ move was invalid, retry BL _checkwin @ check if move was a winning one CMP R0, #1 BEQ _player_won LDR R1, =currentmove @ check if max moves exceeded LDRB R2, [R1] ADD R0, R2, #1 CMP R0, #8 BHI _tie_end @ max moves achieved, its a tie STRB R0, [R1] LDR R1, =currentplayer @ change active player LDRB R0, [R1] CMP R0, #79 @ '79' == 'O', player 1 BEQ _setplayer2 MOV R0, #79 @ set current player to 1 STRB R0, [R1] B _start _setplayer2: MOV R0, #88 @ set current player to 2 STRB R0, [R1] B _start _player_won: LDR R1, =currentplayer LDRB R0, [R1] LDR R1, =output_player_won ADD R2, R1, #7 STRB R0, [R2] @ store the current player as winner MOV R2, #14 BL _print B _end _tie_end: LDR R1, =output_tie MOV R2, #5 BL _print _end: BL _printboard MOV R7, #1 SWI 0 _checkwin: MOV R0, #0 _checkwin_iterate: LDR R2, =boardlines @ base ptr LDR R3, =board ADD R1, R2, R0 @ iteration offset LDRB R2, [R1], #1 @ index to check ADD R4, R2, R3 LDRB R5, [R4] @ cell #1 CMP R5, #95 @ stop if first cell is empty BEQ _checkwin_next_line LDRB R2, [R1], #1 ADD R4, R2, R3 LDRB R6, [R4] @ cell #2 CMP R5, R6 BNE _checkwin_next_line LDRB R2, [R1] ADD R4, R2, R3 LDRB R7, [R4] @ cell #3 CMP R5, R7 BNE _checkwin_next_line B _checkwin_win _checkwin_next_line: ADD R1, R0, #3 MOV R0, R1 CMP R0, #21 BLS _checkwin_iterate _checkwin_nowin: MOV R0, #0 BX lr _checkwin_win: MOV R0, #1 BX lr _isvalidmove: @ checks if the move in R0, R1 is valid and sets R2 accordingly MOV R3, #3 MUL R2, R1, R3 ADD R3, R0, R2 LDR R4, =board ADD R2, R4, R3 LDRB R3, [R2] CMP R3, #95 @ '95' == _ character, empty cell BEQ _isvalidmove_succ MOV R2, #1 @ error, cell already set, retry! BX lr _isvalidmove_succ: LDR R3, =currentplayer @ store the move in the board LDRB R4, [R3] STRB R4, [R2] MOV R2, #0 @ cell set BX lr _getdigit: @ Puts the first read char in R0 MOV R3, lr @ backup lr ptr _getinput: LDR R1, =inputreq MOV R2, #6 BL _print MOV R7, #3 @ syscall read MOV R0, #0 @ from kb device MOV R2, #2 LDR R1, =input @ into SWI 0 @ interrupt to let sys handle the call LDR R1, =input LDRB R2, [R1] CMP R2, #48 @ ascii value of '0' BLS _getinput CMP R2, #51 @ ascii value of '3' BHI _getinput SUB R0, R2, #49 @ subtract ascii value of '1' to bring result into range 0 to 2 MOV lr, R3 @ restore lr ptr BX lr @ Return _printboard: MOV R10, lr MOV R4, #0 @ row index (0, 3 or 6) _printboard_row: MOV R3, #0 @ value index (0, 1, 2) _printboard_nextvalue: ADD R1, R3, R4 @ calculate index LDR R0, =board ADD R2, R0, R1 @ get board array ptr LDRB R0, [R2] @ load board byte LDR R1, =output_row ADD R2, R1, R3 @ get row output str ptr STRB R0, [R2] @ store the player char in output str ADD R0, R3, #1 @ up the value counter MOV R3, R0 CMP R3, #2 @ check if we should print the row BLS _printboard_nextvalue @ no, still 1 or more values to insert LDR R1, =output_row @ prepare to print the row MOV R2, #4 BL _print @ print the row ADD R5, R4, #3 @ get next row MOV R4, R5 CMP R4, #6 @ check if not on last row already BHI _printboard_end @ printed all 3 rows, quit B _printboard_row _printboard_end: BX R10 _print: @ prints the message pointed at by R1 with size in R2 MOV R7, #4 @ syscall write MOV R0, #1 @ to the screen SWI 0 BX lr .data currentplayer: .byte 79 currentmove: .byte 0x00 .align 9 board: .byte 95, 95, 95, 95, 95, 95, 95, 95, 95 .align 24 boardlines: .byte 0, 1, 2, 3, 4, 5, 6, 7, 8, 0, 3, 6, 1, 4, 7, 2, 5, 8, 0, 4, 8, 6, 4, 2 @ 8 x 3 firstmove: .byte 0x00 endline: .ascii "\n" inputreq: .ascii "Input:" @6 input: .ascii " " output_row: .ascii " \n" @4 output_tie: .ascii "tie!\n" @5 output_player_won: .ascii "player X won!\n" @ size 14, X at index 7