const std = @import("std"); const Error = error{ParseError}; const Point = struct { X: i32, Y: i32, Steps: i32, // number of steps taken to reach this point }; const Points = std.ArrayList(Point); const Direction = enum(u8) { Up = 'U', Right = 'R', Down = 'D', Left = 'L', pub fn parse(in: u8) anyerror!Direction { return switch (in) { 'U' => .Up, 'R' => .Right, 'D' => .Down, 'L' => .Left, else => Error.ParseError, }; } }; const Step = struct { d: Direction, l: i32, pub fn parse(in: []const u8) anyerror!Step { if (in.len < 2) { return error.ParseError; } return Step{ .d = try Direction.parse(in[0]), .l = try std.fmt.parseInt(i32, in[1..in.len], 10), }; } }; const World = struct { entries: Points, ticks: i32, x: i32, y: i32, pub fn step(self: *World, in: Step) void { std.debug.warn("Step {}: {}\n", self.ticks, in); var i: i32 = 0; switch (in.d) { .Up => { while (i < in.l) : (i += 1) { self.y -= 1; self.fill(); } }, .Down => { while (i < in.l) : (i += 1) { self.y += 1; self.fill(); } }, .Left => { while (i < in.l) : (i += 1) { self.x -= 1; self.fill(); } }, .Right => { while (i < in.l) : (i += 1) { self.x += 1; self.fill(); } }, } } fn fill(self: *World) void { self.ticks += 1; const point = Point{ .X = self.x, .Y = self.y, .Steps = self.ticks }; std.debug.warn("\t{}\n", point); self.entries.appendAssumeCapacity(point); } }; fn getLine(stream: *std.fs.File.InStream.Stream) anyerror![]Step { var buf: [10240]u8 = undefined; var out: [1000]Step = undefined; var i: u32 = 0; var line = (try stream.readUntilDelimiterOrEof(&buf, '\n')) orelse return Error.ParseError; var iter = std.mem.separate(line, ","); while (iter.next()) |value| { std.debug.assert(i < out.len); out[i] = try Step.parse(value); i += 1; } return out[0..i]; } fn manhattan(x: i32, y: i32) u32 { return std.math.absCast(x) + std.math.absCast(y); } const maxEntries = 1024 * 1024; pub fn main() anyerror!void { var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer arena.deinit(); const alloc = &arena.allocator; const file = std.io.getStdIn(); const stream = &file.inStream().stream; var world: World = World{ .entries = try Points.initCapacity(alloc, maxEntries), .ticks = 0, .x = 0, .y = 0, }; // Line 1 for (try getLine(stream)) |item| { world.step(item); } // reset to origin const entriesA = world.entries; world.entries = try Points.initCapacity(alloc, maxEntries); world.ticks = 0; world.x = 0; world.y = 0; // Line 2 for (try getLine(stream)) |item| { world.step(item); } const entriesB = world.entries; std.debug.warn("A: {} entries\nB: {} entries\n", entriesA.len, entriesB.len); for (entriesA.toSlice()) |a| { for (entriesB.toSlice()) |b| { if (a.X == b.X and a.Y == b.Y) { std.debug.warn("Match! {}, {} => {} : {}\n", a, b, manhattan(a.X, a.Y), a.Steps + b.Steps); } } } }