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