diff --git a/uttt.c b/uttt.c new file mode 100644 index 0000000..4030ef5 --- /dev/null +++ b/uttt.c @@ -0,0 +1,215 @@ +#include +#include +#include +#include +#include +#if 0 +#include +#endif + +struct state +{ + char tiles[9][9]; + char boards[3][3]; + int playBoard; + char player; +}; + +#define communism(state) abolish(state) +void abolish(struct state *the_state){ +} + +char turn(char player) +{ + switch(player) + { + case 'X': return 'O'; + case 'O': return 'X'; + default: return 0; + } +} + +#define T(r, c) (tiles[offset + stride * r + c]) +char winner(char *tiles, int offset, int stride) { + + // whoreizontal wins + for (int y = 0; y < 3; y++) { + char tile = T(y, 0); + if (tile == '\0') {continue;} + if (tile == T(y, 1) && tile == T(y, 2)) {return tile;} + } + + // vertical wins + for (int x = 0; x < 3; x++) { + char tile = T(0, x); + if (tile == '\0') {continue;} + if (tile == T(1, x) && tile == T(2, x)) {return tile;} + } + + // diagonalz + char tile = T(1, 1); + if (tile == '\0') {return '\0';} + if (tile == T(0, 0) && tile == T(2, 2)) {return tile;} + if (tile == T(2, 0) && tile == T(0, 2)) {return tile;} + + return '\0'; +} + +int move(struct state *new_state, const struct state *old_state, int col, int row) +{ + // bad move - out of bounds + if(row < 0 || row >= 9 || col < 0 || col >= 9) {return 1;} + int board = 3 * (row / 3) + (col / 3); + // state->playBoard == -1 means all boards playable; otherwise + // only one board is playable + if (old_state->playBoard != -1 && old_state->playBoard != board) { + return 1; + /* + int boardRow = old_state->playBoard % 3; + int boardCol = old_state->playBoard / 3; + // bad move - not within the playable board + if ( + row < boardRow || row >= boardRow + 3 || + col < boardCol || col >= boardCol + 3 + ) {return 1;} + */ + } + + // bad move - tile is occupied + if(old_state->tiles[row][col] != '\0') {return 1;} // replace with ' ' maybe + + // copy old_state->{tiles,boards} to new_state->{tiles,boards} + memmove(new_state->tiles, old_state->tiles, sizeof(old_state->tiles)); + memmove(new_state->boards, old_state->boards, sizeof(old_state->boards)); + + // do move + new_state->tiles[row][col] = old_state->player; + new_state->boards[row / 3][col / 3] = winner((char *)new_state->tiles, 27 * (row % 3) + 3 * (col % 3), 9); + + // next play board + new_state->playBoard = 3 * (row % 3) + (col % 3); + // if next play board is not playable, play any board + if(new_state->boards[board / 3][board % 3] != '\0') { + new_state->playBoard = -1; + } + + new_state->player = turn(old_state->player); + return 0; +} + +void show(const struct state *state) { + #define tiles state->tiles + printf("Turn: %c\nPlay board: %d\n", (int)state->player, state->playBoard); + int play_board_row = -1; + int play_board_col = -1; + if (state->playBoard != -1) { + play_board_row = state->playBoard / 3; + play_board_col = state->playBoard % 3; + } + /*for(int i = 0; i < 3; i++) + { + putchar(' '); + for(int j = 0; j < 3; j++) + { + printf("%d "); + } + } + for(int br = 0; br < 3; br++) + { + for(int r = 0; r < 3; r++) + { + }for(int bc = 0; bc < 3; bc++) + { + + } + }*/ + printf(" 012 345 678\n"); + for(int y = 0; y < 9; y++) + { + if (y == 3 || y == 6) { + printf(" ---+---+---\n"); + } + printf("%d ", y); + for(int x = 0; x < 9; x++) + { + if (x == 3 || x == 6) { + putchar('|'); + } + putchar(tiles[y][x] ? tiles[y][x] : ' '); + } + if (y / 3 == play_board_row) { + printf("<"); + } + putchar('\n'); + } + if (play_board_col != -1) { + printf(" "); + for (int i = 0; i < play_board_col; i++) { + printf(" "); + } + printf("^^^"); + putchar('\n'); + } + putchar('\n'); + #undef tiles +} + +bool getpos(const struct state *state, int *x, int *y) { + while (true) { + printf("Place token %c at position x,y (col |, row -): ", state->player); + char line[5] = {0}; + if (fgets(line, 5, stdin) == NULL) + return false; + // line was too short + if (line[3] == '\0') + continue; + // line was too long + if (line[3] != '\n') { + // consume rest of line + while (true) { + int garbage = getchar(); + if (garbage == EOF) + return false; + if (garbage == '\n') + break; + } + continue; + } + int sscanf_result = sscanf(line, "%d,%d", x, y); + if (sscanf_result == EOF) + return false; + if (sscanf_result != 2) + continue; + /* + if ( + *x >= 0 && *x < 9 && *y >= 0 && *y < 9 + && board->tiles[*y][*x] == '\0' + ) */ break; + } + return true; +} + +int main(int *argc, char **argv) { + struct state state = { + .boards = {0}, + .tiles = {0}, + .playBoard = -1, + .player = 'X' + }; + while (true) { + int x, y; + show(&state); + bool ok = getpos(&state, &x, &y); + //printf("pos: %d %d\n", x, y); + if (!ok) {continue;} + int err = move(&state, &state, x, y); + if (err) {continue;} + char w = winner((char *)state.boards, 0, 3); + if(w) + { + printf("\n%c Wins!\n", (int)w); + return 0; + } + } + return 0; +}