Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "room-finder",
"version": "0.1.1",
"version": "0.2.0-beta.2",
"repository": "github:WalnutProgramming/room-finder",
"homepage": "https://room-finder.walnut.direct/",
"license": "AGPL-3.0-only",
Expand Down
8 changes: 8 additions & 0 deletions src/BasicRoomNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export class BasicRoomNode {
readonly _type = "BasicRoomNode";
readonly name: string;

constructor(name: string) {
this.name = name;
}
}
160 changes: 158 additions & 2 deletions src/Building.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
reverseConnection,
onFloor,
} from ".";
import { isValidBuilding } from "./buildingValidity";
import { assertValidBuilding, isValidBuilding } from "./buildingValidity";

const { RIGHT, LEFT, FRONT } = Direction;

Expand Down Expand Up @@ -533,10 +533,166 @@ describe("accessibility", () => {
expect.objectContaining({
valid: false,
reason:
"The hallway at index 4 has no nodes (Forks or Stairs) to connect it to the rest of the building.",
"The hallway at index 4 has no connector nodes (Forks or Stairs) to connect it to the rest of the building.",
})
);
});
});

describe("one-way hallways", () => {
const hallway10 = [
new Stairs(RIGHT, onFloor("b", 1)),
new Room("101"),
new Room("102"),
new Room("103"),
new Fork(RIGHT, "a", "the 11s"),
];
const hallway11 = [
new Fork(FRONT, reverseConnection("a"), "the 10s"),
new Room("111"),
new Room("112"),
new Room("113"),
new Stairs(RIGHT, onFloor("c", 1)),
];

const hallway20 = [
new Stairs(RIGHT, onFloor("b", 2)),
new Room("201"),
new Room("202"),
new Room("203"),
new Fork(RIGHT, "e", "the 11s"),
];
const hallway21 = [
new Fork(FRONT, reverseConnection("e"), "the 11s"),
new Room("211"),
new Room("212"),
new Room("213"),
new Stairs(RIGHT, onFloor("c", 2)),
];

let controlAnswer: string | null;

test("control case", () => {
const building = new Building([
new Hallway(hallway10),
new Hallway(hallway11),
new Hallway(hallway20),
new Hallway(hallway21),
]);
assertValidBuilding(building);

controlAnswer = building.getDirections("103", "111");

expect(controlAnswer).toMatchInlineSnapshot(`
"Turn left out of room 103
Continue, then turn right into the 11s
Continue, then turn left into room 111"
`);
});

test("one-way hallway with same directions", () => {
const building = new Building([
new Hallway(hallway10, { oneWay: "forward" }),
new Hallway(hallway11, { oneWay: "forward" }),
new Hallway(hallway20),
new Hallway(hallway21),
]);
assertValidBuilding(building);

expect(building.getDirections("103", "111")).toBe(controlAnswer);
});

test("one-way hallway 1", () => {
const building = new Building([
new Hallway(hallway10, { oneWay: "backward" }),
new Hallway(hallway11, { oneWay: "backward" }),
new Hallway(hallway20),
new Hallway(hallway21),
]);
assertValidBuilding(building);

expect(building.getDirections("103", "111")).not.toBe(controlAnswer);

expect(building.getDirections("103", "111")).toMatchInlineSnapshot(`
"Turn right out of room 103
Continue, then turn left into the stairs
Go up 1 floor of stairs
Turn right out of the stairs
Continue, then turn right into the 11s
Continue, then turn right into the stairs
Go down 1 floor of stairs
Turn left out of the stairs
Continue, then turn right into room 111"
`);
});

test("one-way hallway 2", () => {
const building = new Building([
new Hallway(hallway10, { oneWay: "backward" }),
new Hallway(hallway11),
new Hallway(hallway20),
new Hallway(hallway21),
]);
assertValidBuilding(building);

expect(building.getDirections("103", "111")).not.toBe(controlAnswer);

expect(building.getDirections("103", "111")).toMatchInlineSnapshot(`
"Turn right out of room 103
Continue, then turn left into the stairs
Go up 1 floor of stairs
Turn right out of the stairs
Continue, then turn right into the 11s
Continue, then turn right into the stairs
Go down 1 floor of stairs
Turn left out of the stairs
Continue, then turn right into room 111"
`);
});

test("one-way hallway 3", () => {
const building = new Building([
new Hallway(hallway10, { oneWay: "backward" }),
new Hallway(hallway11),
new Hallway(hallway20),
new Hallway(hallway21),
]);
assertValidBuilding(building);

expect(building.getDirections("101", "103")).toMatchInlineSnapshot(`
"Turn right out of room 101
Continue, then turn left into the stairs
Go up 1 floor of stairs
Turn right out of the stairs
Continue, then turn right into the 11s
Continue, then turn right into the stairs
Go down 1 floor of stairs
Turn left out of the stairs
Continue, then after entering the 10s, turn left
Continue, then turn right into room 103"
`);
});

test("unconnected one-way building 1", () => {
const building = new Building([
new Hallway(hallway10, { oneWay: "backward" }),
new Hallway(hallway11, { oneWay: "forward" }),
new Hallway(hallway20),
new Hallway(hallway21),
]);
expect(isValidBuilding(building).valid).toBe(false);
});
test("unconnected one-way building 2", () => {
const building = new Building([
new Hallway(hallway10, { oneWay: "forward" }),
new Hallway(hallway11, { oneWay: "backward" }),
new Hallway(hallway20),
new Hallway(hallway21),
]);
expect(isValidBuilding(building).valid).toBe(false);
});
});

