Leave without saving?

Your editor changes will be lost.

Match-3-3 adds match detection. After an animated swap finishes, the board finds horizontal and vertical runs of at least three equal-colour tiles and draws a red rounded outline around every matched tile. Matches are only identified in this lesson; removal and replacement come next.

Start with a Matchless Board

A random board could already contain a match before the player moves. Board.initializePlayBoard() repeatedly creates a grid and detects matches until it finds one with none.

do {
this.initializeBoard();
this.calculateMatches();
} while (this.matches.length > 0);

Detecting Runs

Board.calculateMatches() resets the previous result, then scans every horizontal row and every vertical column. Both passes turn one row or column into a Tile[] and give it to resolveLine().

calculateMatches() {
this.matches = [];
this.resolveHorizontalMatches();
this.resolveVerticalMatches();
}

resolveLine() holds the current same-colour run in run. A matching tile extends that run. A different-colour tile ends it: if the run has reached minimumMatchLength, it is stored; then the new tile starts the next run. The method performs the same check after the loop so a run ending at the edge of the board is not missed.

for (const tile of tiles.slice(1)) {
if (tile.colour === run[0].colour) {
run.push(tile);
continue;
}
if (run.length >= this.minimumMatchLength) {
matches.push([...run].reverse());
}
run = [tile];
}

The result is a Tile[][]: each inner array is one horizontal or vertical match. A tile in a T- or cross-shaped result can belong to two match arrays.

Detect After the Swap

Match-3-2’s animated swap still runs first. When its promise resolves, PlayState.swapTiles() clears the selection and calls calculateMatches() once.

await board.swapTilesAnimated(this.selectedTile, highlightedTile);
this.selectedTile = undefined;
this.calculateMatches();

Calling detection after the await means the board coordinates and rendered positions have both reached their final swap state before the result is displayed.

Rendering Match Feedback

Board.render() draws the regular tile grid and then calls renderMatches(). The match renderer flattens the match arrays into a Set, so an intersecting tile receives one outline even if it appears in both a horizontal and vertical match.

context.strokeStyle = 'red';
context.lineWidth = 4;
for (const tile of new Set(this.matches.flat())) {
context.beginPath();
context.roundRect(tile.x + this.x, tile.y + this.y, Tile.SIZE, Tile.SIZE, 8);
context.stroke();
}

The red outlines make the algorithm’s result visible without changing gameplay. Match-3-4 will turn those stored matches into removal, falling, and replacement tiles.

Powered by WebContainers
Files
Preparing Environment