One new display function has been added: show_move(...). show_move() displays an 'X', 'O', or blank in each board position.
Three functions have been added to support the tic tac toe game: init_board(), get_move(...), and check_win(...). init_board() simply clears all board positions and sets the winner, x_turn, move_count, and last_move variables to appropriate values. get_move() translates a mouse click into a row and column position. check_win() returns TRUE if a player has won the game; FALSE otherwise.
Finally, new_game() has been implemented. new_game() initializes the board, board window, and status winow.
[...]
#define GAME_MENU "game_menu"
#define UNDO "undo"
#define INSET 5
#define X_WIN "X won!"
#define O_WIN "O won!"
#define TIE "Tie game."
#define X_MOVE "X's turn."
#define O_MOVE "O's turn."
[...]
/* --- Prototypes - display functions --- */
void show_board();
void show_status();
void show_move(int move_x, int move_y);
/* */
/* --- Prototypes - game functions --- */
void init_board();
void get_move(int mouse_x, int mouse_y, int *move_x, int *move_y);
bool check_win(int move_r, int move_c);
/* */
void main(int argc, void *argv[])
{
init_board();
GSinterfaceinit(NAME, IFILE, BSTORE, "wc", G640x480x256, argc, argv);
GSinterface();
}
void init_board()
{
int i, j;
winner = PNONE;
x_turn = TRUE;
move_count = 0;
last_move = NO_MOVE;
for (i=0; i<3; i++)
for (j=0; j<3; j++)
board[i][j] = PNONE;
}
[...]
bool new_game()
{
init_board();
show_board();
show_status();
GSdisablemenuitem(GAME_MENU, UNDO);
return TRUE;
}
[...]
bool make_move(int mouse_x, int mouse_y, DragStatusType status)
{
int move_r, move_c;
if ((status == MOUSE_CLICK) || (status == DRAG_FINAL)) {
if ((move_count < MAX_MOVES) && (winner == PNONE)) {
get_move(mouse_x, mouse_y, &move_r, &move_c);
if (board[move_r][move_c] == PNONE) {
move_count++;
board[move_r][move_c] = x_turn? X : O;
show_move(move_r, move_c);
last_move = move_r*3 + move_c;
GSenablemenuitem(GAME_MENU, UNDO);
if (check_win(move_r, move_c))
winner = x_turn? X : O;
x_turn = !x_turn;
show_status();
}
}
}
return TRUE;
}
void show_board()
{
int x, y, wd, ht;
int i, j;
GSgetdragareaspecs(GAME_WIND, GAME_DRAG, &x, &y, &wd, &ht, NULL, NULL);
GSsetcurrentnamedwindow(GAME_WIND);
/* show board */
GSsetlinesize(5);
GSsetcolor(GSconvertcolor("black"));
GSwdrawline(x+(wd/3), y, x+(wd/3), y+ht);
GSwdrawline(x+(2*wd/3), y, x+(2*wd/3), y+ht);
GSwdrawline(x, y+(ht/3), x+wd, y+(ht/3));
GSwdrawline(x, y+(2*ht/3), x+wd, y+(2*ht/3));
/* show moves */
for (i=0; i<3; i++)
for (j=0; j<3; j++)
show_move(i, j);
}
void show_move(int move_r, int move_c)
{
int x, y, wd, ht;
int bx, by, bwd, bht;
GSColor col;
GSgetdragareaspecs(GAME_WIND, GAME_DRAG, &x, &y, &wd, &ht, NULL, &col);
bx = x + (wd/3)*move_c + INSET;
by = y + (ht/3)*move_r + INSET;
bwd = wd/3 - 2*INSET;
bht = ht/3 - 2*INSET;
GSsetcurrentnamedwindow(GAME_WIND);
GSsetcolor(GSconvertcolor("black"));
if (board[move_r][move_c] == X) {
GSwdrawline(bx, by, bx+bwd, by+bht);
GSwdrawline(bx+bwd, by, bx, by+bht);
}
else if (board[move_r][move_c] == O)
GSwdrawellipse(bx, by, bwd, bht);
else {
GSsetcolor(col);
GSwfillrect(bx-1, by-1, bwd+2, bht+2);
}
}
[...]
void get_move(int mouse_x, int mouse_y, int *move_r, int *move_c)
{
int wd, ht;
GSgetdragareaspecs(GAME_WIND, GAME_DRAG, NULL, NULL, &wd, &ht, NULL, NULL);
*move_r = mouse_y / (ht/3);
*move_c = mouse_x / (wd/3);
}
bool check_win(move_r, move_c)
{
int i, j;
if ((board[0][move_c] == board[1][move_c])
&& (board[1][move_c] == board[2][move_c])
&& (board[0][move_c] != PNONE))
return TRUE;
if ((board[move_r][0] == board[move_r][1])
&& (board[move_r][1] == board[move_r][2])
&& (board[move_r][0] != PNONE))
return TRUE;
if (move_r == move_c) {
if ((board[0][0] == board[1][1])
&& (board[1][1] == board[2][2])
&& (board[0][0] != PNONE))
return TRUE;
}
if (move_r == 2-move_c) {
if ((board[0][2] == board[1][1])
&& (board[1][1] == board[2][0])
&& (board[0][2] != PNONE))
return TRUE;
}
return FALSE;
}
[...]