#define BOARD_WIDTH 8 #define BOARD_HEGIHT 8 typedef char game_board[BOARD_HEGIHT][BOARD_WIDTH];
#define BOARD_WIDTH 8
#define BOARD_HEIGHT 8
typedef char game_board[BOARD_HEIGHT][BOARD_WIDTH];
Use system()
with care. system("/usr/bin/clear")
would be better, since you can't rely on users having a sane PATH
. And on other platforms, is this function really supposed to do nothing? Perhaps:
#define BOARD_WIDTH 8 #define BOARD_HEGIHT 8 typedef char game_board[BOARD_HEGIHT][BOARD_WIDTH];
Use system
with care. system("/usr/bin/clear")
would be better, since you can't rely on users having a sane PATH
. And on other platforms, is this function really supposed to do nothing?
#define BOARD_WIDTH 8
#define BOARD_HEIGHT 8
typedef char game_board[BOARD_HEIGHT][BOARD_WIDTH];
Use system()
with care. system("/usr/bin/clear")
would be better, since you can't rely on users having a sane PATH
. And on other platforms, is this function really supposed to do nothing? Perhaps:
What's <conio.h>
? It's not mentioned in the C standard, and if I remove it, the code kind of compiles, so I guess it's not required.
I say "kind of" because of the warnings it generates, which shouldn't be ignored:
gcc -std=c17 -fPIC -g -Wall -Wextra -Wwrite-strings -Wno-parentheses -Wpedantic -Warray-bounds -Wstrict-prototypes -Wconversion 256860.c -o 256860
256860.c:23:1: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
23 | void clearScreen();
| ^~~~
256860.c:34:1: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
34 | int promptReplay();
| ^~~
256860.c:38:5: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
38 | int main()
| ^~~~
256860.c: In function ‘main’:
256860.c:40:24: warning: ISO C forbids empty initializer braces [-Wpedantic]
40 | char board[8][8] = {
| ^
256860.c:49:20: warning: passing argument 1 of ‘resetBoard’ from incompatible pointer type [-Wincompatible-pointer-types]
49 | resetBoard(board, &turn);
| ^~~~~
| |
| char (*)[8]
256860.c:24:23: note: expected ‘char * (*)[8]’ but argument is of type ‘char (*)[8]’
24 | void resetBoard(char* board[8][8], int* turn);
| ~~~~~~^~~~~~~~~~~
256860.c:52:23: warning: passing argument 1 of ‘drawBoard’ from incompatible pointer type [-Wincompatible-pointer-types]
52 | drawBoard(board);
| ^~~~~
| |
| char (*)[8]
256860.c:25:22: note: expected ‘char * (*)[8]’ but argument is of type ‘char (*)[8]’
25 | void drawBoard(char* board[8][8]);
| ~~~~~~^~~~~~~~~~~
256860.c:54:24: warning: passing argument 1 of ‘addToBoard’ from incompatible pointer type [-Wincompatible-pointer-types]
54 | addToBoard(board, &player, &turn, &posX, &posY);
| ^~~~~
| |
| char (*)[8]
256860.c:26:23: note: expected ‘char * (*)[8]’ but argument is of type ‘char (*)[8]’
26 | void addToBoard(char* board[8][8], int* player, int* turn, char* posX, char* posY);
| ~~~~~~^~~~~~~~~~~
256860.c:55:41: warning: passing argument 1 of ‘checkWin’ from incompatible pointer type [-Wincompatible-pointer-types]
55 | currentGameState = checkWin(board, &turn);
| ^~~~~
| |
| char (*)[8]
256860.c:29:21: note: expected ‘char * (*)[8]’ but argument is of type ‘char (*)[8]’
29 | int checkWin(char* (board)[8][8], int* turn);
| ~~~~~~~^~~~~~~~~~~~
256860.c:59:19: warning: passing argument 1 of ‘drawBoard’ from incompatible pointer type [-Wincompatible-pointer-types]
59 | drawBoard(board);
| ^~~~~
| |
| char (*)[8]
256860.c:25:22: note: expected ‘char * (*)[8]’ but argument is of type ‘char (*)[8]’
25 | void drawBoard(char* board[8][8]);
| ~~~~~~^~~~~~~~~~~
256860.c: In function ‘drawBoard’:
256860.c:75:29: warning: passing argument 1 of ‘putchar’ makes integer from pointer without a cast [-Wint-conversion]
75 | putchar(board[i][j]);
| ~~~~~~~~^~~
| |
| char *
In file included from 256860.c:2:
/usr/include/stdio.h:528:25: note: expected ‘int’ but argument is of type ‘char *’
528 | extern int putchar (int __c);
| ~~~~^~~
256860.c: In function ‘addToBoard’:
256860.c:140:34: warning: comparison between pointer and integer
140 | if(board[arrayRow][arrayCol] == ' ')
| ^~
256860.c:144:39: warning: assignment to ‘char *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
144 | board[arrayRow][arrayCol] = 'X';
| ^
256860.c:149:39: warning: assignment to ‘char *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
149 | board[arrayRow][arrayCol] = 'O';
| ^
256860.c: In function ‘checkHorizontalVictory’:
256860.c:201:28: warning: comparison between pointer and integer
201 | if(board[i][j] == ' ')
| ^~
256860.c:205:33: warning: comparison between pointer and integer
205 | else if(board[i][j] == 'X')
| ^~
256860.c:209:33: warning: comparison between pointer and integer
209 | else if(board[i][j] == 'O')
| ^~
256860.c: In function ‘checkVerticalVictory’:
256860.c:234:28: warning: comparison between pointer and integer
234 | if(board[i][j] == ' ')
| ^~
256860.c:238:33: warning: comparison between pointer and integer
238 | else if(board[i][j] == 'X')
| ^~
256860.c:242:33: warning: comparison between pointer and integer
242 | else if(board[i][j] == 'O')
| ^~
256860.c: In function ‘checkDiagonalVictory’:
256860.c:263:24: warning: comparison between pointer and integer
263 | if(board[i][i] == ' ')
| ^~
256860.c:267:29: warning: comparison between pointer and integer
267 | else if(board[i][i] == 'X')
| ^~
256860.c:271:29: warning: comparison between pointer and integer
271 | else if(board[i][i] == 'O')
| ^~
256860.c:286:24: warning: comparison between pointer and integer
286 | if(board[i][j] == ' ')
| ^~
256860.c:290:29: warning: comparison between pointer and integer
290 | else if(board[i][j] == 'X')
| ^~
256860.c:294:29: warning: comparison between pointer and integer
294 | else if(board[i][j] == 'O')
| ^~
256860.c: At top level:
256860.c:306:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
306 | checkDraw(int* turn)
| ^~~~~~~~~
256860.c:316:5: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
316 | int promptReplay()
| ^~~~~~~~~~~~
256860.c: In function ‘promptReplay’:
256860.c:320:14: warning: conversion from ‘int’ to ‘char’ may change value [-Wconversion]
320 | choice = getchar();
| ^~~~~~~
256860.c: In function ‘resetBoard’:
256860.c:348:25: warning: assignment to ‘char *’ from ‘char’ makes pointer from integer without a cast [-Wint-conversion]
348 | board[i][j] = emptyboard[i][j];
| ^
256860.c: In function ‘declareWinner’:
256860.c:355:5: warning: enumeration value ‘Playing’ not handled in switch [-Wswitch]
355 | switch (currentGameState)
| ^~~~~~
256860.c: At top level:
256860.c:366:6: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
366 | void clearScreen()
| ^~~~~~~~~~~
256860.c: In function ‘promptReplay’:
256860.c:338:1: warning: control reaches end of non-void function [-Wreturn-type]
338 | }
| ^
There are some serious problems there, in particular where we pass a matrix of char
to functions expecting a matrix of char*
.
I suggest creating a typedef for the frequently-used matrix:
#define BOARD_WIDTH 8 #define BOARD_HEGIHT 8 typedef char game_board[BOARD_HEGIHT][BOARD_WIDTH];
That makes our declarations much easier to keep consistent.
const game_board emptyboard = {
{'-','-','-','-','-','-','-',' '},
{'|',' ','|',' ','|',' ','|','3'},
{'-','-','-','-','-','-','-',' '},
{'|',' ','|',' ','|',' ','|','2'},
{'-','-','-','-','-','-','-',' '},
{'|',' ','|',' ','|',' ','|','1'},
{'-','-','-','-','-','-','-',' '},
{' ','a',' ','b',' ','c',' ',' '}
};
void clearScreen(void);
void resetBoard(game_board board, int* turn);
void drawBoard(game_board board);
void addToBoard(game_board board, int* player, int* turn, char* posX, char* posY);
void declareWinner(gameState currentGameState);
int getPlayerInput(int player, char* posX, char* posY); //Returns 1 if valid
int checkWin(game_board board, int* turn);
int checkVerticalVictory(game_board board);
int checkHorizontalVictory(game_board board);
int checkDiagonalVictory(game_board board);
int checkDraw(int* turn);
int promptReplay(void);
Normally, I'd make the board 3✕3, since the other entries in the matrix are for presentation rather than actual state.
char choice; puts("\n\nPlay Again? (y/n): "); choice = getchar();
Here, we not only fail to check for EOF, but we can no longer do so, as we converted the input to char
. Use int
, or turn to scanf()
:
for (;;) {
puts("Play Again? (y/n): ");
char choice;
if (scanf(" %c%*[^\n]", &choice) < 1) {
/* EOF */
return 0;
}
switch (choice) {
case 'y': case 'Y':
return 1;
case 'n': case 'N':
return 0;
}
puts("\nWrong input.\n");
/* loop; ask again */
}
#ifdef _WIN32 system("cls"); #elif __linux__ system("clear"); #endif
Use system
with care. system("/usr/bin/clear")
would be better, since you can't rely on users having a sane PATH
. And on other platforms, is this function really supposed to do nothing?
#else
#error Please add support for clearing screen