import { Direction, rotateDirection } from "../constants/Direction"; import { TrackType } from "../constants/TrackType"; import { Cell } from "./Cell"; import { InternalNode } from "./InternalNode"; import { PlacedPiece } from "./PlacedPiece"; import { InternalNodeType } from "../constants/InternalNodeType"; export interface PieceProps { readonly useInternalTracks: boolean; readonly internalNodeType?: InternalNodeType; readonly trackDefinitions: { readonly startPoint: Direction; readonly endPoint?: Direction; readonly type: TrackType; }[]; } type Track = { readonly joinedPoints: { readonly firstPoint: Direction; readonly secondPoint: Direction | InternalNode; }; readonly type: TrackType; }; export class Piece { readonly tracks: Set; readonly internalNode?: InternalNode; constructor(pieceProps: PieceProps) { if (pieceProps.useInternalTracks) { if (!pieceProps.internalNodeType) { throw Error( "Expected to find internal node type when useInternalTracks is set", ); } this.internalNode = new InternalNode(pieceProps.internalNodeType); this.tracks = new Set( pieceProps.trackDefinitions.map((trackDefinition) => { return { joinedPoints: { firstPoint: trackDefinition.startPoint, secondPoint: this.internalNode!, }, type: trackDefinition.type, }; }), ); } else { this.internalNode = undefined; this.tracks = new Set( pieceProps.trackDefinitions.map((trackDefinition) => { if (!trackDefinition.endPoint) { throw Error("Missing end point for non-internal track"); } return { joinedPoints: { firstPoint: trackDefinition.startPoint, secondPoint: trackDefinition.endPoint, }, type: trackDefinition.type, }; }), ); } } rotate(rotation: 0 | 90 | 180 | 270): Piece { return new Piece({ useInternalTracks: this.internalNode !== undefined, internalNodeType: this.internalNode?.type, trackDefinitions: Array.from(this.tracks).map((track) => { if (track.joinedPoints.secondPoint instanceof InternalNode) { return { type: track.type, startPoint: rotateDirection( track.joinedPoints.firstPoint, rotation, ), }; } else { return { type: track.type, startPoint: rotateDirection( track.joinedPoints.firstPoint, rotation, ), endPoint: rotateDirection(track.joinedPoints.secondPoint, rotation), }; } }), }); } toPlacedPiece(cell: Cell) { return new PlacedPiece( new Set( Array.from(this.tracks).map((track) => { return { nodes: { firstNode: cell.getNodeAt(track.joinedPoints.firstPoint), secondNode: track.joinedPoints.secondPoint instanceof InternalNode ? (track.joinedPoints.secondPoint as InternalNode) : cell.getNodeAt(track.joinedPoints.secondPoint as Direction), }, type: track.type, }; }), ), this.internalNode, cell, ); } }