// describe("one-way connections", () => {});

// TODO: add tests with SimpleHallway and rooms that are nodes
44 changes: 32 additions & 12 deletions src/Building.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
import { Hallway } from "./Hallway";
import { Room } from "./Room";
import { getShortestPath, isConnectedGraph, getGraph } from "./graph";
import {
getShortestPath,
isConnectedGraph,
getGraph,
HallConnectorsStructures,
} from "./graph";
import { isLeftOrRight } from "./Direction";
import { ForkNode } from "./ForkNode";
import { StairNode } from "./StairNode";
import { nodeToString } from "./node";
import { serializeNode, Node } from "./node";
import { BasicRoomNode } from "./BasicRoomNode";

/**
* @ignore
Expand Down Expand Up @@ -61,15 +67,29 @@ export class Building<
*/
constructor(
readonly hallways: Hallway<ForkName, StairName>[],
readonly allowedConnections: (
| ForkName
| StairName
)[] = hallways.flatMap(h => h.nodes.map(n => n.nodeId.name))
readonly allowedConnections: (ForkName | StairName)[] = hallways.flatMap(
h =>
h.nodes
.map(n => n.nodeId)
.filter(
(nodeId): nodeId is ForkNode<ForkName> | StairNode<StairName> =>
!(nodeId instanceof BasicRoomNode)
)
.map(nodeId => nodeId.name)
)
) {
const hallwayNodes = this.hallways.map(h => {
return h.nodes.filter(({ nodeId }) =>
allowedConnections.includes(nodeId.name)
);
const hallwayNodes: HallConnectorsStructures<
ForkName,
StairName
> = this.hallways.map(h => {
return {
nodes: h.nodes.filter(
({ nodeId }) =>
nodeId instanceof BasicRoomNode ||
allowedConnections.includes(nodeId.name)
),
oneWay: h.oneWay,
};
});
this.graph = getGraph(hallwayNodes);
this.roomsList = hallways
Expand Down Expand Up @@ -110,14 +130,14 @@ export class Building<
* hallway
*/
private getHallwayIndexAndIndexFromNode(
nodeId: ForkNode<ForkName> | StairNode<StairName>
nodeId: Node<ForkName, StairName>
): [number, number] {
const inds = this.hallways.map(h =>
h.partList.findIndex(
r =>
"nodeId" in r &&
r.nodeId != null &&
nodeToString(r.nodeId) === nodeToString(nodeId)
serializeNode(r.nodeId) === serializeNode(nodeId)
)
);
const hallwayInd = inds.findIndex(a => a !== -1);
Expand Down
Loading