mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 07:50:45 +00:00
First Commit
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
import {GameImpl, PlayerImpl} from '../src/core/GameImpl';
|
||||
import {EventBus} from '../src/core/EventBus';
|
||||
import {Game, Cell, MutablePlayer, PlayerInfo, TerrainMap, TerrainTypes, Tile} from '../src/core/Game';
|
||||
|
||||
describe('borderTilesWith', () => {
|
||||
let game: GameImpl;
|
||||
let player1: PlayerImpl;
|
||||
let player2: PlayerImpl;
|
||||
let terrainMap: TerrainMap;
|
||||
|
||||
beforeEach(() => {
|
||||
// Create a 5x5 terrain map
|
||||
terrainMap = {
|
||||
terrain: jest.fn().mockReturnValue(TerrainTypes.Land),
|
||||
width: jest.fn().mockReturnValue(5),
|
||||
height: jest.fn().mockReturnValue(5)
|
||||
};
|
||||
const eventBus = new EventBus();
|
||||
game = new GameImpl(terrainMap, eventBus);
|
||||
player1 = game.addPlayer(new PlayerInfo('Player 1', false)) as PlayerImpl;
|
||||
player2 = game.addPlayer(new PlayerInfo('Player 2', false)) as PlayerImpl;
|
||||
});
|
||||
|
||||
test('should return an empty set when players have no bordering tiles', () => {
|
||||
const borderTiles = player1.borderTilesWith(player2);
|
||||
expect(borderTiles.size).toBe(0);
|
||||
});
|
||||
|
||||
test('should return correct border tiles when players are adjacent', () => {
|
||||
game.conquer(player1, new Cell(0, 0));
|
||||
game.conquer(player2, new Cell(1, 0));
|
||||
|
||||
const borderTilesP1 = player1.borderTilesWith(player2);
|
||||
const borderTilesP2 = player2.borderTilesWith(player1);
|
||||
|
||||
expect(borderTilesP1.size).toBe(1);
|
||||
expect(borderTilesP2.size).toBe(1);
|
||||
|
||||
const p1BorderTile = Array.from(borderTilesP1)[0];
|
||||
const p2BorderTile = Array.from(borderTilesP2)[0];
|
||||
|
||||
expect(p1BorderTile.cell()).toEqual(new Cell(0, 0));
|
||||
expect(p2BorderTile.cell()).toEqual(new Cell(1, 0));
|
||||
});
|
||||
|
||||
test('should update border tiles when a new tile is conquered', () => {
|
||||
game.conquer(player1, new Cell(0, 0));
|
||||
game.conquer(player2, new Cell(2, 0));
|
||||
|
||||
expect(player1.borderTilesWith(player2).size).toBe(0);
|
||||
|
||||
game.conquer(player2, new Cell(1, 0));
|
||||
|
||||
const borderTiles = player1.borderTilesWith(player2);
|
||||
expect(borderTiles.size).toBe(1);
|
||||
expect(Array.from(borderTiles)[0].cell()).toEqual(new Cell(0, 0));
|
||||
});
|
||||
|
||||
test('should handle multiple border tiles correctly', () => {
|
||||
game.conquer(player1, new Cell(0, 0));
|
||||
game.conquer(player1, new Cell(0, 1));
|
||||
game.conquer(player2, new Cell(1, 0));
|
||||
game.conquer(player2, new Cell(1, 1));
|
||||
|
||||
const borderTiles = player1.borderTilesWith(player2);
|
||||
expect(borderTiles.size).toBe(2);
|
||||
|
||||
const borderCells = Array.from(borderTiles).map(tile => tile.cell());
|
||||
expect(borderCells).toEqual(expect.arrayContaining([new Cell(0, 0), new Cell(0, 1)]));
|
||||
});
|
||||
|
||||
test('should update border tiles when a tile changes ownership', () => {
|
||||
game.conquer(player1, new Cell(0, 0));
|
||||
game.conquer(player1, new Cell(1, 0));
|
||||
game.conquer(player2, new Cell(2, 0));
|
||||
|
||||
expect(player1.borderTilesWith(player2).size).toBe(1);
|
||||
|
||||
game.conquer(player2, new Cell(1, 0));
|
||||
|
||||
const borderTilesP1 = player1.borderTilesWith(player2);
|
||||
const borderTilesP2 = player2.borderTilesWith(player1);
|
||||
|
||||
expect(borderTilesP1.size).toBe(1);
|
||||
expect(borderTilesP2.size).toBe(1);
|
||||
|
||||
expect(Array.from(borderTilesP1)[0].cell()).toEqual(new Cell(0, 0));
|
||||
expect(Array.from(borderTilesP2).map(t => t.cell())).toEqual(
|
||||
expect.arrayContaining([new Cell(1, 0)])
|
||||
);
|
||||
});
|
||||
|
||||
test('should handle border tiles with TerraNullius', () => {
|
||||
game.conquer(player1, new Cell(0, 0));
|
||||
|
||||
const borderWithTerraNullius = player1.borderTilesWith(game.terraNullius());
|
||||
expect(borderWithTerraNullius.size).toBe(1);
|
||||
|
||||
const borderCells = Array.from(borderWithTerraNullius).map(tile => tile.cell());
|
||||
expect(borderCells).toEqual(expect.arrayContaining([new Cell(0, 0)]));
|
||||
});
|
||||
|
||||
test('should not include diagonal tiles as borders', () => {
|
||||
game.conquer(player1, new Cell(0, 0));
|
||||
game.conquer(player2, new Cell(1, 1));
|
||||
|
||||
expect(player1.borderTilesWith(player2).size).toBe(0);
|
||||
expect(player2.borderTilesWith(player1).size).toBe(0);
|
||||
});
|
||||
|
||||
// test('should handle complex border scenarios', () => {
|
||||
// // Create a more complex border scenario
|
||||
// // 0 1 2 3 4
|
||||
// // 0 1 1 2 2 2
|
||||
// // 1 1 1 2 2 2
|
||||
// // 2 1 1 1 2 2
|
||||
// // 3 1 1 1 1 2
|
||||
// // 4 1 1 1 1 1
|
||||
|
||||
// for (let y = 0; y < 5; y++) {
|
||||
// for (let x = 0; x < 5; x++) {
|
||||
// if (x + y < 6) {
|
||||
// game.conquer(player1, new Cell(x, y));
|
||||
// } else {
|
||||
// game.conquer(player2, new Cell(x, y));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// const borderTilesP1 = player1.borderTilesWith(player2);
|
||||
// const borderTilesP2 = player2.borderTilesWith(player1);
|
||||
|
||||
// expect(borderTilesP1.size).toBe(5);
|
||||
// expect(borderTilesP2.size).toBe(5);
|
||||
|
||||
// const expectedBorderP1 = [
|
||||
// new Cell(2, 0),
|
||||
// new Cell(2, 1),
|
||||
// new Cell(3, 2),
|
||||
// new Cell(3, 3),
|
||||
// new Cell(4, 3)
|
||||
// ];
|
||||
|
||||
// const expectedBorderP2 = [
|
||||
// new Cell(2, 2),
|
||||
// new Cell(3, 1),
|
||||
// new Cell(3, 2),
|
||||
// new Cell(4, 1),
|
||||
// new Cell(4, 2)
|
||||
// ];
|
||||
|
||||
// const actualBorderP1 = Array.from(borderTilesP1).map(t => t.cell());
|
||||
// const actualBorderP2 = Array.from(borderTilesP2).map(t => t.cell());
|
||||
|
||||
// expect(actualBorderP1).toEqual(expect.arrayContaining(expectedBorderP1));
|
||||
// expect(actualBorderP2).toEqual(expect.arrayContaining(expectedBorderP2));
|
||||
// });
|
||||
|
||||
test('should handle border updates when a player loses all tiles', () => {
|
||||
game.conquer(player1, new Cell(0, 0));
|
||||
game.conquer(player2, new Cell(1, 0));
|
||||
|
||||
expect(player1.borderTilesWith(player2).size).toBe(1);
|
||||
|
||||
game.conquer(player1, new Cell(1, 0)); // Player 1 takes Player 2's only tile
|
||||
|
||||
expect(player1.borderTilesWith(player2).size).toBe(0);
|
||||
expect(player2.borderTilesWith(player1).size).toBe(0);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,194 @@
|
||||
// import {Game, Player, Tile, Cell, TerraNullius, PlayerInfo} from '../src/core/GameApi';
|
||||
// import {placeName, calculateBoundingBox, createGrid, findLargestInscribedRectangle, largestRectangleInHistogram, calculateFontSize} from '../src/client/NameBoxCalculator';
|
||||
|
||||
|
||||
// class MockPlayer implements Player {
|
||||
// constructor(private playerTiles: [number, number][]) { }
|
||||
|
||||
// info(): PlayerInfo {
|
||||
// return new PlayerInfo("TestPlayer", false);
|
||||
// }
|
||||
|
||||
// id(): PlayerID {
|
||||
// return 1;
|
||||
// }
|
||||
|
||||
// troops(): number {
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// ownsTile(cell: Cell): boolean {
|
||||
// return this.playerTiles.some(([x, y]) => x === cell.x && y === cell.y);
|
||||
// }
|
||||
|
||||
// isAlive(): boolean {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// gameState(): Game {
|
||||
// return {} as Game; // This should be properly implemented
|
||||
// }
|
||||
|
||||
// executions(): ExecutionView[] {
|
||||
// return [];
|
||||
// }
|
||||
|
||||
// borderTilesWith(other: Player | TerraNullius): ReadonlySet<Tile> {
|
||||
// return new Set();
|
||||
// }
|
||||
|
||||
// isPlayer(): this is Player {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// neighbors(): (Player | TerraNullius)[] {
|
||||
// return [];
|
||||
// }
|
||||
// }
|
||||
|
||||
// class MockGame implements Game {
|
||||
// private tiles: Tile[][] = [];
|
||||
// private mockPlayer: Player;
|
||||
|
||||
// constructor(width: number, height: number, playerTiles: [number, number][]) {
|
||||
// this.tiles = Array(height).fill(null).map(() => Array(width).fill(null));
|
||||
// this.mockPlayer = new MockPlayer(playerTiles);
|
||||
|
||||
// for (let y = 0; y < height; y++) {
|
||||
// for (let x = 0; x < width; x++) {
|
||||
// this.tiles[y][x] = {
|
||||
// owner: () => playerTiles.some(([px, py]) => px === x && py === y) ? this.mockPlayer : this.terraNullius(),
|
||||
// hasOwner: () => playerTiles.some(([px, py]) => px === x && py === y),
|
||||
// isBorder: () => false,
|
||||
// isInterior: () => false,
|
||||
// cell: () => new Cell(x, y),
|
||||
// terrain: () => ({expansionCost: 1, expansionTime: 1}),
|
||||
// game: () => this,
|
||||
// neighbors: () => []
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// player(id: PlayerID): Player {return this.mockPlayer;}
|
||||
// tile(cell: Cell): Tile {return this.tiles[cell.y][cell.x];}
|
||||
// isOnMap(cell: Cell): boolean {return cell.x >= 0 && cell.x < this.width() && cell.y >= 0 && cell.y < this.height();}
|
||||
// neighbors(cell: Cell): Cell[] {return [];}
|
||||
// width(): number {return this.tiles[0].length;}
|
||||
// height(): number {return this.tiles.length;}
|
||||
// forEachTile(fn: (tile: Tile) => void): void {this.tiles.flat().forEach(fn);}
|
||||
// executions(): ExecutionView[] {return [];}
|
||||
// terraNullius(): TerraNullius {return {ownsTile: () => false, isPlayer: () => false};}
|
||||
// tick() { }
|
||||
// addExecution(...exec: Execution[]) { }
|
||||
// }
|
||||
|
||||
// // Mock implementations
|
||||
// class MockGame implements Game {
|
||||
// private tiles: Tile[][] = [];
|
||||
// private mockPlayer: Player;
|
||||
|
||||
// constructor(width: number, height: number, playerTiles: [number, number][]) {
|
||||
// this.tiles = Array(height).fill(null).map(() => Array(width).fill(null));
|
||||
// this.mockPlayer = {
|
||||
// info: () => new PlayerInfo("TestPlayer", false),
|
||||
// id: () => 1,
|
||||
// troops: () => 0,
|
||||
// ownsTile: (cell: Cell) => playerTiles.some(([x, y]) => x === cell.x && y === cell.y),
|
||||
// isAlive: () => true,
|
||||
// gameState: () => this,
|
||||
// executions: () => [],
|
||||
// borderTilesWith: () => new Set(),
|
||||
// isPlayer: function (this: Player): this is Player {return true},
|
||||
// neighbors: () => []
|
||||
// };
|
||||
|
||||
// for (let y = 0; y < height; y++) {
|
||||
// for (let x = 0; x < width; x++) {
|
||||
// this.tiles[y][x] = {
|
||||
// owner: () => playerTiles.some(([px, py]) => px === x && py === y) ? this.mockPlayer : this.terraNullius(),
|
||||
// hasOwner: () => playerTiles.some(([px, py]) => px === x && py === y),
|
||||
// isBorder: () => false,
|
||||
// isInterior: () => false,
|
||||
// cell: () => new Cell(x, y),
|
||||
// terrain: () => ({expansionCost: 1, expansionTime: 1}),
|
||||
// game: () => this,
|
||||
// neighbors: () => []
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// player(id: number): Player {return this.mockPlayer;}
|
||||
// tile(cell: Cell): Tile {return this.tiles[cell.y][cell.x];}
|
||||
// isOnMap(cell: Cell): boolean {return cell.x >= 0 && cell.x < this.width() && cell.y >= 0 && cell.y < this.height();}
|
||||
// neighbors(cell: Cell): Cell[] {return [];}
|
||||
// width(): number {return this.tiles[0].length;}
|
||||
// height(): number {return this.tiles.length;}
|
||||
// forEachTile(fn: (tile: Tile) => void): void {this.tiles.flat().forEach(fn);}
|
||||
// executions(): any[] {return [];}
|
||||
// terraNullius(): TerraNullius {return {ownsTile: () => false, isPlayer: () => false};}
|
||||
// tick() { }
|
||||
// addExecution(...exec: any[]) { }
|
||||
// }
|
||||
|
||||
// describe('Territory Name Placement', () => {
|
||||
// test('placeName should return a position and font size', () => {
|
||||
// const game = new MockGame(5, 5, [[1, 1], [2, 1], [3, 1], [2, 2], [2, 3]]);
|
||||
// const player = game.player(1);
|
||||
// const result = placeName(game, player);
|
||||
|
||||
// expect(result).toHaveProperty('position');
|
||||
// expect(result).toHaveProperty('fontSize');
|
||||
// expect(result.position).toHaveProperty('x');
|
||||
// expect(result.position).toHaveProperty('y');
|
||||
// expect(typeof result.fontSize).toBe('number');
|
||||
// });
|
||||
|
||||
// test('calculateBoundingBox should return correct bounding box', () => {
|
||||
// const game = new MockGame(5, 5, [[1, 1], [3, 3]]);
|
||||
// const player = game.player(1);
|
||||
// const boundingBox = calculateBoundingBox(game, player);
|
||||
|
||||
// expect(boundingBox).toEqual({min: {x: 1, y: 1}, max: {x: 3, y: 3}});
|
||||
// });
|
||||
|
||||
// test('createGrid should create correct boolean grid', () => {
|
||||
// const game = new MockGame(3, 3, [[0, 0], [1, 1], [2, 2]]);
|
||||
// const player = game.player(1);
|
||||
// const boundingBox = {min: {x: 0, y: 0}, max: {x: 2, y: 2}};
|
||||
// const grid = createGrid(game, player, boundingBox);
|
||||
|
||||
// expect(grid).toEqual([
|
||||
// [true, false, false],
|
||||
// [false, true, false],
|
||||
// [false, false, true]
|
||||
// ]);
|
||||
// });
|
||||
|
||||
// test('findLargestInscribedRectangle should find correct rectangle', () => {
|
||||
// const grid = [
|
||||
// [true, true, true],
|
||||
// [true, true, false],
|
||||
// [true, true, false]
|
||||
// ];
|
||||
// const result = findLargestInscribedRectangle(grid);
|
||||
|
||||
// expect(result).toEqual({x: 0, y: 0, width: 2, height: 3});
|
||||
// });
|
||||
|
||||
// test('largestRectangleInHistogram should find correct rectangle', () => {
|
||||
// const heights = [2, 1, 5, 6, 2, 3];
|
||||
// const result = largestRectangleInHistogram(heights);
|
||||
|
||||
// expect(result).toEqual({x: 2, y: 0, width: 2, height: 5});
|
||||
// });
|
||||
|
||||
// test('calculateFontSize should return correct font size', () => {
|
||||
// const rectangle = {x: 0, y: 0, width: 100, height: 50};
|
||||
// const name = "TestPlayer";
|
||||
// const fontSize = calculateFontSize(rectangle, name);
|
||||
|
||||
// expect(fontSize).toBe(25); // 50 / 2 = 25 (height constrained)
|
||||
// });
|
||||
// });
|
||||
Reference in New Issue
Block a user