import { CellType } from "../constants/CellType"; import { Direction } from "../constants/Direction"; import { ExitType } from "../constants/ExitType"; import { PieceId, pieceMap } from "../constants/Pieces"; import { Exit } from "./Exit"; import { ExternalNode } from "./ExternalNode"; import { InternalNode } from "./InternalNode"; import { PlacedPiece } from "./PlacedPiece"; export class Cell { public readonly externalNodes: Map; public readonly cellType: CellType; public placedPiece?: { piece: PlacedPiece; id: PieceId; }; 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 node!; } public placePiece(pieceId: PieceId) { if (this.placedPiece !== undefined) return; const piece = pieceMap[pieceId]; const connectionTypes = Array.from(piece.tracks).flatMap((track) => { const directions = track.joinedPoints.secondPoint instanceof InternalNode ? [track.joinedPoints.firstPoint] : [track.joinedPoints.firstPoint, track.joinedPoints.secondPoint]; return directions.map((direction) => { return { direction: direction, type: track.type }; }); }); connectionTypes.forEach(({ direction, type }) => { const adjacentPoint = this.getNodeAt(direction).traverseBorder(); if (adjacentPoint instanceof Exit) { if ( adjacentPoint.type !== ExitType.AMBIVALENT && adjacentPoint.type.toString() !== type.toString() ) { throw Error( `Unable to place piece, invalid border at direction ${direction}`, ); } } else { if (adjacentPoint.cell.placedPiece !== undefined) { const adjacentTrack = adjacentPoint.cell.placedPiece.piece.findTrackForDirection( adjacentPoint.direction, ); if (adjacentTrack !== undefined && adjacentTrack.type !== type) { throw Error( `Unable to place piece next to another due to conflicting track types at ${direction}`, ); } } } }); this.placedPiece = { piece: piece.toPlacedPiece(this), id: pieceId, }; } }