use "collections" use "files" use "itertools" primitive Math fun gcd(x: ISize, y: ISize): ISize => var a = x var b = y var d: USize = 0 while ((a % 2) == 0) and ((b % 2) == 0) do a = a / 2 b = b / 2 d = d + 1 end while a != b do if (a % 2) == 0 then a = a / 2 elseif (b % 2) == 0 then b = b / 2 elseif a > b then a = (a - b) / 2 else b = (b - a) / 2 end end if d > 0 then a * (2 << (d-1)).isize() else a end // A basic two-dimensional point class class val Point is Hashable let x: ISize let y: ISize new val create(_x: ISize, _y: ISize) => x = _x y = _y // because we want to use this as a key in a hashmap fun hash(): USize => // hey this is probably bad, huh? (x.hash() + y.hash()).usize() fun eq(other: Point): Bool => (x == other.x) and (y == other.y) fun ne(other: Point): Bool => not eq(other) fun sub(other: Point): Point => Point(x - other.x, y - other.y) fun simplify(): Point => let d = Math.gcd(x, y) Point(x/d, y/d) actor Asteroid let _loc: Point let _field: AsteroidField tag let _io: IO tag let _visible: Map[Point, Point] = Map[Point, Point]() new create(p: Point, field: AsteroidField tag, io: IO tag) => _loc = p _field = field _io = io be print() => _io.print("Asteroid(" + _loc.x.string() + ", " + _loc.y.string() + ")") be find_visible(loc: Point, other: Asteroid) => None actor AsteroidField var _io: IO var _locs: Set[Point] = Set[Point]() new create(io: IO) => _io = io be register(p: Point) => _locs.set(p) be print() => _io.print("whoo") actor IO let _env: Env new create(env: Env) => _env = env be print(str: String) => _env.out.print(str) actor Main new create(env: Env) => let io = IO(env) let field = AsteroidField(io) build_field(env, io, field) field.print() fun build_field(env: Env, io: IO, field: AsteroidField): (Array[Asteroid] | None) => let caps = recover val FileCaps.>set(FileRead).>set(FileStat) end let target_file = try env.args(1)? else "input.txt" end try var asteroids: Array[Asteroid] = Array[Asteroid]() with file = OpenFile(FilePath(env.root as AmbientAuth, target_file, caps)?) as File do for (y, line) in Iter[String](file.lines()).enum() do for (x, char) in Iter[U8](line.values()).enum() do if char == '#' then let p = Point(x.isize(), y.isize()) field.register(p) asteroids.push(Asteroid(p, field, io)) end end end end for a in asteroids.values() do a.print() end asteroids else env.err.print("Couldn't read file `" + target_file + "`") env.exitcode(99) end