Create board object builder and supporting classes and types

pull/6/head
MiguelMLorente 2024-11-23 22:49:51 +01:00
parent 4497a0a2f2
commit e9305893cb
10 changed files with 224 additions and 0 deletions

110
interface/BoardBuilder.ts Normal file
View File

@ -0,0 +1,110 @@
import { CellType } from "./constants/CellType";
import { Direction } from "./constants/Direction";
import { ExitType } from "./constants/ExitType";
import { Cell } from "./types/Cell";
import { Exit } from "./types/Exit";
const boardSize = 7;
const universityLocations = [
[2, 0],
[4, 1],
[3, 3],
];
const factoryLocations = [
[0, 0],
[5, 2],
[4, 6],
];
const houseLocations = [
[0, 2],
[1, 5],
[2, 4],
[5, 4],
];
const mapPosition = (position: number[], type: CellType) => {
return {
row: position[0],
col: position[1],
type: type,
};
};
const specialUniversityCells = universityLocations.map((position) =>
mapPosition(position, CellType.UNIVERSITY),
);
const specialFactoryCells = factoryLocations.map((position) =>
mapPosition(position, CellType.FACTORY),
);
const specialHouseCells = houseLocations.map((position) =>
mapPosition(position, CellType.HOUSE),
);
const specialCells = specialUniversityCells
.concat(specialFactoryCells)
.concat(specialHouseCells);
const specialExitIndexes1 = [1, 5];
const specialExitIndexes2 = [3];
function createBoard(): Cell[][] {
const indexes = Array.from(Array(boardSize).keys());
return indexes.map((rowIndex) =>
indexes.map((colIndex) => {
const specialCell = specialCells.find(
(specialCell) =>
specialCell.row === rowIndex && specialCell.col === colIndex,
);
return new Cell(specialCell ? specialCell.type : CellType.NORMAL);
}),
);
}
function connectAdjacentCells(board: Cell[][]) {
const indexes = Array.from(Array(boardSize).keys());
for (const rowIndex of indexes.slice(0, -1)) {
for (const colIndex of indexes.slice(0, -1)) {
const cell = board[rowIndex][colIndex];
const rightCell = board[rowIndex][colIndex + 1];
const bottomCell = board[rowIndex + 1][colIndex];
cell
.getNodeAt(Direction.SOUTH)
.linkToNode(bottomCell.getNodeAt(Direction.NORTH));
cell
.getNodeAt(Direction.EAST)
.linkToNode(rightCell.getNodeAt(Direction.WEST));
}
}
}
function addExits(board: Cell[][]) {
// Add exits to top row
board[0].forEach((cell, colIndex) => {
let exitType = ExitType.AMBIVALENT;
if (specialExitIndexes1.includes(colIndex)) exitType = ExitType.ROAD;
if (specialExitIndexes2.includes(colIndex)) exitType = ExitType.RAIL;
cell.getNodeAt(Direction.NORTH).linkToNode(new Exit(exitType));
});
// Add exits to bottom row
board[boardSize - 1].forEach((cell, colIndex) => {
let exitType = ExitType.AMBIVALENT;
if (specialExitIndexes1.includes(colIndex)) exitType = ExitType.ROAD;
if (specialExitIndexes2.includes(colIndex)) exitType = ExitType.RAIL;
cell.getNodeAt(Direction.SOUTH).linkToNode(new Exit(exitType));
});
// Add exits to left and right columns
board.forEach((row, rowIndex) => {
let exitType = ExitType.AMBIVALENT;
if (specialExitIndexes1.includes(rowIndex)) exitType = ExitType.RAIL;
if (specialExitIndexes2.includes(rowIndex)) exitType = ExitType.ROAD;
row[0].getNodeAt(Direction.WEST).linkToNode(new Exit(exitType));
row[boardSize - 1].getNodeAt(Direction.EAST).linkToNode(new Exit(exitType));
});
}
export function buildBoard(): Cell[][] {
const board: Cell[][] = createBoard();
connectAdjacentCells(board);
addExits(board);
return board;
}

