123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127 |
- 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
|