Re-structure pieces builder and add include first pieces batch

landing-page-layout
MiguelMLorente 2024-12-01 12:30:59 +01:00
parent 6bb0e1aa74
commit 6fab2d94a0
8 changed files with 273 additions and 46 deletions

View File

@ -13,5 +13,7 @@ module.exports = {
jest: true, jest: true,
}, },
ignorePatterns: [".eslintrc.js", "dist/"], ignorePatterns: [".eslintrc.js", "dist/"],
rules: {}, rules: {
"@typescript-eslint/no-non-null-assertion": "off",
},
}; };

View File

@ -0,0 +1,4 @@
export enum InternalNodeType {
NONE = "NONE",
STATION = "STATION",
}

View File

@ -0,0 +1,200 @@
import { Piece } from "../types/Piece";
import { Direction } from "./Direction";
import { InternalNodeType } from "./InternalNodeType";
import { TrackType } from "./TrackType";
const STRAIGHT_RAIL: Piece = new Piece({
useInternalTracks: false,
trackDefinitions: [
{
startPoint: Direction.NORTH,
endPoint: Direction.SOUTH,
type: TrackType.RAIL,
},
],
});
const TURN_RAIL: Piece = new Piece({
useInternalTracks: false,
trackDefinitions: [
{
startPoint: Direction.SOUTH,
endPoint: Direction.EAST,
type: TrackType.RAIL,
},
],
});
const FOUR_WAY_CROSS_RAIL: Piece = new Piece({
useInternalTracks: true,
internalNodeType: InternalNodeType.NONE,
trackDefinitions: [
{
startPoint: Direction.NORTH,
type: TrackType.RAIL,
},
{
startPoint: Direction.EAST,
type: TrackType.RAIL,
},
{
startPoint: Direction.SOUTH,
type: TrackType.RAIL,
},
{
startPoint: Direction.WEST,
type: TrackType.RAIL,
},
],
});
const T_JUNCTION_RAIL: Piece = new Piece({
useInternalTracks: true,
internalNodeType: InternalNodeType.NONE,
trackDefinitions: [
{
startPoint: Direction.WEST,
type: TrackType.RAIL,
},
{
startPoint: Direction.SOUTH,
type: TrackType.RAIL,
},
{
startPoint: Direction.EAST,
type: TrackType.RAIL,
},
],
});
const DEAD_END_STATION_RAIL: Piece = new Piece({
useInternalTracks: true,
internalNodeType: InternalNodeType.STATION,
trackDefinitions: [
{
startPoint: Direction.SOUTH,
type: TrackType.RAIL,
},
],
});
const TURN_RAIL_TO_ROAD: Piece = new Piece({
useInternalTracks: true,
internalNodeType: InternalNodeType.STATION,
trackDefinitions: [
{
startPoint: Direction.SOUTH,
type: TrackType.RAIL,
},
{
startPoint: Direction.EAST,
type: TrackType.ROAD,
},
],
});
const T_JUNCTION_WITH_ROAD_ON_SIDE: Piece = new Piece({
useInternalTracks: true,
internalNodeType: InternalNodeType.STATION,
trackDefinitions: [
{
startPoint: Direction.SOUTH,
type: TrackType.RAIL,
},
{
startPoint: Direction.WEST,
type: TrackType.RAIL,
},
{
startPoint: Direction.EAST,
type: TrackType.ROAD,
},
],
});
const FOUR_WAY_WITH_ONE_ROAD: Piece = new Piece({
useInternalTracks: true,
internalNodeType: InternalNodeType.STATION,
trackDefinitions: [
{
startPoint: Direction.NORTH,
type: TrackType.RAIL,
},
{
startPoint: Direction.EAST,
type: TrackType.ROAD,
},
{
startPoint: Direction.SOUTH,
type: TrackType.RAIL,
},
{
startPoint: Direction.WEST,
type: TrackType.RAIL,
},
],
});
const T_JUNCTION_WITH_ROAD_AT_CENTER: Piece = new Piece({
useInternalTracks: true,
internalNodeType: InternalNodeType.STATION,
trackDefinitions: [
{
startPoint: Direction.NORTH,
type: TrackType.RAIL,
},
{
startPoint: Direction.EAST,
type: TrackType.ROAD,
},
{
startPoint: Direction.SOUTH,
type: TrackType.RAIL,
},
],
});
const STRAIGHT_TRACK_CHANGE: Piece = new Piece({
useInternalTracks: true,
internalNodeType: InternalNodeType.STATION,
trackDefinitions: [
{
startPoint: Direction.EAST,
type: TrackType.ROAD,
},
{
startPoint: Direction.WEST,
type: TrackType.RAIL,
},
],
});
export enum PieceId {
P01 = "P01",
P02 = "P02",
P03 = "P03",
P04 = "P04",
P05 = "P05",
P06 = "P06",
P07 = "P07",
P08 = "P08",
P09 = "P09",
P10 = "P10",
P11 = "P11",
P12 = "P12",
P13 = "P13",
P14 = "P14",
P15 = "P15",
P16 = "P16",
P17 = "P17",
P18 = "P18",
P19 = "P19",
P20 = "P20",
P21 = "P21",
P22 = "P22",
}
export const pieceMap: Record<PieceId, Piece> = {
[PieceId.P01]: STRAIGHT_RAIL,
[PieceId.P02]: TURN_RAIL,
[PieceId.P03]: FOUR_WAY_CROSS_RAIL,
[PieceId.P04]: T_JUNCTION_RAIL,
[PieceId.P05]: DEAD_END_STATION_RAIL,
[PieceId.P06]: TURN_RAIL_TO_ROAD,
[PieceId.P07]: T_JUNCTION_WITH_ROAD_ON_SIDE,
[PieceId.P08]: FOUR_WAY_WITH_ONE_ROAD,
[PieceId.P09]: T_JUNCTION_WITH_ROAD_AT_CENTER,
[PieceId.P10]: STRAIGHT_TRACK_CHANGE,
};

