fix: address code review issues (listener leak, pause, shuffle, board validation)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-07 21:33:04 +07:00
co-authored by Claude Sonnet 4.6
parent 401f0e5ee2
commit 5db71bbc5e
3 changed files with 35 additions and 11 deletions
+16
View File
@@ -1,6 +1,7 @@
import { Board, Difficulty, TileData, Point } from "../types";
import { DIFFICULTY_CONFIGS } from "./constants";
import { getEmojisForDifficulty } from "./emoji";
import { hasAnyValidMove } from "./pathfinder";
let nextTileId = 0;
@@ -34,6 +35,21 @@ export function createBoard(difficulty: Difficulty): Board {
board.push(row);
}
// Validate at least one valid move exists; reshuffle if not
while (!hasAnyValidMove(board)) {
const allTiles = board.flat().filter((t): t is TileData => t !== null);
for (let i = allTiles.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[allTiles[i], allTiles[j]] = [allTiles[j], allTiles[i]];
}
let idx2 = 0;
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
board[r][c] = allTiles[idx2++];
}
}
}
return board;
}
+5 -1
View File
@@ -12,6 +12,10 @@ export const EMOJI_POOL: string[] = [
export function getEmojisForDifficulty(difficulty: Difficulty): string[] {
const count = DIFFICULTY_CONFIGS[difficulty].pairCount;
const shuffled = [...EMOJI_POOL].sort(() => Math.random() - 0.5);
const shuffled = [...EMOJI_POOL];
for (let i = shuffled.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
}
return shuffled.slice(0, count);
}
+14 -10
View File
@@ -19,6 +19,8 @@ export class GameScene extends Phaser.Scene {
private lineGraphics!: Phaser.GameObjects.Graphics;
private isProcessing = false;
private timerEvent: Phaser.Time.TimerEvent | null = null;
private hintHandler!: () => void;
private shuffleHandler!: () => void;
constructor() {
super({ key: "GameScene" });
@@ -35,8 +37,10 @@ export class GameScene extends Phaser.Scene {
this.startTimer();
// Listen for external actions (hint, shuffle)
this.stateManager.on("hint", () => this.handleHint());
this.stateManager.on("shuffle", () => this.handleShuffle());
this.hintHandler = () => this.handleHint();
this.shuffleHandler = () => this.handleShuffle();
this.stateManager.on("hint", this.hintHandler);
this.stateManager.on("shuffle", this.shuffleHandler);
}
private renderBoard(): void {
@@ -106,6 +110,7 @@ export class GameScene extends Phaser.Scene {
}
private onTileClick(pos: Point): void {
if (this.stateManager.getState().status !== "playing") return;
const tile = this.board[pos.row][pos.col];
if (!tile) return;
@@ -302,20 +307,19 @@ export class GameScene extends Phaser.Scene {
private performShuffle(): void {
this.clearSelection();
this.board = shuffleBoard(this.board);
do {
this.board = shuffleBoard(this.board);
} while (getRemainingTiles(this.board).length > 0 && !hasAnyValidMove(this.board));
this.renderBoard();
if (
getRemainingTiles(this.board).length > 0 &&
!hasAnyValidMove(this.board)
) {
this.performShuffle();
}
}
destroy(): void {
if (this.timerEvent) {
this.timerEvent.destroy();
}
if (this.stateManager) {
this.stateManager.off("hint", this.hintHandler);
this.stateManager.off("shuffle", this.shuffleHandler);
}
}
}