Reputation: 1
I'm programming a tic tac toe game in C.
Everything seems to be going okay, but I like to implement error handling techniques for programs like this in case a user inputs bad data.
I ask the user to input a number between 1-9 to fill a slot on the tic tac toe graph. When I used fgets and sscanf together, it ran well during the first game. Then, when a user selected 'Y' or 'y' to continue playing a new game, it seemed as if none of the variable values refreshed, and it was basically causing chaos within the program.
Any tips?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
int printmatch(int array[3][3]);
int check(int array[3][3]);
char y;
char Y;
int complacer = 0;
int complacer2 = 0;
int main()
{
do
{
int fill = 0;
int j = 0;
int slot = 0;
int array[3][3];
array[0][0] = 0;
array[0][1] = 0;
array[0][2] = 0;
array[1][0] = 0;
array[2][0] = 0;
array[1][1] = 0;
array[2][1] = 0;
array[1][2] = 0;
array[2][2] = 0;
srand(time(NULL ));
printmatch(array);
char line[20];
do
{
do
{
tryagain: printf("\nEnter Position 1-9(from left to right):");
//I was using fgets and sscanf as an error handling technique incase user inputs incompatible data type, but after the 1st game is over, it seems this code messes up the functionality of the program
//fgets(line,sizeof(line),stdin);
//sscanf(line,"%d",&slot);
//when I just use scanf for data input, all is fine, but limited error handling
scanf("%d", &slot);
if (slot > 9 || slot < 1)
{
printf("Incorrect data input! Try again. \n");
}
} while (!(slot > 0 && slot < 10));
switch (slot)
{
case 1:
if (array[0][0] == -1)
{
printf("\nWoops, try again!");
goto tryagain;
}
array[0][0] = 1;
check(array);
break;
case 2:
if (array[1][0] == -1)
{
printf("\nWoops, try again!");
goto tryagain;
}
array[1][0] = 1;
check(array);
break;
case 3:
if (array[2][0] == -1)
{
printf("\nWoops, try again!");
goto tryagain;
}
array[2][0] = 1;
check(array);
break;
case 4:
if (array[0][1] == -1)
{
printf("\nWoops, try again!");
goto tryagain;
}
array[0][1] = 1;
check(array);
break;
case 5:
if (array[1][1] == -1)
{
printf("\nWoops, try again!");
goto tryagain;
}
array[1][1] = 1;
check(array);
break;
case 6:
if (array[2][1] == -1)
{
printf("\nWoops, try again!");
goto tryagain;
}
array[2][1] = 1;
check(array);
break;
case 7:
if (array[0][2] == -1)
{
printf("\nWoops, try again!");
goto tryagain;
}
array[0][2] = 1;
check(array);
break;
case 8:
if (array[1][2] == -1)
{
printf("\nWoops, try again!");
goto tryagain;
}
array[1][2] = 1;
check(array);
break;
case 9:
if (array[2][2] == -1)
{
printf("\nWoops, try again!");
goto tryagain;
}
array[2][2] = 1;
check(array);
break;
}
if (array[0][0] != 0 && array[0][1] != 0 && array[0][2] != 0
&& array[1][0] != 0 && array[2][0] != 0 && array[1][1] != 0
&& array[2][1] != 0 && array[1][2] != 0 && array[2][2] != 0)
{
check(array);
if (check(array) == 1)
{
printf("The user wins!\n");
}
else if (check(array) == -1)
{
printf("The computer wins.\n");
}
else
{
printmatch(array);
printf("It's a draw!\n");
}
goto done;
}
++fill;
label:
complacer = rand() % 3;
complacer2 = rand() % 3;
if (array[complacer][complacer2] == 0)
{
array[complacer][complacer2] = -1;
check(array);
}
else
goto label;
++fill;
printmatch(array);
int fullcheck = check(array);
if (fullcheck == 1)
{
printf("The user wins!");
break;
}
if (fullcheck == -1)
{
printf("The computer wins.");
break;
}
if (fill > 9)
break;
} while (fill < 10);
done: printf("\nDo you want to continue? Y/N\n");
scanf("%c %c", &y, &Y);
} while ((Y == 'Y' || Y == 'y'));
getchar();
return 0;
}
int printmatch(int array[3][3])
{
int i;
int j;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
printf("%d\t", array[j][i]);
}
printf("\n");
}
}
int check(int array[3][3])
{
int settle;
if (array[0][0] == 1 && array[1][1] == 1 && array[2][2] == 1)
{
settle = 1;
}
else if (array[0][0] == -1 && array[1][1] == -1 && array[2][2] == -1)
{
settle = -1;
}
if (array[0][0] == 1 && array[0][1] == 1 && array[0][2] == 1)
{
settle = 1;
}
else if (array[0][0] == -1 && array[0][1] == -1 && array[0][2] == -1)
{
settle = -1;
}
if (array[0][2] == 1 && array[1][2] == 1 && array[2][2] == 1)
{
settle = 1;
}
else if (array[0][2] == -1 && array[1][2] == -1 && array[2][2] == -1)
{
settle = -1;
}
if (array[0][1] == 1 && array[1][1] == 1 && array[2][1] == 1)
{
settle = 1;
}
else if (array[0][1] == -1 && array[1][1] == -1 && array[2][1] == -1)
{
settle = -1;
}
if (array[1][0] == 1 && array[1][1] == 1 && array[1][2] == 1)
{
settle = 1;
}
else if (array[1][0] == -1 && array[1][1] == -1 && array[1][2] == -1)
{
settle = -1;
}
if (array[0][0] == 1 && array[1][0] == 1 && array[2][0] == 1)
{
settle = 1;
}
else if (array[1][0] == -1 && array[1][1] == -1 && array[1][2] == -1)
{
settle = -1;
}
if (array[2][0] == 1 && array[1][1] == 1 && array[0][2] == 1)
{
settle = 1;
}
else if (array[1][0] == -1 && array[1][1] == -1 && array[1][2] == -1)
{
settle = -1;
}
if (array[2][0] == 1 && array[2][1] == 1 && array[2][2] == 1)
{
settle = 1;
}
else if (array[2][0] == -1 && array[2][1] == -1 && array[2][2] == 1)
{
settle = -1;
}
return settle;
}
Upvotes: 0
Views: 1188
Reputation: 153498
User input is evil. When you want a number, someone types 'A'. You want a 'y' or 'n' and you get a input of dozens of letters. Kudos for trying to improve your coding with defensive error handling.
When using sscanf()
or scanf()
, etc., be sure to check the results
int result;
result = sscanf(buffer, "%this %that ...", &var1);
if (result != ExpectedResult) // handle error
Mixing fgets()
with getchar()
and scanf()
is likely to confuse the issue. Recommend not using fgets()
with those 2. fgets()
is line orientated, scanf()
often stops before consuming the new-line.
Its fun to only type a 'Y' or 'y' to continue, but using a "letter & enter_key" combo is not so bad and it is easier to sort out at first.
The fgets()
sscanf()
pair may have caused a hiccup, but in the end it easier to sort out. Recommend returning to that style and checking the result of the sscanf()
.
Example
scanf("%d", &slot);
Here you do not know if the user typed any number before pressing 'Enter'. Even is the user did type a number, your scanf() consumes the leading spaces and the digits, but leaves the 'Enter' for the next input function. Instead:
int ScanCount;
const char *prompt = "\nEnter Position 1-9(from left to right):";
do {
fputs(prompt, stdout);
prompt = "Incorrect data input! Try again. \n"; // For the maybe next time around
if (fgets(line, sizeof(line), stdin) == NULL) {
// Standard input is closed or some grievous I/O error, let's go home.
return 0;
}
ScanCount = sscanf(line,"%d",&slot);
} while ((ScanCount != 1) || (slot < 1) || slot > 9));
BTW: Here is a little trick to test if extra text was entered after a number like "9z". Replace ScanCount = ... slot > 9));
with
char c;
ScanCount = sscanf(line,"%d%[^\n]",&slot, &c);
} while ((ScanCount != 1) || (slot < 1) || slot > 9)); // still ScanCount != 1
Upvotes: 1