mirror of
https://github.com/HenkKalkwater/aoc-2020
synced 2024-11-22 11:05:18 +00:00
Day 17: improve doc, fix Point bug
Accidentily swapped the arguments of opIndexAssign, which caused auto p = Point!2(1,2) p[0] = 3; assert(p.x == 3) to fail
This commit is contained in:
parent
1cdbb2f945
commit
34c56ba047
|
@ -3,8 +3,11 @@ import std.format;
|
||||||
import dayutil;
|
import dayutil;
|
||||||
version(unittest) import fluent.asserts;
|
version(unittest) import fluent.asserts;
|
||||||
|
|
||||||
immutable char[26] letters = "xyzabcdefghijklmnopqrstuvw";
|
immutable char[26] letters = "xyzwvutsrqpomnlkjihgfedcba";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A point with 'dim' dimensions.
|
||||||
|
*/
|
||||||
struct Point(size_t dim) {
|
struct Point(size_t dim) {
|
||||||
int[dim] elements;
|
int[dim] elements;
|
||||||
|
|
||||||
|
@ -12,7 +15,7 @@ struct Point(size_t dim) {
|
||||||
return elements[index];
|
return elements[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
void opIndexAssign(size_t index, int value) {
|
void opIndexAssign(T : int) (T value, size_t index) {
|
||||||
elements[index] = value;
|
elements[index] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +23,7 @@ struct Point(size_t dim) {
|
||||||
mixin("@property int %s() const { return elements[%d]; }".format(name, index));
|
mixin("@property int %s() const { return elements[%d]; }".format(name, index));
|
||||||
mixin("@property void %s(int newValue) { elements[%d] = newValue; }".format(name, index));
|
mixin("@property void %s(int newValue) { elements[%d] = newValue; }".format(name, index));
|
||||||
}
|
}
|
||||||
|
|
||||||
static foreach(i; 0..dim) {
|
static foreach(i; 0..dim) {
|
||||||
mixin element!([letters[i]], i);
|
mixin element!([letters[i]], i);
|
||||||
}
|
}
|
||||||
|
@ -31,6 +35,21 @@ struct Point(size_t dim) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
unittest {
|
||||||
|
Point!4 p = Point!4(5,2,3);
|
||||||
|
p.x.should.equal(p[0]);
|
||||||
|
p.x.should.equal(5);
|
||||||
|
|
||||||
|
p.x = 9;
|
||||||
|
p[0].should.equal(9);
|
||||||
|
|
||||||
|
p[0] = 1;
|
||||||
|
p.x.should.equal(1);
|
||||||
|
|
||||||
|
assert(p.w == 0);
|
||||||
|
}
|
||||||
|
|
||||||
Variant run(int part, File input, bool bigboy, string[] args) {
|
Variant run(int part, File input, bool bigboy, string[] args) {
|
||||||
string[] lines = input.byLineCopy.array;
|
string[] lines = input.byLineCopy.array;
|
||||||
return Variant(parts!int(part,
|
return Variant(parts!int(part,
|
||||||
|
@ -123,10 +142,16 @@ int part1(bool[Point!3] start){
|
||||||
return cast(int) prev.byValue.count!((x) => x);
|
return cast(int) prev.byValue.count!((x) => x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generates code for the nested loops within part2
|
||||||
|
* Params:
|
||||||
|
* dim: The amount of dimensions the pocket dimensions has
|
||||||
|
* Returns: the generated code as a string
|
||||||
|
*/
|
||||||
string GenLoops(size_t dim)() {
|
string GenLoops(size_t dim)() {
|
||||||
string code = "";
|
string code = ""; // The generated code
|
||||||
string xyz = "";
|
string xyz = ""; // Generates the string x, y, z, w, ...
|
||||||
string dxyz = "";
|
string dxyz = ""; // Genereates the string dx, dy, dz, dw, ...
|
||||||
static foreach(j; 0..dim) {
|
static foreach(j; 0..dim) {
|
||||||
xyz ~= [letters[j]];
|
xyz ~= [letters[j]];
|
||||||
dxyz ~= "d" ~ [letters[j]];
|
dxyz ~= "d" ~ [letters[j]];
|
||||||
|
@ -137,17 +162,19 @@ string GenLoops(size_t dim)() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Generate outer loop to go over each point
|
||||||
static foreach(j; 0..dim) {
|
static foreach(j; 0..dim) {
|
||||||
|
|
||||||
code ~= "foreach(%1$s; min[%2$s]..max[%2$s]) {\n".format(letters[j], j);
|
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 ~= "bool active = prev.get(DPoint(" ~ xyz ~ "), false);\n";
|
||||||
code ~= "int neighboursActive = 0;\n";
|
code ~= "int neighboursActive = 0;\n";
|
||||||
|
|
||||||
|
// Generate code to loop over the neighbours
|
||||||
static foreach(j; 0..dim) {
|
static foreach(j; 0..dim) {
|
||||||
code ~= "foreach(d%1$s; %1$s-1..%1$s+2) {\n".format(letters[j]);
|
code ~= "foreach(d%1$s; %1$s-1..%1$s+2) {\n".format(letters[j]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skip if the current coördinate is not a neighbour, but our current node itself.
|
||||||
code ~= "if (";
|
code ~= "if (";
|
||||||
static foreach(j; 0..dim) {
|
static foreach(j; 0..dim) {
|
||||||
code ~= "%1s == d%1$s".format(letters[j]);
|
code ~= "%1s == d%1$s".format(letters[j]);
|
||||||
|
@ -155,17 +182,22 @@ string GenLoops(size_t dim)() {
|
||||||
}
|
}
|
||||||
code ~= ") continue;\n";
|
code ~= ") continue;\n";
|
||||||
|
|
||||||
|
// Increment the activeNeighbours count if the neighbour we're visiting is active
|
||||||
code ~= "if (prev.get(DPoint(" ~ dxyz ~ "), false)) neighboursActive++;\n";
|
code ~= "if (prev.get(DPoint(" ~ dxyz ~ "), false)) neighboursActive++;\n";
|
||||||
|
|
||||||
|
// Generate closing brackers for the inner loop
|
||||||
static foreach(j; 0..dim) {
|
static foreach(j; 0..dim) {
|
||||||
code ~= "}\n";
|
code ~= "}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the current point should stay active.
|
||||||
code ~= "if (active && (neighboursActive < 2 || neighboursActive > 3)) {";
|
code ~= "if (active && (neighboursActive < 2 || neighboursActive > 3)) {";
|
||||||
code ~= " newState[DPoint(" ~ xyz ~ ")] = false;";
|
code ~= " newState[DPoint(" ~ xyz ~ ")] = false;";
|
||||||
code ~= "} else if (!active && neighboursActive == 3) {";
|
code ~= "} else if (!active && neighboursActive == 3) {";
|
||||||
code ~= " newState[DPoint(" ~ xyz ~ ")] = true;";
|
code ~= " newState[DPoint(" ~ xyz ~ ")] = true;";
|
||||||
code ~= "}\n";
|
code ~= "}\n";
|
||||||
|
|
||||||
|
// Generate closing brackers for the outer loop
|
||||||
static foreach(j; 0..dim) {
|
static foreach(j; 0..dim) {
|
||||||
code ~= "}\n";
|
code ~= "}\n";
|
||||||
}
|
}
|
||||||
|
@ -184,6 +216,7 @@ int part2(size_t dim)(bool[Point!dim] start){
|
||||||
int[dim] min;
|
int[dim] min;
|
||||||
int[dim] max;
|
int[dim] max;
|
||||||
foreach(e; prev.byKey) {
|
foreach(e; prev.byKey) {
|
||||||
|
// Determine the bounds for each dimension
|
||||||
static foreach(j; 0..dim) {
|
static foreach(j; 0..dim) {
|
||||||
if (e[j] < min[j]) min[j] = e[j];
|
if (e[j] < min[j]) min[j] = e[j];
|
||||||
if (e[j] > max[j]) max[j] = e[j];
|
if (e[j] > max[j]) max[j] = e[j];
|
||||||
|
@ -194,7 +227,10 @@ int part2(size_t dim)(bool[Point!dim] start){
|
||||||
max[j] += 2;
|
max[j] += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
//writeln(GenLoops!(dim));
|
//debug writeln(GenLoops!(dim));
|
||||||
|
|
||||||
|
// Sadly, the only way I am a ware of to generate dim amount of nested loops
|
||||||
|
// is by using mixins
|
||||||
mixin(GenLoops!(dim));
|
mixin(GenLoops!(dim));
|
||||||
|
|
||||||
prev = newState;
|
prev = newState;
|
||||||
|
|
Loading…
Reference in a new issue