Finish day 17
This commit is contained in:
parent
dcc4dfce6a
commit
b28fd56a8a
|
@ -0,0 +1,27 @@
|
|||
const Builder = @import("std").build.Builder;
|
||||
|
||||
pub fn build(b: *Builder) void {
|
||||
// Standard target options allows the person running `zig build` to choose
|
||||
// what target to build for. Here we do not override the defaults, which
|
||||
// means any target is allowed, and the default is native. Other options
|
||||
// for restricting supported target set are available.
|
||||
const target = b.standardTargetOptions(.{});
|
||||
|
||||
// Standard release options allow the person running `zig build` to select
|
||||
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
|
||||
const mode = b.standardReleaseOptions();
|
||||
|
||||
const exe = b.addExecutable("day17", "src/main.zig");
|
||||
exe.setTarget(target);
|
||||
exe.setBuildMode(mode);
|
||||
exe.install();
|
||||
|
||||
const run_cmd = exe.run();
|
||||
run_cmd.step.dependOn(b.getInstallStep());
|
||||
if (b.args) |args| {
|
||||
run_cmd.addArgs(args);
|
||||
}
|
||||
|
||||
const run_step = b.step("run", "Run the app");
|
||||
run_step.dependOn(&run_cmd.step);
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
####...#
|
||||
......#.
|
||||
#..#.##.
|
||||
.#...#.#
|
||||
..###.#.
|
||||
##.###..
|
||||
.#...###
|
||||
.##....#
|
|
@ -0,0 +1,633 @@
|
|||
const std = @import("std");
|
||||
|
||||
pub fn main() anyerror!void {
|
||||
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
|
||||
defer arena.deinit();
|
||||
var gpa = &arena.allocator;
|
||||
|
||||
var f = try std.fs.cwd().openFile("input", .{});
|
||||
var contents = try f.readToEndAlloc(gpa, std.math.maxInt(u64));
|
||||
defer gpa.free(contents);
|
||||
|
||||
var sim = try Simulation.init(gpa);
|
||||
defer sim.deinit();
|
||||
|
||||
var sim4d = try Simulation4D.init(gpa);
|
||||
defer sim4d.deinit();
|
||||
|
||||
var it = std.mem.tokenize(contents, "\n");
|
||||
var y : i64 = 0;
|
||||
while (it.next()) |line| {
|
||||
for (line) |c, k| {
|
||||
var state : CubeState = .inactive;
|
||||
if (c == '#') {
|
||||
state = .active;
|
||||
}
|
||||
try sim.add_cube([_]i64 {@intCast(i64, k), y, 0}, state);
|
||||
try sim4d.add_cube([_]i64 {@intCast(i64, k), y, 0, 0}, state);
|
||||
}
|
||||
y += 1;
|
||||
}
|
||||
|
||||
// Run 6 rounds
|
||||
try sim.do_round(); // 1
|
||||
try sim.do_round(); // 2
|
||||
try sim.do_round(); // 3
|
||||
try sim.do_round(); // 4
|
||||
try sim.do_round(); // 5
|
||||
try sim.do_round(); // 6
|
||||
|
||||
std.log.info("After 6 rounds, there are {} active cubes",
|
||||
.{sim.count_active_cubes()});
|
||||
|
||||
// Part 2
|
||||
try sim4d.do_round(); // 1
|
||||
try sim4d.do_round(); // 2
|
||||
try sim4d.do_round(); // 3
|
||||
try sim4d.do_round(); // 4
|
||||
try sim4d.do_round(); // 5
|
||||
try sim4d.do_round(); // 6
|
||||
|
||||
std.log.info("After 6 rounds, there are {} active cubes",
|
||||
.{sim4d.count_active_cubes()});
|
||||
}
|
||||
|
||||
const CubeState = enum {
|
||||
inactive,
|
||||
active
|
||||
};
|
||||
|
||||
const Cube = struct {
|
||||
pos: [3]i64,
|
||||
state: CubeState = .inactive,
|
||||
next_state: ?CubeState = null,
|
||||
neighbours: u64 = 0,
|
||||
|
||||
pub fn get_neighbour_positions(self: *Cube) [26][3]i64 {
|
||||
return [_][3]i64 {
|
||||
// z-1
|
||||
[_]i64 {self.pos[0], self.pos[1], self.pos[2]-1},
|
||||
[_]i64 {self.pos[0], self.pos[1]+1, self.pos[2]-1},
|
||||
[_]i64 {self.pos[0], self.pos[1]-1, self.pos[2]-1},
|
||||
[_]i64 {self.pos[0]-1, self.pos[1], self.pos[2]-1},
|
||||
[_]i64 {self.pos[0]-1, self.pos[1]+1, self.pos[2]-1},
|
||||
[_]i64 {self.pos[0]-1, self.pos[1]-1, self.pos[2]-1},
|
||||
[_]i64 {self.pos[0]+1, self.pos[1], self.pos[2]-1},
|
||||
[_]i64 {self.pos[0]+1, self.pos[1]+1, self.pos[2]-1},
|
||||
[_]i64 {self.pos[0]+1, self.pos[1]-1, self.pos[2]-1},
|
||||
// z+0
|
||||
[_]i64 {self.pos[0], self.pos[1]+1, self.pos[2]},
|
||||
[_]i64 {self.pos[0], self.pos[1]-1, self.pos[2]},
|
||||
[_]i64 {self.pos[0]-1, self.pos[1], self.pos[2]},
|
||||
[_]i64 {self.pos[0]-1, self.pos[1]+1, self.pos[2]},
|
||||
[_]i64 {self.pos[0]-1, self.pos[1]-1, self.pos[2]},
|
||||
[_]i64 {self.pos[0]+1, self.pos[1], self.pos[2]},
|
||||
[_]i64 {self.pos[0]+1, self.pos[1]+1, self.pos[2]},
|
||||
[_]i64 {self.pos[0]+1, self.pos[1]-1, self.pos[2]},
|
||||
// z+1
|
||||
[_]i64 {self.pos[0], self.pos[1], self.pos[2]+1},
|
||||
[_]i64 {self.pos[0], self.pos[1]+1, self.pos[2]+1},
|
||||
[_]i64 {self.pos[0], self.pos[1]-1, self.pos[2]+1},
|
||||
[_]i64 {self.pos[0]-1, self.pos[1], self.pos[2]+1},
|
||||
[_]i64 {self.pos[0]-1, self.pos[1]+1, self.pos[2]+1},
|
||||
[_]i64 {self.pos[0]-1, self.pos[1]-1, self.pos[2]+1},
|
||||
[_]i64 {self.pos[0]+1, self.pos[1], self.pos[2]+1},
|
||||
[_]i64 {self.pos[0]+1, self.pos[1]+1, self.pos[2]+1},
|
||||
[_]i64 {self.pos[0]+1, self.pos[1]-1, self.pos[2]+1},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn print_state(self: *Cube) !void {
|
||||
var stdout = std.io.getStdOut().writer();
|
||||
var c : u8 = '.';
|
||||
if (self.state == .active) {
|
||||
c = '#';
|
||||
}
|
||||
try stdout.print("({}x, {}y, {}z) {c}\n", .{self.pos[0], self.pos[1], self.pos[2], c});
|
||||
}
|
||||
};
|
||||
|
||||
const Simulation = struct {
|
||||
map: std.hash_map.AutoHashMap([3]i64, Cube),
|
||||
allocator: *std.mem.Allocator,
|
||||
|
||||
pub fn init(allocator: *std.mem.Allocator) !*Simulation {
|
||||
var self = try allocator.create(Simulation);
|
||||
errdefer allocator.destroy(self);
|
||||
|
||||
self.* = Simulation {
|
||||
.map = std.hash_map.AutoHashMap([3]i64, Cube).init(allocator),
|
||||
.allocator = allocator,
|
||||
};
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Simulation) void {
|
||||
self.map.deinit();
|
||||
self.allocator.destroy(self);
|
||||
}
|
||||
|
||||
pub fn add_cube(self: *Simulation, pos: [3]i64, state: CubeState) !void {
|
||||
try self.map.put(pos, Cube {.pos = pos, .state = state});
|
||||
}
|
||||
|
||||
pub fn print_state(self: *Simulation) !void {
|
||||
// @TODO Organize the output somehow
|
||||
var stdout = std.io.getStdOut().writer();
|
||||
var z_min : i64 = std.math.maxInt(i64);
|
||||
var z_max : i64 = std.math.minInt(i64);
|
||||
var y_min : i64 = std.math.maxInt(i64);
|
||||
var y_max : i64 = std.math.minInt(i64);
|
||||
var x_min : i64 = std.math.maxInt(i64);
|
||||
var x_max : i64 = std.math.minInt(i64);
|
||||
|
||||
var it = self.map.iterator();
|
||||
while (it.next()) |entry| {
|
||||
//try entry.value.print_state();
|
||||
x_max = std.math.max(x_max, entry.value.pos[0]);
|
||||
x_min = std.math.min(x_min, entry.value.pos[0]);
|
||||
y_max = std.math.max(y_max, entry.value.pos[1]);
|
||||
y_min = std.math.min(y_min, entry.value.pos[1]);
|
||||
z_max = std.math.max(z_max, entry.value.pos[2]);
|
||||
z_min = std.math.min(z_min, entry.value.pos[2]);
|
||||
}
|
||||
|
||||
// For from lowest to highest then
|
||||
var z_pos = z_min;
|
||||
while (z_pos <= z_max) : (z_pos += 1) {
|
||||
try stdout.print("z={} x=[{}..{}],y=[{}..{}]\n", .{z_pos, x_min, x_max, y_min, y_max});
|
||||
var y_pos = y_min;
|
||||
while (y_pos <= y_max) : (y_pos += 1) {
|
||||
var x_pos = x_min;
|
||||
while (x_pos <= x_max) : (x_pos += 1) {
|
||||
//try stdout.print("({}, {}, {})\n", .{x_pos, y_pos, z_pos});
|
||||
var c : u8 = '.';
|
||||
if (self.map.get([_]i64{x_pos, y_pos, z_pos})) |cube| {
|
||||
if (cube.state == .active) {
|
||||
c = '#';
|
||||
}
|
||||
}
|
||||
try stdout.print("{c}", .{c});
|
||||
}
|
||||
_ = try stdout.write("\n");
|
||||
}
|
||||
_ = try stdout.write("\n");
|
||||
}
|
||||
_ = try stdout.write("\n");
|
||||
|
||||
}
|
||||
|
||||
pub fn print_state_neighbour_count (self: *Simulation) !void {
|
||||
// @TODO Organize the output somehow
|
||||
var stdout = std.io.getStdOut().writer();
|
||||
var z_min : i64 = std.math.maxInt(i64);
|
||||
var z_max : i64 = std.math.minInt(i64);
|
||||
var y_min : i64 = std.math.maxInt(i64);
|
||||
var y_max : i64 = std.math.minInt(i64);
|
||||
var x_min : i64 = std.math.maxInt(i64);
|
||||
var x_max : i64 = std.math.minInt(i64);
|
||||
|
||||
var it = self.map.iterator();
|
||||
while (it.next()) |entry| {
|
||||
//try entry.value.print_state();
|
||||
x_max = std.math.max(x_max, entry.value.pos[0]);
|
||||
x_min = std.math.min(x_min, entry.value.pos[0]);
|
||||
y_max = std.math.max(y_max, entry.value.pos[1]);
|
||||
y_min = std.math.min(y_min, entry.value.pos[1]);
|
||||
z_max = std.math.max(z_max, entry.value.pos[2]);
|
||||
z_min = std.math.min(z_min, entry.value.pos[2]);
|
||||
}
|
||||
|
||||
// For from lowest to highest then
|
||||
var z_pos = z_min;
|
||||
while (z_pos <= z_max) : (z_pos += 1) {
|
||||
try stdout.print("z={} x=[{}..{}],y=[{}..{}]\n", .{z_pos, x_min, x_max, y_min, y_max});
|
||||
var y_pos = y_min;
|
||||
while (y_pos <= y_max) : (y_pos += 1) {
|
||||
var x_pos = x_min;
|
||||
while (x_pos <= x_max) : (x_pos += 1) {
|
||||
//try stdout.print("({}, {}, {})\n", .{x_pos, y_pos, z_pos});
|
||||
var c : u64 = 0;
|
||||
if (self.map.get([_]i64{x_pos, y_pos, z_pos})) |cube| {
|
||||
c = cube.neighbours;
|
||||
}
|
||||
try stdout.print("{:02}", .{c});
|
||||
}
|
||||
_ = try stdout.write("\n");
|
||||
}
|
||||
_ = try stdout.write("\n");
|
||||
}
|
||||
_ = try stdout.write("\n");
|
||||
|
||||
}
|
||||
|
||||
pub fn do_round(self: *Simulation) !void {
|
||||
// For each cube, check all of it's neighbours
|
||||
var it = self.map.iterator();
|
||||
var neighbours_to_add = std.ArrayList([3]i64).init(self.allocator);
|
||||
defer neighbours_to_add.deinit();
|
||||
|
||||
// Get the neighbours we need possibly create for this round
|
||||
while (it.next()) |entry| {
|
||||
var neighbours = entry.value.get_neighbour_positions();
|
||||
var n_active : u64 = 0;
|
||||
for (neighbours) |n_pos| {
|
||||
if (self.map.get(n_pos)) |n| {
|
||||
// Noop, we already have a cube
|
||||
}
|
||||
else {
|
||||
// The neighbour doesn't yet exist, we should create it
|
||||
// but we don't want to do that while iterating over
|
||||
// the current entries.
|
||||
// We also want to make sure that we're not adding a
|
||||
// value that's already in the list to be added.
|
||||
// For the moment, we'll check that when iterating
|
||||
// over neighbours_to_add.
|
||||
try neighbours_to_add.append(n_pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add any new neighbours
|
||||
for (neighbours_to_add.items) |new_pos| {
|
||||
// Double-check we don't already have this neighbour
|
||||
if (self.map.get(new_pos)) |v| {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
try self.map.putNoClobber(new_pos, Cube {.pos = new_pos, .state = .inactive});
|
||||
}
|
||||
}
|
||||
|
||||
self.calculate_neighbour_states();
|
||||
try self.print_state_neighbour_count();
|
||||
|
||||
// Now next state should be set, we go through again to swap
|
||||
// @TODO Update state
|
||||
it = self.map.iterator();
|
||||
while (it.next()) |entry| {
|
||||
if (entry.value.state == .active) {
|
||||
if (entry.value.neighbours >= 2 and entry.value.neighbours <= 3) {
|
||||
entry.value.state = .active;
|
||||
}
|
||||
else {
|
||||
entry.value.state = .inactive;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (entry.value.neighbours == 3) {
|
||||
entry.value.state = .active;
|
||||
}
|
||||
}
|
||||
entry.value.next_state = null;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn calculate_neighbour_states(self: *Simulation) void {
|
||||
var it = self.map.iterator();
|
||||
while (it.next()) |entry| {
|
||||
var neighbours = entry.value.get_neighbour_positions();
|
||||
var n_active : u64 = 0;
|
||||
std.log.warn("Checking neighbours for ({}, {}, {})",
|
||||
.{entry.value.pos[0], entry.value.pos[1], entry.value.pos[2]});
|
||||
for (neighbours) |n_pos| {
|
||||
if (self.map.get(n_pos)) |n| {
|
||||
if (n.state == .active) {
|
||||
std.log.warn("Neighbour at ({}, {}, {}) is active",
|
||||
.{n.pos[0], n.pos[1], n.pos[2]});
|
||||
n_active += 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Noop, another function creates our neighbours, and it should
|
||||
// be run before this one.
|
||||
}
|
||||
}
|
||||
entry.value.neighbours = n_active;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn count_active_cubes(self: *Simulation) u64 {
|
||||
var it = self.map.iterator();
|
||||
var count : u64 = 0;
|
||||
while (it.next()) |entry| {
|
||||
if (entry.value.state == .active) {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
};
|
||||
|
||||
// Part 2, is just more tedious
|
||||
const Cube4D = struct {
|
||||
pos: [4]i64,
|
||||
state: CubeState = .inactive,
|
||||
neighbours: u64 = 0,
|
||||
|
||||
pub fn get_neighbour_positions(self: *Cube4D, a: *std.mem.Allocator) [80][4]i64 {
|
||||
var neighbours : [80][4]i64 = undefined;
|
||||
var x = self.pos[0]-1;
|
||||
var idx : usize = 0;
|
||||
while (x <= self.pos[0]+1) : (x += 1) {
|
||||
var y = self.pos[1]-1;
|
||||
while (y <= self.pos[1]+1) : (y +=1) {
|
||||
var z = self.pos[2]-1;
|
||||
while (z <= self.pos[2]+1) : (z +=1) {
|
||||
var w = self.pos[3]-1;
|
||||
while (w <= self.pos[3]+1) : (w+=1) {
|
||||
if (x == self.pos[0] and y == self.pos[1] and z == self.pos[2]
|
||||
and w == self.pos[3]) {
|
||||
continue;
|
||||
}
|
||||
neighbours[idx] = [_]i64{x, y, z, w};
|
||||
idx += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return neighbours;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const Simulation4D = struct {
|
||||
map: std.hash_map.AutoHashMap([4]i64, Cube4D),
|
||||
allocator: *std.mem.Allocator,
|
||||
|
||||
pub fn init(allocator: *std.mem.Allocator) !*Simulation4D {
|
||||
var self = try allocator.create(Simulation4D);
|
||||
errdefer allocator.destroy(self);
|
||||
|
||||
self.* = Simulation4D {
|
||||
.map = std.hash_map.AutoHashMap([4]i64, Cube4D).init(allocator),
|
||||
.allocator = allocator,
|
||||
};
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Simulation4D) void {
|
||||
self.map.deinit();
|
||||
self.allocator.destroy(self);
|
||||
}
|
||||
|
||||
pub fn add_cube(self: *Simulation4D, pos: [4]i64, state: CubeState) !void {
|
||||
try self.map.put(pos, Cube4D {.pos = pos, .state = state});
|
||||
}
|
||||
|
||||
// pub fn print_state(self: *Simulation) !void {
|
||||
// // @TODO Organize the output somehow
|
||||
// var stdout = std.io.getStdOut().writer();
|
||||
// var z_min : i64 = std.math.maxInt(i64);
|
||||
// var z_max : i64 = std.math.minInt(i64);
|
||||
// var y_min : i64 = std.math.maxInt(i64);
|
||||
// var y_max : i64 = std.math.minInt(i64);
|
||||
// var x_min : i64 = std.math.maxInt(i64);
|
||||
// var x_max : i64 = std.math.minInt(i64);
|
||||
|
||||
// var it = self.map.iterator();
|
||||
// while (it.next()) |entry| {
|
||||
// //try entry.value.print_state();
|
||||
// x_max = std.math.max(x_max, entry.value.pos[0]);
|
||||
// x_min = std.math.min(x_min, entry.value.pos[0]);
|
||||
// y_max = std.math.max(y_max, entry.value.pos[1]);
|
||||
// y_min = std.math.min(y_min, entry.value.pos[1]);
|
||||
// z_max = std.math.max(z_max, entry.value.pos[2]);
|
||||
// z_min = std.math.min(z_min, entry.value.pos[2]);
|
||||
// }
|
||||
|
||||
// // For from lowest to highest then
|
||||
// var z_pos = z_min;
|
||||
// while (z_pos <= z_max) : (z_pos += 1) {
|
||||
// try stdout.print("z={} x=[{}..{}],y=[{}..{}]\n", .{z_pos, x_min, x_max, y_min, y_max});
|
||||
// var y_pos = y_min;
|
||||
// while (y_pos <= y_max) : (y_pos += 1) {
|
||||
// var x_pos = x_min;
|
||||
// while (x_pos <= x_max) : (x_pos += 1) {
|
||||
// //try stdout.print("({}, {}, {})\n", .{x_pos, y_pos, z_pos});
|
||||
// var c : u8 = '.';
|
||||
// if (self.map.get([_]i64{x_pos, y_pos, z_pos})) |cube| {
|
||||
// if (cube.state == .active) {
|
||||
// c = '#';
|
||||
// }
|
||||
// }
|
||||
// try stdout.print("{c}", .{c});
|
||||
// }
|
||||
// _ = try stdout.write("\n");
|
||||
// }
|
||||
// _ = try stdout.write("\n");
|
||||
// }
|
||||
// _ = try stdout.write("\n");
|
||||
|
||||
// }
|
||||
|
||||
// pub fn print_state_neighbour_count (self: *Simulation) !void {
|
||||
// // @TODO Organize the output somehow
|
||||
// var stdout = std.io.getStdOut().writer();
|
||||
// var z_min : i64 = std.math.maxInt(i64);
|
||||
// var z_max : i64 = std.math.minInt(i64);
|
||||
// var y_min : i64 = std.math.maxInt(i64);
|
||||
// var y_max : i64 = std.math.minInt(i64);
|
||||
// var x_min : i64 = std.math.maxInt(i64);
|
||||
// var x_max : i64 = std.math.minInt(i64);
|
||||
|
||||
// var it = self.map.iterator();
|
||||
// while (it.next()) |entry| {
|
||||
// //try entry.value.print_state();
|
||||
// x_max = std.math.max(x_max, entry.value.pos[0]);
|
||||
// x_min = std.math.min(x_min, entry.value.pos[0]);
|
||||
// y_max = std.math.max(y_max, entry.value.pos[1]);
|
||||
// y_min = std.math.min(y_min, entry.value.pos[1]);
|
||||
// z_max = std.math.max(z_max, entry.value.pos[2]);
|
||||
// z_min = std.math.min(z_min, entry.value.pos[2]);
|
||||
// }
|
||||
|
||||
// // For from lowest to highest then
|
||||
// var z_pos = z_min;
|
||||
// while (z_pos <= z_max) : (z_pos += 1) {
|
||||
// try stdout.print("z={} x=[{}..{}],y=[{}..{}]\n", .{z_pos, x_min, x_max, y_min, y_max});
|
||||
// var y_pos = y_min;
|
||||
// while (y_pos <= y_max) : (y_pos += 1) {
|
||||
// var x_pos = x_min;
|
||||
// while (x_pos <= x_max) : (x_pos += 1) {
|
||||
// //try stdout.print("({}, {}, {})\n", .{x_pos, y_pos, z_pos});
|
||||
// var c : u64 = 0;
|
||||
// if (self.map.get([_]i64{x_pos, y_pos, z_pos})) |cube| {
|
||||
// c = cube.neighbours;
|
||||
// }
|
||||
// try stdout.print("{:02}", .{c});
|
||||
// }
|
||||
// _ = try stdout.write("\n");
|
||||
// }
|
||||
// _ = try stdout.write("\n");
|
||||
// }
|
||||
// _ = try stdout.write("\n");
|
||||
|
||||
// }
|
||||
|
||||
pub fn do_round(self: *Simulation4D) !void {
|
||||
// For each cube, check all of it's neighbours
|
||||
var it = self.map.iterator();
|
||||
var neighbours_to_add = std.ArrayList([4]i64).init(self.allocator);
|
||||
defer neighbours_to_add.deinit();
|
||||
|
||||
// Get the neighbours we need possibly create for this round
|
||||
while (it.next()) |entry| {
|
||||
var neighbours = entry.value.get_neighbour_positions(self.allocator);
|
||||
//defer self.allocator.free(neighbours);
|
||||
var n_active : u64 = 0;
|
||||
for (neighbours) |n_pos| {
|
||||
if (self.map.get(n_pos)) |n| {
|
||||
// Noop, we already have a cube
|
||||
}
|
||||
else {
|
||||
// The neighbour doesn't yet exist, we should create it
|
||||
// but we don't want to do that while iterating over
|
||||
// the current entries.
|
||||
// We also want to make sure that we're not adding a
|
||||
// value that's already in the list to be added.
|
||||
// For the moment, we'll check that when iterating
|
||||
// over neighbours_to_add.
|
||||
try neighbours_to_add.append(n_pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add any new neighbours
|
||||
for (neighbours_to_add.items) |new_pos| {
|
||||
// Double-check we don't already have this neighbour
|
||||
if (self.map.get(new_pos)) |v| {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
try self.map.putNoClobber(new_pos, Cube4D {.pos = new_pos, .state = .inactive});
|
||||
}
|
||||
}
|
||||
|
||||
self.calculate_neighbour_states();
|
||||
|
||||
// Now next state should be set, we go through again to swap
|
||||
// @TODO Update state
|
||||
it = self.map.iterator();
|
||||
while (it.next()) |entry| {
|
||||
if (entry.value.state == .active) {
|
||||
if (entry.value.neighbours >= 2 and entry.value.neighbours <= 3) {
|
||||
entry.value.state = .active;
|
||||
}
|
||||
else {
|
||||
entry.value.state = .inactive;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (entry.value.neighbours == 3) {
|
||||
entry.value.state = .active;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn calculate_neighbour_states(self: *Simulation4D) void {
|
||||
var it = self.map.iterator();
|
||||
while (it.next()) |entry| {
|
||||
var neighbours = entry.value.get_neighbour_positions(self.allocator);
|
||||
//defer self.allocator.free(neighbours);
|
||||
var n_active : u64 = 0;
|
||||
//std.log.warn("Checking neighbours for ({}, {}, {})",
|
||||
// .{entry.value.pos[0], entry.value.pos[1], entry.value.pos[2]});
|
||||
for (neighbours) |n_pos| {
|
||||
if (self.map.get(n_pos)) |n| {
|
||||
if (n.state == .active) {
|
||||
//std.log.warn("Neighbour at ({}, {}, {}) is active",
|
||||
// .{n.pos[0], n.pos[1], n.pos[2]});
|
||||
n_active += 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Noop, another function creates our neighbours, and it should
|
||||
// be run before this one.
|
||||
}
|
||||
}
|
||||
entry.value.neighbours = n_active;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn count_active_cubes(self: *Simulation4D) u64 {
|
||||
var it = self.map.iterator();
|
||||
var count : u64 = 0;
|
||||
while (it.next()) |entry| {
|
||||
if (entry.value.state == .active) {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
};
|
||||
|
||||
test "get_neighbour_positions" {
|
||||
var cube = Cube{
|
||||
.pos = [_]i64{0, 0, 0},
|
||||
};
|
||||
var neighbours = cube.get_neighbour_positions();
|
||||
for (neighbours) |n| {
|
||||
std.log.warn("({}, {}, {})", .{n[0], n[1], n[2]});
|
||||
}
|
||||
}
|
||||
|
||||
test "small_cubeway" {
|
||||
var sim = try Simulation.init(std.testing.allocator);
|
||||
defer sim.deinit();
|
||||
try sim.add_cube([_]i64 {0, 0, 0}, .inactive);
|
||||
try sim.add_cube([_]i64 {1, 0, 0}, .active);
|
||||
try sim.add_cube([_]i64 {2, 0, 0}, .inactive);
|
||||
|
||||
try sim.add_cube([_]i64 {0, 1, 0}, .inactive);
|
||||
try sim.add_cube([_]i64 {1, 1, 0}, .inactive);
|
||||
try sim.add_cube([_]i64 {2, 1, 0}, .active);
|
||||
|
||||
try sim.add_cube([_]i64 {0, 2, 0}, .active);
|
||||
try sim.add_cube([_]i64 {1, 2, 0}, .active);
|
||||
try sim.add_cube([_]i64 {2, 2, 0}, .active);
|
||||
|
||||
try sim.print_state();
|
||||
sim.calculate_neighbour_states();
|
||||
try sim.print_state_neighbour_count();
|
||||
std.testing.expectEqual(@as(u64, 5), sim.count_active_cubes());
|
||||
|
||||
std.log.warn("\n\n --- First round --- \n", .{});
|
||||
try sim.do_round(); // 1
|
||||
try sim.print_state();
|
||||
std.testing.expectEqual(@as(u64, 11), sim.count_active_cubes());
|
||||
|
||||
try sim.do_round(); // 2
|
||||
try sim.do_round(); // 3
|
||||
try sim.do_round(); // 4
|
||||
try sim.do_round(); // 5
|
||||
try sim.do_round(); // 6
|
||||
|
||||
var active = sim.count_active_cubes();
|
||||
std.testing.expectEqual(@as(u64, 112), active);
|
||||
}
|
||||
|
||||
test "4d_cubeway" {
|
||||
var sim = try Simulation4D.init(std.testing.allocator);
|
||||
defer sim.deinit();
|
||||
try sim.add_cube([_]i64 {0, 0, 0, 0}, .inactive);
|
||||
try sim.add_cube([_]i64 {1, 0, 0, 0}, .active);
|
||||
try sim.add_cube([_]i64 {2, 0, 0, 0}, .inactive);
|
||||
|
||||
try sim.add_cube([_]i64 {0, 1, 0, 0}, .inactive);
|
||||
try sim.add_cube([_]i64 {1, 1, 0, 0}, .inactive);
|
||||
try sim.add_cube([_]i64 {2, 1, 0, 0}, .active);
|
||||
|
||||
try sim.add_cube([_]i64 {0, 2, 0, 0}, .active);
|
||||
try sim.add_cube([_]i64 {1, 2, 0, 0}, .active);
|
||||
try sim.add_cube([_]i64 {2, 2, 0, 0}, .active);
|
||||
|
||||
try sim.do_round(); // 1
|
||||
try sim.do_round(); // 2
|
||||
try sim.do_round(); // 3
|
||||
try sim.do_round(); // 4
|
||||
try sim.do_round(); // 5
|
||||
try sim.do_round(); // 6
|
||||
|
||||
var active = sim.count_active_cubes();
|
||||
std.testing.expectEqual(@as(u64, 848), active);
|
||||
}
|
Loading…
Reference in New Issue