Created
March 19, 2023 14:48
-
-
Save object71/b77cffffff75d80132288616a9b8c61b to your computer and use it in GitHub Desktop.
TicTacToe example implementation in Plain C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <raylib.h> | |
#include <stdint.h> | |
const uint8_t kEmptyPlayer = 0; | |
typedef struct Board { | |
uint8_t positions[3][3]; | |
} Board; | |
Board ConstructBoard() { | |
Board board; | |
for (uint8_t x = 0; x < 3; x += 1) { | |
for (uint8_t y = 0; y < 3; y += 1) { | |
board.positions[x][y] = kEmptyPlayer; | |
} | |
} | |
return board; | |
} | |
/** | |
* Checks whether a given player has won. | |
* @param board The current game board | |
* @param player The player we want to check for | |
* @return True if that player wins on this board | |
*/ | |
bool CheckPlayerWins(Board board, uint8_t player) { | |
for (uint8_t i = 0; i < 3; i += 1) { | |
// horizontals | |
if (board.positions[i][0] == player | |
&& board.positions[i][1] == player | |
&& board.positions[i][2] == player) { | |
return true; | |
} | |
// verticals | |
if (board.positions[0][i] == player | |
&& board.positions[1][i] == player | |
&& board.positions[2][i] == player) { | |
return true; | |
} | |
} | |
// diagonal | |
if (board.positions[0][0] == player | |
&& board.positions[1][1] == player | |
&& board.positions[2][2] == player) { | |
return true; | |
} | |
// diagonal | |
if (board.positions[2][0] == player | |
&& board.positions[1][1] == player | |
&& board.positions[0][2] == player) { | |
return true; | |
} | |
return false; | |
} | |
/** | |
* @param board The current game board | |
* @return True if the board is full (meaning no 0 values on it) | |
*/ | |
bool BoardIsFull(Board board) { | |
for (uint8_t x = 0; x < 3; x += 1) { | |
for (uint8_t y = 0; y < 3; y += 1) { | |
if (board.positions[x][y] == kEmptyPlayer) { | |
return false; | |
} | |
} | |
} | |
return true; | |
} | |
void InitializeWindow() { | |
const uint16_t kWindowWidth = 800; | |
const uint16_t kWindowHeight = 600; | |
InitWindow(kWindowWidth, kWindowHeight, "Tic-Tac-Toe"); | |
SetTargetFPS(60); | |
} | |
uint8_t NextPlayer(uint8_t current_player) { | |
return current_player == 2 ? 1 : 2; | |
} | |
/** | |
* Draws the square on the screen as well as its current value. | |
* Will also check if the square has been clicked | |
* | |
* @return True if the square has been clicked and is active | |
*/ | |
bool UpdateSquare(uint8_t x, uint8_t y, uint8_t current_value) { | |
const uint16_t square_size = 60; | |
const uint16_t offset_x = (GetScreenWidth() - square_size * 3) / 2; | |
const uint16_t offset_y = (GetScreenHeight() - square_size * 3) / 2; | |
uint16_t position_x = offset_x + x * square_size; | |
uint16_t position_y = offset_y + y * square_size; | |
DrawRectangleLines(position_x, position_y, square_size, square_size, BLACK); | |
if (current_value == 1) { | |
DrawText("x", position_x + 20, position_y + 10, square_size - 20, BLACK); | |
} else if (current_value == 2) { | |
DrawText("o", position_x + 20, position_y + 10, square_size - 20, BLACK); | |
} else if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) { | |
Vector2 mouse_position = GetMousePosition(); | |
if (mouse_position.x > position_x | |
&& mouse_position.x < position_x + square_size | |
&& mouse_position.y > position_y | |
&& mouse_position.y < position_y + square_size) { | |
return true; | |
} | |
} | |
return false; | |
} | |
/** | |
* Draws the board and if a square has been clicked | |
* the value will be updated for that square and the players will be switched. | |
*/ | |
void UpdateBoard(Board *board, uint8_t *current_player) { | |
for (uint8_t x = 0; x < 3; x += 1) { | |
for (uint8_t y = 0; y < 3; y += 1) { | |
if (UpdateSquare(x, y, board->positions[x][y])) { | |
board->positions[x][y] = *current_player; | |
*current_player = NextPlayer(*current_player); | |
} | |
} | |
} | |
} | |
void Run() { | |
uint8_t current_player = NextPlayer(0); | |
Board board = ConstructBoard(); | |
char *won_message = ""; | |
while (!WindowShouldClose()) { | |
BeginDrawing(); | |
ClearBackground(RAYWHITE); | |
UpdateBoard(&board, ¤t_player); | |
if (CheckPlayerWins(board, 1)) { | |
board = ConstructBoard(); | |
won_message = "Player 'x' won!"; | |
} | |
if (CheckPlayerWins(board, 2)) { | |
board = ConstructBoard(); | |
won_message = "Player 'o' won!"; | |
} | |
if (BoardIsFull(board)) { | |
board = ConstructBoard(); | |
won_message = "Game was a draw!"; | |
} | |
DrawText(TextFormat("Current Player %c", current_player == 1 ? 'x' : 'o'), 25, 10, 40, BLACK); | |
DrawText(won_message, 25, 60, 40, BLACK); | |
EndDrawing(); | |
} | |
} | |
int main() { | |
InitializeWindow(); | |
Run(); | |
CloseWindow(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment