Skip to content

Instantly share code, notes, and snippets.

@JamesC01
Last active December 8, 2025 02:52
Show Gist options
  • Select an option

  • Save JamesC01/479fca5e0a9074e39656faaccb038763 to your computer and use it in GitHub Desktop.

Select an option

Save JamesC01/479fca5e0a9074e39656faaccb038763 to your computer and use it in GitHub Desktop.
A simple tic-tac-toe game written in C. My first larger C program.
// Tic Tac Toe in C. V1.0 by James 26/05/2019
// This is my first bigger C project. It was actually a lot easier than a I
// thought it would be! It's not great, but it works perfectly decently.
// I started working on it sometime around 4 in the morning, and I'm done before
// 7 in the morning. So I didn't spend much time on it.
// Also, I can't really claim I did the check function myself, though. The first time
// I ever made tic tac toe (in C#), I ended up writing looping functions which could
// check any size tic tac toe board, but I saw this current easier hard-coded solution
// that just checks the cases of a 3x3 board in someone else's implementation of
// the game. So I'm not sure I can take credit for it.
// I think I thought about hard-coding it the first time I made tic-tac-toe, but I
// thought there would be too many cases, it seems that there wasn't too many, though.
// Also, I reasise I probably could've used 2d arrays, but I wanted to try it without,
// since if you hadn't heard of a 2d array, you probably wouldn't be using them.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define SIZE 3
// Draws the board along with rows/cols, numbered.
void draw_board(char board[])
{
system("clear");
printf("# 1 2 3\n");
// Rows
for (int i = 0, n = 0; i < SIZE; i++)
{
// Columns
printf("%d ", i + 1);
for (int j = 0; j < SIZE; j++)
{
printf("%c ", board[n]);
n++;
}
printf("\n");
}
}
// Initializes board to '-' characters.
void init_board(char board[])
{
for (int i = 0; i < SIZE * SIZE; i++)
{
board[i] = '-';
}
}
// Returns true if the piece was successfully placed,
// false if the position was invalid or already taken.
bool place(char board[], char player)
{
char posinput[64];
printf("%c, pick your position (xy, rc): ", player);
scanf("%s", posinput); // <-- I realise that this is potentially bad, but realistically,
// the user would have to be trying to break something, and
// this is just a little program I made for practice.
int row = (posinput[0] - '0') - 1;
int col = (posinput[1] - '0') - 1;
int pos = col + row * SIZE;
if (pos >= 0 && pos < SIZE * SIZE)
{
if (board[pos] == 'x' || board[pos] == 'o')
return false;
board[pos] = player;
return true;
}
return false;
}
// Returns true if there are three of the same chars in a row.
// b = board, p = player. Shortened for readability.
bool check(char b[], char p)
{
// Check rows
if (b[0] == p && b[1] == p && b[2] == p)
return true;
if (b[3] == p && b[4] == p && b[5] == p)
return true;
if (b[6] == p && b[7] == p && b[8] == p)
return true;
// Check columns
if (b[0] == p && b[3] == p && b[6] == p)
return true;
if (b[1] == p && b[4] == p && b[7] == p)
return true;
if (b[2] == p && b[5] == p && b[8] == p)
return true;
// Check diagonals
if (b[0] == p && b[4] == p && b[8] == p)
return true;
if (b[2] == p && b[4] == p && b[6] == p)
return true;
// If no one won, return false
return false;
}
int main(void)
{
char board[SIZE * SIZE];
char player = 'x';
init_board(board);
while (true)
{
draw_board(board);
if (place(board, player))
{
if (check(board, player))
break;
if (player == 'x')
player = 'o';
else
player = 'x';
}
}
draw_board(board);
printf("-----------------------------\n");
printf("Player %c wins!!!\n", player);
printf("-----------------------------\n");
}
@ninveli
Copy link

ninveli commented Nov 26, 2020

it doesnt work

@BA-24
Copy link

BA-24 commented Dec 8, 2021

Works fine for me, just remember to change system("clear"); to system("cls"); if you're running on windows

Copy link

ghost commented Jan 22, 2025

Works fine for me, just remember to change system("clear"); to system("cls"); if you're running on windows

Predefined macros can be used for this, changing the code is bad solution.

@BA-24
Copy link

BA-24 commented Jan 23, 2025

If you're only trying to get it to work on Windows, checking for predefined macros seems needlessly overcomplicated compared to just changing the system call, although I seriously doubt this code will ever be used in production so the difference between the solutions is probably negligible

Copy link

ghost commented Jan 23, 2025

If you're only trying to get it to work on Windows, checking for predefined macros seems needlessly overcomplicated compared to just changing the system call, although I seriously doubt this code will ever be used in production so the difference between the solutions is probably negligible

I guess it's like 3-6 lines of code, this is not overcomplicated. Also these comments are useful for others, because this section is public. Everyone can see.

@atlairovikin
Copy link

Necroposting here, but I just tried doing the same sort of thing but with a 2D array instead of without:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

char board[3][3];
char PLAYERS[] = {'x', 'o'};

void draw_board(void)
{
#ifdef _WIN32
  system("cls");
#else
  system("clear");
#endif
  printf("# 1 2 3\n");
  for (int i = 0; i < 3; i++)
    {
      printf("%d ", i + 1);
      for (int j = 0; j < 3; j++)
        {
          printf("%c", board[i][j]);
          if (j != 2) printf(" ");
        }
      printf("\n");
    }
}

void init_board(void)
{
  for (int i = 0; i < 3; i++)
    for (int j = 0; j < 3; j++)
      board[i][j] = '-';
}

bool place(char p)
{
  char pos[3] = "00";
  printf("Player %c, pick your position (RowColumn):\n", p);
  scanf("%s", pos);
  int row = pos[0] - '0' - 1;
  int col = pos[1] - '0' - 1;
  if ((row >= 0 && row <= 2) && (col >= 0 && col <= 2))
    {
      if (board[row][col] != '-')
        return false;
      board[row][col] = p;
      return true;
    }
  return false;
}

bool check(char p)
{
  for (int r = 0; r < 3; r++)
    if (board[r][0] == p && board[r][1] == p && board[r][2] == p)
      return true;
  for (int c = 0; c < 3; c++)
    if (board[0][c] == p && board[1][c] == p && board[2][c] == p)
      return true;
  if (board[0][0] == p && board[1][1] == p && board[2][2] == p)
    return true;
  else if (board[0][2] == p && board[1][1] == p && board[2][0] == p)
    return true;
  return false;
}

bool is_board_full(void)
{
  for (int i = 0; i < 3; i++)
    for (int j = 0; j < 3; j++)
      if (board[i][j] == '-')
        return false;
  return true;
}

int main(void)
{
  init_board();
  int player_index = 0;
  while(true)
    {
      draw_board();
      if (place(PLAYERS[player_index]))
        {
          if (check(PLAYERS[player_index]))
            break;
          else if (is_board_full())
            {
              draw_board();
              printf("-----------------------------\nDraw!\n-----------------------------\n");
              return 0;
            }
          player_index = 1 - player_index;
        }
    }
  draw_board();
  printf("-----------------------------\nPlayer %c wins!\n-----------------------------\n", PLAYERS[player_index]);
  return 0;
}

I also tried to add a check for draw as well as making it cross-platform.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment