From 09db23ada1f1afac3d1dd97b666e51a66a6c391b Mon Sep 17 00:00:00 2001 From: Alexey Plutalov Date: Wed, 13 Nov 2024 18:03:02 +0300 Subject: [PATCH] add solutions for 2015/03 --- native/solutions/2015/03/common.zig | 184 +++++++++++++++++++++++++ native/solutions/2015/03/input.fixture | 1 + native/solutions/2015/03/part_1.zig | 43 ++++++ native/solutions/2015/03/part_2.zig | 54 ++++++++ native/solutions/registry.zig | 2 + native/solutions/solutions.zig | 2 + 6 files changed, 286 insertions(+) create mode 100644 native/solutions/2015/03/common.zig create mode 100644 native/solutions/2015/03/input.fixture create mode 100644 native/solutions/2015/03/part_1.zig create mode 100644 native/solutions/2015/03/part_2.zig diff --git a/native/solutions/2015/03/common.zig b/native/solutions/2015/03/common.zig new file mode 100644 index 0000000..f750024 --- /dev/null +++ b/native/solutions/2015/03/common.zig @@ -0,0 +1,184 @@ +const std = @import("std"); + +const AnyReader = std.io.AnyReader; +const Direction = enum { north, south, east, west }; + +pub const Parser = struct { + is_end: bool, + is_invalid: bool, + + reader: AnyReader, + + pub fn init(reader: AnyReader) Parser { + return .{ + .is_end = false, + .is_invalid = false, + + .reader = reader, + }; + } + + pub fn read(self: *Parser) !Direction { + if (self.is_invalid) { + return error.InvalidInput; + } + + if (self.is_end) { + return error.EndOfStream; + } + + if (self.reader.readByte()) |byte| { + return switch (byte) { + '^' => .north, + 'v' => .south, + '>' => .east, + '<' => .west, + '\n' => self.onEndOfStream(), + else => self.onInvalidInput(), + }; + } else |err| { + return self.onError(err); + } + } + + fn onError(self: *Parser, err: anyerror) anyerror!Direction { + switch (err) { + error.EndOfStream => return self.onEndOfStream(), + error.InvalidInput => return self.onInvalidInput(), + else => { + self.is_end = true; + self.is_invalid = true; + + return err; + }, + } + } + + fn onEndOfStream(self: *Parser) !Direction { + self.is_end = true; + + return error.EndOfStream; + } + + fn onInvalidInput(self: *Parser) !Direction { + self.is_end = true; + self.is_invalid = true; + + return error.InvalidInput; + } +}; + +pub const Point = struct { + x: i32, + y: i32, + + pub fn init() Point { + return .{ + .x = 0, + .y = 0, + }; + } + + pub fn move(self: *Point, dir: Direction) void { + switch (dir) { + .north => self.y += 1, + .south => self.y -= 1, + .east => self.x += 1, + .west => self.x -= 1, + } + } +}; + +fn checkInput(comptime input: []const u8, comptime output: []const Direction, is_valid: bool) !void { + var stream = std.io.fixedBufferStream(input); + + var parser = Parser.init(stream.reader().any()); + + for (output) |expected| { + try std.testing.expectEqual(expected, parser.read()); + } + + const expected_error = if (is_valid) error.EndOfStream else error.InvalidInput; + + try std.testing.expectError(expected_error, parser.read()); +} + +fn checkValidInput(comptime input: []const u8, comptime output: []const Direction) !void { + try checkInput(input, output, true); +} + +fn checkInvalidInput(comptime input: []const u8, comptime output: []const Direction) !void { + try checkInput(input, output, false); +} + +test "parser" { + try checkValidInput( + "", + &.{}, + ); + + try checkValidInput( + "\n", + &.{}, + ); + + try checkValidInput( + "^v><", + &.{ + .north, + .south, + .east, + .west, + }, + ); + + try checkValidInput( + "^v><\n", + &.{ + .north, + .south, + .east, + .west, + }, + ); + + try checkValidInput( + "^v><\n^v><", + &.{ + .north, + .south, + .east, + .west, + }, + ); + + try checkInvalidInput( + "^vV\n", + &.{ + .north, + .south, + }, + ); +} + +test "point" { + var point = Point.init(); + + try std.testing.expectEqual(Point{ .x = 0, .y = 0 }, point); + + point.move(.north); + + try std.testing.expectEqual(Point{ .x = 0, .y = 1 }, point); + + point.move(.east); + + try std.testing.expectEqual(Point{ .x = 1, .y = 1 }, point); + + point.move(.south); + + try std.testing.expectEqual(Point{ .x = 1, .y = 0 }, point); + + point.move(.west); + + try std.testing.expectEqual(Point{ .x = 0, .y = 0 }, point); +} diff --git a/native/solutions/2015/03/input.fixture b/native/solutions/2015/03/input.fixture new file mode 100644 index 0000000..e69cd4f --- /dev/null +++ b/native/solutions/2015/03/input.fixture @@ -0,0 +1 @@ +^^<<>^^>^^^><^>v^>v><><><^^v>v^v>>>^<>v<^<^>>>>><>^>>^>v^>><<^>v>v<>^v^v^vvv><>^^>v><>^><^^^v>>^v^>v><>v^^><vv^<<>v>>><<<>>^^^vv>>>^><<<>><><^>v<>^>v<^v^><<<<>^<>v>^v>vv<^<<>>>>^^v>vv^^<>^<>^^^^<^^^vv<^^v^^>v>^v^^^^>><v<>^v^><>^^><<^^<^^>vv<>v^<^v^>^^>^<>v^^vv<>>v><<<>vvv<>v<>><^<^v<>^vv>^^v<^<>>vv<^>>^>>vv^v>^v^<>^>>>>vv>^^>v>vv>v><^vv^<^<<^^vv^^v>^>>v><^<>v<><>^^<>v>><>^^>^^>>vvv^><<<<<^<^vv<^<>^^^<<<^>^^^vv<>^<>v<^v>^<<>^v<>>v<<^<^<<<><><>^>>>>^>v^v<>vv<^vvv^^^^vv>^v^^v^<^vv<^vv>v<^>vv<>>^>^><^>v>^v>vvv<>^>^v<><>vv>><^v^<><>>v^v^><^<^>vv>v<^>vvv>v<<<<<^>^vv>^><><>^<v^>^><><>>^>^>><^^^>^^>^^v^^<^v^^>v^^>>><<><><>^^<<^^v^>v>><>^^^><^vvv<^^^^^v><<><><>>^>vv>>^vv^^><v<^^>^<^^<^>>>^v<>v<^^^>vvv^v<<^><>>>>v>>>^^vvv^vvv<^^^^v^v^^<<^>v^v^<<><>><^v><<>><<<>^v>v<>^^vv>>^<>v^^<<^v>>v<>>^v^^>><^>v^<^v^^>><>v^>^v^v<<v<><>vv>>>>^>v<>v<<<>^^>vv^v<>^<<<<>>^^>^v<>^v<>>^v^<<^<^>>>^vv<>v^>>v<^^v>>^>><<><<<>>>^v>><^^vv>><>v^><>vv<^^v^^^v<>><^vvv<<^<>v>>>v>><>>><>>^v>v>^^<^>^>v><>vv>^v><<>>>>>>>^<<^vv^^vvvv<^^><<vvv<>^><v<>>^^<<^^vv>v>^vv>>^v^^vvvv>^^>>v^v^^><<^>v>>^^>^<^^<>vvv^vv>v>^v<><^vv^>^v>>>^^<^<^>^v^>^>>>^v>^>^^^>>^<>v^^<>^v<<^^>^^v<^v^>><^v^>^<>>^vv^vv^>v^><^^<^v<^><>v><^v^v^^^v>v^<>^<^^>^v^^<>v^<<>>vv<>>>>v>v<>^>>>v<>^^>^<^><>^><><>^<<>>><<^>^vv^v>>vv^<<^^<<><<^v^>>>v<<<v>^vv<^v>v<^>^^vv>v>><>><>^<>><><<^<<^v^v<v>vvv<^v^^^v^><^v>^<^>^<<>v^<><>>^v<>vvv<^>><^^>^>^v^vv<^><<^v>><^^v>^v<>^>vvvv><^>^<<>v>^>>^<^<<<^v^^^>^>>^>><><<^>v^^>v<<<^>vvv^^<<><^v^v^^^>^^>^vv<>v>>v^>vv^vv>v<^v^^>>^v^v<>>^^><><>>>^>^<>^^v^^><^<>><<^>vv^>>>v<<><<^>vv>vvv>^<><>>>>vv><<><<<<>><v>v^><>v^v^^><>v>v>^^v<^v<>>^^^^^>^^>v<^<^>>>^><^^>><<>>^><>^^^>v^^^>^^v^<>^^><^>>><><^>>vv<^>v<^v>v^<^vv^^><<<><><^v^v>v^>>^^vv^^v>^<^v<>^>^><^^v><^<^<>v^^>^><>>><<<><>v<<^v^^<^><>^<><>v<^^>^^<<>>^><^><^<^>^^v<>v>>><><<>^>v><><<<>^^^v>><<^v>^>>>>^vv<^<>>^<^^<^v>v^<<^<<<<<^<^>>^><<>><>v^v>^<^>v^<>^v^v^v><^vv<<^<>^^^<>^v>^v<>>^>v<<>v<>v^v>v<<<>>v>vv>>v<<>v<>v<^>^>^>v>^>^^^v<<>>>^vvv^^>^^<^vv^^^^>v>^v^>v^^v^>>^v>^vv>^^v^<<<<>^<><^<^<<^^>v^^^v<>>vvv>vv>^<^v>>^v<^^v^v>v<>^v<<<^^v^^^<^v>v^v^v>>v<>^v>vv^v>vv<<^v^v>v>><^vv>>>><<<><>^v^<^vvv>v<>><^v>^>>vv<><><>v><>>><^>vv>>^<>v^>>^><<<^><<>^v^>>><><>vv>^<>^>^v^^><^>>><<>v^<^vv>^<^vv>>vv<><<^><>v<^^<^>vv^^^^vv<<>vv<>v<>>>>^><>^<><>v<>><<>^^vvv>^^^<><>>vvv^v>><>vv^^^v^<<>^^v<><<^^v<>^^>^<^^v>>v^v^^>>v>>>^<<^<>^>^^v>>>>^v<<<^^vv><^>vv<>>vv^>v>>v^vvv^^>vv^<v^>>v^<>>><><<^^<^v>^>>>v>v>^v<>vv>v>^v<<<>><<><><>v^>>>v^>v^>>vv^^^<>>><^>v^<>^^>v<><<<>v^v>^>v<^<>v>v^^>>v>vv^v<>>^^^^<>v^>>>>>>>>^v<^<<>>><<<^<<^>^>v^<>^<<<>v>><^vv^>^>^>>>^v<<>^>^v^><>>v^>v^>^>>v<>vv^v<<>^^>>vv<>vv>>^v<^vv>^v>v<>v^<><>v^^><<<><>^>^v^<>>v^v>v<>>^^<<^<^^vv^<>>^vv^<>>^^^^v>v><^^^v^<<<>^<^<<>><>>v<<^v^>><>>^vv^v>vv>>>>>>^^<<>v^>v^v>^^>>>^v>>^^^<>><>v^<<v>v^^^>^v>^v<^<<><>vv>^^^<^^vv^^>vv>v<<^>^vv><^>^^^^v<v^<<^^>>^^vvvv^v^>vv>>v^vvv<>>^><>>v^^>>^<>>vvvv^>>>v<<^<<^>v^>><<v>v^>^v><>v<<>vv>>><^>>^^v>^>><>vv^><<>>vv<<<^<^^>^<<^>>>>>v>vv<^>^v><>>vv^vvvv>v^>>v><<^^^v>>vv^^>v>^v>^v^^>^<^vvvv<<^>>^<<^^>>^<^>v^><^vv>^^v>>><>v^v>^v<^><<<>vv>v<><>>v^<>^^>^<>^<<^>>vv^><^>v^>>v^>v>vv><>>v<^>><<vvv^vvv^vv^>^>v>>>>vv^>^<>v<^>^<^v>vv<^<<>>^<^<^^<>^<v<<>v>><^v<<^vvv>v>v<<^^<^^>v^^^>^>vv^^^vv>v<>>>vv>><><^><><<>vv>vv^v^>>><>v>>vv>^^vvv^>^^>^>^>^v<<^vv^>vvv^^vv><^>^v^>^><>v<^^vv<^<>>^^v^v>v^vv<>><^v>^<^v>^<>^v>>>><>>>v><^v^vv><<^v<<>^^<^v>vvv<><^^><<^v><>^<^v<^^<^vvvv^^>>>>vv>v>>>v<<<>v^>>vv^vvv<>vvv>>>><>>><>^v>><>>^vv<<^^vv><^v^vv^^^vv>^><^vvv<<>^vvv^>>>^<<<><<<<<^v<^^>>>>^>^v<<<^<^>>v^<<><<^^vvv^>v<>>^^>v>^v>>v>>>^<^<^>v^v^>><>^<<^vvv^^<>^v^>^^<<^>^vv>>v^v^>v>^<^^<>^>^>>>^^vvv^<<>v^<<>><>v<^<^>v^>^vv>^>>^<^v^<<<<^v^>v^><<<><^^^^>v>^^>v><>>^><<><^<>>^^>vv<^><^v^>>>vvv<^<>>^>>^v^<^^v>^^^v<^vv^>>^v><<^<><>>^>vv<<>^^^v^^><>>vv>v^>vvv^^v>^>>^>>v^<<v^<^v^vv^><^<^v<v>^v^<<^^>>^^^v>>>><^^v^>>^^>>^v^<^v>v^v^v^v^>v^vv<><>^^<>^><^^^<<<^v<<>^<^^^^^v^<^<<^^>^vv<>v^>><>>^>v>v<>^>v>><>^<>>>^>^>>v^>v><^vv^>v<v<><^><^v<<>v<>^^><<>v>vv<^vvv><><>vv^<<>^>^<^>>>^v>v<^v^^^vv<>>>^<<^>>><<^^v^>v^<^v>vvv>v^^vv>^^>>v<>^<<>^<><^^v^>><>^>v>>^^^<<^^v<>^^>^<>^>><^>^vvv><^>^<^>^>>vv<^>>^v>>^<>>^^>>>v^>v<>v^^vv>v><^v^^>v<<>v^^<><>^>vvv><^^^>^v^>v>>^vvv<^vv>^^>^>>v<>><<^v<^><>vv^<<^^vv>>^<^><^^v^<<>^v^^>v^>>^^^<^vv>v^>>>vv<<>v>>>^>v^^>v^<<>>vv<<^v>v<<^^>v>>v>v^>>^>>v>^><<^<<>^v>><^^<^<<^>vv<<>^<>^vv>^^^v<^v>vv>^^^^>v>v><<^<<<^vv><^<<<>>v<v>^v^v^<^<^vv>vvv<^^v<>v<<<<>v^<<><<<>v<^>^^v<^^v^>vv>vvv>v>>^><^>>v<v<<^^^v<<^v^^><><<<><<>v>^<<>v<<<^v>>v>><<^<><^v^^v^>^>vvvv<<><<>>^^^>v>v^><>>><^><<><<<^<>v^>>^v^>v^<>>v>^^><^<^v^>v>^vvv<>>v<>^vvvv><<<<<<<v<<<<^v<<><^<<>vv^<<>><^^<<>>>vv>>>>>>^v>v^v^^><<^v^^^<>^>>><>v^v^vvv^>>v>>>^^<<^^vv><<<^^^<<<^^>>>>vvv^v<^>^^>v<^<>v>>>^vv<<^^v^>^>^v>v>v^v^>v<><>>>>><<^v^<>^v<>vvv^>v>v^<><><>^>>><>^>^^<>v^^>^><>><>v^v^^v>>>>vv>>^v<<^v^<>^>v^^>^^<^><<<^^^v^^^^v<^<>v<^^<>vv^^v^<>^<<^>>v>v<<<^^^^vvv^<^<><>v<>><<><<^^^^vv><<>>>^v<<>^>>>v^>v>^^<>^<^>v>^>>>><>^^>v^^v>^vv^^v^><<<>>v<>v<<<>^<^<<>v>>>>^<vvv<^><^<<^>v>>v><>^>>>^v^v>v^^vv^>^<^^>>^><^vv^^vv^<>>^^^^<^^><>>^>>^>^vvv<^<^><>>>^^<><><<>>>>^<<>>>^<^v^>><<^>>>^<^>><>^^<>^v^^vv<><^>vv^^v^<^^^v^vvv^>><>>v<>^<^vvv<<^^>vv^^<<>>><^^vvv<<<^>^<><^>vv^><^<<>vv<>vv>v>v^<<>^^^^v^^^^^<<^><><^^v^>v>^>><^><<>v^>>^vvv>>^<^<>^^v^vv^^v><>>v<<<>v>^<>v<<>v^>^<<><<>v^>v<><^^>^<^v^^><^>vv>^>vvvv>^^><<>vv^>^v<<^<<^<<>vv>>^>>>>>v^v<^v>v>^^^vv^v<^<>v><>>vv>v><>v>^v<><<<<<>v^vv<<<<^<>^>><>^^vv>^<^<<>vv>>vv><>><^^><^<>^><>v^^^^v^^vv<>v<>v>^vv^>^<>^^^>v^>>>v><<^>>v<^v<>^^v<><<>v<^<^>v<>v^>v>^^<<<^^vv^<><<<>>v>^^<>v>>>><<>v^v<>v>><<<<^<<^>^>v^vv^><^v^^<>^^><>vv>^>vvv<^v^>>^>^>^^<<^>^>^v><>>^<^^v>^>>^^<><>>>^^>^^vvv>v<^^<>v^v^^v^v>><<^^^>>v>^vv>^>^^v<>^^<>v^^<>v^><<>vv<<^vvvv><<v>v^>v^<>v^>^^<>^>^^v<>><<<>^v^^v^v<<<^v^<>^<>v>^^>vv>^^<<<><<^>v<^^<^<<>^>>>>>^v^v<vvv<<>v>v>>^v^v^>><<<<>v^<<>>>^>>^>>< diff --git a/native/solutions/2015/03/part_1.zig b/native/solutions/2015/03/part_1.zig new file mode 100644 index 0000000..269360b --- /dev/null +++ b/native/solutions/2015/03/part_1.zig @@ -0,0 +1,43 @@ +const panic = @import("panic"); +const std = @import("std"); + +const common = @import("./common.zig"); + +const Allocator = std.mem.Allocator; +const AnyReader = std.io.AnyReader; +const Direction = common.Direction; +const Parser = common.Parser; +const Point = common.Point; + +const Visited = std.hash_map.AutoHashMap(Point, void); + +pub fn solve(allocator: Allocator, reader: AnyReader) ![]const u8 { + var parser = Parser.init(reader); + + var visited = Visited.init(allocator); + defer visited.deinit(); + + var santa = Point.init(); + + while (parser.read()) |dir| { + santa.move(dir); + + try visited.put(santa, undefined); + } else |err| { + if (err != error.EndOfStream) { + return err; + } + } + + return try std.fmt.allocPrint(allocator, "{d}", .{visited.count()}); +} + +test "solution 2015/03/01" { + const input_file = @embedFile("./input.fixture"); + var input = std.io.fixedBufferStream(input_file); + + const answer = try solve(std.testing.allocator, input.reader().any()); + defer std.testing.allocator.free(answer); + + try std.testing.expectEqualStrings(answer, "2565"); +} diff --git a/native/solutions/2015/03/part_2.zig b/native/solutions/2015/03/part_2.zig new file mode 100644 index 0000000..a672564 --- /dev/null +++ b/native/solutions/2015/03/part_2.zig @@ -0,0 +1,54 @@ +const panic = @import("panic"); +const std = @import("std"); + +const common = @import("./common.zig"); + +const Allocator = std.mem.Allocator; +const AnyReader = std.io.AnyReader; +const Direction = common.Direction; +const Parser = common.Parser; +const Point = common.Point; + +const Visited = std.hash_map.AutoHashMap(Point, void); + +pub fn solve(allocator: Allocator, reader: AnyReader) ![]const u8 { + var parser = Parser.init(reader); + + var visited = Visited.init(allocator); + defer visited.deinit(); + + var is_santa_will_move = true; + + var santa = Point.init(); + var robo_santa = Point.init(); + + while (parser.read()) |dir| { + if (is_santa_will_move) { + santa.move(dir); + + try visited.put(santa, undefined); + } else { + robo_santa.move(dir); + + try visited.put(robo_santa, undefined); + } + + is_santa_will_move = !is_santa_will_move; + } else |err| { + if (err != error.EndOfStream) { + return err; + } + } + + return try std.fmt.allocPrint(allocator, "{d}", .{visited.count()}); +} + +test "solution 2015/03/02" { + const input_file = @embedFile("./input.fixture"); + var input = std.io.fixedBufferStream(input_file); + + const answer = try solve(std.testing.allocator, input.reader().any()); + defer std.testing.allocator.free(answer); + + try std.testing.expectEqualStrings(answer, "2639"); +} diff --git a/native/solutions/registry.zig b/native/solutions/registry.zig index 6f025c6..d984dc5 100644 --- a/native/solutions/registry.zig +++ b/native/solutions/registry.zig @@ -74,6 +74,8 @@ pub const items = [_]Entry{ entry(.year_2015, .day_01, .part_two, index.solver_2015_01_02), entry(.year_2015, .day_02, .part_one, index.solver_2015_02_01), entry(.year_2015, .day_02, .part_two, index.solver_2015_02_02), + entry(.year_2015, .day_03, .part_one, index.solver_2015_03_01), + entry(.year_2015, .day_03, .part_two, index.solver_2015_03_02), }; pub fn lookup(year: Year, day: Day, part: Part) ?Solver { diff --git a/native/solutions/solutions.zig b/native/solutions/solutions.zig index 96c5e86..5edef2a 100644 --- a/native/solutions/solutions.zig +++ b/native/solutions/solutions.zig @@ -2,6 +2,8 @@ pub const solver_2015_01_01 = @import("./2015/01/part_1.zig").solve; pub const solver_2015_01_02 = @import("./2015/01/part_2.zig").solve; pub const solver_2015_02_01 = @import("./2015/02/part_1.zig").solve; pub const solver_2015_02_02 = @import("./2015/02/part_2.zig").solve; +pub const solver_2015_03_01 = @import("./2015/03/part_1.zig").solve; +pub const solver_2015_03_02 = @import("./2015/03/part_2.zig").solve; test { @import("std").testing.refAllDecls(@This());