├── LICENSE ├── README.md ├── main.c ├── tcc.patch └── thumbnail.png /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2022 Alexey Kutepov 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tic Tac Toe in C but with Auto Dereferencing 2 | 3 | A simple experiment that adds [Auto Dereferencing](https://twitter.com/tsoding/status/1527660533201178625) of the Structures to C Programming Languages. 4 | 5 | This is a simple Tic Tac Toe game that won't compile on your machine unless you change it's code or compile with [TCC](https://bellard.org/tcc/) that is patched with [tcc.patch](./tcc.patch) 6 | 7 | ## Quick Start 8 | 9 | ```console 10 | $ wget http://download.savannah.gnu.org/releases/tinycc/tcc-0.9.27.tar.bz2 11 | $ tar fvx tcc-0.9.27.tar.bz2 && cd tcc-0.9.27 12 | $ patch ./tccgen.c < ../tcc.patch 13 | $ ./configure && make && make install && cd .. 14 | $ tcc -o main main.c && ./main 15 | ``` 16 | 17 | ## Screencast 18 | 19 | [![thumbnail](./thumbnail.png)](https://www.youtube.com/watch?v=yKI-VOBBFu8) 20 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define SIZE 3 7 | #define ROWS SIZE 8 | #define COLS SIZE 9 | 10 | typedef enum { 11 | SHAPE_X = 0, 12 | SHAPE_O, 13 | COUNT_SHAPES, 14 | } Shape; 15 | 16 | typedef enum { 17 | CELL_EMPTY = 0, 18 | CELL_FULL, 19 | } Cell; 20 | 21 | char shape_chars[COUNT_SHAPES] = { 22 | [SHAPE_X] = 'x', 23 | [SHAPE_O] = 'o', 24 | }; 25 | 26 | typedef struct { 27 | bool quit; 28 | Cell cells[ROWS][COLS]; 29 | int filled_count; 30 | int cur_row; 31 | int cur_col; 32 | Shape shape; 33 | } Game; 34 | 35 | void game_render(const Game *game) 36 | { 37 | for (int row = 0; row < ROWS; ++row) { 38 | for (int col = 0; col < COLS; ++col) { 39 | bool selected = row == game.cur_row && col == game.cur_col; 40 | 41 | putc(selected ? '[' : ' ', stdout); 42 | Cell cell = game.cells[row][col]; 43 | putc(cell == CELL_EMPTY ? '.' : shape_chars[cell - CELL_FULL], stdout); 44 | putc(selected ? ']' : ' ', stdout); 45 | } 46 | putc('\n', stdout); 47 | } 48 | } 49 | 50 | typedef int Outcome; 51 | 52 | bool check_row(const Game *game, int row, Shape s) 53 | { 54 | for (int col = 0; col < COLS; ++col) { 55 | if (game.cells[row][col] - CELL_FULL != s) { 56 | return false; 57 | } 58 | } 59 | return true; 60 | } 61 | 62 | bool check_col(const Game *game, int col, Shape s) 63 | { 64 | for (int row = 0; row < ROWS; ++row) { 65 | if (game.cells[row][col] - CELL_FULL != s) { 66 | return false; 67 | } 68 | } 69 | return true; 70 | } 71 | 72 | bool check_main_diag(const Game *game, Shape s) 73 | { 74 | for (int i = 0; i < SIZE; ++i) { 75 | if (game.cells[i][i] - CELL_FULL != s) { 76 | return false; 77 | } 78 | } 79 | return true; 80 | } 81 | 82 | bool check_sec_diag(const Game *game, Shape s) 83 | { 84 | for (int i = 0; i < SIZE; ++i) { 85 | if (game.cells[i][SIZE - i - 1] - CELL_FULL != s) { 86 | return false; 87 | } 88 | } 89 | return true; 90 | } 91 | 92 | typedef int Outcome; 93 | 94 | Outcome game_check_victory(Game *game) 95 | { 96 | for (Shape s = 0; s < COUNT_SHAPES; ++s) { 97 | for (int i = 0; i < SIZE; ++i) { 98 | if (check_row(game, i, s)) return s + 1; 99 | if (check_col(game, i, s)) return s + 1; 100 | } 101 | if (check_main_diag(game, s)) return s + 1; 102 | if (check_sec_diag(game, s)) return s + 1; 103 | } 104 | return 0; 105 | } 106 | 107 | void game_move(Game *game, char c) 108 | { 109 | switch (c) { 110 | case 'a': 111 | game.cur_col -= 1; 112 | break; 113 | case 'd': 114 | game.cur_col += 1; 115 | break; 116 | case 'w': 117 | game.cur_row -= 1; 118 | break; 119 | case 's': 120 | game.cur_row += 1; 121 | break; 122 | case 'q': 123 | game.quit = true; 124 | break; 125 | case ' ': { 126 | Cell *cell = &game.cells[game.cur_row][game.cur_col]; 127 | if (*cell == CELL_EMPTY) { 128 | *cell = CELL_FULL + game.shape; 129 | game.filled_count += 1; 130 | 131 | Outcome outcome = game_check_victory(game); 132 | if (outcome) { 133 | game_render(game); 134 | printf("%c won\n", shape_chars[outcome-1]); 135 | game.quit = true; 136 | } else if (game.filled_count == ROWS*COLS) { 137 | game_render(game); 138 | printf("tie\n"); 139 | game.quit = true; 140 | } 141 | 142 | game.shape = 1 - game.shape; 143 | } 144 | } break; 145 | 146 | default: 147 | {} 148 | } 149 | if (game.cur_col < 0) game.cur_col = 0; 150 | if (game.cur_col >= COLS) game.cur_col = COLS-1; 151 | if (game.cur_row < 0) game.cur_row = 0; 152 | if (game.cur_row >= ROWS) game.cur_row = ROWS-1; 153 | 154 | } 155 | 156 | int main(void) 157 | { 158 | static Game game = {0}; 159 | static char cmd[256]; 160 | 161 | while (!game.quit) { 162 | game_render(&game); 163 | printf("> "); 164 | fgets(cmd, sizeof(cmd), stdin); 165 | size_t n = strlen(cmd); 166 | for (size_t i = 0; i < n; ++i) { 167 | game_move(&game, cmd[i]); 168 | } 169 | } 170 | 171 | return 0; 172 | } 173 | -------------------------------------------------------------------------------- /tcc.patch: -------------------------------------------------------------------------------- 1 | --- ./tcc-0.9.27/tccgen.c 2017-12-17 15:27:05.000000000 +0700 2 | +++ ./tcc-0.9.27-patched/tccgen.c 2022-06-10 23:53:17.869447393 +0700 3 | @@ -18,6 +18,7 @@ 4 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 5 | */ 6 | 7 | +#include 8 | #include "tcc.h" 9 | 10 | /********************************************************/ 11 | @@ -5115,8 +5116,13 @@ 12 | } else if (tok == '.' || tok == TOK_ARROW || tok == TOK_CDOUBLE) { 13 | int qualifiers; 14 | /* field */ 15 | - if (tok == TOK_ARROW) 16 | + if (tok == TOK_ARROW) { 17 | indir(); 18 | + } else if (tok == '.') { 19 | + if ((vtop->type.t & VT_BTYPE) == VT_PTR) { 20 | + indir(); 21 | + } 22 | + } 23 | qualifiers = vtop->type.t & (VT_CONSTANT | VT_VOLATILE); 24 | test_lvalue(); 25 | gaddrof(); 26 | -------------------------------------------------------------------------------- /thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tsoding/tic-tac-toe-auto-deref/69239f76b15392139b889ea52363636fe972c4ed/thumbnail.png --------------------------------------------------------------------------------