Finish day 15
This commit is contained in:
parent
d39285ca0f
commit
a546f1ae80
|
@ -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("day15", "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,203 @@
|
||||||
|
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(u32));
|
||||||
|
|
||||||
|
// Starting numbers 0,8,15,2,12,1,4
|
||||||
|
var seed = [_]u64 {0, 8, 15, 2, 12, 1, 4};
|
||||||
|
var game = try MemoryGame.create(gpa);
|
||||||
|
defer game.deinit();
|
||||||
|
|
||||||
|
try game.seed_game(seed[0..]);
|
||||||
|
try game.run_until(2020);
|
||||||
|
std.log.info("Round {} spoke {}", .{game.round-1, game.last_number});
|
||||||
|
|
||||||
|
// Part 2
|
||||||
|
try game.run_until(30000000);
|
||||||
|
std.log.info("Round {} spoke {}", .{game.round-1, game.last_number});
|
||||||
|
}
|
||||||
|
|
||||||
|
const NumberEntry = struct {
|
||||||
|
last: u64,
|
||||||
|
second_last: ?u64 = null,
|
||||||
|
};
|
||||||
|
|
||||||
|
const MemoryGame = struct {
|
||||||
|
map: std.hash_map.AutoHashMap(u64, NumberEntry),
|
||||||
|
allocator: *std.mem.Allocator,
|
||||||
|
round: u64 = 1, // Starting at one to match the puzzle
|
||||||
|
last_number: u64 = 0,
|
||||||
|
|
||||||
|
pub fn create(a: *std.mem.Allocator) !*MemoryGame {
|
||||||
|
var self = try a.create(MemoryGame);
|
||||||
|
errdefer a.destroy(self);
|
||||||
|
self.* = .{
|
||||||
|
.map = std.hash_map.AutoHashMap(u64, NumberEntry).init(a),
|
||||||
|
.allocator = a,
|
||||||
|
};
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *MemoryGame) void {
|
||||||
|
self.map.deinit();
|
||||||
|
self.allocator.destroy(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assumes there's not repeated number in the seed
|
||||||
|
pub fn seed_game(self: *MemoryGame, seed: []u64) !void {
|
||||||
|
for (seed) |s, k| {
|
||||||
|
try self.map.put(s, NumberEntry{.last = self.round});
|
||||||
|
self.last_number = s;
|
||||||
|
self.round += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns the number spoken, but also updates everything
|
||||||
|
pub fn do_round(self: *MemoryGame) !u64 {
|
||||||
|
// Consider last number "spoken"
|
||||||
|
// Has it been said before?
|
||||||
|
var retval : u64 = 0;
|
||||||
|
if (self.map.get(self.last_number)) |v| {
|
||||||
|
//std.log.debug("Found previously spoken number {} for round {}. Previous spoken on round {}, has a previous occurence: {}\n",
|
||||||
|
// .{self.last_number, self.round, v.last, v.second_last != null});
|
||||||
|
if ((v.last == (self.round-1)) and (v.second_last == null)) {
|
||||||
|
// The previously spoken number was new
|
||||||
|
retval = 0;
|
||||||
|
if (self.map.get(0)) |v2| {
|
||||||
|
self.map.putAssumeCapacity(0, NumberEntry {.last = self.round, .second_last = v2.last});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// 0 is our new number
|
||||||
|
try self.map.put(0, NumberEntry {.last = self.round});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// The previous number was already spoken, so we speak the diff
|
||||||
|
retval = v.last - v.second_last.?;
|
||||||
|
if (self.map.get(retval)) |v2| {
|
||||||
|
self.map.putAssumeCapacity(retval, NumberEntry {.last = self.round, .second_last = v2.last});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
try self.map.put(retval, NumberEntry {.last = self.round});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
|
self.last_number = retval;
|
||||||
|
self.round += 1;
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_until(self: *MemoryGame, target_round: u64) !void {
|
||||||
|
var last : u64 = 0;
|
||||||
|
while (self.round <= target_round) {
|
||||||
|
//std.log.warn("Round {} before running do_round()", .{self.round});
|
||||||
|
last = try self.do_round();
|
||||||
|
//std.log.warn("Round {} spoke {}", .{self.round-1, self.last_number});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
test "036_ten_turns" {
|
||||||
|
var seed = [_]u64 {0, 3, 6};
|
||||||
|
var game = try MemoryGame.create(std.testing.allocator);
|
||||||
|
defer game.deinit();
|
||||||
|
try game.seed_game(seed[0..]);
|
||||||
|
if (game.map.get(0)) |value| {
|
||||||
|
std.testing.expectEqual(value.last, 1);
|
||||||
|
}
|
||||||
|
if (game.map.get(3)) |value| {
|
||||||
|
std.testing.expectEqual(value.last, 2);
|
||||||
|
}
|
||||||
|
if (game.map.get(6)) |value| {
|
||||||
|
std.testing.expectEqual(value.last, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
var response = try game.do_round();
|
||||||
|
std.testing.expectEqual(response, 0); // Round 4
|
||||||
|
|
||||||
|
response = try game.do_round();
|
||||||
|
std.testing.expectEqual(response, 3); // Round 5
|
||||||
|
|
||||||
|
response = try game.do_round();
|
||||||
|
std.testing.expectEqual(response, 3); // ROund 6
|
||||||
|
|
||||||
|
response = try game.do_round();
|
||||||
|
std.testing.expectEqual(response, 1); // Round 7
|
||||||
|
|
||||||
|
response = try game.do_round();
|
||||||
|
std.testing.expectEqual(response, 0); // Round 8
|
||||||
|
|
||||||
|
response = try game.do_round();
|
||||||
|
std.testing.expectEqual(response, 4); // Roiund 9
|
||||||
|
|
||||||
|
response = try game.do_round();
|
||||||
|
std.testing.expectEqual(response, 0); // Round 10
|
||||||
|
}
|
||||||
|
|
||||||
|
test "132_to_2020" {
|
||||||
|
var seed = [_]u64 {1, 3, 2};
|
||||||
|
var game = try MemoryGame.create(std.testing.allocator);
|
||||||
|
defer game.deinit();
|
||||||
|
try game.seed_game(seed[0..]);
|
||||||
|
try game.run_until(2020);
|
||||||
|
//std.log.warn("Last number spoken was {}", .{game.last_number});
|
||||||
|
std.testing.expectEqual(game.last_number, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "213_to_2020" {
|
||||||
|
var seed = [_]u64 {2, 1, 3};
|
||||||
|
var game = try MemoryGame.create(std.testing.allocator);
|
||||||
|
defer game.deinit();
|
||||||
|
try game.seed_game(seed[0..]);
|
||||||
|
try game.run_until(2020);
|
||||||
|
//std.log.warn("Last number spoken was {}", .{game.last_number});
|
||||||
|
std.testing.expectEqual(game.last_number, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "123_to_2020" {
|
||||||
|
var seed = [_]u64 {1, 2, 3};
|
||||||
|
var game = try MemoryGame.create(std.testing.allocator);
|
||||||
|
defer game.deinit();
|
||||||
|
try game.seed_game(seed[0..]);
|
||||||
|
try game.run_until(2020);
|
||||||
|
//std.log.warn("Last number spoken was {}", .{game.last_number});
|
||||||
|
std.testing.expectEqual(game.last_number, 27);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "231_to_2020" {
|
||||||
|
var seed = [_]u64 {2, 3, 1};
|
||||||
|
var game = try MemoryGame.create(std.testing.allocator);
|
||||||
|
defer game.deinit();
|
||||||
|
try game.seed_game(seed[0..]);
|
||||||
|
try game.run_until(2020);
|
||||||
|
//std.log.warn("Last number spoken was {}", .{game.last_number});
|
||||||
|
std.testing.expectEqual(game.last_number, 78);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "321_to_2020" {
|
||||||
|
var seed = [_]u64 {3, 2, 1};
|
||||||
|
var game = try MemoryGame.create(std.testing.allocator);
|
||||||
|
defer game.deinit();
|
||||||
|
try game.seed_game(seed[0..]);
|
||||||
|
try game.run_until(2020);
|
||||||
|
//std.log.warn("Last number spoken was {}", .{game.last_number});
|
||||||
|
std.testing.expectEqual(game.last_number, 438);
|
||||||
|
}
|
||||||
|
|
||||||
|
test "312_to_2020" {
|
||||||
|
var seed = [_]u64 {3, 1, 2};
|
||||||
|
var game = try MemoryGame.create(std.testing.allocator);
|
||||||
|
defer game.deinit();
|
||||||
|
try game.seed_game(seed[0..]);
|
||||||
|
try game.run_until(2020);
|
||||||
|
//std.log.warn("Last number spoken was {}", .{game.last_number});
|
||||||
|
std.testing.expectEqual(game.last_number, 1836);
|
||||||
|
}
|
Reference in New Issue