/* Copyright (C) 2014 by Alexandru Cojocaru */
/* This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see . */
#include
#include
#include
#include
enum {MX = 1, MO = 2, Draw = 3};
static bool
win_p (int b[3][3], int mark)
{
for (int i = 0; i < 3; ++i) {
if (b[i][0] == mark &&
b[i][1] == mark &&
b[i][2] == mark)
return 1;
if (b[0][i] == mark &&
b[1][i] == mark &&
b[2][i] == mark)
return 1;
}
if (b[0][0] == mark && b[1][1] == mark && b[2][2] == mark)
return 1;
if (b[2][0] == mark && b[1][1] == mark && b[0][2] == mark)
return 1;
return 0;
}
static bool
draw_p (int b[3][3])
{
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j)
if (b[i][j] == 0)
return 0;
return ! (win_p (b, MX) || win_p (b, MO));
}
static bool
gameover_p (int b[3][3])
{
return win_p (b, MX) || win_p (b, MO) || draw_p (b);
}
static int
negamax (int b[3][3], int mark, int move)
{
int opponentmark;
if (mark == MX)
opponentmark = MO;
else
opponentmark = MX;
if (win_p (b, mark))
return 1;
else if (win_p (b, opponentmark))
return -1;
else if (draw_p (b))
return 0;
int max, maxi, maxj;
max = -2;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
if (b[i][j] == 0) {
b[i][j] = mark;
int m = -negamax (b, opponentmark, 0);
if (m > max) {
max = m;
maxi = i;
maxj = j;
}
b[i][j] = 0;
}
}
}
if (move) {
printf ("AI marks `%d'\n", maxj+1 + (maxi)*3);
b[maxi][maxj] = mark;
}
return max;
}
static char
tochar (int mark)
{
if (mark == MX)
return 'X';
else if (mark == MO)
return 'O';
else
return ' ';
}
static void
printb (int b[3][3])
{
for (int i = 0; i < 3; ++i) {
printf ("|");
for (int j = 0; j < 3; ++j)
printf (" %c |", tochar (b[i][j]));
printf ("\n");
if (i != 2)
for (int j = 0; j < 13; ++j)
printf ("-");
printf ("\n");
}
}
static void
usermove (int b[3][3], int mark)
{
int n;
printf ("Where to put the mark (1-9): ");
scanf ("%d", &n);
if (n < 1 || n > 9) {
error (0, 0, "number must be between `0' and `9' (was given: %d)", n);
usermove (b, mark);
return;
}
--n;
if (b[n/3][n%3]) {
error (0, 0, "cell not empty");
usermove (b, mark);
return;
}
b[n/3][n%3] = mark;
printb (b);
}
int
main (void)
{
int b[3][3];
memset (b, 0, sizeof (b));
printb (b);
while (1) {
usermove (b, MO);
if (gameover_p (b))
break;
negamax (b, MX, 1);
printb (b);
if (gameover_p (b))
break;
}
if (win_p (b, MX))
printf ("X wins\n");
else if (win_p (b, MO))
printf ("O wins\n");
else
printf ("draw\n");
return 0;
}