View File

@ -19,6 +19,6 @@ export class Cell {
public getNodeAt(direction: Direction): ExternalNode { public getNodeAt(direction: Direction): ExternalNode {
const node = this.externalNodes.get(direction); const node = this.externalNodes.get(direction);
if (!node) throw Error(`Could not find node at ${direction}`); if (!node) throw Error(`Could not find node at ${direction}`);
return this.externalNodes.get(direction) as ExternalNode; return node!;
} }
} }

View File

@ -24,6 +24,6 @@ export class ExternalNode {
if (!this.border) { if (!this.border) {
throw Error(`Missing border for node`); throw Error(`Missing border for node`);
} }
return (this.border as Border).traverseFrom(this); return this.border.traverseFrom(this);
} }
} }

View File

@ -1,11 +1,12 @@
import { randomUUID } from "crypto"; import { randomUUID } from "crypto";
import { InternalNodeType } from "../constants/InternalNodeType";
export class InternalNode { export class InternalNode {
id: string; id: string;
type: string; type: InternalNodeType;
constructor() { constructor(type: InternalNodeType) {
this.id = randomUUID(); this.id = randomUUID();
this.type = "STATION"; this.type = type;
} }
} }

View File

@ -4,46 +4,66 @@ import { Cell } from "./Cell";
import { InternalNode } from "./InternalNode"; import { InternalNode } from "./InternalNode";
import { PlacedPiece } from "./PlacedPiece"; import { PlacedPiece } from "./PlacedPiece";
import { Node } from "./Node"; import { Node } from "./Node";
import { InternalNodeType } from "../constants/InternalNodeType";
export interface TrackProps { export interface PieceProps {
startPoint: Direction; readonly useInternalTracks: boolean;
endPoint?: Direction; readonly internalNodeType?: InternalNodeType;
isInternal: boolean; readonly trackDefinitions: {
type: TrackType; readonly startPoint: Direction;
readonly endPoint?: Direction;
readonly type: TrackType;
}[];
} }
export class Piece { type Track = {
tracks: Set<{ readonly joinedPoints: {
joinedPoints: { readonly firstPoint: Direction;
firstPoint: Direction; readonly secondPoint: Direction | InternalNode;
secondPoint: Direction | InternalNode;
}; };
type: TrackType; readonly type: TrackType;
}>; };
internalNodes: Set<InternalNode>;
constructor(hasInternalNode: boolean, trackDefinitions: TrackProps[]) { export class Piece {
const internalNode = new InternalNode(); readonly tracks: Set<Track>;
this.internalNodes = new Set(); readonly internalNode?: InternalNode;
if (hasInternalNode) {
this.internalNodes.add(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( this.tracks = new Set(
trackDefinitions.map((track) => { pieceProps.trackDefinitions.map((trackDefinition) => {
if (!track.isInternal && !track.endPoint) {
throw Error("Missing direction for non-internal track");
}
return { return {
joinedPoints: { joinedPoints: {
firstPoint: track.startPoint, firstPoint: trackDefinition.startPoint,
secondPoint: track.isInternal secondPoint: this.internalNode!,
? internalNode
: (track.endPoint as Direction),
}, },
type: track.type, 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,
};
}),
);
}
} }
toPlacedPiece(cell: Cell) { toPlacedPiece(cell: Cell) {
@ -55,14 +75,14 @@ export class Piece {
firstNode: cell.getNodeAt(track.joinedPoints.firstPoint), firstNode: cell.getNodeAt(track.joinedPoints.firstPoint),
secondNode: secondNode:
track.joinedPoints.secondPoint instanceof Node track.joinedPoints.secondPoint instanceof Node
? track.joinedPoints.secondPoint as Node ? (track.joinedPoints.secondPoint as Node)
: cell.getNodeAt(track.joinedPoints.secondPoint as Direction), : cell.getNodeAt(track.joinedPoints.secondPoint as Direction),
}, },
type: track.type, type: track.type,
}; };
}), }),
), ),
this.internalNodes, this.internalNode,
cell, cell,
); );
} }

View File

@ -11,7 +11,7 @@ export class PlacedPiece {
}; };
type: TrackType; type: TrackType;
}>; }>;
internalNodes: Set<InternalNode>; internalNode?: InternalNode;
cell: Cell; cell: Cell;
constructor( constructor(
@ -19,11 +19,11 @@ export class PlacedPiece {
nodes: { firstNode: Node; secondNode: Node }; nodes: { firstNode: Node; secondNode: Node };
type: TrackType; type: TrackType;
}>, }>,
internalNodes: Set<InternalNode>, internalNodes: InternalNode | undefined,
cell: Cell, cell: Cell,
) { ) {
this.tracks = tracks; this.tracks = tracks;
this.internalNodes = internalNodes; this.internalNode = internalNodes;
this.cell = cell; this.cell = cell;
} }
} }