;********************************************************************** ; ; What: tic_tac_toe.s ; Author: David Ljung ; Platform: HP-PA PCXU (PA-8000) assembly ; Description: This plays a mean game of Tic Tac Toe. Prepare to lose. ; ; It was originally written as part of a testrom (as a joke, mostly) - so ; it needs some I/O routines - if you have some weird desire to run this ; you'll need to port the I/O defines below. ; ;********************************************************************** ; -------------------- I/O Defines ------------------------------------- #define GET_CHAR(to_upper,wait,echo) ! \ ldi to_upper,Arg0 ! \ ldi echo,Arg2 ! \ IMMU (GET_CHAR_STUB,Arg1) ! \ bl .+8,r2 ! \ bv (Arg1) ! \ ldi wait,Arg1 #define PRINT_ARG0(len) ! \ IMMU (PRINT_STUB,Arg1) ! \ bl .+8,r2 ! \ bv (Arg1) ! \ ldi len,Arg1 ; Can't use the IMMUR macro in here because it makes the preprocessor hang! #define PRINT_LEN(lbl,len) ! \ .import lbl ! \ .label L_##lbl ! \ bl .+8,Arg0 ! \ IMMU (lbl-L_##lbl-8,Arg1) ! \ add Arg1,Arg0,Arg0 ! \ PRINT_ARG0(len) #define PRINT(lbl) PRINT_LEN(lbl,0) ; -------------------- The Code ---------------------------------------- ; Board is at memory locations 1-9 ; Ascii: #define X 0x58 #define O 0x4F #define EMPTY SPACE #define BAR 0x7C #define DASH 0x2D #define CR 0x0D #define LF 0x0A #define SPACE 0x20 #define ASCII_0 0x30 #define Y 0x59 main ;************************************************** ; Say hi ;************************************************** PRINT (tic_string_welcome) start_game PRINT (tic_string_initial_board) ;************************************************** ; Initialize the board ;************************************************** ldi 1,r1 ldi EMPTY,r2 stb,ma r2,1(r1) stb,ma r2,1(r1) stb,ma r2,1(r1) stb,ma r2,1(r1) stb,ma r2,1(r1) stb,ma r2,1(r1) stb,ma r2,1(r1) stb,ma r2,1(r1) stb,ma r2,1(r1) ;************************************************** ; Computer's first move: ;************************************************** ldi 9,r1 ldi X,r2 stb r2,(r1) ldi 1,r13 ; r13 is the turn counter turn ;************************************************** ; Player move ;************************************************** bl players_move,r2 nop ;************************************************** ; Computers move ;************************************************** bl computers_move,r2 copy ret0,Arg0 ;************************************************** ; Increment turn counter ;************************************************** addi 1,r13,r13 ;************************************************** ; Are we done? ;************************************************** comb,= r0,ret0,turn nop ;************************************************** ; Show the finished board ;************************************************** bl show_board,r2 nop ;************************************************** ; Play again? ;************************************************** PRINT (tic_string_play_again) GET_CHAR (1,-1,1) ldi Y,r1 comb,= r1,ret0,start_game nop PRINT (tic_string_thanks) EXIT ; -------------------- Functions --------------------------------------- ; IO Space #define IO 0x10 #define GET_BUFFER IMMU(IO,Arg0) #define ADD_REG(r) stb,ma r,1(Arg0) #define ADD_CHAR(ch) ldi ch,r1 ! ADD_REG(r1) #define PRINT_BUFFER ADD_REG(r0) ! GET_BUFFER ! PRINT_ARG0(0) ;************************************************** ; Show the board ;************************************************** show_board copy r2,r10 ldi 1,r4 ; Board GET_BUFFER ADD_CHAR (CR) ADD_CHAR (LF) ADD_CHAR (CR) ADD_CHAR (LF) ; First row ADD_CHAR (SPACE) ldb,ma 1(r4),r1 ! ADD_REG (r1) ADD_CHAR (SPACE) ADD_CHAR (BAR) ADD_CHAR (SPACE) ldb,ma 1(r4),r1 ! ADD_REG (r1) ADD_CHAR (SPACE) ADD_CHAR (BAR) ADD_CHAR (SPACE) ldb,ma 1(r4),r1 ! ADD_REG (r1) ADD_CHAR (CR) ADD_CHAR (LF) ADD_CHAR (DASH) ADD_CHAR (DASH) ADD_CHAR (DASH) ADD_CHAR (DASH) ADD_CHAR (DASH) ADD_CHAR (DASH) ADD_CHAR (DASH) ADD_CHAR (DASH) ADD_CHAR (DASH) ADD_CHAR (DASH) ADD_CHAR (DASH) ADD_CHAR (CR) ADD_CHAR (LF) ; Second row ADD_CHAR (SPACE) ldb,ma 1(r4),r1 ! ADD_REG (r1) ADD_CHAR (SPACE) ADD_CHAR (BAR) ADD_CHAR (SPACE) ldb,ma 1(r4),r1 ! ADD_REG (r1) ADD_CHAR (SPACE) ADD_CHAR (BAR) ADD_CHAR (SPACE) ldb,ma 1(r4),r1 ! ADD_REG (r1) ADD_CHAR (CR) ADD_CHAR (LF) ADD_CHAR (DASH) ADD_CHAR (DASH) ADD_CHAR (DASH) ADD_CHAR (DASH) ADD_CHAR (DASH) ADD_CHAR (DASH) ADD_CHAR (DASH) ADD_CHAR (DASH) ADD_CHAR (DASH) ADD_CHAR (DASH) ADD_CHAR (DASH) ADD_CHAR (CR) ADD_CHAR (LF) ; Third row ADD_CHAR (SPACE) ldb,ma 1(r4),r1 ! ADD_REG (r1) ADD_CHAR (SPACE) ADD_CHAR (BAR) ADD_CHAR (SPACE) ldb,ma 1(r4),r1 ! ADD_REG (r1) ADD_CHAR (SPACE) ADD_CHAR (BAR) ADD_CHAR (SPACE) ldb,ma 1(r4),r1 ! ADD_REG (r1) ADD_CHAR (CR) ADD_CHAR (LF) PRINT_BUFFER bv,n (r10) ;************************************************** ; Do the players move ; Returns: Move location ;************************************************** players_move copy r2,r11 move_loop ; Show the board bl show_board,r2 nop ; Prompt PRINT (tic_string_your_move) GET_CHAR (1,-1,1) ; Check answer ldi ASCII_0,r3 sub ret0,r3,r3 ldi 1,r1 comb,<,n r3,r1,invalid_move ldi 9,r1 comb,<=,n r3,r1,move_ok invalid_move PRINT (tic_string_invalid_move) b move_loop nop move_ok ; Check if the space is occupied ldb (r3),r4 ldi EMPTY,r5 comb,=,n r5,r4,not_occupied PRINT (tic_string_occupied) b move_loop nop not_occupied ; Store the 'O' ldi O,r1 stb r1,(r3) bv (r11) copy r3,ret0 ;************************************************** ; Do the computers move ; Argument: Players move location ; Returns: 1 if game done ;************************************************** computers_move copy r2,r10 copy Arg0,r12 ldi 0,ret0 ; Game not done yet ;************************************************** ; Which turn? ;************************************************** comib,<>,n 1,r13,not_turn_one ;************************************************** ; First turn ; r3 move ; r14 force 1 ; r15 force 2 ; r16 next move ; r17 next force 1 ; r18 next force 2 ;************************************************** turn_one ; 1->7, force at 8, next move at 3, next forces at 5,6 comib,<>,n 1,r12,.+28 ldi 7,r3 ldi 8,r14 ldi 0,r15 ldi 3,r16 ldi 5,r17 ldi 6,r18 ; 2->3, force at 6, next move at 5, next forces at 1,7 comib,<>,n 2,r12,.+28 ldi 3,r3 ldi 6,r14 ldi 0,r15 ldi 5,r16 ldi 1,r17 ldi 7,r18 ; 3->7, force at 8, next move at 1, next forces at 4,5 comib,<>,n 3,r12,.+28 ldi 7,r3 ldi 8,r14 ldi 0,r15 ldi 1,r16 ldi 4,r17 ldi 5,r18 ; 4->3, force at 6, next move at 5, next forces at 1,7 comib,<>,n 4,r12,.+28 ldi 3,r3 ldi 6,r14 ldi 0,r15 ldi 5,r16 ldi 1,r17 ldi 7,r18 ; 5->1 comib,<>,n 5,r12,.+28 ldi 1,r3 ldi 0,r14 ldi 0,r15 ldi 0,r16 ldi 0,r17 ldi 0,r18 ; 6->7, force at 8, next move at 1, next forces at 4,5 comib,<>,n 6,r12,.+28 ldi 7,r3 ldi 8,r14 ldi 0,r15 ldi 1,r16 ldi 4,r17 ldi 5,r18 ; 7->3, force at 6, next move at 1, next forces at 2,5 comib,<>,n 7,r12,.+28 ldi 3,r3 ldi 6,r14 ldi 0,r15 ldi 1,r16 ldi 2,r17 ldi 5,r18 ; 8->3, force at 6, next move at 1, next forces at 2,5 comib,<>,n 8,r12,.+28 ldi 3,r3 ldi 6,r14 ldi 0,r15 ldi 1,r16 ldi 2,r17 ldi 5,r18 b,n got_move ;************************************************** ; Do we have a force situation? ;************************************************** not_turn_one comb,=,n r0,r14,no_move ; Did they move there? copy r14,r3 comb,<>,n r12,r14,win took_force_1 ; Did we have a second force? comb,=,n r0,r15,take_next_move ; Did they move there? copy r15,r3 comb,<>,n r12,r15,win take_next_move ; Take the next move comb,=,n r0,r16,no_move copy r16,r3 ; move gets next move copy r17,r14 ; force 1 gets next force 1 copy r18,r15 ; force 2 gets next force 2 copy r0,r16 copy r0,r17 b got_move copy r0,r18 no_move ; This can only happen if they went to five. ; Just counter their moves and look for possible forces. ; 2->8, possible force at 7 comib,<>,n 2,r12,.+24 ldi 8,r3 ldi 7,r14 ldb (r14),r1 subi,= EMPTY,r1,r0 copy r0,r14 ; 3->7, possible forces at 4,8 comib,<>,n 3,r12,.+48 ldi 7,r3 ldi 4,r14 ldb (r14),r1 subi,= EMPTY,r1,r0 copy r0,r14 ldi 8,r15 ldb (r15),r1 subi,= EMPTY,r1,r0 copy r0,r15 sub,<> r0,r14,r0 copy r15,r14 ; 4->6, possible force at 3 comib,<>,n 4,r12,.+24 ldi 6,r3 ldi 3,r14 ldb (r15),r1 subi,= EMPTY,r1,r0 copy r0,r14 ; 6->4, possible force at 7 comib,<>,n 6,r12,.+24 ldi 4,r3 ldi 7,r14 ldb (r14),r1 subi,= EMPTY,r1,r0 copy r0,r14 ; 7->3, possible forces at 2,6 comib,<>,n 7,r12,.+48 ldi 3,r3 ldi 2,r14 ldb (r14),r1 subi,= EMPTY,r1,r0 copy r0,r14 ldi 6,r15 ldb (r15),r1 subi,= EMPTY,r1,r0 copy r0,r15 sub,<> r0,r14,r0 copy r15,r14 ; 8->2, possible force at 3 comib,<>,n 8,r12,.+24 ldi 2,r3 ldi 3,r14 ldb (r14),r1 subi,= EMPTY,r1,r0 copy r0,r14 ; If its turn 4, then we are done comib,<>,n 4,r13,got_move tie PRINT (tic_string_tie) b got_move ldi 1,ret0 ; Game done win PRINT (tic_string_win) b got_move ldi 1,ret0 ; Game done got_move ldi X,r1 bv (r10) stb r1,(r3) ; -------------------- The Strings ------------------------------------- tic_string_welcome STRINGZ("\r\n\ Welcome to Phase II Tic-Tac-Toe\r\n\ Author: David Ljung\r\n\ Version: 1.0\r\n") tic_string_initial_board STRINGZ("\r\n\r\n\ 1 | 2 | 3\r\n\ -----------\r\n\ 4 | 5 | 6\r\n\ -----------\r\n\ 7 | 8 | 9\r\n") tic_string_your_move STRINGZ("\r\nYour move: ") tic_string_invalid_move STRINGZ("\r\n Invalid move - please use locations 1-9\r\n") tic_string_occupied STRINGZ("\r\n That space is occupied\r\n") tic_string_win STRINGZ("\r\n\r\n ------\r\n I WIN!\r\n ------\r\n") tic_string_tie STRINGZ("\r\n\r\n --------\r\n TIE GAME\r\n --------\r\n") tic_string_play_again STRINGZ("\r\nPlay again? [y/n] ") tic_string_thanks STRINGZ("\r\n\r\n Thanks for playing!\r\n\r\n") .end