mirror of
https://github.com/HenkKalkwater/aoc-2020
synced 2024-12-22 16:35:18 +00:00
Add day 17 part 2
Implemented in an overkill way by compile-time code generation
This commit is contained in:
parent
38ea587b5b
commit
1cdbb2f945
175
source/day17.d
175
source/day17.d
|
@ -1,38 +1,68 @@
|
|||
import std.format;
|
||||
|
||||
import dayutil;
|
||||
version(unittest) import fluent.asserts;
|
||||
|
||||
struct Point {
|
||||
int x, y, z;
|
||||
immutable char[26] letters = "xyzabcdefghijklmnopqrstuvw";
|
||||
|
||||
int opCmp(ref const Point p) const {
|
||||
return x - p.x + y - p.y + z - p.z;
|
||||
struct Point(size_t dim) {
|
||||
int[dim] elements;
|
||||
|
||||
int opIndex(size_t index) {
|
||||
return elements[index];
|
||||
}
|
||||
|
||||
void opIndexAssign(size_t index, int value) {
|
||||
elements[index] = value;
|
||||
}
|
||||
|
||||
mixin template element(string name, size_t index) {
|
||||
mixin("@property int %s() const { return elements[%d]; }".format(name, index));
|
||||
mixin("@property void %s(int newValue) { elements[%d] = newValue; }".format(name, index));
|
||||
}
|
||||
static foreach(i; 0..dim) {
|
||||
mixin element!([letters[i]], i);
|
||||
}
|
||||
|
||||
this(T...)(T args) {
|
||||
foreach(idx, arg; args) {
|
||||
elements[idx] = arg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Variant run(int part, File input, bool bigboy, string[] args) {
|
||||
bool[Point] parsedInput = parseInput(input.byLine);
|
||||
string[] lines = input.byLineCopy.array;
|
||||
return Variant(parts!int(part,
|
||||
() => part1(parsedInput)));
|
||||
() {
|
||||
bool[Point!3] parsedInput3 = parseInput!3(lines);
|
||||
return part1(parsedInput3);
|
||||
},
|
||||
() {
|
||||
bool[Point!4] parsedInput4 = parseInput!4(lines);
|
||||
return part2!4(parsedInput4);
|
||||
}));
|
||||
}
|
||||
|
||||
bool[Point] parseInput(Range)(Range range) if (isInputRange!Range && isSomeString!(ElementType!Range)){
|
||||
bool[Point] result;
|
||||
bool[Point!dim] parseInput(size_t dim, Range)(Range range) if (isInputRange!Range && isSomeString!(ElementType!Range) && dim >= 2){
|
||||
bool[Point!dim] result;
|
||||
foreach(y, line; range.enumerate) {
|
||||
foreach(x, c; line) {
|
||||
if (c == '#') {
|
||||
result[Point(cast(int) x, cast(int) y, 0)] = true;
|
||||
result[Point!dim(cast(int) x, cast(int) y)] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int part1(bool[Point] start) {
|
||||
int part1(bool[Point!3] start){
|
||||
alias DPoint = Point!3;
|
||||
immutable int BOOT_LENGTH = 6;
|
||||
|
||||
bool[Point] prev = start.dup;
|
||||
bool[DPoint] prev = start.dup;
|
||||
foreach(i; 0..BOOT_LENGTH) {
|
||||
bool[Point] newState = prev.dup;
|
||||
bool[DPoint] newState = prev.dup;
|
||||
assert(newState == prev);
|
||||
|
||||
int minX, minY, minZ, maxX, maxY, maxZ;
|
||||
|
@ -44,17 +74,17 @@ int part1(bool[Point] start) {
|
|||
if (e.y > maxY) maxY = e.y;
|
||||
if (e.z > maxZ) maxZ = e.z;
|
||||
}
|
||||
Point min = Point(minX - 1, minY - 1, minZ - 1);
|
||||
Point max = Point(maxX + 2, maxY + 2, maxZ + 2);
|
||||
DPoint min = DPoint(minX - 1, minY - 1, minZ - 1);
|
||||
DPoint max = DPoint(maxX + 2, maxY + 2, maxZ + 2);
|
||||
|
||||
foreach(z; min.z..max.z) {
|
||||
writeln("z=", z);
|
||||
// debug writeln("z=", z);
|
||||
foreach(y; min.y..max.y) {
|
||||
foreach(x; min.x..max.x) {
|
||||
// Point
|
||||
bool active = prev.get(Point(x,y,z), false);
|
||||
bool active = prev.get(DPoint(x,y,z), false);
|
||||
|
||||
if (active) { debug write("\x1B[42m"); }
|
||||
// debug if (active) { write("\x1B[42m"); }
|
||||
|
||||
//write(active ? '#' : '.');
|
||||
int neighboursActive = 0;
|
||||
|
@ -62,41 +92,126 @@ int part1(bool[Point] start) {
|
|||
foreach(dy; y-1..y+2) {
|
||||
foreach(dz; z-1..z+2) {
|
||||
if (dx == x && dy == y && dz == z) continue;
|
||||
if (prev.get(Point(dx, dy, dz), false)) neighboursActive++;
|
||||
if (prev.get(DPoint(dx, dy, dz), false)) neighboursActive++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (neighboursActive > 9) {
|
||||
write("+");
|
||||
} else {
|
||||
write(neighboursActive);
|
||||
}
|
||||
/+debug {
|
||||
if (neighboursActive > 9) {
|
||||
write("+");
|
||||
} else {
|
||||
write(neighboursActive);
|
||||
}
|
||||
}+/
|
||||
|
||||
if (active && (neighboursActive < 2 || neighboursActive > 3)) {
|
||||
newState[Point(x,y,z)] = false;
|
||||
newState[DPoint(x,y,z)] = false;
|
||||
} else if (!active && neighboursActive == 3) {
|
||||
newState[Point(x,y,z)] = true;
|
||||
newState[DPoint(x,y,z)] = true;
|
||||
}
|
||||
debug write("\x1B[0m");
|
||||
//debug write("\x1B[0m");
|
||||
}
|
||||
writeln();
|
||||
// debug writeln();
|
||||
}
|
||||
writeln();
|
||||
// debug writeln();
|
||||
}
|
||||
assert(newState != prev);
|
||||
|
||||
writeln("---");
|
||||
// debug writeln("---");
|
||||
prev = newState;
|
||||
}
|
||||
return cast(int) prev.byValue.count!((x) => x);
|
||||
}
|
||||
|
||||
string GenLoops(size_t dim)() {
|
||||
string code = "";
|
||||
string xyz = "";
|
||||
string dxyz = "";
|
||||
static foreach(j; 0..dim) {
|
||||
xyz ~= [letters[j]];
|
||||
dxyz ~= "d" ~ [letters[j]];
|
||||
|
||||
if (j != dim - 1) {
|
||||
xyz ~= ", ";
|
||||
dxyz ~= ", ";
|
||||
}
|
||||
}
|
||||
|
||||
static foreach(j; 0..dim) {
|
||||
|
||||
code ~= "foreach(%1$s; min[%2$s]..max[%2$s]) {\n".format(letters[j], j);
|
||||
}
|
||||
code ~= "bool active = prev.get(DPoint(" ~ xyz ~ "), false);\n";
|
||||
code ~= "int neighboursActive = 0;\n";
|
||||
|
||||
static foreach(j; 0..dim) {
|
||||
code ~= "foreach(d%1$s; %1$s-1..%1$s+2) {\n".format(letters[j]);
|
||||
}
|
||||
|
||||
code ~= "if (";
|
||||
static foreach(j; 0..dim) {
|
||||
code ~= "%1s == d%1$s".format(letters[j]);
|
||||
if (j != dim - 1) code ~= " && ";
|
||||
}
|
||||
code ~= ") continue;\n";
|
||||
|
||||
code ~= "if (prev.get(DPoint(" ~ dxyz ~ "), false)) neighboursActive++;\n";
|
||||
static foreach(j; 0..dim) {
|
||||
code ~= "}\n";
|
||||
}
|
||||
|
||||
code ~= "if (active && (neighboursActive < 2 || neighboursActive > 3)) {";
|
||||
code ~= " newState[DPoint(" ~ xyz ~ ")] = false;";
|
||||
code ~= "} else if (!active && neighboursActive == 3) {";
|
||||
code ~= " newState[DPoint(" ~ xyz ~ ")] = true;";
|
||||
code ~= "}\n";
|
||||
|
||||
static foreach(j; 0..dim) {
|
||||
code ~= "}\n";
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
int part2(size_t dim)(bool[Point!dim] start){
|
||||
alias DPoint = Point!dim;
|
||||
immutable int BOOT_LENGTH = 6;
|
||||
|
||||
bool[DPoint] prev = start.dup;
|
||||
foreach(i; 0..BOOT_LENGTH) {
|
||||
bool[DPoint] newState = prev.dup;
|
||||
assert(newState == prev);
|
||||
|
||||
int[dim] min;
|
||||
int[dim] max;
|
||||
foreach(e; prev.byKey) {
|
||||
static foreach(j; 0..dim) {
|
||||
if (e[j] < min[j]) min[j] = e[j];
|
||||
if (e[j] > max[j]) max[j] = e[j];
|
||||
}
|
||||
}
|
||||
static foreach(j; 0..dim) {
|
||||
min[j] -= 1;
|
||||
max[j] += 2;
|
||||
}
|
||||
|
||||
//writeln(GenLoops!(dim));
|
||||
mixin(GenLoops!(dim));
|
||||
|
||||
prev = newState;
|
||||
}
|
||||
return cast(int) prev.byValue.count!((x) => x);
|
||||
}
|
||||
|
||||
|
||||
unittest {
|
||||
string[] input = [
|
||||
".#.",
|
||||
"..#",
|
||||
"###"
|
||||
];
|
||||
bool[Point] parsedInput = parseInput(input);
|
||||
bool[Point!3] parsedInput = parseInput!3(input);
|
||||
bool[Point!4] parsedInput4 = parseInput!4(input);
|
||||
part1(parsedInput).should.equal(112);
|
||||
part2!3(parsedInput).should.equal(112);
|
||||
part2!4(parsedInput4).should.equal(848);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue