- Is my implementation idiomatic?
- Does it suffer from any undefined behaviour?
Any pointers/tips would be greatly appreciated. Particularly, I think that the winner function could be improved.
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
/* ascii values */
#define X 88
#define O 79
void print_board(char* b) {
char buf[19] = {0};
int p = 0;
for (int i = 0; i < 9; i++) {
buf[p++] = b[i] == 0 ? i + '1' : b[i];
buf[p++] = (i + 1) % 3 == 0 ? '\n' : ' ';
}
printf("%s", buf);
}
/* 0 is ongoing; 1 is draw. */
char winner(char* b) {
char pieces[2] = {X, O};
for (int i = 0; i < 2; i++) {
char p = pieces[i];
if (/* rows */
b[0] == p && b[1] == p && b[2] == p ||
b[3] == p && b[4] == p && b[5] == p ||
b[6] == p && b[7] == p && b[8] == p ||
/* cols */
b[0] == p && b[3] == p && b[6] == p ||
b[1] == p && b[4] == p && b[7] == p ||
b[2] == p && b[5] == p && b[8] == p ||
/* diagonals */
b[0] == p && b[4] == p && b[8] == p ||
b[2] == p && b[4] == p && b[6] == p)
return p;
}
for (int i=0; i < 9; i++)
if (b[i] == 0)
return 0;
return 1;
}
char getmove(char player, char* b) {
char c;
int ok = 0;
do {
printf("%c to move: ", player);
for (c = getchar(); getchar() != '\n';)
;
putchar('\n');
if (c < '0' || c > '9')
printf("Expected a number 0-9\n");
else if (b[c - '0' - 1])
printf("Square %c is taken\n", c);
else
ok = 1;
} while (!ok);
return c - '1';
}
void makemove(char player, int pos, char* b) {
assert(pos >= 0 && pos < 9);
b[pos] = player;
}
void print_winner(char result) {
assert(result);
if (result == 1)
printf("It's a draw!\n");
else
printf("%c wins!\n", result);
}
int main(void) {
char player = X;
char move;
char board[9] = {0};
int status;
while (!(status = winner(board))) {
print_board(board);
move = getmove(player, board);
makemove(player, move, board);
player = player == X ? O : X;
}
print_board(board);
print_winner(status);
return 0;
}