Finish day 15

This commit is contained in:
Kienan Stewart 2020-12-15 01:10:11 -05:00
parent d39285ca0f
commit a546f1ae80
2 changed files with 230 additions and 0 deletions

27
day15/build.zig Normal file
View File

@ -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);
}

203
day15/src/main.zig Normal file
View File

@ -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);
}