Skip to main content

Step 1 - Basic Setup: Creating the Board

Let's set up the canvas and create the grid system for our Tic-Tac-Toe game.

Understanding the Grid

Tic-Tac-Toe uses a 3×3 grid with 9 spaces:

[0,0] | [1,0] | [2,0]
------|-------|------
[0,1] | [1,1] | [2,1]
------|-------|------
[0,2] | [1,2] | [2,2]

We'll store this as a 2D array where:

  • First number = column (0, 1, or 2)
  • Second number = row (0, 1, or 2)
  • Each cell can be: empty '', 'X', or 'O'

Step 1: Create the Canvas

Open the p5.js Web Editor at https://editor.p5js.org/ and start with:

function setup() {
createCanvas(400, 400);
}

function draw() {
background(255);
}

Breaking it down

  • createCanvas(400, 400) - Square canvas, perfect for our square grid
  • background(255) - White background

Test it: Click play ▶️ - you should see a white square!

Step 2: Add Grid Variables

Let's define our grid system:

let cellSize = 400 / 3;  // Each cell is 133.33 pixels
let board = [
['', '', ''],
['', '', ''],
['', '', '']
];

function setup() {
createCanvas(400, 400);
}

function draw() {
background(255);
}

Breaking it down

  • cellSize = 400 / 3 - Canvas is 400px, divided by 3 = 133.33px per cell
  • board = [['', '', ''], ['', '', ''], ['', '', '']] - 2D array representing the grid
    • Each inner array is a row
    • board[0][0] = top-left cell
    • board[2][2] = bottom-right cell
    • Empty string '' means cell is available

Step 3: Draw Grid Lines

Now let's draw the grid lines:

let cellSize = 400 / 3;
let board = [
['', '', ''],
['', '', ''],
['', '', '']
];

function setup() {
createCanvas(400, 400);
}

function draw() {
background(255);

// Draw grid lines
stroke(0);
strokeWeight(4);

// Vertical lines
line(cellSize, 0, cellSize, height);
line(cellSize * 2, 0, cellSize * 2, height);

// Horizontal lines
line(0, cellSize, width, cellSize);
line(0, cellSize * 2, width, cellSize * 2);
}

Breaking it down

  • stroke(0) - Black lines
  • strokeWeight(4) - Thick lines (4 pixels)
  • Vertical lines:
    • line(cellSize, 0, cellSize, height) - First vertical line at x = 133.33
    • line(cellSize * 2, 0, cellSize * 2, height) - Second vertical line at x = 266.66
  • Horizontal lines:
    • line(0, cellSize, width, cellSize) - First horizontal line at y = 133.33
    • line(0, cellSize * 2, width, cellSize * 2) - Second horizontal line at y = 266.66

Test it: You should see a perfect 3×3 grid!

Step 4: Add Current Player Variable

Let's track whose turn it is:

let cellSize = 400 / 3;
let board = [
['', '', ''],
['', '', ''],
['', '', '']
];
let currentPlayer = 'X'; // X goes first

function setup() {
createCanvas(400, 400);
}

Breaking it down

  • currentPlayer = 'X' - Tracks whose turn it is
  • Will switch between 'X' and 'O' after each move
  • X traditionally goes first

Step 5: Add Helper Function to Draw Symbols

Let's create a function to draw X's and O's:

let cellSize = 400 / 3;
let board = [
['', '', ''],
['', '', ''],
['', '', '']
];
let currentPlayer = 'X';

function setup() {
createCanvas(400, 400);
}

function draw() {
background(255);

// Draw grid lines
stroke(0);
strokeWeight(4);
line(cellSize, 0, cellSize, height);
line(cellSize * 2, 0, cellSize * 2, height);
line(0, cellSize, width, cellSize);
line(0, cellSize * 2, width, cellSize * 2);

// Draw X's and O's
drawBoard();
}

function drawBoard() {
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
let x = i * cellSize + cellSize / 2;
let y = j * cellSize + cellSize / 2;
let symbol = board[i][j];

if (symbol === 'X') {
drawX(x, y);
} else if (symbol === 'O') {
drawO(x, y);
}
}
}
}

function drawX(x, y) {
let offset = cellSize / 4;
stroke(255, 0, 0); // Red X
strokeWeight(8);
line(x - offset, y - offset, x + offset, y + offset);
line(x + offset, y - offset, x - offset, y + offset);
}

function drawO(x, y) {
stroke(0, 0, 255); // Blue O
strokeWeight(8);
noFill();
circle(x, y, cellSize / 2);
}

Breaking it down

  • drawBoard() - Loops through all 9 cells

    • for (let i = 0; i < 3; i++) - Loop through columns
    • for (let j = 0; j < 3; j++) - Loop through rows
    • let x = i * cellSize + cellSize / 2 - Center X position of cell
    • let y = j * cellSize + cellSize / 2 - Center Y position of cell
    • board[i][j] - Gets the symbol in this cell
  • drawX(x, y) - Draws an X at the center position

    • offset = cellSize / 4 - Distance from center to edge of X
    • Two diagonal lines creating an X shape
    • Red color (255, 0, 0)
  • drawO(x, y) - Draws an O at the center position

    • circle(x, y, cellSize / 2) - Circle with diameter half the cell size
    • Blue color (0, 0, 255)
    • noFill() - Hollow circle (outline only)

Test it: Nothing shows yet because the board is empty! Let's test by manually adding symbols.

Step 6: Test the Drawing Functions

Temporarily add some test symbols to see if drawing works:

function setup() {
createCanvas(400, 400);

// Test symbols (we'll remove this later)
board[0][0] = 'X';
board[1][1] = 'O';
board[2][2] = 'X';
}

Breaking it down

  • board[0][0] = 'X' - Place X in top-left
  • board[1][1] = 'O' - Place O in center
  • board[2][2] = 'X' - Place X in bottom-right
  • This is just for testing - we'll remove it next step!

Test it: You should see a red X in top-left, blue O in center, and red X in bottom-right!

Step 7: Remove Test Code

Now remove the test symbols so we start with a clean board:

function setup() {
createCanvas(400, 400);
// Test symbols removed - start with empty board
}

Complete Step 1 Code

Here's everything together:

let cellSize = 400 / 3;
let board = [
['', '', ''],
['', '', ''],
['', '', '']
];
let currentPlayer = 'X';

function setup() {
createCanvas(400, 400);
}

function draw() {
background(255);

// Draw grid lines
stroke(0);
strokeWeight(4);
line(cellSize, 0, cellSize, height);
line(cellSize * 2, 0, cellSize * 2, height);
line(0, cellSize, width, cellSize);
line(0, cellSize * 2, width, cellSize * 2);

// Draw X's and O's
drawBoard();
}

function drawBoard() {
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
let x = i * cellSize + cellSize / 2;
let y = j * cellSize + cellSize / 2;
let symbol = board[i][j];

if (symbol === 'X') {
drawX(x, y);
} else if (symbol === 'O') {
drawO(x, y);
}
}
}
}

function drawX(x, y) {
let offset = cellSize / 4;
stroke(255, 0, 0);
strokeWeight(8);
line(x - offset, y - offset, x + offset, y + offset);
line(x + offset, y - offset, x - offset, y + offset);
}

function drawO(x, y) {
stroke(0, 0, 255);
strokeWeight(8);
noFill();
circle(x, y, cellSize / 2);
}

Understanding 2D Arrays

Our board uses a 2D array. Here's how to think about it:

board[column][row]

board[0][0] board[1][0] board[2][0] // Top row
board[0][1] board[1][1] board[2][1] // Middle row
board[0][2] board[1][2] board[2][2] // Bottom row

What You Learned

In this step, you:

  • ✅ Created a 400×400 canvas
  • ✅ Set up a 2D array to store the game board
  • ✅ Drew grid lines to create 9 cells
  • ✅ Created functions to draw X's and O's
  • ✅ Learned about nested loops for 2D grids
  • ✅ Set up the current player tracker

What's Next?

We have a beautiful grid and functions to draw symbols, but we can't interact with it yet! Next, we'll add mouse click detection so players can actually place their X's and O's.

Coming up: Detecting clicks and placing symbols!


Next Step: Step 2 - Click Detection: Placing Symbols