Skip to content

Commit fe8483d

Browse files
committed
feat(day20): refactor to use levels
1 parent 2c86e88 commit fe8483d

File tree

1 file changed

+127
-25
lines changed

1 file changed

+127
-25
lines changed

day20/transportingMazeSolver.ts

Lines changed: 127 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export type Location = {
77
pos: Position
88
path: Position[]
99
status: LocationStatus
10+
level: number
1011
}
1112

1213
export enum Tile {
@@ -25,10 +26,21 @@ export enum DIRECTION {
2526
const START = 'AA'
2627
const END = 'ZZ'
2728

28-
const isSafe = (maze: MazeString, visited: boolean[], pos: Position) => {
29+
type Visited = {
30+
[key: number]: {
31+
[key: number]: boolean
32+
}
33+
}
34+
35+
const isSafe = (
36+
maze: MazeString,
37+
visited: Visited,
38+
pos: Position,
39+
level: number,
40+
) => {
2941
const p = pos.y * maze.width + pos.x
3042
if (maze.maze[p] === undefined) return false
31-
if (visited[p]) return false
43+
if (visited[level][p]) return false
3244
if (maze.maze[p] !== Tile.PATH) return false
3345
return true
3446
}
@@ -37,28 +49,32 @@ const equals = (a: Position, b: Position) => a.x === b.x && a.y === b.y
3749

3850
const status = (
3951
maze: MazeString,
40-
visited: boolean[],
41-
location: Position,
52+
visited: Visited,
53+
pos: Position,
54+
level: number,
4255
): LocationStatus => {
43-
if (!isSafe(maze, visited, location)) return 'Blocked'
56+
if (!isSafe(maze, visited, pos, level)) return 'Blocked'
4457
return 'Valid'
4558
}
4659

4760
const createLocation = (
4861
maze: MazeString,
49-
visited: boolean[],
62+
visited: Visited,
5063
location: Location,
5164
) => (pos: Position): Location => ({
65+
level: location.level,
5266
pos: pos,
5367
path: [...location.path, location.pos],
54-
status: status(maze, visited, pos),
68+
status: status(maze, visited, pos, location.level),
5569
})
5670

5771
const exploreInDirection = (
5872
maze: MazeString,
59-
visited: boolean[],
73+
visited: Visited,
6074
portals: Portal[],
6175
location: Location,
76+
// whether to apply recursive rules
77+
recursive = false,
6278
) => (direction: DIRECTION): Location => {
6379
let newLocation: Location
6480
const cl = createLocation(maze, visited, location)
@@ -78,25 +94,100 @@ const exploreInDirection = (
7894
}
7995

8096
if (newLocation.status === 'Valid') {
81-
visited[newLocation.pos.y * maze.width + newLocation.pos.x] = true
97+
visited[newLocation.level][
98+
newLocation.pos.y * maze.width + newLocation.pos.x
99+
] = true
82100
// Is this a portal?
83101
const portal = portals.find(({ pos }) => equals(pos, newLocation.pos))
84102
if (portal) {
85-
// Is this the last portal
86-
if (portal.label === END) {
87-
return {
88-
...newLocation,
89-
status: 'Target',
90-
}
91-
}
92103
const pair = portals.find(
93104
p => p !== portal && p.label === portal.label,
94105
) as Portal
95-
visited[pair.pos.y * maze.width + pair.pos.x] = true
96-
return {
97-
pos: pair.pos,
98-
path: [...location.path, location.pos, portal.pos],
99-
status: 'Valid',
106+
if (recursive) {
107+
// When you enter the maze, you are at the outermost level (0);
108+
// when at the outermost level, only the outer labels AA and ZZ
109+
// function (as the start and end, respectively); all other outer
110+
// labeled tiles are effectively walls. At any other level,
111+
// AA and ZZ count as walls, but the other outer labeled tiles
112+
// bring you one level outward.
113+
if (location.level === 0) {
114+
// Outermost level
115+
if (portal.label === END) {
116+
// ZZ is accessible
117+
return {
118+
...newLocation,
119+
status: 'Target',
120+
}
121+
}
122+
// Outer portals are walls at outermost level
123+
if (portal.isOuter) {
124+
return {
125+
...newLocation,
126+
status: 'Blocked',
127+
}
128+
} else {
129+
// Inner portal takes you one level deeper
130+
if (visited[newLocation.level] === undefined) {
131+
visited[newLocation.level] = []
132+
}
133+
visited[newLocation.level + 1][
134+
pair.pos.y * maze.width + pair.pos.x
135+
] = true
136+
return {
137+
pos: pair.pos,
138+
path: [...location.path, location.pos, portal.pos],
139+
status: 'Valid',
140+
level: newLocation.level + 1,
141+
}
142+
}
143+
} else {
144+
// Other level
145+
if (portal.label === END) {
146+
// ZZ is not accessible
147+
return {
148+
...newLocation,
149+
status: 'Blocked',
150+
}
151+
}
152+
if (portal.isOuter) {
153+
// Outer portal takes you one level up
154+
visited[newLocation.level - 1][
155+
pair.pos.y * maze.width + pair.pos.x
156+
] = true
157+
return {
158+
pos: pair.pos,
159+
path: [...location.path, location.pos, portal.pos],
160+
status: 'Valid',
161+
level: newLocation.level - 1,
162+
}
163+
} else {
164+
// Inner portal takes you one level deeper
165+
visited[newLocation.level + 1][
166+
pair.pos.y * maze.width + pair.pos.x
167+
] = true
168+
return {
169+
pos: pair.pos,
170+
path: [...location.path, location.pos, portal.pos],
171+
status: 'Valid',
172+
level: newLocation.level + 1,
173+
}
174+
}
175+
}
176+
} else {
177+
// Is this the last portal
178+
if (portal.label === END) {
179+
return {
180+
...newLocation,
181+
status: 'Target',
182+
}
183+
}
184+
visited[newLocation.level][pair.pos.y * maze.width + pair.pos.x] = true
185+
return {
186+
pos: pair.pos,
187+
path: [...location.path, location.pos, portal.pos],
188+
status: 'Valid',
189+
level: newLocation.level,
190+
}
100191
}
101192
}
102193
}
@@ -109,28 +200,39 @@ export type MazeString = {
109200
width: number
110201
}
111202

112-
export const transportingMazeSolver = (maze: string): Location | undefined => {
203+
export const transportingMazeSolver = (
204+
maze: string,
205+
recursive = false,
206+
): Location | undefined => {
113207
const width = maze.indexOf('\n')
114208
const mazeString: MazeString = {
115209
width,
116210
maze: maze.trimEnd().replace(/\n/g, ''),
117211
}
118212
const portals = findPortals(maze)
119-
const visited = [] as boolean[]
213+
const visited = [] as Visited
214+
visited[0] = []
120215

121216
const startPos = portals.find(({ label }) => label === START) as Portal
122217
const queue = [
123218
{
124219
path: [],
125220
pos: startPos.pos,
126221
status: 'Start',
222+
level: 0,
127223
},
128224
] as Location[]
129-
visited[startPos.pos.y * width + startPos.pos.x] = true
225+
visited[0][startPos.pos.y * width + startPos.pos.x] = true
130226

131227
while (queue.length > 0) {
132228
const location = queue.shift() as Location
133-
const e = exploreInDirection(mazeString, visited, portals, location)
229+
const e = exploreInDirection(
230+
mazeString,
231+
visited,
232+
portals,
233+
location,
234+
recursive,
235+
)
134236

135237
// Up
136238
const up = e(DIRECTION.UP)

0 commit comments

Comments
 (0)