Advertisement
_vim_

tic tac toe in C with SDL2

Jun 5th, 2020
572
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.34 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdbool.h>
  3. #include <SDL2/SDL.h>
  4. #include <SDL2/SDL2_gfxPrimitives.h>
  5.  
  6. #define N 3
  7. #define WIN_WIDTH 640
  8. #define WIN_HEIGHT 480
  9. #define CELL_WIDTH (WIN_WIDTH / N)
  10. #define CELL_HEIGHT (WIN_HEIGHT / N)
  11.  
  12. typedef enum { ST_RUNNING, ST_X_WON, ST_O_WON, ST_DRAW, ST_QUIT } state_T;
  13.  
  14. typedef struct {
  15.     char board[N * N];
  16.     char player;
  17.     state_T state;
  18. } Game;
  19.  
  20. static const SDL_Color X_COLOR    = { .r = 255, .g = 0,   .b = 255 },
  21.                        O_COLOR    = { .r = 50,  .g = 100, .b = 255 },
  22.                        DRAW_COLOR = { .r = 100, .g = 100, .b = 100 },
  23.                        GRID_COLOR = { .r = 255, .g = 255, .b = 255 };
  24.  
  25. void render_grid(SDL_Renderer *ren, const SDL_Color color) {
  26.     SDL_SetRenderDrawColor(ren, color.r, color.g, color.b, 255);
  27.  
  28.     for (int i = 1; i < N; ++i) {
  29.         SDL_RenderDrawLine(ren, i * CELL_WIDTH, 0, i * CELL_WIDTH, WIN_HEIGHT);
  30.         SDL_RenderDrawLine(ren, 0, i * CELL_HEIGHT, WIN_WIDTH, i * CELL_HEIGHT);
  31.     }
  32. }
  33.  
  34. void render_player(SDL_Renderer *ren, const char player, int row, int col, const SDL_Color color) {
  35.     const float HALF_BOX_SIDE = fmin(CELL_WIDTH, CELL_HEIGHT) * .25,
  36.                 CENTER_X      = CELL_WIDTH * .5 + col * CELL_WIDTH,
  37.                 CENTER_Y      = CELL_HEIGHT * .5 + row * CELL_HEIGHT;
  38.  
  39.     if (player == 'X') {
  40.         thickLineRGBA(ren,
  41.                       CENTER_X - HALF_BOX_SIDE,
  42.                       CENTER_Y - HALF_BOX_SIDE,
  43.                       CENTER_X + HALF_BOX_SIDE,
  44.                       CENTER_Y + HALF_BOX_SIDE, 10, color.r, color.g, color.b, 255);
  45.         thickLineRGBA(ren,
  46.                       CENTER_X + HALF_BOX_SIDE,
  47.                       CENTER_Y - HALF_BOX_SIDE,
  48.                       CENTER_X - HALF_BOX_SIDE,
  49.                       CENTER_Y + HALF_BOX_SIDE, 10, color.r, color.g, color.b, 255);
  50.     } else if (player == 'O') {
  51.         filledCircleRGBA(ren, CENTER_X, CENTER_Y, HALF_BOX_SIDE + 5, color.r, color.g, color.b, 255);
  52.         filledCircleRGBA(ren, CENTER_X, CENTER_Y, HALF_BOX_SIDE - 5, 0, 0, 0, 255);
  53.     }
  54. }
  55.  
  56. void render_board(SDL_Renderer *ren, const char *board, const SDL_Color x_col, const SDL_Color o_col) {
  57.     for (int y = 0; y < N; ++y) {
  58.         for (int x = 0; x < N; ++x) {
  59.             render_player(ren, board[x * N + y], y, x, board[x * N + y] == 'X' ? x_col : o_col);
  60.         }
  61.     }
  62. }
  63.  
  64. void render_game_over(SDL_Renderer *ren, const Game *game, const SDL_Color color) {
  65.     render_grid(ren, color);
  66.     render_board(ren, game->board, color, color);
  67. }
  68.  
  69. void render_running(SDL_Renderer *ren, const Game *game) {
  70.     render_grid(ren, GRID_COLOR);
  71.     render_board(ren, game->board, X_COLOR, O_COLOR);
  72. }
  73.  
  74. void render_game(SDL_Renderer *ren, const Game *game) {
  75.     switch (game->state) {
  76.     case ST_RUNNING:
  77.         render_running(ren, game);
  78.         break;
  79.     case ST_X_WON:
  80.         render_game_over(ren, game, X_COLOR);
  81.         break;
  82.     case ST_O_WON:
  83.         render_game_over(ren, game, O_COLOR);
  84.         break;
  85.     case ST_DRAW:
  86.         render_game_over(ren, game, DRAW_COLOR);
  87.         break;
  88.     default:
  89.         break;
  90.     }
  91. }
  92.  
  93. int cell_count(const char *board, char cell) {
  94.     int n = 0;
  95.  
  96.     for (int i = 0; i < N * N; ++i) {
  97.         if (board[i] == cell) {
  98.             ++n;
  99.         }
  100.     }
  101.  
  102.     return n;
  103. }
  104.  
  105. bool won(Game *game, char player) {
  106.     int nrow = 0, ncol = 0, ndiag1 = 0, ndiag2 = 0;
  107.  
  108.     for (int y = 0; y < N; ++y) {
  109.         for (int x = 0; x < N; ++x) {
  110.             if (game->board[y * N + x] == player) {
  111.                 ++nrow;
  112.             }
  113.             if (game->board[x * N + y] == player) {
  114.                 ++ncol;
  115.             }
  116.         }
  117.  
  118.         if (nrow == N || ncol == N) {
  119.             return true;
  120.         }
  121.  
  122.         nrow = ncol = 0;
  123.  
  124.         if (game->board[y * N + y] == player) {
  125.             ++ndiag1;
  126.         }
  127.         if (game->board[y * N + N - y - 1] == player) {
  128.             ++ndiag2;
  129.         }
  130.  
  131.     }
  132.  
  133.     return ndiag1 == N || ndiag2 == N;
  134. }
  135.  
  136. void test_game_over(Game *game) {
  137.     if (won(game, 'X')) {
  138.         game->state = ST_X_WON;
  139.     } else if (won(game, 'O')) {
  140.         game->state = ST_O_WON;
  141.     } else if (cell_count(game->board, 0) == 0) {
  142.         game->state = ST_DRAW;
  143.     }
  144. }
  145.  
  146. void reset_game(Game *game) {
  147.     game->player = 'X';
  148.     game->state = ST_RUNNING;
  149.     memset(game->board, 0, sizeof(game->board));
  150. }
  151.  
  152. void player_turn(Game *game, int row, int col) {
  153.     if (!game->board[row * N + col]) {
  154.         game->board[row * N + col] = game->player;
  155.         game->player = game->player == 'X' ? 'O' : 'X'; // switch players
  156.         test_game_over(game);
  157.     }
  158. }
  159.  
  160. void cell_put(Game *game, int row, int col) {
  161.     if (game->state == ST_RUNNING) {
  162.         player_turn(game, row, col);
  163.     } else {
  164.         reset_game(game);
  165.     }
  166. }
  167.  
  168. int main(void) {
  169.     if (SDL_Init(SDL_INIT_VIDEO)) {
  170.         fprintf(stderr, "couldn't initialize SDL: %s\n", SDL_GetError());
  171.         return 1;
  172.     }
  173.  
  174.     SDL_Window *win = SDL_CreateWindow("Tic Tac Toe",
  175.                                        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
  176.                                        WIN_WIDTH, WIN_HEIGHT,
  177.                                        SDL_WINDOW_SHOWN);
  178.     if (!win) {
  179.         fprintf(stderr, "couldn't create window: %s\n", SDL_GetError());
  180.         return 1;
  181.     }
  182.  
  183.     SDL_Renderer *renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
  184.  
  185.     if (!renderer) {
  186.         fprintf(stderr, "couldn't create renderer for window: %s\n", SDL_GetError());
  187.         return 1;
  188.     }
  189.  
  190.     Game game = { .board = { 0 }, .player = 'X', .state = ST_RUNNING };
  191.     SDL_Event e;
  192.  
  193.     while (game.state != ST_QUIT) {
  194.         while (SDL_PollEvent(&e)) {
  195.             switch (e.type) {
  196.             case SDL_QUIT:
  197.                 game.state = ST_QUIT;
  198.                 break;
  199.             case SDL_MOUSEBUTTONDOWN:
  200.                 cell_put(&game, e.button.x / CELL_WIDTH, e.button.y / CELL_HEIGHT);
  201.                 break;
  202.             default:
  203.                 break;
  204.             }
  205.         }
  206.  
  207.         SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
  208.         SDL_RenderClear(renderer);
  209.         render_game(renderer, &game);
  210.         SDL_RenderPresent(renderer);
  211.     }
  212.  
  213.     SDL_DestroyWindow(win);
  214.     SDL_Quit();
  215.  
  216.     return 0;
  217. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement