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 gridbackground(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 cellboard = [['', '', ''], ['', '', ''], ['', '', '']]- 2D array representing the grid- Each inner array is a row
board[0][0]= top-left cellboard[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 linesstrokeWeight(4)- Thick lines (4 pixels)- Vertical lines:
line(cellSize, 0, cellSize, height)- First vertical line at x = 133.33line(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.33line(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 cellsfor (let i = 0; i < 3; i++)- Loop through columnsfor (let j = 0; j < 3; j++)- Loop through rowslet x = i * cellSize + cellSize / 2- Center X position of celllet y = j * cellSize + cellSize / 2- Center Y position of cellboard[i][j]- Gets the symbol in this cell
-
drawX(x, y)- Draws an X at the center positionoffset = 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 positioncircle(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-leftboard[1][1] = 'O'- Place O in centerboard[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