Huge refactor of web-socket-handler
This commit is contained in:
parent
f68a8d152f
commit
10a4bd64d2
11 changed files with 333 additions and 510 deletions
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue