#include #include #include void draw_board(int boardState[3][3]) { for(int r = 0; r < 3; r++) { char* line = calloc(3, 1); for(int c = 0; c < 3; c++) { if(boardState[c][r] == 0) { line[c] = '-'; } else if(boardState[c][r] == 1) { line[c] = 'x'; } else if(boardState[c][r] == 2) { line[c] = 'o'; } else { line[c] = 'E'; } } printf(line); printf("\n"); free(line); } } int check_dir(int sx, int sy, int dx, int dy, int boardState[3][3]) { int sv = boardState[sx][sy]; if(sv != 0) { for(int i = 0; i < 2; i++) { sx += dx; sy += dy; if(boardState[sx][sy] != sv) { return 0; } } return sv; } return 0; } //return 0 if no win, 1 if x win, 2 if o win int check_win(int boardState[3][3]) { if(boardState[1][1] != 0) { int c = check_dir(1, 0, 0, 1, boardState); if(c != 0) { return c; } c = check_dir(0, 0, 1, 1, boardState); if(c != 0) { return c; } c = check_dir(0, 1, 1, 0, boardState); if(c != 0) { return c; } c = check_dir(0, 2, 1, -1, boardState); if(c != 0) { return c; } } if(boardState[0][0] != 0) { int c = check_dir(0, 0, 1, 0, boardState); if(c != 0) { return c; } c = check_dir(0, 0, 0, 1, boardState); if(c != 0) { return c; } } if(boardState[2][2] != 0) { int c = check_dir(2, 2, -1, 0, boardState); if(c != 0) { return c; } c = check_dir(2, 2, 0, -1, boardState); if(c != 0) { return c; } } return 0; } int is_full(int boardState[3][3]) { //if all squares full, return 1 //else return 0 for(int r = 0; r < 3; r++) { for(int c = 0; c < 3; c++) { if(boardState[c][r] == 0) { return 0; } } } return 1; } int get_game_state(int boardState[3][3]) { //0 if game in progress, 1 if x win, 2 if o win, 3 if drawn int w = check_win(boardState); if(w == 1 || w == 2) { return w; } else if(is_full(boardState)) { return 3; } else { return 0; } } int* user_input_pos(int boardState[3][3], int turn) { int* ip = malloc(2 * sizeof(int)); printf("Enter X coordinate"); scanf("%d", &ip[0]); printf("Enter Y coordinate"); scanf("%d", &ip[1]); return ip; } struct PosInfo { int* pos; int eval; }; struct PosInfo minimax(int boardState[3][3], int turn) { int eval; int bestMove[2] = { -1, -1 }; int s = get_game_state(boardState); if(s == 1) { eval = 10; } else if(s == 2) { eval = -10; } else if(s == 3) { eval = 0; } else { eval = -999; for(int r = 0; r < 3; r++) { for(int c = 0; c < 3; c++) { if(boardState[c][r] == 0) { int simBoard[3][3]; //deep copy boardState to simBoard for(int i = 0; i < 9; i++) { simBoard[i % 3][i / 3] = boardState[i % 3][i / 3]; } simBoard[c][r] = turn + 1; struct PosInfo mr = minimax(simBoard, !turn); if((turn == 0 && mr.eval > eval) || (turn == 1 && mr.eval < eval) || eval == -999) { eval = mr.eval; bestMove[0] = c; bestMove[1] = r; } } } } } //don't forget to clean up bestmove pointers struct PosInfo posInfo; posInfo.eval = eval; posInfo.pos = bestMove; return posInfo; } int* ai_input_pos(int boardState[3][3], int turn) { struct PosInfo i = minimax(boardState, turn); int* nPos = malloc(2 * sizeof(int)); nPos[0] = i.pos[0]; nPos[1] = i.pos[1]; return nPos; } void clear_screen() { system("@cls||clear"); } int main() { int board[3][3] = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }; int turn = 0; int* (*get_move_ptrs[2])(int[3][3], int) = { &user_input_pos, &ai_input_pos }; while(1) { clear_screen(); draw_board(board); int* tl = get_move_ptrs[turn](board, turn); board[tl[0]][tl[1]] = turn + 1; free(tl); int s = get_game_state(board); if(s == 1 || s == 2) { clear_screen(); draw_board(board); printf("Someone won!"); printf("\n"); break; } if(s == 3) { printf("Game is drawn!"); printf("\n"); break; } turn = !turn; } return 0; }