|
@@ -0,0 +1,127 @@
|
|
|
+use "collections"
|
|
|
+use "files"
|
|
|
+use "format"
|
|
|
+use "itertools"
|
|
|
+
|
|
|
+class Orbit
|
|
|
+ let _name: String
|
|
|
+ var _orbits: Array[Orbit ref]
|
|
|
+
|
|
|
+ new create(n: String) =>
|
|
|
+ _name = n
|
|
|
+ _orbits = Array[Orbit]()
|
|
|
+
|
|
|
+ fun ref add(o: Orbit ref) =>
|
|
|
+ _orbits.push(o)
|
|
|
+
|
|
|
+ fun name(): String => _name
|
|
|
+
|
|
|
+ fun print(env: Env) =>
|
|
|
+ env.out.write(_name + ":")
|
|
|
+ for o in _orbits.values() do
|
|
|
+ env.out.write(" " + o.name())
|
|
|
+ end
|
|
|
+ env.out.print("")
|
|
|
+
|
|
|
+ fun checksum(path_len: USize): USize =>
|
|
|
+ var sum = path_len
|
|
|
+ for o in _orbits.values() do
|
|
|
+ sum = sum + o.checksum(path_len + 1)
|
|
|
+ end
|
|
|
+ sum
|
|
|
+
|
|
|
+ fun ref contains(n: String): Bool =>
|
|
|
+ (n == _name) or (Iter[Orbit](_orbits.values()).any({(o) => o.contains(n)}))
|
|
|
+
|
|
|
+ fun ref closest_parent(l: String, r: String): String ? =>
|
|
|
+ for o in _orbits.values() do
|
|
|
+ try
|
|
|
+ return o.closest_parent(l, r)?
|
|
|
+ end
|
|
|
+ end
|
|
|
+ if contains(l) and contains(r) then
|
|
|
+ return _name
|
|
|
+ end
|
|
|
+ error
|
|
|
+
|
|
|
+ fun ref find_distance(n: String, dist: USize = 0): USize ? =>
|
|
|
+ if n == _name then
|
|
|
+ return dist
|
|
|
+ end
|
|
|
+ for o in _orbits.values() do
|
|
|
+ try
|
|
|
+ return o.find_distance(n, dist + 1)?
|
|
|
+ end
|
|
|
+ end
|
|
|
+ error
|
|
|
+
|
|
|
+class System
|
|
|
+ var orbits: Map[String, Orbit]
|
|
|
+
|
|
|
+ new create(mapping: Array[(String, String)]) =>
|
|
|
+ orbits = Map[String, Orbit]()
|
|
|
+
|
|
|
+ orbits.insert("COM", Orbit("COM"))
|
|
|
+ for (inner_name, outer_name) in mapping.values() do
|
|
|
+ let outer = orbits.insert_if_absent(outer_name, Orbit(outer_name))
|
|
|
+ let inner = orbits.insert_if_absent(inner_name, Orbit(inner_name))
|
|
|
+ inner.add(outer)
|
|
|
+ end
|
|
|
+
|
|
|
+ fun print(env: Env) =>
|
|
|
+ for o in orbits.values() do
|
|
|
+ o.print(env)
|
|
|
+ end
|
|
|
+
|
|
|
+ fun checksum(): USize =>
|
|
|
+ try
|
|
|
+ orbits("COM")?.checksum(0)
|
|
|
+ else
|
|
|
+ 0
|
|
|
+ end
|
|
|
+
|
|
|
+ fun ref closest_parent(l: String, r: String): (String | None) =>
|
|
|
+ try
|
|
|
+ orbits("COM")?.closest_parent(l, r)?
|
|
|
+ else
|
|
|
+ None
|
|
|
+ end
|
|
|
+
|
|
|
+ fun ref distance(parent: String, child: String): USize =>
|
|
|
+ try
|
|
|
+ orbits(parent)?.find_distance(child)?
|
|
|
+ else
|
|
|
+ 0
|
|
|
+ end
|
|
|
+
|
|
|
+actor Main
|
|
|
+ new create(env: Env) =>
|
|
|
+ let caps = recover val FileCaps.>set(FileRead).>set(FileStat) end
|
|
|
+
|
|
|
+ let target_file = try env.args(1)? else "input.txt" end
|
|
|
+ try
|
|
|
+ with
|
|
|
+ file = OpenFile(FilePath(env.root as AmbientAuth, target_file, caps)?) as File
|
|
|
+ do
|
|
|
+ let mapping = Array[(String, String)]()
|
|
|
+ for line in file.lines() do
|
|
|
+ try
|
|
|
+ let sline = line.split(")")
|
|
|
+ mapping.push((sline(0)?, sline(1)?))
|
|
|
+ else
|
|
|
+ env.out.write("Failed to parse line: " + line.clone())
|
|
|
+ end
|
|
|
+ end
|
|
|
+ let s = System(mapping)
|
|
|
+ env.out.print("Checksum: " + Format.int[USize](s.checksum()))
|
|
|
+ s.print(env)
|
|
|
+ match s.closest_parent("YOU", "SAN")
|
|
|
+ | None => env.out.print("No connection between the two somehow?")
|
|
|
+ | let o: String =>
|
|
|
+ env.out.print("Closest parent between YOU and SAN is " + o)
|
|
|
+ let d1 = s.distance(o, "YOU")
|
|
|
+ let d2 = s.distance(o, "SAN")
|
|
|
+ env.out.print("Distance is " + Format.int[USize]((d1 + d2) - 2))
|
|
|
+ end
|
|
|
+ end
|
|
|
+ end
|