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);
|
||||
}
|
Loading…
Reference in New Issue