const std = @import("std"); const Error = error{ParseError}; const Point = struct { X: i32, Y: i32, }; 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, pos: Point, pub fn step(self: *World, in: Step) anyerror!void { std.debug.warn("Step: {}\n", in); switch (in.d) { .Up => { try self.lineY(self.pos.Y - in.l, self.pos.Y - 1); self.pos.Y -= in.l; }, .Down => { try self.lineY(self.pos.Y + 1, self.pos.Y + in.l); self.pos.Y += in.l; }, .Left => { try self.lineX(self.pos.X - in.l, self.pos.X - 1); self.pos.X -= in.l; }, .Right => { try self.lineX(self.pos.X + 1, self.pos.X + in.l); self.pos.X += in.l; }, } } fn lineX(self: *World, start: i32, end: i32) anyerror!void { var x: i32 = start; while (x <= end) : (x += 1) { try self.fill(x, self.pos.Y); } } fn lineY(self: *World, start: i32, end: i32) anyerror!void { var y: i32 = start; while (y <= end) : (y += 1) { try self.fill(self.pos.X, y); } } fn fill(self: *World, x: i32, y: i32) anyerror!void { //self.entries = try self.alloc.realloc(self.entries, self.entries.len+1); self.entries.appendAssumeCapacity(Point{ .X = x, .Y = y }); } }; 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), .pos = Point{ .X = 0, .Y = 0 }, }; // Line 1 for (try getLine(stream)) |item| { try world.step(item); } // reset to origin const entriesA = world.entries; world.entries = try Points.initCapacity(alloc, maxEntries); world.pos = Point{ .X = 0, .Y = 0 }; // Line 2 for (try getLine(stream)) |item| { try 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, manhattan(a.X, a.Y)); } } } }