Huge refactor of web-socket-handler

This commit is contained in:
sepia 2025-07-21 22:19:59 -05:00
parent f68a8d152f
commit 10a4bd64d2
11 changed files with 333 additions and 510 deletions

View file

@ -1,9 +1,9 @@
import { GameInstance } from './game-instance';
import { GomokuGame } from './game-instance';
import { expect, test, describe } from 'bun:test';
describe('GameInstance', () => {
test('should initialize with correct default state', () => {
const game = new GameInstance();
const game = new GomokuGame();
expect(game.id).toBeDefined();
expect(game.board.length).toBe(15);
@ -15,7 +15,7 @@ describe('GameInstance', () => {
});
test('should add players correctly', () => {
const game = new GameInstance();
const game = new GomokuGame();
const player1 = 'player1-uuid';
const player2 = 'player2-uuid';
@ -36,7 +36,7 @@ describe('GameInstance', () => {
});
test('should prevent more than two players from joining', () => {
const game = new GameInstance();
const game = new GomokuGame();
const player1 = 'player1-uuid';
const player2 = 'player2-uuid';
@ -56,7 +56,7 @@ describe('GameInstance', () => {
});
test('should validate moves correctly', () => {
const game = new GameInstance();
const game = new GomokuGame();
const player1 = 'player1-uuid';
const player2 = 'player2-uuid';
@ -86,7 +86,7 @@ describe('GameInstance', () => {
});
test('should detect win conditions', () => {
const game = new GameInstance();
const game = new GomokuGame();
const player1 = 'player1-uuid';
const player2 = 'player2-uuid';
@ -106,7 +106,7 @@ describe('GameInstance', () => {
});
test('should detect draw condition', () => {
const game = new GameInstance();
const game = new GomokuGame();
const player1 = 'player1-uuid';
const player2 = 'player2-uuid';

View file

@ -1,89 +1,32 @@
import { v4 as uuidv4 } from 'uuid';
export type PlayerColor = 'black' | 'white';
export type GameStatus = 'waiting' | 'playing' | 'finished';
export type BoardCell = null | 'black' | 'white';
type PlayerColor = 'black' | 'white';
type GameStatus = 'waiting' | 'playing' | 'finished';
type BoardCell = null | 'black' | 'white';
export class GameInstance {
public readonly id: string;
export class GomokuGame {
public readonly board: BoardCell[][];
public currentPlayerColor: PlayerColor | null;
public currentPlayerColor: null | PlayerColor;
public status: GameStatus;
public winnerColor: null | PlayerColor | 'draw';
public players: { black?: string; white?: string };
public history: { row: number, col: number }[];
private readonly boardSize = 15;
private moveCount = 0;
constructor(id?: string) {
this.id = id || uuidv4();
constructor() {
this.board = Array.from({ length: this.boardSize }, () =>
Array(this.boardSize).fill(null),
);
this.currentPlayerColor = null;
this.currentPlayerColor = 'black';
this.status = 'waiting';
this.winnerColor = null;
this.players = {};
}
public getCurrentPlayerId(): string | undefined {
if (this.currentPlayerColor === 'black') {
return this.players.black;
} else {
return this.players.white;
}
}
public getPlayerCount(): number {
return Object.values(this.players).filter(Boolean).length;
}
public addPlayer(playerId: string): boolean {
// If game is full, prevent new players from joining.
if (this.getPlayerCount() >= 2) {
return false;
}
// If player is already in the game, return true.
if (Object.values(this.players).includes(playerId)) {
return true;
}
// Assign black if available, otherwise white
if (!this.players.black) {
this.players.black = playerId;
} else if (!this.players.white) {
this.players.white = playerId;
} else {
return false; // Should not happen if getPlayerCount() check is correct
}
// If both players have joined, start the game.
if (this.players.black && this.players.white) {
this.currentPlayerColor = 'black';
this.status = 'playing';
}
return true;
this.history = [];
}
public makeMove(
playerId: string,
playerColor: PlayerColor,
row: number,
col: number,
): { success: boolean; error?: string } {
// Find player's color
let playerColor: PlayerColor | null = null;
for (const [color, id] of Object.entries(this.players)) {
if (id === playerId) {
playerColor = color as PlayerColor;
break;
}
}
if (!playerColor) {
return { success: false, error: 'Player not in this game' };
}
// Validate it's the player's turn
if (this.currentPlayerColor !== playerColor) {
return { success: false, error: 'Not your turn' };
@ -103,6 +46,14 @@ export class GameInstance {
this.board[row][col] = playerColor;
this.moveCount++;
// If this was the first move, declare the game to have begun
if (this.status === 'waiting') {
this.status = 'playing';
}
// Add the move to the game's history
this.history.push({ row, col });
// Check for win condition
if (this.checkWin(row, col, playerColor)) {
this.winnerColor = playerColor;