I am a beginner C programmer and while writing a tictactoe game in C, I encountered a strange output. I mainly used if statements to check if the "squares" are either 'X' or 'O'
#include <stdio.h>
int main(){
int p1,p2;
char arr[] = {'1','2','3','4','5','6','7','8','9'};
void drawboard(){
printf("%c|%c|%c\n",arr[0],arr[1],arr[2]);
printf("-----\n");
printf("%c|%c|%c\n",arr[3],arr[4],arr[5]);
printf("-----\n");
printf("%c|%c|%c\n",arr[6],arr[7],arr[8]);
}
while(1>0){
drawboard();
printf("Player 1, enter your choice:\n");
scanf("%d",&p1);
printf("Player 2, enter your choice:\n");
scanf("%d",&p2);
arr[p1-1] = 'X';
arr[p2-1] = 'O';
if(arr[0]&&arr[1]&&arr[2]=='X'){
printf("Player 1 won.\n");
return 1;
}
if(arr[3]&&arr[4]&&arr[5]=='X'){
printf("Player 1 won.\n");
return 1;
}
if(arr[6]&&arr[7]&&arr[8]=='X'){
printf("Player 1 won.\n");
return 1;
}
if(arr[0]&&arr[3]&&arr[6]=='X'){
printf("Player 1 won.\n");
return 1;
}
if(arr[1]&&arr[4]&&arr[7]=='X'){
printf("Player 1 won.\n");
return 1;
}
if(arr[2]&&arr[5]&&arr[8]=='X'){
printf("Player 1 won.\n");
return 1;
}
if(arr[0]&&arr[4]&&arr[8]=='X'){
printf("Player 1 won.\n");
return 1;
}
if(arr[2]&&arr[4]&&arr[6]=='X'){
printf("Player 1 won.\n");
return 1;
}
else if(arr[0]&&arr[1]&&arr[2]=='O'){
printf("Player 2 won.\n");
return 1;
}
else if(arr[3]&&arr[4]&&arr[5]=='O'){
printf("Player 2 won.\n");
return 1;
}
else if(arr[6]&&arr[7]&&arr[8]=='O'){
printf("Player 2 won.\n");
return 1;
}
else if(arr[0]&&arr[3]&&arr[6]=='O'){
printf("Player 2 won.\n");
return 1;
}
else if(arr[1]&&arr[4]&&arr[7]=='O'){
printf("Player 2 won.\n");
return 1;
}
else if(arr[2]&&arr[5]&&arr[8]=='O'){
printf("Player 2 won.\n");
return 1;
}
else if(arr[0]&&arr[4]&&arr[8]=='O'){
printf("Player 2 won.\n");
return 1;
}
else if(arr[2]&&arr[4]&&arr[6]=='O'){
printf("Player 2 won.\n");
return 1;
}
else{
continue;
}
}
return 0;
}
After the first and the second player's input, if the input is '8' or '6', it says he won, even if only one space was occupied.
CodePudding user response:
You wrote:
arr[6]&&arr[7]&&arr[8]=='X'
which means:
if
arr[6]
is true andarr[7]
is true andarr[8]=='X'
is true.
True means any character except '\0'
, so all the squares are true and this condition is true as soon as arr[8]
is an X.
You meant:
arr[6]=='X' && arr[7]=='X' && arr[8]=='X'
(spaces are optional) which checks that all 3 of them are X. And you have to fix all the if
statements this way.
CodePudding user response:
Prefaced by my top comments. A few issues ...
- Don't use nested functions
- Put
arr
at global scope. if
syntax is incorrect. (e.g.)if(arr[0]&&arr[1]&&arr[2]=='X')
should beif ((arr[0] == 'X') && (arr[1] == 'X') && (arr[2] == 'X'))
- No check for illegal moves or out of range moves.
- Not all possible win positions checked (e.g. missing a diagonal).
- No need for separate win check for each player. A win [for either player] is all three in a given direction match.
- The program can be greatly simplified with breakup into smaller functions.
Here is the corrected code. It is annotated.
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
char arr[] = { '1', '2', '3', '4', '5', '6', '7', '8', '9' };
void
drawboard(void)
{
printf("%c|%c|%c\n", arr[0], arr[1], arr[2]);
printf("-----\n");
printf("%c|%c|%c\n", arr[3], arr[4], arr[5]);
printf("-----\n");
printf("%c|%c|%c\n", arr[6], arr[7], arr[8]);
}
// match3 -- decide if win
// RETURNS: winning char or zero
int
match3(int a,int b,int c)
{
int x;
--a;
--b;
--c;
x = arr[a];
return ((arr[b] == x) && (arr[c] == x)) ? x : 0;
}
// check -- check for win
int
check(void)
{
int win;
do {
// top row
win = match3(1,2,3);
if (win)
break;
// middle row
win = match3(4,5,6);
if (win)
break;
// bottom row
win = match3(7,8,9);
if (win)
break;
// left column
win = match3(1,4,7);
if (win)
break;
// middle column
win = match3(2,5,8);
if (win)
break;
// right column
win = match3(3,6,9);
if (win)
break;
// left to right diagonal
win = match3(1,5,9);
if (win)
break;
// right to left diagonal
win = match3(3,5,7);
if (win)
break;
} while (0);
switch (win) {
case 'X':
printf("Player 1 won.\n");
break;
case 'O':
printf("Player 2 won.\n");
break;
}
if (win)
drawboard();
return win;
}
// legal -- check for remaining legal moves
void
legal(void)
{
int more;
// look for remaining legal moves
more = 0;
for (int idx = 0; idx < 9; idx) {
more = (arr[idx] != 'X') && (arr[idx] != 'O');
if (more)
break;
}
if (! more) {
printf("No more legal moves -- no winner\n");
drawboard();
exit(0);
}
}
// ask -- ask player for moves
int
ask(int playno,int x)
{
char buf[100];
char *cp;
int move;
printf("\n");
legal();
while (1) {
drawboard();
printf("Player %d, enter your choice:\n",playno);
if (fgets(buf,sizeof(buf),stdin) == NULL) {
printf("EOF\n");
exit(0);
}
// echo for debug input from file
do {
struct termios tio;
if (tcgetattr(fileno(stdin),&tio) < 0)
fputs(buf,stdout);
} while (0);
// get the move
move = strtol(buf,&cp,10);
if (*cp != '\n') {
printf("syntax error\n");
continue;
}
// move is within bounds
if ((move >= 1) && (move <= 9)) {
--move;
// check for move to an already occupied space
if ((arr[move] == 'X') || (arr[move] == 'O')) {
printf("already has an '%c'\n",arr[move]);
continue;
}
// make the move
arr[move] = x;
break;
}
printf("move out of range\n");
}
return check();
}
int
main(void)
{
int more;
while (1) {
if (ask(1,'X'))
break;
if (ask(2,'O'))
break;
}
return 0;
}
Below are some sample games I used to test the program ...
1|2|3
-----
4|5|6
-----
7|8|9
Player 1, enter your choice:
1
X|2|3
-----
4|5|6
-----
7|8|9
Player 2, enter your choice:
4
X|2|3
-----
O|5|6
-----
7|8|9
Player 1, enter your choice:
2
X|X|3
-----
O|5|6
-----
7|8|9
Player 2, enter your choice:
5
X|X|3
-----
O|O|6
-----
7|8|9
Player 1, enter your choice:
3
Player 1 won.
X|X|X
-----
O|O|6
-----
7|8|9
1|2|3
-----
4|5|6
-----
7|8|9
Player 1, enter your choice:
1
X|2|3
-----
4|5|6
-----
7|8|9
Player 2, enter your choice:
4
X|2|3
-----
O|5|6
-----
7|8|9
Player 1, enter your choice:
2
X|X|3
-----
O|5|6
-----
7|8|9
Player 2, enter your choice:
5
X|X|3
-----
O|O|6
-----
7|8|9
Player 1, enter your choice:
3
Player 1 won.
X|X|X
-----
O|O|6
-----
7|8|9
1|2|3
-----
4|5|6
-----
7|8|9
Player 1, enter your choice:
1
X|2|3
-----
4|5|6
-----
7|8|9
Player 2, enter your choice:
2
X|O|3
-----
4|5|6
-----
7|8|9
Player 1, enter your choice:
3
X|O|X
-----
4|5|6
-----
7|8|9
Player 2, enter your choice:
4
X|O|X
-----
O|5|6
-----
7|8|9
Player 1, enter your choice:
5
X|O|X
-----
O|X|6
-----
7|8|9
Player 2, enter your choice:
9
X|O|X
-----
O|X|6
-----
7|8|O
Player 1, enter your choice:
8
X|O|X
-----
O|X|6
-----
7|X|O
Player 2, enter your choice:
7
X|O|X
-----
O|X|6
-----
O|X|O
Player 1, enter your choice:
6
No more legal moves -- no winner
X|O|X
-----
O|X|X
-----
O|X|O