/* 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; }