View File

@ -0,0 +1,6 @@
export enum CellType {
NORMAL = "NORMAL",
HOUSE = "HOUSE",
FACTORY = "FACTORY",
UNIVERSITY = "UNIVERSITY",
}

View File

@ -0,0 +1,6 @@
export enum Direction {
NORTH = "NORTH",
SOUTH = "SOUTH",
EAST = "EAST",
WEST = "WEST",
}

View File

@ -0,0 +1,5 @@
export enum ExitType {
RAIL = "RAIL",
ROAD = "ROAD",
AMBIVALENT = "AMBIVALENT",
}

View File

@ -1 +1,10 @@
export * from "./constants/CellType";
export * from "./constants/Direction";
export * from "./constants/ExitType";
export * from "./constants/TrackType"; export * from "./constants/TrackType";
export * from "./types/Border";
export * from "./types/Cell";
export * from "./types/Exit";
export * from "./types/ExternalNode";
export * from "./types/Node";
export * from "./BoardBuilder";

22
interface/types/Border.ts Normal file
View File

@ -0,0 +1,22 @@
import { Exit } from "./Exit";
import { ExternalNode } from "./ExternalNode";
export class Border {
private readonly firstNode: ExternalNode;
private readonly secondNode: ExternalNode | Exit;
constructor(firstNode: ExternalNode, secondNode: ExternalNode | Exit) {
this.firstNode = firstNode;
this.secondNode = secondNode;
}
public traverseFrom(node: ExternalNode): ExternalNode | Exit {
if (node === this.firstNode) {
return this.secondNode;
}
if (node === this.secondNode) {
return this.firstNode;
}
throw Error("Unable to traverse border");
}
}

24
interface/types/Cell.ts Normal file
View File

@ -0,0 +1,24 @@
import { CellType } from "../constants/CellType";
import { Direction } from "../constants/Direction";
import { ExternalNode } from "./ExternalNode";
export class Cell {
public readonly externalNodes: Map<Direction, ExternalNode>;
public readonly cellType: CellType;
constructor(cellType: CellType) {
this.externalNodes = new Map([
[Direction.NORTH, new ExternalNode(this, Direction.NORTH)],
[Direction.SOUTH, new ExternalNode(this, Direction.SOUTH)],
[Direction.EAST, new ExternalNode(this, Direction.EAST)],
[Direction.WEST, new ExternalNode(this, Direction.WEST)],
]);
this.cellType = cellType;
}
public getNodeAt(direction: Direction): ExternalNode {
const node = this.externalNodes.get(direction);
if (!node) throw Error(`Could not find node at ${direction}`);
return this.externalNodes.get(direction) as ExternalNode;
}
}

9
interface/types/Exit.ts Normal file
View File

@ -0,0 +1,9 @@
import { ExitType } from "../constants/ExitType";
export class Exit {
public readonly type: ExitType;
constructor(type: ExitType) {
this.type = type;
}
}

View File

@ -0,0 +1,24 @@
import { Direction } from "../constants/Direction";
import { Border } from "./Border";
import { Cell } from "./Cell";
import { Exit } from "./Exit";
import { Node } from "./Node";
export class ExternalNode extends Node {
public readonly direction: Direction;
private border?: Border;
constructor(cell: Cell, direction: Direction) {
super(cell);
this.direction = direction;
}
public linkToNode(other: ExternalNode | Exit) {
this.border = new Border(this, other);
}
public traverseBorder(): ExternalNode | Exit {
if (!this.border) throw Error(`Missing border for node`);
return (this.border as Border).traverseFrom(this);
}
}

9
interface/types/Node.ts Normal file
View File

@ -0,0 +1,9 @@
import { Cell } from "./Cell";
export abstract class Node {
public readonly cell: Cell;
constructor(cell: Cell) {
this.cell = cell;
}
}