commit 4ca24e7c89556e46130635585a299b8119d92334
parent 933e5bf29707d8cf7404935b8c4bc239d817ddf3
Author: amin <dev@aminmesbah.com>
Date: Mon, 2 Dec 2019 01:03:40 +0000
Move last year's stuff into its own folder
FossilOrigin-Name: 1351a75186c43ee4b177ae3dc3f88a07f71f041c4fef9ca589a139bbb2aabb6e
Diffstat:
20 files changed, 478 insertions(+), 463 deletions(-)
diff --git a/day_01_1.zig b/2018/day_01_1.zig
diff --git a/day_01_2.zig b/2018/day_01_2.zig
diff --git a/day_02_1.zig b/2018/day_02_1.zig
diff --git a/day_02_2.zig b/2018/day_02_2.zig
diff --git a/day_03_1.zig b/2018/day_03_1.zig
diff --git a/day_03_2.zig b/2018/day_03_2.zig
diff --git a/day_04_1.zig b/2018/day_04_1.zig
diff --git a/day_04_2.zig b/2018/day_04_2.zig
diff --git a/day_05_1.zig b/2018/day_05_1.zig
diff --git a/day_05_2.zig b/2018/day_05_2.zig
diff --git a/day_06.zig b/2018/day_06.zig
diff --git a/day_07.zig b/2018/day_07.zig
diff --git a/day_08.zig b/2018/day_08.zig
diff --git a/day_09.zig b/2018/day_09.zig
diff --git a/day_10.zig b/2018/day_10.zig
diff --git a/day_11.zig b/2018/day_11.zig
diff --git a/2018/day_12.zig b/2018/day_12.zig
@@ -0,0 +1,478 @@
+const std = @import("std");
+const debug = std.debug;
+const math = std.math;
+const mem = std.mem;
+const TypeId = @import("builtin").TypeId;
+
+pub fn main() void {
+ debug.warn("state {}, rules {}\n", input_initial_state.len, input_rules.len);
+ debug.warn("state {}, rules {}\n", test_initial_state.len, test_rules.len);
+}
+
+fn Generation(comptime T: type) type {
+ return struct {
+ const Self = @This();
+
+ gen_num: usize,
+ first_plant: isize,
+ last_plant: isize,
+ pots: []const T,
+
+ fn simNextGeneration(allocator: *std.mem.Allocator, current: Self, rules: u32) Self {
+ var next_pots = std.ArrayList(T).init(allocator);
+ defer next_pots.deinit();
+
+ comptime const pot_int_highest_bit = @truncate(math.Log2Int(T), @typeInfo(T).Int.bits - 1);
+ comptime debug.assert(pot_int_highest_bit == @typeInfo(T).Int.bits - 1);
+
+ var pot_context: u5 = 0;
+ var next_pots_pot_int: T = 0;
+ var next_pot_bit = pot_int_highest_bit;
+
+ for (current.pots) |pot_int, i| {
+ if (i == 0) {
+ // Check the 3 leading pots
+ // 00000
+ // ^
+ // assign corresponding bit from rules
+ {
+ const new_pot_state = @boolToInt((rules & (u32(1) << pot_context)) != 0);
+ debug.warn("Rule result {b}\n", new_pot_state);
+ next_pots_pot_int |= T(new_pot_state) << next_pot_bit;
+ debug.warn("{x}\n", next_pots_pot_int);
+ if (new_pot_state == 1) {
+ next_pot_bit -= 1;
+ }
+ if (next_pot_bit == 0) {
+ _ = next_pots.append(next_pots_pot_int);
+ next_pots_pot_int = 0;
+ next_pot_bit = pot_int_highest_bit;
+ }
+ }
+
+ // 0000X
+ // ^
+ {
+ var shifted: u5 = 0;
+ var overflowHappened = @shlWithOverflow(u5, pot_context, 1, &shifted);
+ debug.warn("Overflow? {}\n", overflowHappened);
+
+ pot_context = shifted;
+ debug.warn("Shifted {b}\n", pot_context);
+
+ const new_bit: u1 = @boolToInt((pot_int & (T(1) << pot_int_highest_bit)) != 0);
+ pot_context |= new_bit;
+ debug.warn("With new bit {b}\n", pot_context);
+
+ // assign corresponding bit from rules
+ const new_pot_state = @boolToInt((rules & (u32(1) << pot_context)) != 0);
+ debug.warn("Rule result {b}\n", new_pot_state);
+ next_pots_pot_int |= T(new_pot_state) << next_pot_bit;
+ debug.warn("{x}\n", next_pots_pot_int);
+ if (new_pot_state == 1) {
+ next_pot_bit -= 1;
+ }
+ if (next_pot_bit == 0) {
+ _ = next_pots.append(next_pots_pot_int);
+ next_pots_pot_int = 0;
+ next_pot_bit = pot_int_highest_bit;
+ }
+ }
+
+ // 000XX
+ // ^
+ {
+ var shifted: u5 = 0;
+ var overflowHappened = @shlWithOverflow(u5, pot_context, 1, &shifted);
+ debug.warn("Overflow? {}\n", overflowHappened);
+
+ pot_context = shifted;
+ debug.warn("Shifted {b}\n", pot_context);
+
+ const new_bit: u1 = @boolToInt((pot_int & (T(1) << pot_int_highest_bit - 1)) != 0);
+ pot_context |= new_bit;
+ debug.warn("With new bit {b}\n", pot_context);
+
+ // assign corresponding bit from rules
+ const new_pot_state = @boolToInt((rules & (u32(1) << pot_context)) != 0);
+ debug.warn("Rule result {b}\n", new_pot_state);
+ next_pots_pot_int |= T(new_pot_state) << next_pot_bit;
+ debug.warn("{x}\n", next_pots_pot_int);
+ if (new_pot_state == 1) {
+ next_pot_bit -= 1;
+ }
+ if (next_pot_bit == 0) {
+ _ = next_pots.append(next_pots_pot_int);
+ next_pots_pot_int = 0;
+ next_pot_bit = pot_int_highest_bit;
+ }
+ }
+ }
+
+ var pot_bit = pot_int_highest_bit - 2;
+ while (pot_bit >= 0) : ({ pot_bit -= 1; next_pot_bit -= 1; }) {
+ var shifted: u5 = 0;
+ var overflowHappened = @shlWithOverflow(u5, pot_context, 1, &shifted);
+ debug.warn("Overflow? {}\n", overflowHappened);
+
+ pot_context = shifted;
+ debug.warn("Shifted {b}\n", pot_context);
+
+ const new_bit: u1 = @boolToInt((pot_int & (T(1) << pot_bit)) != 0);
+ pot_context |= new_bit;
+ debug.warn("With new bit {b}\n", pot_context);
+
+ // assign corresponding bit from rules
+ const new_pot_state = @boolToInt((rules & (u32(1) << pot_context)) != 0);
+ debug.warn("Rule result {b}\n", new_pot_state);
+ next_pots_pot_int |= T(new_pot_state) << next_pot_bit;
+ debug.warn("{x}\n", next_pots_pot_int);
+ if (next_pot_bit == 0) {
+ _ = next_pots.append(next_pots_pot_int);
+ next_pots_pot_int = 0;
+ next_pot_bit = pot_int_highest_bit;
+ }
+
+ if (pot_bit == 0) {
+ break;
+ }
+ }
+ _ = next_pots.append(next_pots_pot_int);
+ }
+
+ // TODO: check the 3 following pots!!
+
+ const result = Self {
+ .gen_num = current.gen_num + 1,
+ .first_plant = current.first_plant,
+ .last_plant = current.last_plant,
+ .pots = next_pots.toSlice(),
+ };
+ return result;
+ }
+ };
+}
+
+test "sim next gen" {
+ const TestPotInt = u128;
+ const TestGeneration = Generation(TestPotInt);
+ var allocator = debug.global_allocator;
+
+ const rules = rulesToInt(u32, test_rules);
+
+ var g = TestGeneration {
+ .gen_num = 0,
+ .first_plant = 0,
+ .last_plant = 24,
+ .pots = potsToIntArray(TestPotInt, test_initial_state),
+ };
+
+ var expected_first_plant: isize = undefined;
+ var expected_last_plant: isize = undefined;
+ var expected_pots: []const TestPotInt = potsToIntArray(TestPotInt, ".........................");
+
+ while (g.gen_num <= 20) {
+ debug.warn("{}\n", g.gen_num);
+ // TODO: replace this with an array of expected `Generation`s
+ switch (g.gen_num) {
+ 0 => {
+ expected_first_plant = 0;
+ expected_last_plant = 24;
+ expected_pots = potsToIntArray(TestPotInt, "#..#.#..##......###...###");
+ },
+ 1 => {
+ expected_first_plant = 0;
+ expected_last_plant = 24;
+ // TODO: Why is the assertion on this passing!?
+ expected_pots = potsToIntArray(TestPotInt, "#...#....#.....#..#..#..#");
+ },
+ 2 => {
+ expected_first_plant = 0;
+ expected_last_plant = 25;
+ expected_pots = potsToIntArray(TestPotInt, "##..##...##....#..#..#..##");
+ },
+ 3 => {
+ expected_first_plant = -1;
+ expected_last_plant = 25;
+ expected_pots = potsToIntArray(TestPotInt, "#.#...#..#.#....#..#..#...#");
+ },
+ 4 => {
+ expected_first_plant = 0;
+ expected_last_plant = 26;
+ expected_pots = potsToIntArray(TestPotInt, "#.#..#...#.#...#..#..##..##");
+ },
+ 5 => {
+ expected_first_plant = 1;
+ expected_last_plant = 26;
+ expected_pots = potsToIntArray(TestPotInt, "#...##...#.#..#..#...#...#");
+ },
+ 6 => {
+ expected_first_plant = 1;
+ expected_last_plant = 27;
+ expected_pots = potsToIntArray(TestPotInt, "##.#.#....#...#..##..##..##");
+ },
+ 7 => {
+ expected_first_plant = 0;
+ expected_last_plant = 27;
+ expected_pots = potsToIntArray(TestPotInt, "#..###.#...##..#...#...#...#");
+ },
+ 8 => {
+ expected_first_plant = 0;
+ expected_last_plant = 28;
+ expected_pots = potsToIntArray(TestPotInt, "#....##.#.#.#..##..##..##..##");
+ },
+ 9 => {
+ expected_first_plant = 0;
+ expected_last_plant = 28;
+ expected_pots = potsToIntArray(TestPotInt, "##..#..#####....#...#...#...#");
+ },
+ 10 => {
+ expected_first_plant = -1;
+ expected_last_plant = 29;
+ expected_pots = potsToIntArray(TestPotInt, "#.#..#...#.##....##..##..##..##");
+ },
+ 11 => {
+ expected_first_plant = 0;
+ expected_last_plant = 29;
+ expected_pots = potsToIntArray(TestPotInt, "#...##...#.#...#.#...#...#...#");
+ },
+ 12 => {
+ expected_first_plant = 0;
+ expected_last_plant = 30;
+ expected_pots = potsToIntArray(TestPotInt, "##.#.#....#.#...#.#..##..##..##");
+ },
+ 13 => {
+ expected_first_plant = -1;
+ expected_last_plant = 30;
+ expected_pots = potsToIntArray(TestPotInt, "#..###.#....#.#...#....#...#...#");
+ },
+ 14 => {
+ expected_first_plant = -1;
+ expected_last_plant = 31;
+ expected_pots = potsToIntArray(TestPotInt, "#....##.#....#.#..##...##..##..##");
+ },
+ 15 => {
+ expected_first_plant = -1;
+ expected_last_plant = 31;
+ expected_pots = potsToIntArray(TestPotInt, "##..#..#.#....#....#..#.#...#...#");
+ },
+ 16 => {
+ expected_first_plant = -2;
+ expected_last_plant = 32;
+ expected_pots = potsToIntArray(TestPotInt, "#.#..#...#.#...##...#...#.#..##..##");
+ },
+ 17 => {
+ expected_first_plant = -1;
+ expected_last_plant = 32;
+ expected_pots = potsToIntArray(TestPotInt, "#...##...#.#.#.#...##...#....#...#");
+ },
+ 18 => {
+ expected_first_plant = -1;
+ expected_last_plant = 33;
+ expected_pots = potsToIntArray(TestPotInt, "##.#.#....#####.#.#.#...##...##..##");
+ },
+ 19 => {
+ expected_first_plant = -2;
+ expected_last_plant = 33;
+ expected_pots = potsToIntArray(TestPotInt, "#..###.#..#.#.#######.#.#.#..#.#...#");
+ },
+ 20 => {
+ expected_first_plant = -2;
+ expected_last_plant = 34;
+ expected_pots = potsToIntArray(TestPotInt, "#....##....#####...#######....#.#..##");
+ },
+ else => unreachable,
+ }
+ debug.warn("Gen {}\n", g.gen_num);
+ debug.warn("{} == {}\n", expected_pots[0], g.pots[0]);
+ //debug.assert(expected_first_plant == g.first_plant);
+ //debug.assert(expected_last_plant == g.last_plant);
+ debug.assert(g.pots.len == 1);
+ debug.assert(expected_pots.len == 1);
+ debug.assert(expected_pots[0] == g.pots[0]);
+ debug.assert(mem.eql(TestPotInt, expected_pots, g.pots));
+ g = TestGeneration.simNextGeneration(allocator, g, rules);
+ }
+}
+
+fn rulesToInt(comptime T: type, rules: []const []const u8) T {
+ comptime {
+ debug.assert(@typeId(T) == TypeId.Int);
+ debug.assert(!@typeInfo(T).Int.is_signed);
+ }
+ debug.assert(rules.len <= @typeInfo(T).Int.bits);
+ var num: T = 0;
+
+ for (rules) |r| {
+ var it = mem.split(r, " =>");
+ const pattern = potsToInt(u8, it.next().?);
+ const result = it.next().?;
+ debug.assert(it.next() == null);
+
+ const bit_value = switch (result[0]) {
+ '.' => T(0),
+ '#' => T(1),
+ else => unreachable,
+ };
+
+ comptime const ShiftInt = math.Log2Int(T);
+ num |= bit_value << @intCast(ShiftInt, pattern);
+ }
+ return num;
+}
+
+test "rules to int" {
+ debug.assert(rulesToInt(u32, test_rules) == 0x7CA09D18);
+}
+
+fn potsToIntArray(comptime T: type, comptime pots: []const u8) []const T {
+ comptime {
+ debug.assert(!@typeInfo(T).Int.is_signed);
+ }
+ comptime const int_bits = @typeInfo(T).Int.bits;
+
+ // round up to account for remainder pots
+ comptime const result_array_len: usize = (pots.len + int_bits - 1) / int_bits;
+
+ var result = []T{0} ** result_array_len;
+
+ for (result) |*elem, i| {
+ const pot_slice_index = i * int_bits;
+
+ var pot_slice: []const u8 = undefined;
+
+ if (i == result.len - 1) {
+ // we need right-padding
+ var padded_pots = "." ** int_bits;
+ for (pots[pot_slice_index..]) |p, p_i| {
+ padded_pots[p_i] = p;
+ }
+ pot_slice = padded_pots;
+ } else {
+ const next_slice_index = pot_slice_index + int_bits;
+ pot_slice = pots[pot_slice_index..next_slice_index];
+ }
+
+ elem.* = potsToInt(T, pot_slice);
+ }
+
+ return result;
+}
+
+test "pots to int array" {
+ {
+ const potArray = potsToIntArray(u8, test_initial_state);
+ debug.assert(potArray.len == 4);
+ debug.assert(potArray[0] == 0x94); // #..#.#..
+ debug.assert(potArray[1] == 0xC0); // ##......
+ debug.assert(potArray[2] == 0xE3); // ###...##
+ debug.assert(potArray[3] == 0x80); // #.......
+ }
+
+ {
+ const potArray = potsToIntArray(u32, test_initial_state);
+ debug.assert(potArray.len == 1);
+ debug.assert(potArray[0] == 0x94C0E380);
+ }
+}
+
+fn potsToInt(comptime T: type, pots: []const u8) T {
+ comptime {
+ debug.assert(@typeId(T) == TypeId.Int);
+ debug.assert(!@typeInfo(T).Int.is_signed);
+ }
+ comptime const int_bits = @typeInfo(T).Int.bits;
+ debug.assert(pots.len <= int_bits);
+
+ var num: T = 0;
+ var i: u8 = 0;
+
+ for (pots) |p| {
+ if (p == '#') {
+ comptime const ShiftInt = math.Log2Int(T);
+ num |= T(1) << @intCast(ShiftInt, pots.len - 1 - i);
+ }
+ i += 1;
+ }
+ return num;
+}
+
+test "pots to int" {
+ debug.assert(potsToInt(u8, ".....") == 0);
+ debug.assert(potsToInt(u8, "....#") == 1);
+ debug.assert(potsToInt(u8, "...##") == 3);
+ debug.assert(potsToInt(u8, "..###") == 7);
+ debug.assert(potsToInt(u8, ".####") == 15);
+ debug.assert(potsToInt(u8, "#####") == 31);
+ debug.assert(potsToInt(u8, "####.") == 30);
+ debug.assert(potsToInt(u8, "###..") == 28);
+ debug.assert(potsToInt(u8, "##...") == 24);
+ debug.assert(potsToInt(u8, "#....") == 16);
+ debug.assert(potsToInt(u8, "#") == 1);
+ debug.assert(potsToInt(u5, "#####") == 31);
+ debug.assert(potsToInt(u128, ".#.#.") == 10);
+ debug.assert(potsToInt(u128, "#.#.#") == 21);
+ debug.assert(potsToInt(u32, test_initial_state) == 0x12981C7);
+ debug.assert(potsToInt(u128, input_initial_state) == 0xC9A1A56AFCD5E918842DC9C44);
+}
+
+const test_initial_state = "#..#.#..##......###...###";
+
+const test_rules = []const []const u8 {
+ "...## => #",
+ "..#.. => #",
+ ".#... => #",
+ ".#.#. => #",
+ ".#.## => #",
+ ".##.. => #",
+ ".#### => #",
+ "#.#.# => #",
+ "#.### => #",
+ "##.#. => #",
+ "##.## => #",
+ "###.. => #",
+ "###.# => #",
+ "####. => #",
+};
+
+const input_initial_state = "##..#..##.#....##.#..#.#.##.#.#.######..##.#.#.####.#..#...##...#....#....#.##.###..#..###...#...#..";
+
+// Hey, look at that:
+// - there are exactly 32 rules
+// - the patterns, if interpreted as bits, correspond to u8 0 through 31
+// - the results, by themselves, could fit in a single u32
+// That's... interesting...
+const input_rules = []const []const u8 {
+ "#..#. => .",
+ ".#..# => #",
+ "..#.# => .",
+ "..... => .",
+ ".#... => #",
+ "#..## => #",
+ "..##. => #",
+ "#.##. => #",
+ "#.#.# => .",
+ "###.# => #",
+ ".#### => .",
+ "..### => .",
+ ".###. => .",
+ "#.#.. => #",
+ "###.. => .",
+ "##.#. => .",
+ "##..# => .",
+ "##.## => .",
+ "#.### => .",
+ "...## => #",
+ "##... => #",
+ "####. => .",
+ ".#.## => .",
+ "#...# => #",
+ ".#.#. => #",
+ "....# => .",
+ ".##.. => .",
+ "...#. => .",
+ "..#.. => .",
+ "#.... => .",
+ ".##.# => #",
+ "##### => #",
+};
diff --git a/input_01.txt b/2018/input_01.txt
diff --git a/input_08.txt b/2018/input_08.txt
diff --git a/day_12.zig b/day_12.zig
@@ -1,463 +0,0 @@
-const std = @import("std");
-const debug = std.debug;
-const math = std.math;
-const mem = std.mem;
-const TypeId = @import("builtin").TypeId;
-
-pub fn main() void {
- debug.warn("state {}, rules {}\n", input_initial_state.len, input_rules.len);
- debug.warn("state {}, rules {}\n", test_initial_state.len, test_rules.len);
-}
-
-fn Generation(comptime T: type) type {
- return struct {
- const Self = @This();
-
- gen_num: usize,
- first_plant: isize,
- last_plant: isize,
- pots: []const T,
-
- fn simNextGeneration(allocator: *std.mem.Allocator, current: Self, rules: u32) Self {
- var next_pots = std.ArrayList(T).init(allocator);
- defer next_pots.deinit();
-
- comptime const pot_int_highest_bit = @truncate(math.Log2Int(T), @typeInfo(T).Int.bits - 1);
- comptime debug.assert(pot_int_highest_bit == @typeInfo(T).Int.bits - 1);
-
- var pot_context: u5 = 0;
- var next_pots_pot_int: T = 0;
- var next_pot_bit = pot_int_highest_bit;
-
- for (current.pots) |pot_int, i| {
- if (i == 0) {
- // Check the 3 leading pots
- // 00000
- // ^
- // assign corresponding bit from rules
- {
- const new_pot_state = @boolToInt((rules & (u32(1) << pot_context)) != 0);
- debug.warn("Rule result {b}\n", new_pot_state);
- next_pots_pot_int |= T(new_pot_state) << next_pot_bit;
- debug.warn("{x}\n", next_pots_pot_int);
- if (next_pot_bit == 0) {
- _ = next_pots.append(next_pots_pot_int);
- next_pots_pot_int = 0;
- next_pot_bit = pot_int_highest_bit;
- }
- }
-
- // 0000X
- // ^
- {
- var shifted: u5 = 0;
- var overflowHappened = @shlWithOverflow(u5, pot_context, 1, &shifted);
- debug.warn("Overflow? {}\n", overflowHappened);
-
- pot_context = shifted;
- debug.warn("Shifted {b}\n", pot_context);
-
- const new_bit: u1 = @boolToInt((pot_int & (T(1) << pot_int_highest_bit)) != 0);
- pot_context |= new_bit;
- debug.warn("With new bit {b}\n", pot_context);
-
- // assign corresponding bit from rules
- const new_pot_state = @boolToInt((rules & (u32(1) << pot_context)) != 0);
- debug.warn("Rule result {b}\n", new_pot_state);
- next_pots_pot_int |= T(new_pot_state) << next_pot_bit;
- debug.warn("{x}\n", next_pots_pot_int);
- if (next_pot_bit == 0) {
- _ = next_pots.append(next_pots_pot_int);
- next_pots_pot_int = 0;
- next_pot_bit = pot_int_highest_bit;
- }
- }
-
- // 000XX
- // ^
- {
- var shifted: u5 = 0;
- var overflowHappened = @shlWithOverflow(u5, pot_context, 1, &shifted);
- debug.warn("Overflow? {}\n", overflowHappened);
-
- pot_context = shifted;
- debug.warn("Shifted {b}\n", pot_context);
-
- const new_bit: u1 = @boolToInt((pot_int & (T(1) << pot_int_highest_bit - 1)) != 0);
- pot_context |= new_bit;
- debug.warn("With new bit {b}\n", pot_context);
-
- // assign corresponding bit from rules
- const new_pot_state = @boolToInt((rules & (u32(1) << pot_context)) != 0);
- debug.warn("Rule result {b}\n", new_pot_state);
- next_pots_pot_int |= T(new_pot_state) << next_pot_bit;
- debug.warn("{x}\n", next_pots_pot_int);
- }
- }
-
- var pot_bit = pot_int_highest_bit - 2;
- while (pot_bit >= 0) : ({ pot_bit -= 1; next_pot_bit -= 1; }) {
- var shifted: u5 = 0;
- var overflowHappened = @shlWithOverflow(u5, pot_context, 1, &shifted);
- debug.warn("Overflow? {}\n", overflowHappened);
-
- pot_context = shifted;
- debug.warn("Shifted {b}\n", pot_context);
-
- const new_bit: u1 = @boolToInt((pot_int & (T(1) << pot_bit)) != 0);
- pot_context |= new_bit;
- debug.warn("With new bit {b}\n", pot_context);
-
- // assign corresponding bit from rules
- const new_pot_state = @boolToInt((rules & (u32(1) << pot_context)) != 0);
- debug.warn("Rule result {b}\n", new_pot_state);
- next_pots_pot_int |= T(new_pot_state) << next_pot_bit;
- debug.warn("{x}\n", next_pots_pot_int);
- if (next_pot_bit == 0) {
- _ = next_pots.append(next_pots_pot_int);
- next_pots_pot_int = 0;
- next_pot_bit = pot_int_highest_bit;
- }
-
- if (pot_bit == 0) {
- break;
- }
- }
- _ = next_pots.append(next_pots_pot_int);
- }
-
- // TODO: check the 3 following pots!!
-
- const result = Self {
- .gen_num = current.gen_num + 1,
- .first_plant = current.first_plant,
- .last_plant = current.last_plant,
- .pots = next_pots.toSlice(),
- };
- return result;
- }
- };
-}
-
-test "sim next gen" {
- const TestPotInt = u128;
- const TestGeneration = Generation(TestPotInt);
- var allocator = debug.global_allocator;
-
- const rules = rulesToInt(u32, test_rules);
-
- var g = TestGeneration {
- .gen_num = 0,
- .first_plant = 0,
- .last_plant = 24,
- .pots = potsToIntArray(TestPotInt, test_initial_state),
- };
-
- var expected_first_plant: isize = undefined;
- var expected_last_plant: isize = undefined;
- var expected_pots: []const TestPotInt = potsToIntArray(TestPotInt, ".........................");
-
- while (g.gen_num <= 20) {
- debug.warn("{}\n", g.gen_num);
- // TODO: replace this with an array of expected `Generation`s
- switch (g.gen_num) {
- 0 => {
- expected_first_plant = 0;
- expected_last_plant = 24;
- expected_pots = potsToIntArray(TestPotInt, "#..#.#..##......###...###");
- },
- 1 => {
- expected_first_plant = 0;
- expected_last_plant = 24;
- // TODO: Why is the assertion on this passing!?
- expected_pots = potsToIntArray(TestPotInt, "#...#....#.....#..#..#..#");
- },
- 2 => {
- expected_first_plant = 0;
- expected_last_plant = 25;
- expected_pots = potsToIntArray(TestPotInt, "##..##...##....#..#..#..##");
- },
- 3 => {
- expected_first_plant = -1;
- expected_last_plant = 25;
- expected_pots = potsToIntArray(TestPotInt, "#.#...#..#.#....#..#..#...#");
- },
- 4 => {
- expected_first_plant = 0;
- expected_last_plant = 26;
- expected_pots = potsToIntArray(TestPotInt, "#.#..#...#.#...#..#..##..##");
- },
- 5 => {
- expected_first_plant = 1;
- expected_last_plant = 26;
- expected_pots = potsToIntArray(TestPotInt, "#...##...#.#..#..#...#...#");
- },
- 6 => {
- expected_first_plant = 1;
- expected_last_plant = 27;
- expected_pots = potsToIntArray(TestPotInt, "##.#.#....#...#..##..##..##");
- },
- 7 => {
- expected_first_plant = 0;
- expected_last_plant = 27;
- expected_pots = potsToIntArray(TestPotInt, "#..###.#...##..#...#...#...#");
- },
- 8 => {
- expected_first_plant = 0;
- expected_last_plant = 28;
- expected_pots = potsToIntArray(TestPotInt, "#....##.#.#.#..##..##..##..##");
- },
- 9 => {
- expected_first_plant = 0;
- expected_last_plant = 28;
- expected_pots = potsToIntArray(TestPotInt, "##..#..#####....#...#...#...#");
- },
- 10 => {
- expected_first_plant = -1;
- expected_last_plant = 29;
- expected_pots = potsToIntArray(TestPotInt, "#.#..#...#.##....##..##..##..##");
- },
- 11 => {
- expected_first_plant = 0;
- expected_last_plant = 29;
- expected_pots = potsToIntArray(TestPotInt, "#...##...#.#...#.#...#...#...#");
- },
- 12 => {
- expected_first_plant = 0;
- expected_last_plant = 30;
- expected_pots = potsToIntArray(TestPotInt, "##.#.#....#.#...#.#..##..##..##");
- },
- 13 => {
- expected_first_plant = -1;
- expected_last_plant = 30;
- expected_pots = potsToIntArray(TestPotInt, "#..###.#....#.#...#....#...#...#");
- },
- 14 => {
- expected_first_plant = -1;
- expected_last_plant = 31;
- expected_pots = potsToIntArray(TestPotInt, "#....##.#....#.#..##...##..##..##");
- },
- 15 => {
- expected_first_plant = -1;
- expected_last_plant = 31;
- expected_pots = potsToIntArray(TestPotInt, "##..#..#.#....#....#..#.#...#...#");
- },
- 16 => {
- expected_first_plant = -2;
- expected_last_plant = 32;
- expected_pots = potsToIntArray(TestPotInt, "#.#..#...#.#...##...#...#.#..##..##");
- },
- 17 => {
- expected_first_plant = -1;
- expected_last_plant = 32;
- expected_pots = potsToIntArray(TestPotInt, "#...##...#.#.#.#...##...#....#...#");
- },
- 18 => {
- expected_first_plant = -1;
- expected_last_plant = 33;
- expected_pots = potsToIntArray(TestPotInt, "##.#.#....#####.#.#.#...##...##..##");
- },
- 19 => {
- expected_first_plant = -2;
- expected_last_plant = 33;
- expected_pots = potsToIntArray(TestPotInt, "#..###.#..#.#.#######.#.#.#..#.#...#");
- },
- 20 => {
- expected_first_plant = -2;
- expected_last_plant = 34;
- expected_pots = potsToIntArray(TestPotInt, "#....##....#####...#######....#.#..##");
- },
- else => unreachable,
- }
- debug.warn("{} == {}\n", expected_pots[0], g.pots[0]);
- debug.assert(expected_first_plant == g.first_plant);
- debug.assert(expected_last_plant == g.last_plant);
- debug.assert(g.pots.len == 1);
- debug.assert(expected_pots.len == 1);
- //debug.assert(mem.eql(TestPotInt, expected_pots, g.pots));
- debug.assert(expected_pots[0] == g.pots[0]);
- g = TestGeneration.simNextGeneration(allocator, g, rules);
- }
-}
-
-fn rulesToInt(comptime T: type, rules: []const []const u8) T {
- comptime {
- debug.assert(@typeId(T) == TypeId.Int);
- debug.assert(!@typeInfo(T).Int.is_signed);
- }
- debug.assert(rules.len <= @typeInfo(T).Int.bits);
- var num: T = 0;
-
- for (rules) |r| {
- var it = mem.split(r, " =>");
- const pattern = potsToInt(u8, it.next().?);
- const result = it.next().?;
- debug.assert(it.next() == null);
-
- const bit_value = switch (result[0]) {
- '.' => T(0),
- '#' => T(1),
- else => unreachable,
- };
-
- comptime const ShiftInt = math.Log2Int(T);
- num |= bit_value << @intCast(ShiftInt, pattern);
- }
- return num;
-}
-
-test "rules to int" {
- debug.assert(rulesToInt(u32, test_rules) == 0x7CA09D18);
-}
-
-fn potsToIntArray(comptime T: type, comptime pots: []const u8) []const T {
- comptime {
- debug.assert(!@typeInfo(T).Int.is_signed);
- }
- comptime const int_bits = @typeInfo(T).Int.bits;
-
- // round up to account for remainder pots
- comptime const result_array_len: usize = (pots.len + int_bits - 1) / int_bits;
-
- var result = []T{0} ** result_array_len;
-
- for (result) |*elem, i| {
- const pot_slice_index = i * int_bits;
-
- var pot_slice: []const u8 = undefined;
-
- if (i == result.len - 1) {
- // we need right-padding
- var padded_pots = "." ** int_bits;
- for (pots[pot_slice_index..]) |p, p_i| {
- padded_pots[p_i] = p;
- }
- pot_slice = padded_pots;
- } else {
- const next_slice_index = pot_slice_index + int_bits;
- pot_slice = pots[pot_slice_index..next_slice_index];
- }
-
- elem.* = potsToInt(T, pot_slice);
- }
-
- return result;
-}
-
-test "pots to int array" {
- {
- const potArray = potsToIntArray(u8, test_initial_state);
- debug.assert(potArray.len == 4);
- debug.assert(potArray[0] == 0x94); // #..#.#..
- debug.assert(potArray[1] == 0xC0); // ##......
- debug.assert(potArray[2] == 0xE3); // ###...##
- debug.assert(potArray[3] == 0x80); // #.......
- }
-
- {
- const potArray = potsToIntArray(u32, test_initial_state);
- debug.assert(potArray.len == 1);
- debug.assert(potArray[0] == 0x94C0E380);
- }
-}
-
-fn potsToInt(comptime T: type, pots: []const u8) T {
- comptime {
- debug.assert(@typeId(T) == TypeId.Int);
- debug.assert(!@typeInfo(T).Int.is_signed);
- }
- comptime const int_bits = @typeInfo(T).Int.bits;
- debug.assert(pots.len <= int_bits);
-
- var num: T = 0;
- var i: u8 = 0;
-
- for (pots) |p| {
- if (p == '#') {
- comptime const ShiftInt = math.Log2Int(T);
- num |= T(1) << @intCast(ShiftInt, pots.len - 1 - i);
- }
- i += 1;
- }
- return num;
-}
-
-test "pots to int" {
- debug.assert(potsToInt(u8, ".....") == 0);
- debug.assert(potsToInt(u8, "....#") == 1);
- debug.assert(potsToInt(u8, "...##") == 3);
- debug.assert(potsToInt(u8, "..###") == 7);
- debug.assert(potsToInt(u8, ".####") == 15);
- debug.assert(potsToInt(u8, "#####") == 31);
- debug.assert(potsToInt(u8, "####.") == 30);
- debug.assert(potsToInt(u8, "###..") == 28);
- debug.assert(potsToInt(u8, "##...") == 24);
- debug.assert(potsToInt(u8, "#....") == 16);
- debug.assert(potsToInt(u8, "#") == 1);
- debug.assert(potsToInt(u5, "#####") == 31);
- debug.assert(potsToInt(u128, ".#.#.") == 10);
- debug.assert(potsToInt(u128, "#.#.#") == 21);
- debug.assert(potsToInt(u32, test_initial_state) == 0x12981C7);
- debug.assert(potsToInt(u128, input_initial_state) == 0xC9A1A56AFCD5E918842DC9C44);
-}
-
-const test_initial_state = "#..#.#..##......###...###";
-
-const test_rules = []const []const u8 {
- "...## => #",
- "..#.. => #",
- ".#... => #",
- ".#.#. => #",
- ".#.## => #",
- ".##.. => #",
- ".#### => #",
- "#.#.# => #",
- "#.### => #",
- "##.#. => #",
- "##.## => #",
- "###.. => #",
- "###.# => #",
- "####. => #",
-};
-
-const input_initial_state = "##..#..##.#....##.#..#.#.##.#.#.######..##.#.#.####.#..#...##...#....#....#.##.###..#..###...#...#..";
-
-// Hey, look at that:
-// - there are exactly 32 rules
-// - the patterns, if interpreted as bits, correspond to u8 0 through 31
-// - the results, by themselves, could fit in a single u32
-// That's... interesting...
-const input_rules = []const []const u8 {
- "#..#. => .",
- ".#..# => #",
- "..#.# => .",
- "..... => .",
- ".#... => #",
- "#..## => #",
- "..##. => #",
- "#.##. => #",
- "#.#.# => .",
- "###.# => #",
- ".#### => .",
- "..### => .",
- ".###. => .",
- "#.#.. => #",
- "###.. => .",
- "##.#. => .",
- "##..# => .",
- "##.## => .",
- "#.### => .",
- "...## => #",
- "##... => #",
- "####. => .",
- ".#.## => .",
- "#...# => #",
- ".#.#. => #",
- "....# => .",
- ".##.. => .",
- "...#. => .",
- "..#.. => .",
- "#.... => .",
- ".##.# => #",
- "##### => #",
-};