-
Notifications
You must be signed in to change notification settings - Fork 1
/
dayC.toit
70 lines (57 loc) · 2.11 KB
/
dayC.toit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
import .aoc
import .resources
class Field:
lines_ /List
constructor:
lines_ = INPUTC.trim.split "\n"
position_of needle/string -> Coord:
lines_.size.repeat: | y |
idx := lines_[y].index_of needle
if idx >= 0: return Coord idx y
unreachable
elevation x/int y/int -> int:
c := lines_[y][x]
if 'a' <= c <= 'z': return c - 'a'
if c == 'S': return 0
if c == 'E': return 'z' - 'a'
unreachable
height -> int: return lines_.size
width -> int: return lines_[0].size
four_dirs c/Coord -> List:
result := []
if c.x > 0: result.add (Coord c.x - 1 c.y)
if c.y > 0: result.add (Coord c.x c.y - 1)
if c.x < width - 1: result.add (Coord c.x + 1 c.y)
if c.y < height - 1: result.add (Coord c.x c.y + 1)
return result
main:
field := Field
start := field.position_of "S"
end := field.position_of "E"
from_start_distances := calculate_distances field start: | neighbour_elevation elevation | neighbour_elevation - elevation < 2
print from_start_distances[end.y][end.x]
from_end_distances := calculate_distances field end: | neighbour_elevation elevation | neighbour_elevation - elevation > -2
best := 1_000_000
field.height.repeat: | y |
field.width.repeat: | x |
dist := from_end_distances[y][x]
if dist and dist < best and (field.elevation x y) == 0:
best = dist
print best
calculate_distances field/Field start/Coord [can_move_block] -> List:
shortest := List field.height: List field.width: null
shortest[start.y][start.x] = 0
work_list := Deque
work_list.add start
while work_list.size != 0:
here := work_list.remove_first
elevation := field.elevation here.x here.y
short/int := shortest[here.y][here.x]
(field.four_dirs here).do: | neighbour/Coord |
neighbour_elevation := field.elevation neighbour.x neighbour.y
if can_move_block.call neighbour_elevation elevation:
old_shortest := shortest[neighbour.y][neighbour.x]
if old_shortest == null or old_shortest > short + 1:
shortest[neighbour.y][neighbour.x] = short + 1
work_list.add neighbour
return shortest