Skip to content

Commit e6c3215

Browse files
committed
Add accessibility feature
1 parent e3166f3 commit e6c3215

File tree

5 files changed

+141
-26
lines changed

5 files changed

+141
-26
lines changed

src/Building.test.ts

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
reverseConnection,
1010
onFloor,
1111
} from ".";
12+
import { isValidBuilding } from "./buildingValidity";
1213

1314
const { RIGHT, LEFT, FRONT } = Direction;
1415

@@ -451,4 +452,91 @@ describe("correct transition phrasing", () => {
451452
});
452453
});
453454

455+
describe("accessibility", () => {
456+
test("example with elevators", () => {
457+
type MyForks = "fork1";
458+
type MyStairs = "stair-a" | "stair-b" | "elevator-a";
459+
460+
const building = new Building<MyForks, MyStairs>([
461+
// hallway 11 (on 1st floor)
462+
new Hallway([
463+
new Stairs(LEFT, onFloor("stair-a", 1)),
464+
new Room("111"),
465+
new Room("112"),
466+
new Stairs(LEFT, onFloor("elevator-a", 1), "the elevator"),
467+
]),
468+
469+
// hallway 21 (on 2nd floor)
470+
new Hallway([
471+
new Stairs(LEFT, onFloor("stair-a", 2)),
472+
new Room("211"),
473+
new Room("212"),
474+
new Fork(RIGHT, reverseConnection("fork1"), "the 22s"),
475+
new Stairs(LEFT, onFloor("elevator-a", 2), "the elevator"),
476+
]),
477+
478+
// hallway 22 (on 2nd floor)
479+
new Hallway([
480+
new Room("221"),
481+
new Room("222"),
482+
new Stairs(LEFT, onFloor("stair-b", 2)),
483+
new Fork(FRONT, "fork1", "the 21s"),
484+
]),
485+
486+
// hallway 31 (on 3rd floor)
487+
new Hallway([
488+
new Room("311", RIGHT),
489+
new Stairs(LEFT, onFloor("stair-a", 3)),
490+
new Room("312"),
491+
new Stairs(LEFT, onFloor("elevator-a", 3), "the elevator"),
492+
]),
493+
494+
// hallway 32 (on 3rd floor)
495+
new Hallway([
496+
new Room("321"),
497+
new Stairs(LEFT, onFloor("stair-b", 3)),
498+
new Room("322"),
499+
]),
500+
]);
501+
502+
const buildingNonAccessible = building.withAllowedConnectionTypes(
503+
s => !s.includes("elevator")
504+
);
505+
506+
const buildingAccessible = building.withAllowedConnectionTypes(
507+
s => !s.includes("stair")
508+
);
509+
510+
expect(buildingNonAccessible.getDirections("111", "312"))
511+
.toMatchInlineSnapshot(`
512+
"Turn right out of room 111
513+
Continue, then turn right into the stairs
514+
Go up 2 floors of stairs
515+
Turn left out of the stairs
516+
Continue, then turn left into room 312"
517+
`);
518+
519+
expect(buildingAccessible.getDirections("111", "312"))
520+
.toMatchInlineSnapshot(`
521+
"Turn left out of room 111
522+
Continue, then turn left into the elevator
523+
Go to floor 3
524+
Turn right out of the elevator
525+
Continue, then turn right into room 312"
526+
`);
527+
528+
expect(isValidBuilding(buildingNonAccessible)).toEqual(
529+
expect.objectContaining({ valid: true })
530+
);
531+
532+
expect(isValidBuilding(buildingAccessible)).toEqual(
533+
expect.objectContaining({
534+
valid: false,
535+
reason:
536+
"The hallway at index 4 has no nodes (Forks or Stairs) to connect it to the rest of the building.",
537+
})
538+
);
539+
});
540+
});
541+
454542
// TODO: add tests with SimpleHallway and rooms that are nodes

