const std = @import("std"); // https://stackoverflow.com/a/328122 fn isBetween(a: Point, b: Point, c: Point) bool { const crossproduct = (c.y - a.y) * (b.x - a.x) - (c.x - a.x) * (b.y - a.y); // compare versus epsilon if (std.math.absFloat(crossproduct) > std.math.f64_epsilon) return false; const dotproduct = (c.x - a.x) * (b.x - a.x) + (c.y - a.y) * (b.y - a.y); if (dotproduct < 0.0) return false; const squaredlengthba = (b.x - a.x) * (b.x - a.x) + (b.y - a.y) * (b.y - a.y); if (dotproduct > squaredlengthba) return false; return true; } const Point = struct { x: f64, y: f64, fn eql(self: Point, other: Point) bool { return self.x == other.x and self.y == other.y; } }; const Asteroid = struct { p: Point, visible: usize = 0, }; const Asteroids = std.ArrayList(Asteroid); const input = @embedFile("../input"); fn part1(asteroids: Asteroids) void { for (asteroids.toSlice()) |*a| { for (asteroids.toSlice()) |b| { if (a.p.eql(b.p)) continue; // Check every asteroid to see if they fall between A and B var blocked: bool = false; for (asteroids.toSlice()) |c| { if (a.p.eql(c.p) or b.p.eql(c.p)) continue; //var dist = distToSegment(a.p, b.p, c.p); if (isBetween(a.p, b.p, c.p)) { blocked = true; break; } } // A can see B, so add it to A's score if (!blocked) a.visible += 1; } } var best: usize = 0; for (asteroids.toSlice()) |asteroid| { if (asteroid.visible > best) best = asteroid.visible; } std.debug.warn("Day 10, Part 1: {}\n", best); } pub fn main() anyerror!void { var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); defer arena.deinit(); const alloc = &arena.allocator; var asteroids = Asteroids.init(alloc); var lines = std.mem.separate(input, "\n"); var y: usize = 0; while (lines.next()) |line| { for (line) |byte, x| { if (byte == '#') { const px = @intToFloat(f64, x) + 0.5; const py = @intToFloat(f64, y) + 0.5; try asteroids.append(Asteroid{ .p = Point{ .x = px, .y = py } }); } } y += 1; } part1(asteroids); }