Disallow piece placement when piece is not connected to adjacent piece or exit

pull/8/head
MiguelMLorente 2024-12-03 18:09:04 +01:00
parent b1d57ebfcd
commit 035b7da335
2 changed files with 66 additions and 37 deletions

View File

@ -294,7 +294,7 @@ const T_JUNCTION_ROAD: Piece = new Piece({
},
{
startPoint: Direction.WEST,
type: TrackType.RAIL,
type: TrackType.ROAD,
},
],
});

View File

@ -1,10 +1,12 @@
import { CellType } from "../constants/CellType";
import { Direction } from "../constants/Direction";
import { Direction, directions } from "../constants/Direction";
import { ExitType } from "../constants/ExitType";
import { PieceId, pieceMap } from "../constants/Pieces";
import { TrackType } from "../constants/TrackType";
import { Exit } from "./Exit";
import { ExternalNode } from "./ExternalNode";
import { InternalNode } from "./InternalNode";
import { Piece } from "./Piece";
import { PlacedPiece } from "./PlacedPiece";
export class Cell {
@ -33,45 +35,72 @@ export class Cell {
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}`,
);
}
}
}
});
const piece: Piece = pieceMap[pieceId];
this.validatePiecePlacement(piece);
this.placedPiece = {
piece: piece.toPlacedPiece(this),
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");
}
}
}