1
0
Fork 0
mirror of https://github.com/HenkKalkwater/aoc-2020 synced 2024-11-22 11:05:18 +00:00
aoc-2020/source/day11.d
2020-12-11 08:29:43 +01:00

184 lines
3.6 KiB
D

import std.array;
import std.algorithm;
import std.range;
import std.string;
import std.stdio;
import std.traits;
import std.variant;
import dayutil;
enum Spot {
FLOOR,
EMPTY,
TAKEN
}
Variant run(int part, File input, bool bigboy, string[] args) {
Spot[][] spots = parseInput(input.byLineCopy);
return Variant(parts!size_t(part,
() => part1(spots),
() => part2(spots)));
}
Spot[][] parseInput(Range)(Range range) if (isInputRange!Range && isSomeString!(ElementType!Range)) {
return range.map!(row => row.map!((spot) {
switch(spot) {
case '.':
return Spot.FLOOR;
case 'L':
return Spot.EMPTY;
case '#':
return Spot.TAKEN;
default:
assert(false, "Unknown type");
}
}).array).array;
}
size_t part1(Spot[][] input) {
Spot[][] prev = input.dup;
do {
foreach (i, row; input.enumerate) {
prev[i] = row.dup;
}
//prev = input.dup;
for (int y = 0; y < input.length; y++) {
for (int x = 0; x < input[y].length; x++) {
if(input[y][x] == Spot.FLOOR) continue;
uint adjacent_taken = 0;
for (int dy = max(0, y - 1); dy <= min(prev.length - 1, y + 1); dy++) {
for (int dx = max(0, x - 1); dx <= min(prev[y].length - 1, x + 1); dx++) {
if (dx == x && dy == y) continue;
switch(prev[dy][dx]) {
case Spot.TAKEN:
adjacent_taken++;
break;
default:
break;
}
}
}
import std.format;
if (adjacent_taken == 0) {
input[y][x] = Spot.TAKEN;
} else if (adjacent_taken >= 4) {
input[y][x] = Spot.EMPTY;
}
}
}
} while(!prev.equal(input));
return input.joiner.count(Spot.TAKEN);
}
unittest {
import std.format;
string layout = q"EOS
L.LL.LL.LL
LLLLLLL.LL
L.L.L..L..
LLLL.LL.LL
L.LL.LL.LL
L.LLLLL.LL
..L.L.....
LLLLLLLLLL
L.LLLLLL.L
L.LLLLL.LL
EOS";
size_t result = parseInput(layout.lineSplitter).part1();
assert(result == 37, "Result is %d (expected 37)".format(result));
}
size_t part2(Spot[][] input) {
Spot[][] prev = input.dup;
do {
foreach (i, row; input.enumerate) {
prev[i] = row.dup;
}
//prev = input.dup;
for (int y = 0; y < prev.length; y++) {
for (int x = 0; x < prev[y].length; x++) {
if(prev[y][x] == Spot.FLOOR) {
//debug write('.');
continue;
}
import std.format;
int adjacent_taken = 0;
for (int dy = -1; dy <= 1; dy++) {
for (int dx = -1; dx <= 1; dx++) {
if (dx == 0 && dy == 0) continue;
Spot spot;
int i = 1;
do {
int nx = x + i * dx;
int ny = y + i * dy;
i++;
if (ny < 0 || ny >= prev.length || nx < 0 || nx >= prev[ny].length) {
//debug write("\x1B[41m");
spot = Spot.EMPTY;
break;
}
spot = prev[ny][nx];
} while(spot == Spot.FLOOR);
if (spot == Spot.TAKEN) {
adjacent_taken++;
}
}
}
//debug write(adjacent_taken);
//debug write("\x1B[0m");
if (adjacent_taken == 0) {
input[y][x] = Spot.TAKEN;
} else if (adjacent_taken >= 5) {
input[y][x] = Spot.EMPTY;
}
}
//debug writeln();
}
//debug writeln();
/+debug {
void printSpots(Spot[][] flop) {
foreach(row; flop) {
foreach(seat; row) {
write(seat == Spot.TAKEN ? '#' : (seat == Spot.EMPTY ? 'L' : '.'));
}
writeln();
}
}
printSpots(input);
}+/
} while(!prev.equal(input));
return input.joiner.count(Spot.TAKEN);
}
unittest {
import std.format;
string layout = q"EOS
L.LL.LL.LL
LLLLLLL.LL
L.L.L..L..
LLLL.LL.LL
L.LL.LL.LL
L.LLLLL.LL
..L.L.....
LLLLLLLLLL
L.LLLLLL.L
L.LLLLL.LL
EOS";
size_t result = parseInput(layout.lineSplitter).part2();
assert(result == 26, "Result is %d (expected 26)".format(result));
}