Disallow piece placement when piece is not connected to adjacent piece or exit
parent
b1d57ebfcd
commit
035b7da335
|
|
@ -294,7 +294,7 @@ const T_JUNCTION_ROAD: Piece = new Piece({
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
startPoint: Direction.WEST,
|
startPoint: Direction.WEST,
|
||||||
type: TrackType.RAIL,
|
type: TrackType.ROAD,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
import { CellType } from "../constants/CellType";
|
import { CellType } from "../constants/CellType";
|
||||||
import { Direction } from "../constants/Direction";
|
import { Direction, directions } from "../constants/Direction";
|
||||||
import { ExitType } from "../constants/ExitType";
|
import { ExitType } from "../constants/ExitType";
|
||||||
import { PieceId, pieceMap } from "../constants/Pieces";
|
import { PieceId, pieceMap } from "../constants/Pieces";
|
||||||
|
import { TrackType } from "../constants/TrackType";
|
||||||
import { Exit } from "./Exit";
|
import { Exit } from "./Exit";
|
||||||
import { ExternalNode } from "./ExternalNode";
|
import { ExternalNode } from "./ExternalNode";
|
||||||
import { InternalNode } from "./InternalNode";
|
import { InternalNode } from "./InternalNode";
|
||||||
|
import { Piece } from "./Piece";
|
||||||
import { PlacedPiece } from "./PlacedPiece";
|
import { PlacedPiece } from "./PlacedPiece";
|
||||||
|
|
||||||
export class Cell {
|
export class Cell {
|
||||||
|
|
@ -33,45 +35,72 @@ export class Cell {
|
||||||
|
|
||||||
public placePiece(pieceId: PieceId) {
|
public placePiece(pieceId: PieceId) {
|
||||||
if (this.placedPiece !== undefined) return;
|
if (this.placedPiece !== undefined) return;
|
||||||
const piece = pieceMap[pieceId];
|
const piece: Piece = pieceMap[pieceId];
|
||||||
const connectionTypes = Array.from(piece.tracks).flatMap((track) => {
|
|
||||||
const directions =
|
this.validatePiecePlacement(piece);
|
||||||
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 = {
|
this.placedPiece = {
|
||||||
piece: piece.toPlacedPiece(this),
|
piece: piece.toPlacedPiece(this),
|
||||||
id: pieceId,
|
id: pieceId,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private validatePiecePlacement(piece: Piece) {
|
||||||
|
const hasAnyConnection = Array.from(piece.tracks)
|
||||||
|
.map((track) => {
|
||||||
|
const trackExternalNodes = [
|
||||||
|
this.getNodeAt(track.joinedPoints.firstPoint),
|
||||||
|
];
|
||||||
|
if (!(track.joinedPoints.secondPoint instanceof InternalNode)) {
|
||||||
|
trackExternalNodes.push(
|
||||||
|
this.getNodeAt(track.joinedPoints.secondPoint),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
trackExternalNodes: trackExternalNodes,
|
||||||
|
trackType: track.type,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.some(({ trackExternalNodes, trackType }) => {
|
||||||
|
let isTrackConnected: boolean = false;
|
||||||
|
trackExternalNodes
|
||||||
|
.filter((node) => node.traverseBorder() instanceof Exit)
|
||||||
|
.forEach((node) => {
|
||||||
|
const exitType = (node.traverseBorder() as Exit).type;
|
||||||
|
isTrackConnected = true;
|
||||||
|
if (
|
||||||
|
exitType !== ExitType.AMBIVALENT &&
|
||||||
|
exitType.toString() !== trackType.toString()
|
||||||
|
) {
|
||||||
|
throw Error(
|
||||||
|
`Unable to place piece, invalid exit type at direction ${node.direction}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
trackExternalNodes
|
||||||
|
.filter((node) => node.traverseBorder() instanceof ExternalNode)
|
||||||
|
.forEach((node) => {
|
||||||
|
const adjacentExternalNode = node.traverseBorder() as ExternalNode;
|
||||||
|
const adjacentTrack =
|
||||||
|
adjacentExternalNode.cell.placedPiece?.piece.findTrackForDirection(
|
||||||
|
adjacentExternalNode.direction,
|
||||||
|
);
|
||||||
|
if (adjacentTrack !== undefined) {
|
||||||
|
isTrackConnected = true;
|
||||||
|
if (adjacentTrack.type !== trackType) {
|
||||||
|
throw Error(
|
||||||
|
`Unable to place piece next to another due to conflicting track types at ${node.direction}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return isTrackConnected;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!hasAnyConnection) {
|
||||||
|
throw Error("No adjacent exit or piece available to connect to");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue