Compare commits
7 Commits
d72984851e
...
e7beb85302
| Author | SHA1 | Date |
|---|---|---|
|
|
e7beb85302 | |
|
|
835ce2c62a | |
|
|
39d1ec9a77 | |
|
|
406e4d2f75 | |
|
|
7354586ef5 | |
|
|
163ca86734 | |
|
|
af133bae8b |
|
|
@ -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",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
export enum InternalNodeType {
|
||||||
|
NONE = "NONE",
|
||||||
|
STATION = "STATION",
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,412 @@
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const DEAD_END_STATION_ROAD: Piece = new Piece({
|
||||||
|
useInternalTracks: true,
|
||||||
|
internalNodeType: InternalNodeType.STATION,
|
||||||
|
trackDefinitions: [
|
||||||
|
{
|
||||||
|
startPoint: Direction.EAST,
|
||||||
|
type: TrackType.RAIL,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const T_JUNCTION_WITH_RAIL_AT_CENTER: Piece = new Piece({
|
||||||
|
useInternalTracks: true,
|
||||||
|
internalNodeType: InternalNodeType.STATION,
|
||||||
|
trackDefinitions: [
|
||||||
|
{
|
||||||
|
startPoint: Direction.EAST,
|
||||||
|
type: TrackType.ROAD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startPoint: Direction.SOUTH,
|
||||||
|
type: TrackType.RAIL,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startPoint: Direction.WEST,
|
||||||
|
type: TrackType.ROAD,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const FOUR_WAY_PERPENDICULAR_CROSSING: Piece = new Piece({
|
||||||
|
useInternalTracks: true,
|
||||||
|
internalNodeType: InternalNodeType.STATION,
|
||||||
|
trackDefinitions: [
|
||||||
|
{
|
||||||
|
startPoint: Direction.NORTH,
|
||||||
|
type: TrackType.RAIL,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startPoint: Direction.SOUTH,
|
||||||
|
type: TrackType.RAIL,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startPoint: Direction.WEST,
|
||||||
|
type: TrackType.ROAD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startPoint: Direction.EAST,
|
||||||
|
type: TrackType.ROAD,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const FOUR_WAY_WITH_ONE_RAIL: Piece = new Piece({
|
||||||
|
useInternalTracks: true,
|
||||||
|
internalNodeType: InternalNodeType.STATION,
|
||||||
|
trackDefinitions: [
|
||||||
|
{
|
||||||
|
startPoint: Direction.NORTH,
|
||||||
|
type: TrackType.ROAD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startPoint: Direction.EAST,
|
||||||
|
type: TrackType.ROAD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startPoint: Direction.SOUTH,
|
||||||
|
type: TrackType.RAIL,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startPoint: Direction.WEST,
|
||||||
|
type: TrackType.ROAD,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const FOUR_WAY_TURNING_CROSSING: Piece = new Piece({
|
||||||
|
useInternalTracks: true,
|
||||||
|
internalNodeType: InternalNodeType.STATION,
|
||||||
|
trackDefinitions: [
|
||||||
|
{
|
||||||
|
startPoint: Direction.NORTH,
|
||||||
|
type: TrackType.ROAD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startPoint: Direction.EAST,
|
||||||
|
type: TrackType.ROAD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startPoint: Direction.SOUTH,
|
||||||
|
type: TrackType.RAIL,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startPoint: Direction.WEST,
|
||||||
|
type: TrackType.RAIL,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const LEVEL_CROSSING: Piece = new Piece({
|
||||||
|
useInternalTracks: false,
|
||||||
|
trackDefinitions: [
|
||||||
|
{
|
||||||
|
startPoint: Direction.NORTH,
|
||||||
|
endPoint: Direction.SOUTH,
|
||||||
|
type: TrackType.RAIL,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startPoint: Direction.EAST,
|
||||||
|
endPoint: Direction.WEST,
|
||||||
|
type: TrackType.ROAD,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const STRAIGHT_ROAD: Piece = new Piece({
|
||||||
|
useInternalTracks: false,
|
||||||
|
trackDefinitions: [
|
||||||
|
{
|
||||||
|
startPoint: Direction.EAST,
|
||||||
|
endPoint: Direction.WEST,
|
||||||
|
type: TrackType.ROAD,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const T_JUNCTION_ROAD: Piece = new Piece({
|
||||||
|
useInternalTracks: true,
|
||||||
|
internalNodeType: InternalNodeType.NONE,
|
||||||
|
trackDefinitions: [
|
||||||
|
{
|
||||||
|
startPoint: Direction.EAST,
|
||||||
|
type: TrackType.ROAD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startPoint: Direction.SOUTH,
|
||||||
|
type: TrackType.ROAD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startPoint: Direction.WEST,
|
||||||
|
type: TrackType.RAIL,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const FOUR_WAY_CROSS_ROAD: Piece = new Piece({
|
||||||
|
useInternalTracks: true,
|
||||||
|
internalNodeType: InternalNodeType.NONE,
|
||||||
|
trackDefinitions: [
|
||||||
|
{
|
||||||
|
startPoint: Direction.NORTH,
|
||||||
|
type: TrackType.ROAD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startPoint: Direction.EAST,
|
||||||
|
type: TrackType.ROAD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startPoint: Direction.SOUTH,
|
||||||
|
type: TrackType.ROAD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startPoint: Direction.WEST,
|
||||||
|
type: TrackType.RAIL,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const DOUBLE_TURN_ROAD: Piece = new Piece({
|
||||||
|
useInternalTracks: false,
|
||||||
|
trackDefinitions: [
|
||||||
|
{
|
||||||
|
startPoint: Direction.NORTH,
|
||||||
|
endPoint: Direction.WEST,
|
||||||
|
type: TrackType.ROAD,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startPoint: Direction.EAST,
|
||||||
|
endPoint: Direction.SOUTH,
|
||||||
|
type: TrackType.ROAD,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const TURN_ROAD: Piece = new Piece({
|
||||||
|
useInternalTracks: false,
|
||||||
|
trackDefinitions: [
|
||||||
|
{
|
||||||
|
startPoint: Direction.NORTH,
|
||||||
|
endPoint: Direction.WEST,
|
||||||
|
type: TrackType.ROAD,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const DOUBLE_TURN_RAIL: Piece = new Piece({
|
||||||
|
useInternalTracks: false,
|
||||||
|
trackDefinitions: [
|
||||||
|
{
|
||||||
|
startPoint: Direction.NORTH,
|
||||||
|
endPoint: Direction.WEST,
|
||||||
|
type: TrackType.RAIL,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
startPoint: Direction.EAST,
|
||||||
|
endPoint: Direction.SOUTH,
|
||||||
|
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,
|
||||||
|
[PieceId.P11]: DEAD_END_STATION_ROAD,
|
||||||
|
[PieceId.P12]: T_JUNCTION_WITH_RAIL_AT_CENTER,
|
||||||
|
[PieceId.P13]: FOUR_WAY_PERPENDICULAR_CROSSING,
|
||||||
|
[PieceId.P14]: FOUR_WAY_WITH_ONE_RAIL,
|
||||||
|
[PieceId.P15]: FOUR_WAY_TURNING_CROSSING,
|
||||||
|
[PieceId.P16]: LEVEL_CROSSING,
|
||||||
|
[PieceId.P17]: STRAIGHT_ROAD,
|
||||||
|
[PieceId.P18]: T_JUNCTION_ROAD,
|
||||||
|
[PieceId.P19]: FOUR_WAY_CROSS_ROAD,
|
||||||
|
[PieceId.P20]: DOUBLE_TURN_ROAD,
|
||||||
|
[PieceId.P21]: TURN_ROAD,
|
||||||
|
[PieceId.P22]: DOUBLE_TURN_RAIL,
|
||||||
|
};
|
||||||
|
|
@ -1,10 +1,15 @@
|
||||||
export * from "./constants/CellType";
|
export * from "./constants/CellType";
|
||||||
export * from "./constants/Direction";
|
export * from "./constants/Direction";
|
||||||
export * from "./constants/ExitType";
|
export * from "./constants/ExitType";
|
||||||
|
export * from "./constants/InternalNodeType";
|
||||||
|
export * from "./constants/Pieces";
|
||||||
export * from "./constants/TrackType";
|
export * from "./constants/TrackType";
|
||||||
export * from "./types/Border";
|
export * from "./types/Border";
|
||||||
export * from "./types/Cell";
|
export * from "./types/Cell";
|
||||||
export * from "./types/Exit";
|
export * from "./types/Exit";
|
||||||
export * from "./types/ExternalNode";
|
export * from "./types/ExternalNode";
|
||||||
|
export * from "./types/InternalNode";
|
||||||
|
export * from "./types/Piece";
|
||||||
|
export * from "./types/PlacedPiece";
|
||||||
export * from "./types/Node";
|
export * from "./types/Node";
|
||||||
export * from "./BoardBuilder";
|
export * from "./BoardBuilder";
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,9 @@
|
||||||
"name": "interface",
|
"name": "interface",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"uuid": "^11.0.3"
|
||||||
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^8.0.0",
|
"@eslint/js": "^8.0.0",
|
||||||
"@types/node": "^22.9.0",
|
"@types/node": "^22.9.0",
|
||||||
|
|
@ -1855,6 +1858,19 @@
|
||||||
"punycode": "^2.1.0"
|
"punycode": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/uuid": {
|
||||||
|
"version": "11.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.3.tgz",
|
||||||
|
"integrity": "sha512-d0z310fCWv5dJwnX1Y/MncBAqGMKEzlBb1AOf7z9K8ALnd0utBX/msg/fA0+sbyN1ihbMsLhrBlnl1ak7Wa0rg==",
|
||||||
|
"funding": [
|
||||||
|
"https://github.com/sponsors/broofa",
|
||||||
|
"https://github.com/sponsors/ctavan"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"uuid": "dist/esm/bin/uuid"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
|
|
||||||
|
|
@ -21,5 +21,8 @@
|
||||||
"globals": "^15.12.0",
|
"globals": "^15.12.0",
|
||||||
"typescript": "^5.6.3",
|
"typescript": "^5.6.3",
|
||||||
"typescript-eslint": "^8.15.0"
|
"typescript-eslint": "^8.15.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"uuid": "^11.0.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,14 @@ import { Direction } from "../constants/Direction";
|
||||||
import { Border } from "./Border";
|
import { Border } from "./Border";
|
||||||
import { Cell } from "./Cell";
|
import { Cell } from "./Cell";
|
||||||
import { Exit } from "./Exit";
|
import { Exit } from "./Exit";
|
||||||
import { Node } from "./Node";
|
|
||||||
|
|
||||||
export class ExternalNode extends Node {
|
export class ExternalNode {
|
||||||
public readonly direction: Direction;
|
public readonly direction: Direction;
|
||||||
private border?: Border;
|
private border?: Border;
|
||||||
|
public readonly cell: Cell;
|
||||||
|
|
||||||
constructor(cell: Cell, direction: Direction) {
|
constructor(cell: Cell, direction: Direction) {
|
||||||
super(cell);
|
this.cell = cell;
|
||||||
this.direction = direction;
|
this.direction = direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -24,6 +24,6 @@ export class ExternalNode extends Node {
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { v4 as uuidv4 } from "uuid";
|
||||||
|
import { InternalNodeType } from "../constants/InternalNodeType";
|
||||||
|
|
||||||
|
export class InternalNode {
|
||||||
|
id: string;
|
||||||
|
type: InternalNodeType;
|
||||||
|
|
||||||
|
constructor(type: InternalNodeType) {
|
||||||
|
this.id = uuidv4();
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,4 @@
|
||||||
import { Cell } from "./Cell";
|
import { ExternalNode } from "./ExternalNode";
|
||||||
|
import { InternalNode } from "./InternalNode";
|
||||||
|
|
||||||
export abstract class Node {
|
export type Node = ExternalNode | InternalNode;
|
||||||
public readonly cell: Cell;
|
|
||||||
|
|
||||||
constructor(cell: Cell) {
|
|
||||||
this.cell = cell;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
import { Direction } from "../constants/Direction";
|
||||||
|
import { TrackType } from "../constants/TrackType";
|
||||||
|
import { Cell } from "./Cell";
|
||||||
|
import { InternalNode } from "./InternalNode";
|
||||||
|
import { PlacedPiece } from "./PlacedPiece";
|
||||||
|
import { Node } from "./Node";
|
||||||
|
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<Track>;
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 Node
|
||||||
|
? (track.joinedPoints.secondPoint as Node)
|
||||||
|
: cell.getNodeAt(track.joinedPoints.secondPoint as Direction),
|
||||||
|
},
|
||||||
|
type: track.type,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
this.internalNode,
|
||||||
|
cell,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { TrackType } from "../constants/TrackType";
|
||||||
|
import { Cell } from "./Cell";
|
||||||
|
import { InternalNode } from "./InternalNode";
|
||||||
|
import { Node } from "./Node";
|
||||||
|
|
||||||
|
export class PlacedPiece {
|
||||||
|
tracks: Set<{
|
||||||
|
nodes: {
|
||||||
|
firstNode: Node;
|
||||||
|
secondNode: Node;
|
||||||
|
};
|
||||||
|
type: TrackType;
|
||||||
|
}>;
|
||||||
|
internalNode?: InternalNode;
|
||||||
|
cell: Cell;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
tracks: Set<{
|
||||||
|
nodes: { firstNode: Node; secondNode: Node };
|
||||||
|
type: TrackType;
|
||||||
|
}>,
|
||||||
|
internalNodes: InternalNode | undefined,
|
||||||
|
cell: Cell,
|
||||||
|
) {
|
||||||
|
this.tracks = tracks;
|
||||||
|
this.internalNode = internalNodes;
|
||||||
|
this.cell = cell;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 43 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
|
@ -1,6 +1,3 @@
|
||||||
@use "node_modules/@picocss/pico/scss/pico" with (
|
@use "node_modules/@picocss/pico/scss/pico" with (
|
||||||
$theme-color: "pumpkin"
|
$theme-color: "pumpkin"
|
||||||
);
|
);
|
||||||
|
|
||||||
@import "./pages/game/GamePage.scss";
|
|
||||||
@import "./pages/game/components/GameBoard.scss";
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { io } from "socket.io-client";
|
import { io } from "socket.io-client";
|
||||||
import GamePage from "./pages/game/GamePage";
|
import GamePage from "./pages/game/GamePage";
|
||||||
|
import "./App.scss";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const socket = io("http://localhost:3010");
|
const socket = io("http://localhost:3010");
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ReactDOM from "react-dom/client";
|
import ReactDOM from "react-dom/client";
|
||||||
import App from "./App";
|
import App from "./App";
|
||||||
import "./App.scss";
|
|
||||||
|
|
||||||
const root = ReactDOM.createRoot(
|
const root = ReactDOM.createRoot(
|
||||||
document.getElementById("root") as HTMLElement,
|
document.getElementById("root") as HTMLElement,
|
||||||
|
|
|
||||||
|
|
@ -3,3 +3,14 @@ h1 {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.game-panel {
|
||||||
|
user-select: none; /* Standard syntax */
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
|
||||||
|
.right-panel {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import GameBoard from "./components/GameBoard";
|
import GameBoard from "./components/GameBoard";
|
||||||
|
import DiceSet from "./components/DiceSet";
|
||||||
|
import "./GamePage.scss";
|
||||||
|
|
||||||
const GamePage = () => {
|
const GamePage = () => {
|
||||||
return (
|
return (
|
||||||
|
|
@ -7,6 +9,9 @@ const GamePage = () => {
|
||||||
<h1>Game Page Title</h1>
|
<h1>Game Page Title</h1>
|
||||||
<div className="game-panel">
|
<div className="game-panel">
|
||||||
<GameBoard />
|
<GameBoard />
|
||||||
|
<div className="rigth-panel">
|
||||||
|
<DiceSet />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
.dice-set {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, auto);
|
||||||
|
gap: 20px;
|
||||||
|
padding: 50px;
|
||||||
|
|
||||||
|
.dice {
|
||||||
|
height: 150px;
|
||||||
|
width: 150px;
|
||||||
|
border: 2px solid black;
|
||||||
|
border-radius: 10%;
|
||||||
|
|
||||||
|
img{
|
||||||
|
border-radius: 10%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { PieceId } from "interface";
|
||||||
|
import "./DiceSet.scss";
|
||||||
|
|
||||||
|
const DiceSet = () => {
|
||||||
|
const getRandomPieceId = () => {
|
||||||
|
const randomId = Math.floor(Math.random() * Object.keys(PieceId).length);
|
||||||
|
return Object.values(PieceId)[randomId];
|
||||||
|
};
|
||||||
|
const displayedPieceIds = [1, 2, 3, 4].map(getRandomPieceId);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="dice-set">
|
||||||
|
{displayedPieceIds.map((pieceId) => (
|
||||||
|
<div className="dice">
|
||||||
|
<img src={`pieces/${pieceId}.jpeg`}></img>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DiceSet;
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
.game-board {
|
.game-board {
|
||||||
height: 850px;
|
height: 850px;
|
||||||
width: 850px;
|
width: 850px;
|
||||||
|
min-height: 850px;
|
||||||
|
min-width: 850px;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(7, auto);
|
grid-template-columns: repeat(7, auto);
|
||||||
gap: auto;
|
gap: auto;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { buildBoard, Cell, directions, Exit } from "interface";
|
import { buildBoard, Cell, directions, Exit } from "interface";
|
||||||
|
import "./GameBoard.scss";
|
||||||
|
|
||||||
const GameBoard = () => {
|
const GameBoard = () => {
|
||||||
const board: Cell[][] = buildBoard();
|
const board: Cell[][] = buildBoard();
|
||||||
|
|
|
||||||