Build a Five‑in‑a‑Row (Gomoku) Game with Pure JavaScript: Step‑by‑Step Guide
This tutorial walks you through creating a complete five‑in‑a‑row (Gomoku) web game using vanilla JavaScript, covering development approaches, board rendering, event delegation, win‑checking algorithms, piece placement logic, game reset, testing strategies, and essential JavaScript event handling techniques.
Game Development Approaches
Small‑scale games can be built by one or two developers directly in the browser without formal specifications. Large‑scale games typically follow three phases: design (concept and target audience), specification (class and method definitions), and implementation (edit‑run cycle).
Gobang Rules
Two players use opposite‑colored stones.
The board starts empty.
Black moves first; players alternate placing one stone per turn.
Stones are placed on intersecting points and never moved or removed.
Black’s first stone may be placed on any intersection.
Core Implementation
Drawing the Board
The board is a 15×15 grid (n = 15). The drawGobang function creates a div for each cell, assigns an id block_i_j, and adds edge‑specific classes ( top, bottom, left, right) for styling.
function drawGobang(n) {
for (var i = 0; i < n; i++) {
for (var j = 0; j < n; j++) {
var block = document.createElement("div");
block.className = "gobang_block";
block.id = "block_" + i + "_" + j;
gobang.appendChild(block);
if (i === 0) block.className += " top";
if (i === n - 1) block.className += " bottom";
if (j === 0) block.className += " left";
if (j === n - 1) block.className += " right";
}
}
}Placing Pieces with Event Delegation
A single click handler is attached to the board’s container element. The handler extracts the cell coordinates from the element’s id (e.g., block_3_7) and draws the appropriate stone.
var gobang = document.getElementById("gobang_main");
EventUtil.addHandler(gobang, "click", drawPiece);When the event fires, the target id is split to obtain i and j:
i = +targetId.split("_")[1];
j = +targetId.split("_")[2];Tracking Moves and Preventing Overwrites
Active stones receive the active class together with black or white.
Before drawing, the code checks target.className.indexOf("active") < 0 to ensure the cell is empty.
Relying solely on a board array (e.g., gobangArr[i][j]) is unsafe unless the array is explicitly cleared during reset.
Win Detection Algorithm
The chessWin(i, j, color) function counts consecutive stones of the same color in four directions: horizontal, vertical, diagonal (45°), and anti‑diagonal (135°). It starts with count = 1 (the newly placed stone) and scans up to four cells forward and backward in each direction. If count == 5 at any point, the player wins.
function chessWin(i, j, color) {
var dirs = [
{x: 0, y: 1}, // vertical
{x: 1, y: 0}, // horizontal
{x: 1, y: 1}, // 45° diagonal
{x: 1, y: -1} // 135° diagonal
];
for (var d = 0; d < dirs.length; d++) {
var count = 1;
// forward direction
for (var step = 1; step < 5; step++) {
var x = i + dirs[d].x * step;
var y = j + dirs[d].y * step;
if (x < 0 || x >= 15 || y < 0 || y >= 15) break;
if (gobangArr[x][y] === color) count++; else break;
}
// backward direction
for (var step = 1; step < 5; step++) {
var x = i - dirs[d].x * step;
var y = j - dirs[d].y * step;
if (x < 0 || x >= 15 || y < 0 || y >= 15) break;
if (gobangArr[x][y] === color) count++; else break;
}
if (count >= 5) return true;
}
return false;
}Resetting the Game
Reset clears all stones, empties the gobangArr matrix, restores the default turn (black first), updates UI prompts, and re‑binds the click handler. After a win, the click handler is removed to prevent further moves until the game is restarted.
Testing the Implementation
Validate edge cases such as placing stones on the board’s border cells.
Verify win detection for vertical, horizontal, 45°, and 135° lines.
JavaScript Event Fundamentals
Event Handler Types
HTML attribute handlers (e.g., onclick="...") – discouraged because they tightly couple markup and logic.
DOM0 – assign a function to element.onclick; only one handler per event.
DOM2 – addEventListener / removeEventListener support multiple listeners and allow capture/bubble control.
IE attachEvent – similar to DOM2 but runs in the global scope and invokes listeners in reverse order.
Cross‑browser utility – a lightweight EventUtil object abstracts the differences.
var EventUtil = {
addHandler: function (element, type, handler) {
if (element.addEventListener) {
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
},
getEvent: function (event) {
return event ? event : window.event;
},
getTarget: function (event) {
return event.target || event.srcElement;
}
};Event Object and Target Normalization
Both DOM0 and DOM2 pass an event object to the handler. In older IE versions the event is accessed via window.event. EventUtil.getEvent returns a normalized event, and EventUtil.getTarget returns the actual element that triggered the event.
Source Code and References
Online demo: http://labs.qiang.it/qqpai/test/wcn/gobang/gobang.html
GitHub repository: https://github.com/Newcandy/gobang
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Aotu Lab
Aotu Lab, founded in October 2015, is a front-end engineering team serving multi-platform products. The articles in this public account are intended to share and discuss technology, reflecting only the personal views of Aotu Lab members and not the official stance of JD.com Technology.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
