-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy path06.php
99 lines (80 loc) · 2.07 KB
/
06.php
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
<?php
$time_start = microtime(true);
$input = trim(file_get_contents('06.txt'));
$grid = explode("\n", $input);
const NORTH = 0;
const EAST = 1;
const SOUTH = 2;
const WEST = 3;
function find_pos(array $grid): array {
for ($row = 0; $row < count($grid); $row++) {
for ($col = 0; $col < strlen($grid[$row]); $col++) {
if ($grid[$row][$col] === '^') {
return [$row, $col];
}
}
}
throw new Exception('No guard in grid?!');
}
function walk(array $grid, int $r, int $c) {
static $dirs = [
NORTH => [-1, 0],
EAST => [0, 1],
SOUTH => [1, 0],
WEST => [0, -1],
];
$dir = NORTH; // guard starts facing up
$seen = [];
$height = count($grid);
$width = strlen($grid[0]);
while (true) {
$r2 = $r + $dirs[$dir][0];
$c2 = $c + $dirs[$dir][1];
// check for grid bounds
if ($r2 < 0 || $c2 < 0 || $r2 >= $height || $c2 >= $width) {
break;
}
// check for obstacle
if ($grid[$r2][$c2] === '#') {
$dir = ($dir + 1) % 4;
continue;
}
// take a step
$r = $r2;
$c = $c2;
$h = ($r << 8) + $c;
if (!isset($seen[$h])) {
$seen[$h] = 0;
} else if ($seen[$h] & (1 << $dir)) {
return false;
}
// mark (row, col) location as seen with value storing the orientation
$seen[$h] |= (1 << $dir);
}
return $seen;
}
[$rs, $cs] = find_pos($grid);
$grid[$rs][$cs] = '.';
// for part 1, simply walk grid and count seen positions
$positions = walk($grid, $rs, $cs);
$pt1 = count($positions);
// for part 2, brute-force place an obstacle at each visited location from part 1
$pt2 = 0;
foreach ($positions as $p => $_) {
$r = $p >> 8; // bytes 8-16 hold the row
$c = $p & 0xFF; // bytes 0-8 hold the column
// skip if already obstacle or guard starting pos
if ($grid[$r][$c] === '#' || ($r === $rs && $c === $cs)) continue;
$grid[$r][$c] = '#';
if (!walk($grid, $rs, $cs)) {
$pt2++;
}
$grid[$r][$c] = '.';
}
echo "--- Day 6: Guard Gallivant ---", PHP_EOL;
echo "Part 1: ", $pt1, PHP_EOL;
echo "Part 2: ", $pt2, PHP_EOL;
echo "Took ", (microtime(true) - $time_start) * 1000, " ms", PHP_EOL;
echo PHP_EOL;
assert($pt1 === 5409);
assert($pt2 === 2022);