src/Building.ts

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,17 @@ export class Building<
5959
* @param hallways - All of the hallways in this building
6060
* @category Important
6161
*/
62-
constructor(readonly hallways: Hallway<ForkName, StairName>[]) {
62+
constructor(
63+
readonly hallways: Hallway<ForkName, StairName>[],
64+
readonly allowedConnections: (
65+
| ForkName
66+
| StairName
67+
)[] = hallways.flatMap(h => h.nodes.map(n => n.nodeId.name))
68+
) {
6369
const hallwayNodes = this.hallways.map(h => {
64-
return h.nodes;
70+
return h.nodes.filter(({ nodeId }) =>
71+
allowedConnections.includes(nodeId.name)
72+
);
6573
});
6674
this.graph = getGraph(hallwayNodes);
6775
this.roomsList = hallways
@@ -71,6 +79,17 @@ export class Building<
7179
.sort();
7280
}
7381

82+
withAllowedConnectionTypes(
83+
allowedConnections: (ForkName | StairName)[] | ((name: string) => boolean)
84+
) {
85+
return new Building(
86+
this.hallways,
87+
typeof allowedConnections === "function"
88+
? this.allowedConnections.filter(allowedConnections)
89+
: allowedConnections
90+
);
91+
}
92+
7493
/**
7594
* @param name - The name of the room
7695
* @returns An array, where the first element is the index of the hallway where
@@ -108,21 +127,22 @@ export class Building<
108127
/**
109128
*
110129
* @ignore
111-
* @param id1 The first StairNode
112-
* @param id2 The second StairNode in the same staircase
130+
* TODO
113131
* @returns The instructions to go up/down that staircase the correct number
114132
* of floors
115133
*/
116-
private getStairConnectionInstruction(
117-
id1: StairNode<StairName>,
118-
id2: StairNode<StairName>
134+
getStairConnectionInstruction(
135+
stairName: StairName,
136+
floor1: number,
137+
floor2: number
119138
): string {
120-
const goingUp = id2.floor > id1.floor;
121-
const numFlights = Math.abs(id1.floor - id2.floor);
139+
if (stairName.includes("elevator")) {
140+
return `go to floor ${floor2}\n`;
141+
}
142+
const upOrDown = floor2 > floor1 ? "up" : "down";
143+
const numFlights = Math.abs(floor1 - floor2);
122144
const maybeS = numFlights > 1 ? "s" : "";
123-
return `go ${
124-
goingUp ? "up" : "down"
125-
} ${numFlights} floor${maybeS} of stairs\n`;
145+
return `go ${upOrDown} ${numFlights} floor${maybeS} of stairs\n`;
126146
}
127147

128148
/**
@@ -171,9 +191,10 @@ export class Building<
171191
// Find IDs of the nodes (stairs or hallways) closest to these rooms
172192
const closestNodeFromInd = this.hallways[
173193
fromHallwayInd
174-
].idOfClosestNodeToIndex(fromInd);
194+
].idOfClosestNodeToIndex(fromInd, this.allowedConnections);
175195
const closestNodeToInd = this.hallways[toHallwayInd].idOfClosestNodeToIndex(
176-
toInd
196+
toInd,
197+
this.allowedConnections
177198
);
178199

179200
// This is to keep track of whether we entered the next hallway through a
@@ -210,7 +231,11 @@ export class Building<
210231
entranceWasStraight,
211232
}
212233
);
213-
directions += this.getStairConnectionInstruction(prevId, nextId);
234+
directions += this.getStairConnectionInstruction(
235+
prevId.name,
236+
prevId.floor,
237+
nextId.floor
238+
);
214239
[currentHallwayInd, currentInd] = this.getHallwayIndexAndIndexFromNode(
215240
nextId
216241
);

src/Hallway.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,15 @@ export class Hallway<ForkName extends string, StairName extends string> {
5151
* @returns The id of the "closest" node to the given room within this hallway
5252
*/
5353
idOfClosestNodeToIndex(
54-
roomInd: number
54+
roomInd: number,
55+
allowedConnections: (ForkName | StairName)[]
5556
): ForkNode<ForkName> | StairNode<StairName> {
5657
let closestNodeInd: number;
5758
this.partList.forEach((r, currentInd) => {
5859
if (
5960
"nodeId" in r &&
6061
r.nodeId != null &&
62+
allowedConnections.includes(r.nodeId.name) &&
6163
(closestNodeInd === undefined ||
6264
Math.abs(currentInd - roomInd) < Math.abs(closestNodeInd - roomInd))
6365
) {

src/Stairs.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,19 @@ import { StairNode } from "./StairNode";
99
*/
1010
export class Stairs<StairName extends string> extends HallwayElement {
1111
readonly nodeId: StairNode<StairName>;
12+
readonly fullName: string;
1213

1314
constructor(
1415
side: Direction,
1516
nodeId: StairNode<StairName>,
16-
public stairNumber?: string | undefined,
17+
fullName: string = "the stairs",
1718
edgeLengthFromPreviousNodeInHallway?: number | undefined
1819
) {
1920
super(null, side, { edgeLengthFromPreviousNodeInHallway });
21+
this.fullName = fullName;
2022
this.nodeId = nodeId;
2123
}
2224

23-
get fullName() {
24-
if (this.stairNumber) {
25-
return "the " + this.stairNumber + " stairs";
26-
}
27-
return "the stairs";
28-
}
29-
3025
onLeave(
3126
forwardOrBackward: -1 | 1,
3227
_isBeginningOfDirections: boolean,

src/buildingValidity.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,10 @@ export function isValidBuilding<
8585
}
8686

8787
// shouldn't have duplicated or unmatched nodes
88-
const allNodes = b.hallways.flatMap(h => h.nodes).map(({ nodeId }) => nodeId);
88+
const allNodes = b.hallways
89+
.flatMap(h => h.nodes)
90+
.map(({ nodeId }) => nodeId)
91+
.filter(nodeId => b.allowedConnections.includes(nodeId.name));
8992
for (const nodeId of allNodes) {
9093
if (nodeId instanceof StairNode) {
9194
const sameStaircase = allNodes
@@ -175,7 +178,9 @@ export function isValidBuilding<
175178
// If there's more than 1 hallway, each hallway should have a node to
176179
// connect it to the rest of the hallways
177180
const indexOfHallwayWithNoNodes = b.hallways.findIndex(
178-
h => h.nodes.length === 0
181+
h =>
182+
h.nodes.filter(({ nodeId }) => b.allowedConnections.includes(nodeId.name))
183+
.length === 0
179184
);
180185
if (b.hallways.length > 1 && indexOfHallwayWithNoNodes !== -1) {
181186
return {

0 commit comments

Comments
 (0)