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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
#!/usr/bin/env raku
sub MAIN (
Int $part where * == 1|2 = 1 #= part to run (1 or 2)
) {
my @input = "input".IO.lines;
my Int $x-max = @input[0].chars - 1;
my Int $row-length = $x-max + 1;
my @seats = @input.join.comb;
my $max-seats = @seats.end;
my @directions = (+$row-length, -$row-length); # down, up
# @non-left-corner contains directions that left corner can't
# follow. It should only be followed by non-left corner seats.
my @non-left-corner = (
-$row-length - 1, # up-left
-1, # left
+$row-length - 1, # down-left
);
# @non-right-corner contains directions that right corner can't
# follow. It should only be followed by non-right corner seats.
my @non-right-corner = (
-$row-length + 1, # up-right
+1, # right
+$row-length + 1, # down-right
);
my Int $round = 0;
loop {
my @changed;
my Bool $change = False;
INNER: for @seats.kv -> $idx, $seat {
@changed[$idx] = $seat;
given $seat {
when '.' { next INNER; }
when 'L' {
if adjacent-occupied($idx, 1) == 0 {
@changed[$idx] = '#';
$change = True;
}
}
when '#' {
if adjacent-occupied($idx, 1) >= 4 {
@changed[$idx] = 'L';
$change = True;
}
}
}
}
$round++;
print "Round $round.\r";
last unless $change;
for @changed.kv -> $idx, $changed_seat {
@seats[$idx] = $changed_seat;
}
}
my Int $occupied = @seats.comb('#').elems;
say "Part $part: ", $occupied;
# adjacent-occupied returns the number of adjacent cells that have
# been occupied by others. $visibility_range should be 1 if only
# directly adjacent seats are to be counted. Make it -1 for
# infinite visibility. It ignores floors ('.').
sub adjacent-occupied (
Int $idx, Int $visibility_range --> Int
) {
my Int $occupied = 0;
for @directions -> $direction {
with @seats[$idx + $direction] {
$occupied++ if $_ eq '#';
}
}
# Elements in right corner can't follow @non-right-corner.
unless ($idx + 1) % 10 == 0 {
for @non-right-corner -> $direction {
with @seats[$idx + $direction] {
$occupied++ if $_ eq '#';
}
}
}
# Elements in left corner can't follow @non-left-corner.
unless $idx % 10 == 0 {
for @non-left-corner -> $direction {
with @seats[$idx + $direction] {
$occupied++ if $_ eq '#';
}
}
}
return $occupied;
}
}
|