Note #1 - There is a similar question but that is in Python, and I can't figure out this in C.
Note #2 - This is a human vs. AI game and I will call the AI as 'cpu'. The cpu symbol is 'O' and human symbol is 'X' always.
Note #3 - I want to design the game so that the cpu never loses (either win or draw).
I want the user to go first and choose any of the 9 squares. So basically I want the cpu to brute force calculate the result of every way the game can go, and based on that assign 'scores' to its possible moves (8 remaining choices). This way it backtracks and knows which way to go so as to not lose.
Also I want to do that using the minimax algorithm, and in C.
My problem - What I think is that I'm missing a function that actually makes use of the returned 'scores'. I do not want the code, but I would appreciate it if I could get an idea of how to implement that function. Also the nextMove() function confuses me, I want it to check if there is no unfilled box, then fill it with 'O' and then it's the player's turn. But since it will be called again in the recursion, it might not work correctly. Any suggestions?
Edit - The bounty goes to the answer that guides me on how to implement this game using minimax algorithm as described here: https://en.wikipedia.org/wiki/Minimax#Pseudocode
#include <stdio.h>
#define FALSE 0
#define TRUE 1
#define NEGINF -10000
#define POSINF +10000
struct node { // each node is like a snapshot of the game at that point in time
char board[9]; // the 3x3 square is implemented as an array of 9 chars
int value; // the value of that snapshot (+1 if cpu wins, -1 if cpu loses, 0 for draw)
int position; // 0 to 8 inclusive with 0 being [0][0] and 8 being [2][2] (row major fashion) and indicates position where the next 'X' or 'O' would be assigned
};
int max(int value, int returnedValue) {
return value > returnedValue ? value : returnedValue;
}
int min(int value, int returnedValue) {
return value < returnedValue ? value : returnedValue;
}
int someoneHasWon(struct node someNode) {
if(someNode.board[0] == someNode.board[3] && someNode.board[3] == someNode.board[6] && someNode.board[6] == 'X')
return TRUE;
if(someNode.board[0] == someNode.board[3] && someNode.board[3] == someNode.board[6] && someNode.board[6] == 'O')
return TRUE;
//someNode.value = -1;
if(someNode.board[1] == someNode.board[4] && someNode.board[4] == someNode.board[7] && someNode.board[7] == 'X')
return TRUE;
//someNode.value = 1;//return 1;
if(someNode.board[1] == someNode.board[4] && someNode.board[4] == someNode.board[7] && someNode.board[7] == 'O')
return TRUE;
//someNode.value = -1;//return -1;
if(someNode.board[2] == someNode.board[5] && someNode.board[5] == someNode.board[8] && someNode.board[8] == 'X')
return TRUE;
//someNode.value = 1;//return 1;
if(someNode.board[2] == someNode.board[5] && someNode.board[5] == someNode.board[8] && someNode.board[8] == 'O')
return TRUE;
//someNode.value = -1;//return -1;
if(someNode.board[0] == someNode.board[1] && someNode.board[1] == someNode.board[2] && someNode.board[2] == 'X')
return TRUE;
////someNode.value = 1;//return 1;
if(someNode.board[0] == someNode.board[1] && someNode.board[1] == someNode.board[2] && someNode.board[2] == 'O')
return TRUE;
//someNode.value = -1;//return -1;
if(someNode.board[3] == someNode.board[4] && someNode.board[4] == someNode.board[5] && someNode.board[5] == 'X')
return TRUE;
//someNode.value = 1;//return 1;
if(someNode.board[3] == someNode.board[4] && someNode.board[4] == someNode.board[5] && someNode.board[5] == 'O')
return TRUE;
//someNode.value = -1;//return -1;
if(someNode.board[6] == someNode.board[7] && someNode.board[7] == someNode.board[8] && someNode.board[8] == 'X')
return TRUE;
//someNode.value = 1;//return 1;
if(someNode.board[6] == someNode.board[7] && someNode.board[7] == someNode.board[8] && someNode.board[8] == 'O')
return TRUE;
//someNode.value = -1;//return -1;
if(someNode.board[0] == someNode.board[4] && someNode.board[4] == someNode.board[8] && someNode.board[8] == 'X')
return TRUE;
//someNode.value = 1;//return 1;
if(someNode.board[0] == someNode.board[4] && someNode.board[4] == someNode.board[8] && someNode.board[8] == 'O')
return TRUE;
//someNode.value = -1;//return -1;
if(someNode.board[6] == someNode.board[4] && someNode.board[4] == someNode.board[2] && someNode.board[2] == 'X')
return TRUE;
//someNode.value = 1;//return 1;
if(someNode.board[6] == someNode.board[4] && someNode.board[4] == someNode.board[2] && someNode.board[2] == 'O')
return TRUE;
return FALSE;
}
int isTerminal(struct node someNode) {
for(int i = 0; i < 9; i++)
if(someNode.board[i] == ' ') // if square left to fill then game is yet incomplete
return FALSE;
if(someoneHasWon(someNode) == TRUE) // if any player has won earlier with squares left
return TRUE;
return TRUE; // if it's a draw with no squares left to fill
}
struct node nextMove(struct node someNode) {
for(int i = 0; i < 9; i++)
if(someNode.board[i] == ' ') {
someNode.board[i] = 'O';
break;
}
return someNode;
}
int minimax(struct node someNode, int depth, int maximizingPlayer) {
if(depth == 0 || isTerminal(someNode) == TRUE) {
if(someNode.board[0] == someNode.board[3] && someNode.board[3] == someNode.board[6] && someNode.board[6] == 'X')
someNode.value = 1;
if(someNode.board[0] == someNode.board[3] && someNode.board[3] == someNode.board[6] && someNode.board[6] == 'O')
someNode.value = -1;
if(someNode.board[1] == someNode.board[4] && someNode.board[4] == someNode.board[7] && someNode.board[7] == 'X')
someNode.value = 1;//return 1;
if(someNode.board[1] == someNode.board[4] && someNode.board[4] == someNode.board[7] && someNode.board[7] == 'O')
someNode.value = -1;//return -1;
if(someNode.board[2] == someNode.board[5] && someNode.board[5] == someNode.board[8] && someNode.board[8] == 'X')
someNode.value = 1;//return 1;
if(someNode.board[2] == someNode.board[5] && someNode.board[5] == someNode.board[8] && someNode.board[8] == 'O')
someNode.value = -1;//return -1;
if(someNode.board[0] == someNode.board[1] && someNode.board[1] == someNode.board[2] && someNode.board[2] == 'X')
someNode.value = 1;//return 1;
if(someNode.board[0] == someNode.board[1] && someNode.board[1] == someNode.board[2] && someNode.board[2] == 'O')
someNode.value = -1;//return -1;
if(someNode.board[3] == someNode.board[4] && someNode.board[4] == someNode.board[5] && someNode.board[5] == 'X')
someNode.value = 1;//return 1;
if(someNode.board[3] == someNode.board[4] && someNode.board[4] == someNode.board[5] && someNode.board[5] == 'O')
someNode.value = -1;//return -1;
if(someNode.board[6] == someNode.board[7] && someNode.board[7] == someNode.board[8] && someNode.board[8] == 'X')
someNode.value = 1;//return 1;
if(someNode.board[6] == someNode.board[7] && someNode.board[7] == someNode.board[8] && someNode.board[8] == 'O')
someNode.value = -1;//return -1;
if(someNode.board[0] == someNode.board[4] && someNode.board[4] == someNode.board[8] && someNode.board[8] == 'X')
someNode.value = 1;//return 1;
if(someNode.board[0] == someNode.board[4] && someNode.board[4] == someNode.board[8] && someNode.board[8] == 'O')
someNode.value = -1;//return -1;
if(someNode.board[6] == someNode.board[4] && someNode.board[4] == someNode.board[2] && someNode.board[2] == 'X')
someNode.value = 1;//return 1;
if(someNode.board[6] == someNode.board[4] && someNode.board[4] == someNode.board[2] && someNode.board[2] == 'O')
someNode.value = -1;//return -1;
someNode.value = 0;//return 0;
}
if(maximizingPlayer == TRUE) { //maximizing player is cpu i.e. 'O'
someNode.value = NEGINF;
while(isTerminal(someNode) != TRUE)
someNode.value = max(someNode.value, minimax(nextMove(someNode), depth - 1, FALSE));
return someNode.value;
}
else { //minimizing player is me i.e. 'X'
int boxNumber = 0;
scanf("%d", &boxNumber);
someNode.position = boxNumber;
someNode.board[someNode.position] = 'X';
someNode.value = POSINF;
while(isTerminal(someNode) != TRUE)
someNode.value = min(someNode.value, minimax(nextMove(someNode), depth - 1, TRUE));
return someNode.value;
}
}
int main() {
int boxNumber = 0;
printf("Assume you're X and cpu is O \nInput any box number you like \n(0 to 8 both inclusive) \n...you'll be defeated anyways lol :\n");
scanf("%d", &boxNumber);
struct node origin;
for(int i = 0; i < 9; i++)
origin.board[i] = ' ';
origin.position = boxNumber;
origin.board[origin.position] = 'X';
origin.value = 0;
minimax(origin, 8, TRUE);
}
Code version #2 -
#include <stdio.h>
#define FALSE 0
#define TRUE 1
#define NEGINF -10000
#define POSINF +10000
struct node
{
char board[9];
int value;
int position;
};
//char someNode.board[9] = {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '};
int max(int value, int returnedValue)
{
return value > returnedValue ? value : returnedValue;
}
int min(int value, int returnedValue)
{
return value < returnedValue ? value : returnedValue;
}
int someoneHasWon(struct node someNode)
{
if (someNode.board[0] == someNode.board[3] && someNode.board[3] == someNode.board[6] && someNode.board[6] == 'x')
return TRUE;
if (someNode.board[0] == someNode.board[3] && someNode.board[3] == someNode.board[6] && someNode.board[6] == 'o')
return TRUE;
//someNode.value = -1;
if (someNode.board[1] == someNode.board[4] && someNode.board[4] == someNode.board[7] && someNode.board[7] == 'x')
return TRUE;
//someNode.value = 1;//return 1;
if (someNode.board[1] == someNode.board[4] && someNode.board[4] == someNode.board[7] && someNode.board[7] == 'o')
return TRUE;
//someNode.value = -1;//return -1;
if (someNode.board[2] == someNode.board[5] && someNode.board[5] == someNode.board[8] && someNode.board[8] == 'x')
return TRUE;
//someNode.value = 1;//return 1;
if (someNode.board[2] == someNode.board[5] && someNode.board[5] == someNode.board[8] && someNode.board[8] == 'o')
return TRUE;
//someNode.value = -1;//return -1;
if (someNode.board[0] == someNode.board[1] && someNode.board[1] == someNode.board[2] && someNode.board[2] == 'x')
return TRUE;
////someNode.value = 1;//return 1;
if (someNode.board[0] == someNode.board[1] && someNode.board[1] == someNode.board[2] && someNode.board[2] == 'o')
return TRUE;
//someNode.value = -1;//return -1;
if (someNode.board[3] == someNode.board[4] && someNode.board[4] == someNode.board[5] && someNode.board[5] == 'x')
return TRUE;
//someNode.value = 1;//return 1;
if (someNode.board[3] == someNode.board[4] && someNode.board[4] == someNode.board[5] && someNode.board[5] == 'o')
return TRUE;
//someNode.value = -1;//return -1;
if (someNode.board[6] == someNode.board[7] && someNode.board[7] == someNode.board[8] && someNode.board[8] == 'x')
return TRUE;
//someNode.value = 1;//return 1;
if (someNode.board[6] == someNode.board[7] && someNode.board[7] == someNode.board[8] && someNode.board[8] == 'o')
return TRUE;
//someNode.value = -1;//return -1;
if (someNode.board[0] == someNode.board[4] && someNode.board[4] == someNode.board[8] && someNode.board[8] == 'x')
return TRUE;
//someNode.value = 1;//return 1;
if (someNode.board[0] == someNode.board[4] && someNode.board[4] == someNode.board[8] && someNode.board[8] == 'o')
return TRUE;
//someNode.value = -1;//return -1;
if (someNode.board[6] == someNode.board[4] && someNode.board[4] == someNode.board[2] && someNode.board[2] == 'x')
return TRUE;
//someNode.value = 1;//return 1;
if (someNode.board[6] == someNode.board[4] && someNode.board[4]
== someNode.board[2] && someNode.board[2] == 'o')
return TRUE;
return FALSE;
}
int isTerminal(struct node someNode)
{
for (int i = 0; i < 9; i++)
if (someNode.board[i] == ' ') // if square left to fill then game is yet incomplete
return FALSE;
if (someoneHasWon(someNode) == TRUE) // if any player has won earlier with squares left
return TRUE;
return TRUE; // if it's a draw with no squares left to fill
}
struct node nextMove(struct node someNode)
{
for (int i = 0; i < 9; i++)
if (someNode.board[i] == ' ')
{
someNode.board[i] = 'o';
break;
}
return someNode;
}
int minimax(struct node someNode, int depth, int maximizingPlayer)
{
if (depth == 8 || isTerminal(someNode) == TRUE)
{
if (someNode.board[0] == someNode.board[3] && someNode.board[3] == someNode.board[6] && someNode.board[6] == 'x')
someNode.value = 1;
if (someNode.board[0] == someNode.board[3] && someNode.board[3] == someNode.board[6] && someNode.board[6] == 'o')
someNode.value = -1;
if (someNode.board[1] == someNode.board[4] && someNode.board[4] == someNode.board[7] && someNode.board[7] == 'x')
someNode.value = 1; //return 1;
if (someNode.board[1] == someNode.board[4] && someNode.board[4] == someNode.board[7] && someNode.board[7] == 'o')
someNode.value = -1; //return -1;
if (someNode.board[2] == someNode.board[5] && someNode.board[5] == someNode.board[8] && someNode.board[8] == 'x')
someNode.value = 1; //return 1;
if (someNode.board[2] == someNode.board[5] && someNode.board[5] == someNode.board[8] && someNode.board[8] == 'o')
someNode.value = -1; //return -1;
if (someNode.board[0] == someNode.board[1] && someNode.board[1] == someNode.board[2] && someNode.board[2] == 'x')
someNode.value = 1; //return 1;
if (someNode.board[0] == someNode.board[1] && someNode.board[1] == someNode.board[2] && someNode.board[2] == 'o')
someNode.value = -1; //return -1;
if (someNode.board[3] == someNode.board[4] && someNode.board[4] == someNode.board[5] && someNode.board[5] == 'x')
someNode.value = 1; //return 1;
if (someNode.board[3] == someNode.board[4] && someNode.board[4] == someNode.board[5] && someNode.board[5] == 'o')
someNode.value = -1; //return -1;
if (someNode.board[6] == someNode.board[7] && someNode.board[7] == someNode.board[8] && someNode.board[8] == 'x')
someNode.value = 1; //return 1;
if (someNode.board[6] == someNode.board[7] && someNode.board[7] == someNode.board[8] && someNode.board[8] == 'o')
someNode.value = -1; //return -1;
if (someNode.board[0] == someNode.board[4] && someNode.board[4] == someNode.board[8] && someNode.board[8] == 'x')
someNode.value = 1; //return 1;
if (someNode.board[0] == someNode.board[4] && someNode.board[4] == someNode.board[8] && someNode.board[8] == 'o')
someNode.value = -1; //return -1;
if (someNode.board[6] == someNode.board[4] && someNode.board[4] == someNode.board[2] && someNode.board[2] == 'x')
someNode.value = 1; //return 1;
if (someNode.board[6] == someNode.board[4] && someNode.board[4] == someNode.board[2] && someNode.board[2] == 'o')
someNode.value = -1; //return -1;
someNode.value = 0; //return 0;
}
if (maximizingPlayer == TRUE)
{ //maximizing player is cpu i.e. 'o'
someNode.value = NEGINF;
while (isTerminal(someNode) != TRUE)
someNode.value = max(someNode.value, minimax(nextMove(someNode), depth + 1, FALSE));
if (someNode.value == -1) {
printf("o %d \n", someNode.value);
return someNode.value;
}
}
else
{ //minimizing player is me i.e. 'x'
int boxNumber = 0;
printf("Enter your move :\n");
scanf("%d", &boxNumber);
someNode.position = boxNumber;
someNode.board[someNode.position] = 'x';
someNode.value = POSINF;
while (isTerminal(someNode) != TRUE)
someNode.value = min(someNode.value, minimax(nextMove(someNode), depth + 1, TRUE));
if (someNode.value == 1)
return someNode.value;
}
}
int main()
{
int boxNumber = 0;
printf("Assume you're x and cpu is O \nInput any box number you like \n(0 to 8 both inclusive) \n...you'll be defeated anyways lol :\n");
scanf("%d", &boxNumber);
struct node origin;
origin.position = boxNumber;
origin.board[origin.position] = 'x';
origin.value = 0;
printf("%c %d \n", origin.board[origin.position], origin.position);
int val = minimax(origin, 1, TRUE);
if(val > 0)
printf("You lose");
else if(val < 0)
printf("You win");
else
printf("It's a draw");
return 0;
}
What I think is that I'm missing a function that actually makes use of the returned 'scores'.
Well, no, the the minimax() function itself is the only one that needs the score it (recursively) computes. The issue is that the pseudocode you're looking at on Wikipedia is very "pseudo". It illustrates the idea of the algorithm reasonably well, but it doesn't provide a very good model for actually implementing it. In particular, it omits a key component that any practical implementation requires: in addition to computing a score, minimax() needs to provide at least one move that leads to that score. That's the move the top-level caller chooses.
Also the nextMove() function confuses me, I want it to check if there is no unfilled box, then fill it with 'O' and then it's the player's turn. But since it will be called again in the recursion, it might not work correctly. Any suggestions?
There are at least two possible general approaches:
make temporary copies of the board as needed, so that you can modify these without changing the original, or
keep track of each position tested, and clear it after the test.
Either way, it's helpful to separate the move analysis process from the actual choice of move.
Note well that you are already making copies by passing struct node objects by value. By itself, that's not necessarily a full or correct implementation of option (1), but it's definitely something to be aware of, especially with respect to my main point, above.
Also, I don't particularly like the pseudocode's approach of using a boolean input to minimax() to indicate whether to maximize or minimize. I prefer instead to pass an argument to indicate which player's move it is. In a symmetric game such as Tic Tac Toe, the minimax() function then makes use of the fact that the better a result is for one player, the worse it is for the other. Among other things, this tends to simplify the code because the code then doesn't need separate cases around the value of that parameter.
Tic-tac-toe is a very simple game, so thus doesn't have too many game-states. So you do not need to limit the AI to a depth.
function bestMove(board, maximisingPlayer) is
if tie then
return {value: 0}
else if maximising player won then
return {value: ∞}
else if minimising player won then
return {value: -∞}
if maximisingPlayer then
value := -∞
move := 0
for each child of node do
tempValue := minimax(child, FALSE).value
if tempValue > value then
value := tempValue
move := child
return {value: value, move: move}
else
value := ∞
move := 0
for each child of node do
tempValue := minimax(child, TRUE).value
if tempValue < value then
value := tempValue
move := child
return {value: value, move: move}
/* Returns best child node after move is made. */
currentBestMove := bestMove(currentBoard, currentPlayer).move
Also as a remark on your code, do not put the win logic in the same procedure as the minimax, try to split your code into smaller functions as much as possible. Also, you may store the win combinations in an array.
Related
it gives me EXC_BAD_ACCESS (code=1, address=0xc) at the strcmp in the while (strcmp(parola, temp->next->parola) picture of the xcode debugging session
if (temp->next != NULL){
if (strcmp(temp->next->parola, "\0") != 0 && strcmp(parola, "\0") != 0){
while (strcmp(parola, temp->next->parola) != 0){
if(temp->next != NULL){
if (strcmp(temp->next->parola, "\0") != 0 && strcmp(parola, "\0") != 0){
temp = temp->next;
} else {break;}
} else {break;}
}
}
}
if (temp->next != NULL){
if (strcmp(temp->next->parola, "\0") != 0 && strcmp(parola, "\0") != 0){
while (strcmp(parola, temp->next->parola) != 0){
if (strcmp(temp->next->parola, "\0") != 0 && strcmp(parola, "\0") != 0){
temp = temp->next;
if(temp->next != NULL){
} else {break;}
} else {break;}
}
}
}
Brief Explanation of the Problem - The aim of the code is to make a basic tic tac toe game using C. There are two players X and O , both can enter various numbers as choice from 1-9 for each individual chance.
The game board is similar to a 3 x 3 matrix, where -
Row 1 is for 1 to 3.
Row 2 is for 4 to 6.
Row 3 is for 7 to 9.
Any number except 1-9 will throw an error and will prompt the user to re-enter the number. Unfortunately, I'm getting the same Invalid input error for a valid input. Everything else seems to work except my loop.
Here's the code for reference -
#include<stdio.h> //Tic Tac Toe
#include<stdlib.h>
#include<conio.h>
char square[10] = {'0','1','2','3','4','5','6','7','8','9'};
int choice, player;
int checkForWin();
void displayBoard();
void mrkBoard(char mark);
int main()
{
int i;
char mark;
player = 1;
do
{
displayBoard();
player = (player % 2) ? 1:2;
printf("Player %d, enter the number: ",player);
scanf("%d",&choice);
mark = (player == 1) ? 'X' : 'O';
mrkBoard(mark);
i = checkForWin();
player++;
}while(i == -1);
return 0;
}
int checkForWin()
{
int returnValue = 0;
if (square[1] == square[2] && square[2] == square[3])
{
returnValue = 1;
}
else if (square[4] == square[5] && square[5] == square[6])
returnValue = 1;
else if (square[7] == square[8] && square[8] == square[9])
returnValue = 1;
else if (square[1] == square[5] && square[5] == square[9])
returnValue = 1;
else if (square[3] == square[5] && square[5] == square[7])
returnValue = 1;
else if (square[1] == square[4] && square[4] == square[7])
returnValue = 1;
else if (square[2] == square[5] && square[5] == square[8])
returnValue = 1;
else if (square[3] == square[6] && square[6] == square[9])
returnValue = 1;
else if(square[1] != '1' && square[2] != '2' && square[3] != '3' && square[4] != '4' &&
square[5] != '5' && square[6] != '6' && square[7] != '7' &&
square[8] != '8' && square[9] != '9')
returnValue = 0;
else
returnValue = -1;
return returnValue;
}
void displayBoard()
{
system("cls");
printf("\n\nTic Tac Toe\n\n");
printf("Player 1 (X) - Player 2 (O)\n\n\n");
printf(" | | \n");
printf(" %c | %c | %c \n", square[1], square[2],square[3]);
printf("_____|_____|_____\n");
printf(" | | \n");
printf(" %c | %c | %c\n", square[4], square[5],square[6]);
printf("_____|_____|_____\n");
printf(" | | \n");
printf(" %c | %c | %c\n", square[7], square[8],square[9]);
printf(" | | \n\n");
}
void mrkBoard(char mark)
{
if (choice == 1 && square[1] == '1')
square[1] = mark;
else if (choice == 2 && square[1] == '2')
square[2] = mark;
else if (choice == 3 && square[1] == '3')
square[3] = mark;
else if (choice == 4 && square[1] == '4')
square[4] = mark;
else if (choice == 5 && square[1] == '5')
square[5] = mark;
else if (choice == 6 && square[1] == '6')
square[6] = mark;
else if (choice == 7 && square[1] == '7')
square[7] = mark;
else if (choice == 8 && square[1] == '8')
square[8] = mark;
else if (choice == 9 && square[1] == '9')
square[9] = mark;
else
{
printf("Invalid ");
player--;
getch();
}
}
#include<stdio.h> //Tic Tac Toe
#include<stdlib.h>
#include<conio.h>
char square[10] = {'0','1','2','3','4','5','6','7','8','9'};
int choice, player;
int checkForWin();
void displayBoard();
void mrkBoard(char mark);
int main()
{
int i;
char mark;
player = 1;
do
{
displayBoard();
player = (player % 2) ? 1:2;
printf("Player %d, enter the number: ",player);
scanf("%d",&choice);
mark = (player == 1) ? 'X' : 'O';
mrkBoard(mark);
i = checkForWin();
player++;
}while(i == -1);
return 0;
}
int checkForWin()
{
int returnValue = 0;
if (square[1] == square[2] && square[2] == square[3])
{
returnValue = 1;
}
else if (square[4] == square[5] && square[5] == square[6])
returnValue = 1;
else if (square[7] == square[8] && square[8] == square[9])
returnValue = 1;
else if (square[1] == square[5] && square[5] == square[9])
returnValue = 1;
else if (square[3] == square[5] && square[5] == square[7])
returnValue = 1;
else if (square[1] == square[4] && square[4] == square[7])
returnValue = 1;
else if (square[2] == square[5] && square[5] == square[8])
returnValue = 1;
else if (square[3] == square[6] && square[6] == square[9])
returnValue = 1;
else if(square[1] != '1' && square[2] != '2' && square[3] != '3' && square[4] != '4' &&
square[5] != '5' && square[6] != '6' && square[7] != '7' &&
square[8] != '8' && square[9] != '9')
returnValue = 0;
else
returnValue = -1;
return returnValue;
}
void displayBoard()
{
system("cls");
printf("\n\nTic Tac Toe\n\n");
printf("Player 1 (X) - Player 2 (O)\n\n\n");
printf(" | | \n");
printf(" %c | %c | %c \n", square[1], square[2],square[3]);
printf("_____|_____|_____\n");
printf(" | | \n");
printf(" %c | %c | %c\n", square[4], square[5],square[6]);
printf("_____|_____|_____\n");
printf(" | | \n");
printf(" %c | %c | %c\n", square[7], square[8],square[9]);
printf(" | | \n\n");
}
void mrkBoard(char mark)
{
if (choice == 1 && square[1] == '1')
square[1] = mark;
else if (choice == 2 && square[2] == '2')
square[2] = mark;
else if (choice == 3 && square[3] == '3')
square[3] = mark;
else if (choice == 4 && square[4] == '4')
square[4] = mark;
else if (choice == 5 && square[5] == '5')
square[5] = mark;
else if (choice == 6 && square[6] == '6')
square[6] = mark;
else if (choice == 7 && square[7] == '7')
square[7] = mark;
else if (choice == 8 && square[8] == '8')
square[8] = mark;
else if (choice == 9 && square[9] == '9')
square[9] = mark;
else
{
printf("Invalid ");
player--;
getch();
}
}
I'm currently writing a tic-tac-toe program using C for my CS class and I keep running into errors when running that stop me from placing my move in the positions [2,3],[3,1],[3,2],[3,3], essentially only letting me place moves on the top row, and the left two columns of the second row. I'm assuming it has something to do with my check_legal_option function but I can't figure out what the problem is. Any help would be appreciated
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <stdbool.h>
void clear_table(char table[3][3]);
void generate_player2_move(char table[3][3],int *row,int *col);
int check_table_full(char table[3][3]);
int check_three_in_a_row(char table[3][3]);
void display_table(char table[3][3]);
int check_legal_option(char table[3][3],int moveRow,int moveCol);
void update_table(char table[3][3],int pRow,int pCol);
int main(void){
char emptyTable[3][3];
int row,col,cpuRow,cpuCol,full,three,legal;
printf("This program plays the game of tic-tac-toe\n");
clear_table(emptyTable);
printf("\n");
full = check_table_full(emptyTable);
three = check_three_in_a_row(emptyTable);
while(three == 0 && full == 0){
display_table(emptyTable);
printf("Player 1 enter your selection [row,col]: ");
scanf("%d,%d",&row,&col);
legal=check_legal_option(emptyTable,row,col);
printf("%d",legal);
while(legal!=1){
printf("Player 1 enter your selection [row,col]: ");
scanf("%d,%d",&row,&col);
legal=check_legal_option(emptyTable,row,col);
}
update_table(emptyTable,row-1,col-1);
generate_player2_move(emptyTable,&cpuRow,&cpuCol);
full = check_table_full(emptyTable);
three = check_three_in_a_row(emptyTable);
}
if(three == 1){
printf("Congratulations, Player 1 wins!\n");
}
else if(three == 2){
printf("Congratulations, Computer wins!\n");
}
else{
printf("Game over, no player wins.\n");
}
}
void clear_table(char table[3][3]){
for(int i=0;i<3;i++){
for(int j=0;j<3;j++){
table[i][j] = '_';
}
}
}
void generate_player2_move(char table[3][3],int *row,int *col){
srand (time(NULL));
do{
*row = rand()%3;
*col = rand()%3;
int legal = check_legal_option(table,*row,*col);
}while(!check_legal_option(table,*row,*col));
table[*row][*col] = 'O';
}
int check_table_full(char table[3][3]){
if(table[0][0] == table[0][1] && table[0][1] == table[0][2] && table[0][2] == table[1][0] && table[1][0] == table[1][1] && table[1][1] == table[1][2] && table[1][2]
== table[2][0] && table[2][0] == table[2][1] && table[2][1] == table[2][2] && table[0][0] != '_' && check_three_in_a_row(table) == 0){
return 3;
}
return 0;
}
int check_three_in_a_row(char table[3][3]){
for(int i=0;i<3;i++){
if(table[i][0] == table[i][1] && table[i][1] == table[i][2] && table[i][0] == 'X'){
return 1;
}
if(table[i][0] == table[i][1] && table[i][1] == table[i][2] && table[i][0] == 'O'){
return 2;
}
}
for(int j=0;j<3;j++){
//checks if player 1 or CPU gets vertical win
if(table[0][j] == table[1][j] && table[1][j] == table[2][j] &&
table[0][j] == 'X'){
return 1;
}
if(table[0][j] == table[1][j] && table[1][j] == table[2][j] && table[0][j] == 'O'){
return 2;
}
}
//checks if player 1 or CPU gets diagonal win one way
if(table[0][0] == table[1][1] && table[1][1] == table[2][2] && table[0][0] == 'X'){
return 1;
}
if(table[0][0] == table[1][1] && table[1][1] == table[2][2] && table[0][0] == 'O'){
return 2;
}
//checks if player 1 or CPU gets diagonal win another way
if(table[0][2] == table[1][1] && table[1][1] == table[2][0] && table[0][2] == 'X'){
return 1;
}
if(table[0][2] == table[1][1] && table[1][1] == table[2][0] && table[0][2] == 'O'){
return 2;
}
//if no one has three in a row, return 0
return 0;
}
void display_table(char table[3][3]){
printf("The current state of the game is:");
for(int i=0;i<3;i++){
printf("\n");
for(int j=0;j<3;j++){
printf("%c ",table[i][j]);
}
}
printf("\n");
}
int check_legal_option(char table[3][3],int moveRow,int moveCol){
if(table[moveCol][moveCol]=='_'){
return 1;
}
return 0;
}
void update_table(char table[3][3],int pRow,int pCol){
table[pRow][pCol] = 'X';
}
The check_legal function uses movecol in both the columns and rows.
I tried to program a simple TicTacToe in C. The program itselfs compiles and show no errors.
So the program draws the field, reads the names and let a player put his symbol in a specific field. All this happens in a while loop, the should be run until its a draw or someone wins.
But the program just run the loop one time so there is only one turn then the program stops.
So here is my code:
main.c:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "game.h"
#define NAMELENGTH 20
int main(void) {
char names[2][NAMELENGTH];
// field positions
char field[9];
int winner = -1;
getnames(names);
printf("\n\n");
initField(field);
// set field positions to 'empty'
char actualPlayer = (char)(get_random_number()*10.0) % 2;
while (1) {
drawField(field);
turn(actualPlayer, names, field);
winner = isWinner(actualPlayer, field);
drawField(field);
if (winner >= 1) {
printwinner(winner, names);
return 0;
}
else if (winner == 0) {
printDrawGame(names);
return 0;
}
actualPlayer = (actualPlayer + 1) % 2;
}
return 0;
}
game.h Headerfile:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define NAMELENGTH 20
#pragma warning(disable:4996)
extern void drawField(char *field);
extern void getnames(char nameField[][NAMELENGTH]);
extern void initField(char *field);
extern void turn(char actualPlayer, char names[][NAMELENGTH], char *field);
extern char isWinner(char actualPlayer, char *field);
extern void printwinner(char winnerNumber, char names[][NAMELENGTH]);
extern void printDrawGame(char names[][NAMELENGTH]);
extern double get_random_number();
and then my game.c where I defined my functions:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "game.h"
#define NAMELENGTH 20
#pragma warning(disable:4996)
void drawField(char *field) {
printf("________________________\n");
printf("| | | |\n");
printf("| %c | %c | %c |\n", field[0], field[1], field[2]);
printf("|_______|_______|______|\n");
printf("| | | |\n");
printf("| %c | %c | %c |\n", field[3], field[4], field[5]);
printf("|_______|_______|______|\n");
printf("| | | |\n");
printf("| %c | %c | %c |\n", field[6], field[7], field[8]);
printf("|_______|_______|______|\n");
}
void getnames(char nameField[][NAMELENGTH]) {
printf("Name of the first player: ");
scanf("%s", nameField[0]);
printf("Name of the second player: ");
scanf("%s", nameField[1]);
}
void initField(char *field) {
for (int i = 0; i <= 8; i++)
{
field[i] = i + '1';
}
}
void turn(char actualPlayer, char names[][NAMELENGTH], char *field) {
char symbol = ' ';
int p1fieldnumber;
int p2fieldnumber;
if (actualPlayer == 0)
{
do {
printf("\nIts Player %s's turn.", names[0]);
char symbol = 'X';
printf("\nNumber of the field which you want to put your symbol in: ");
scanf("%d", &p1fieldnumber);
if (field[p1fieldnumber] == 'X' || field[p1fieldnumber] == 'O')
{
printf("\nField is already occupied!");
p1fieldnumber = 10;
}
} while (p1fieldnumber < 1 || p1fieldnumber > 9);
field[p1fieldnumber-1] = 'X';
}
else {
do {
printf("\nIts Player %s's turn.", names[1]);
char symbol = 'O';
printf("\nNumber of the field which you want to put your symbol in: ");
scanf("%d", &p2fieldnumber);
if (field[p2fieldnumber] == 'X' || field[p2fieldnumber] == 'O')
{
printf("\nField is already occupied!");
p2fieldnumber = 10;
}
} while (p2fieldnumber < 1 || p2fieldnumber > 9);
field[p2fieldnumber-1] = 'O';
}
}
char isWinner(char actualPlayer, char *field) {
char pwinner = '3';
if (((field[0] == 'O') && (field[1] == 'O') && (field[2] == 'O')) ||
(field[3] == 'O') && (field[4] == 'O') && (field[5] == 'O') ||
(field[6] == 'O') && (field[7] == 'O') && (field[8] == 'O') ||
(field[0] == 'O') && (field[4] == 'O') && (field[8] == 'O') ||
(field[2] == 'O') && (field[4] == 'O') && (field[6] == 'O') ||
(field[0] == 'O') && (field[3] == 'O') && (field[6] == 'O') ||
(field[1] == 'O') && (field[4] == 'O') && (field[7] == 'O') ||
(field[2] == 'O') && (field[5] == 'O') && (field[8] == 'O'))
{
pwinner = '2';
}
else if (((field[0] == 'X') && (field[1] == 'X') && (field[2] == 'X')) ||
(field[3] == 'X') && (field[4] == 'X') && (field[5] == 'X') ||
(field[6] == 'X') && (field[7] == 'X') && (field[8] == 'X') ||
(field[0] == 'X') && (field[4] == 'X') && (field[8] == 'X') ||
(field[2] == 'X') && (field[4] == 'X') && (field[6] == 'X') ||
(field[0] == 'X') && (field[3] == 'X') && (field[6] == 'X') ||
(field[1] == 'X') && (field[4] == 'X') && (field[7] == 'X') ||
(field[2] == 'X') && (field[5] == 'X') && (field[8] == 'X'))
{
pwinner = '1';
}
else if (((field[0] == 'X') || (field[0] == 'O')) && ((field[1] == 'X') || (field[1] == 'O')) && ((field[2] == 'X') || (field[2] == 'O')) ||
((field[3] == 'X') || (field[3] == 'O')) && ((field[4] == 'X') || (field[4] == 'O')) && ((field[5] == 'X') || (field[5] == 'O')) ||
((field[6] == 'X') || (field[6] == 'O')) && ((field[7] == 'X') || (field[7] == 'O')) && ((field[8] == 'X') || (field[8] == 'O')) ||
((field[0] == 'X') || (field[0] == 'O')) && ((field[4] == 'X') || (field[4] == 'O')) && ((field[8] == 'X') || (field[8] == 'O')) ||
((field[2] == 'X') || (field[2] == 'O')) && ((field[4] == 'X') || (field[4] == 'O')) && ((field[6] == 'X') || (field[6] == 'O')) ||
((field[0] == 'X') || (field[0] == 'O')) && ((field[3] == 'X') || (field[3] == 'O')) && ((field[6] == 'X') || (field[6] == 'O')) ||
((field[1] == 'X') || (field[1] == 'O')) && ((field[4] == 'X') || (field[4] == 'O')) && ((field[7] == 'X') || (field[7] == 'O')) ||
((field[2] == 'X') || (field[2] == 'O')) && ((field[5] == 'X') || (field[5] == 'O')) && ((field[8] == 'X') || (field[8] == 'O')))
{
pwinner = '0';
}
return pwinner;
}
void printwinner(char winnerNumber, char names[][NAMELENGTH]) {
if (winnerNumber == '1') {
printf("Player %s won!", names[0]);
}
else if (winnerNumber == '2') {
printf("Player %s won!", names[1]);
}
}
void printDrawGame(char names[][NAMELENGTH]) {
printf("Draw!");
}
static int _initialized;
double get_random_number() {
if (!_initialized) {
srand(time(NULL));
_initialized = 1;
}
return (double)rand() / ((double)(RAND_MAX)+1);
}
There are multiple issues
isWinner returns characters '0', '1', '2' and '3'. Replace them with numbers 0, 1, 2, 3, because your are comparing with numbers in main.
In main instead of checking if (winner >= 1) {, which is true even if 3 is returned by isWinner, check for if (winner == 1 || winner == 2) {.
Suggest to use parentheses in isWinner around each condition separated by ||.
Parentheses as shown below for the first condition
if (((field[0] == 'O') && (field[1] == 'O') && (field[2] == 'O')) ||
((field[3] == 'O') && (field[4] == 'O') && (field[5] == 'O')) ||
((field[6] == 'O') && (field[7] == 'O') && (field[8] == 'O')) ||
((field[0] == 'O') && (field[4] == 'O') && (field[8] == 'O')) ||
((field[2] == 'O') && (field[4] == 'O') && (field[6] == 'O')) ||
((field[0] == 'O') && (field[3] == 'O') && (field[6] == 'O')) ||
((field[1] == 'O') && (field[4] == 'O') && (field[7] == 'O')) ||
((field[2] == 'O') && (field[5] == 'O') && (field[8] == 'O')))
Here's my code for my tic-tac-toe game:
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
int board[3][3] = {
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}
};
int main (void)
{
int const user1 = 1;
int const user2 = 2;
char move[10];
while (! all_locations_filled()) {
printf("User-1, please enter your move:");
scanf("%s", move);
if(valid_location(move)) {
mark_location(user1, move);
display_board(board[3][3]);
}
else if(won_the_game(user1)) {
printf("Congratulations User-1, You Won the Game!");
break;
}
else {
printf("Invalid Move");
}
printf("User-2, please enter your move:");
scanf("%s", move);
if(valid_location(move)) {
mark_location(user2, move);
display_board();
}
else if(won_the_game(user2) {
printf("Congratulations User-2, You Won the Game!");
break;
}
else {
printf("Invalid Move");
}
}
return 0;
}
bool valid_location(char str[10]) {
int strcmp(x, y);
if (strcmp(str[10], "upperLeft") == 0 || strcmp(str[10], "up") == 0 || strcmp(str[10], "upperRight") == 0 || strcmp(str[10], "left") == 0 || strcmp(str[10], "center") == 0 || strcmp(str[10], "right") == 0 || strcmp(str[10], "lowerLeft") == 0 || strcmp(str[10], "down") == 0 || strcmp(str[10], "lowerRight") == 0)
return true;
}
void mark_location(int userU, char str[10]) {
int strcmp(x, y);
if (strcmp(str[10], "upperLeft") == 0)
board[0][0] = userU;
else if (strcmp(str[10], "up") == 0)
board[0][1] = userU;
else if (strcmp(str[10], "upperRight") == 0)
board[0][2] = userU;
else if (strcmp(str[10], "left") == 0)
board[1][0] = userU;
else if (strcmp(str[10], "center") == 0)
board[1][1] = userU;
else if (strcmp(str[10], "right") == 0)
board[1][2] = userU;
else if (strcmp(str[10], "lowerLeft") == 0)
board[2][0] = userU;
else if (strcmp(str[10], "down") == 0)
board[2][1] = userU;
else if (strcmp(str[10], "lowerRight") == 0)
board [2][2] = userU;
}
char display_board(int array[][]) {
int i, j;
for (i=0; i<3; ++i)
for (j=0; j<3; ++j)
if (array[i][j] == 0)
print("-");
else if (array[i][j] == 1)
print("x");
else if (array[i][j] == 2)
print("o");
}
bool all_locations_filled() {
int i, j;
for (i=0; i<3; ++i)
for (j=0; j<3; ++j)
if board[i][j] == 0
return false;
return true;
}
bool won_the_game(userU) {
int i, j;
if (board[0][0] == userU && board[0][1] == userU && board[0][2] == userU)
return true;
else if (board[1][0] == userU && board[1][1] == userU && board[1][2] == userU)
return true;
else if (board[2][0] == userU && board[2][1] == userU && board[2][2] == userU)
return true;
else if (board[0][0] == userU && board[1][0] == userU && board[2][0] == userU)
return true;
else if (board[0][1] == userU && board[1][1] == userU && board[2][1] == userU)
return true;
else if (board[0][2] == userU && board[1][2] == userU && board[2][2] == userU)
return true;
else if (board[0][0] == userU && board[1][1] == userU && board[2][2] == userU)
return true;
else if (board[2][2] == userU && board[1][1] == userU && board[2][0] == userU)
return true;
else
return false;
}
There are a few errors that I don't understand, here they are:
tictactoe.c:50: error: expected expression before ‘}’ token
This error is at the end of the main function but I'm not sure what I did wrong.
tictactoe.c:52: error: nested functions are disabled, use -fnested-functions to re-enable
I didn't know I used a nested function.
tictactoe.c:53: warning: parameter names (without types) in function declaration
This is referring to int strcmp(x, y)
tictactoe.c:55: warning: passing argument 1 of ‘strcmp’ makes pointer from integer without a cast
What did I do wrong with strcmp?
If someone could help me out I'd greatly appreciate it.
You're missing a closing parenthesis here (line #40):
else if(won_the_game(user2) {
Should be:
else if(won_the_game(user2)) {
You have a couple or problems with the strcmp as well.
strcmp(str[10], "upperRight")
The compiler is complaining about the first parameter str[10]. One problem is that this selects a single character from the string, and not the whole string. Another problem is that in an array of size 10, the positions are numbered 0..9 so there isn't even a position 10!
Also, a string literal like "upperRight" contains 10 visible characters plus an extra zero character as a terminator. So it needs 11 positions when stored in the str.