1 /* tic tac toe (noughts and crosses) Author: Warren Toomey */
3 /* Copyright 1988 by Warren Toomey wkt@cs.adfa.oz.au[@uunet.uu.net]
5 * You may freely copy or distribute this code as long as this notice
8 * You may modify this code, as long as this notice remains intact, and
9 * you add another notice indicating that the code has been modified.
11 * You may NOT sell this code or in any way profit from this code without
12 * prior agreement from the author.
15 /* Compile with cc -o tic tic.c -lcurses -ltermcap */
32 int value
; /* The move returned by the */
33 int path
; /* alphabeta consists of a value */
34 } MOVE
; /* and an actual move (path) */
36 _PROTOTYPE(int main
, (void));
37 _PROTOTYPE(int stateval
, (int board
[], int whosemove
));
38 _PROTOTYPE(MOVE alphabeta
, (int board
[], int whosemove
, int alpha
, int beta
));
39 _PROTOTYPE(void draw
, (int board
[]));
40 _PROTOTYPE(void getmove
, (int board
[]));
41 _PROTOTYPE(int endofgame
, (int board
[]));
42 _PROTOTYPE(int randommove
, (void));
44 /* Static evaluator. Returns 100 if we have 3 in a row -100 if they have 3
47 * Board is array of 9 ints, where 0=empty square 1=our move 4= their move
49 * and board is indices 0 1 2 3 4 5 6 7 8 */
52 int stateval(board
, whosemove
)
56 static int row
[8][3] = {{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, /* Indices of 3in-a-rows */
57 {0, 3, 6}, {1, 4, 7}, {2, 5, 8},
58 {0, 4, 8}, {2, 4, 6}};
60 int temp
; /* Temp row results */
61 int i
, j
; /* Loop counters */
62 int side
; /* Depth multiplier */
70 /* Multiply by -1 if */
75 for (i
= 0; i
< 8; i
++) { /* For every 3-in-a-row */
77 for (j
= 0; j
< 3; j
++) /* Add up the board values */
78 temp
+= board
[row
[i
][j
]];
80 if (temp
== 3) return(win
); /* We've got 3 in a row */
81 if (temp
== 12) return (lose
); /* They've got 3 in a row */
83 return(0); /* Finally return sum */
87 MOVE
alphabeta(board
, whosemove
, alpha
, beta
) /* Alphabeta: takes a board, */
88 int board
[]; /* whose move, alpha & beta cutoffs, */
89 int whosemove
; /* and returns a move to make and */
90 int alpha
; /* the value that the move has */
93 MOVE result
, successor
;
94 int best_score
, i
, best_path
, mademove
;
96 result
.value
= stateval(board
, whosemove
); /* Work out the board's */
98 if ((result
.value
== 100) || /* If a win or loss already */
99 (result
.value
== -100))
100 return(result
); /* return the result */
102 best_score
= beta
; /* Ok, set worst score */
103 mademove
= 0; /* to the beta cutoff */
104 for (i
= 0; i
< 9; i
++) {
105 if (board
[i
] == 0) { /* For all valid moves */
107 board
[i
] = whosemove
; /* make the move on board */
108 successor
= alphabeta(board
, 5 - whosemove
, -best_score
- 1, -alpha
- 1);
109 /* Get value of the move */
110 board
[i
] = 0; /* Take move back */
111 if (-successor
.value
> best_score
) { /* If a better score */
112 best_score
= -successor
.value
; /* update our score */
113 best_path
= i
; /* and move */
114 if (best_score
> alpha
)
115 break; /* If we've beaten alpha */
116 } /* return immediately */
120 result
.value
= best_score
; /* Finally return best score */
121 result
.path
= best_path
;/* and best move */
123 return(result
); /* If no move, return static result */
127 void draw(board
) /* Draw the board */
131 static char out
[] = " X O"; /* Lookup table for character */
137 for (j
= 0; j
< 9; j
+= 3) {
138 printw(" %d | %d | %d ", j
, j
+ 1, j
+ 2);
139 for (i
= 0; i
< 3; i
++) {
140 printw("%c ", out
[board
[j
+ i
]]);
141 if (i
< 2) printw("| ");
149 printw("---+---+--- ---+---+---");
165 void getmove(board
) /* Get a player's move */
176 printw("Your move: "); /* Prompt for move */
179 printw("Your move: "); /* Prompt for move */
181 ItemsRead
= scanf("%d", &Move
); /* Input the move */
182 if (ItemsRead
== 0) scanf("%c", &dumc
); /* Remove the offending character */
184 while (ItemsRead
!= 1);
187 board
[Move
] = 4; /* If legal, add to board */
188 draw(board
); /* Draw the board */
192 int endofgame(board
) /* Determine end of the game */
198 eval
= stateval(board
, 1);
203 printw("I have beaten you.\n");
207 printw("Bus error (core dumped)\n");
211 for (eval
= 0; eval
< 9; eval
++)
212 if (board
[eval
] != 0) count
++;
225 { /* Make an initial random move */
228 i
= abs((int) time((long *) 0));
234 { /* The actual game */
239 for (i
= 0; i
< 9; i
++) board
[i
] = 0; /* Initialise the board */
245 printw(" TIC TAC TOE \n\n");
246 printw(" Your moves are 'O'\n");
247 printw(" My moves are 'X'\n\n");
250 printw("Do you wish to move first: ");
252 while (scanf("%c", &ch
) != 1);
254 printw(" ......."); /* Kludge to get rid */
257 printw(" "); /* of input letter */
261 printw("Do you wish to move first: ");
262 while (scanf("%c", &ch
) != 1);
264 if ((ch
!= 'y') && (ch
!= 'Y')) {
265 i
= randommove(); /* If we move first */
266 board
[i
] = 1; /* make it random */
269 printw("My move: %d\n", i
);
272 printw("My move: %d\n", i
);
279 ourmove
= alphabeta(board
, 1, 99, -99); /* Get a move for us;
281 /* Immediately & ignore losses */
282 board
[ourmove
.path
] = 1;/* and make it */
285 printw("My move: %d\n", ourmove
.path
);
288 printw("My move: %d\n", ourmove
.path
);
291 if (endofgame(board
)) break; /* If end of game, exit */
292 getmove(board
); /* Get opponent's move */
293 if (endofgame(board
)) break; /* If end of game, exit */