main.pony 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. use "collections"
  2. use "files"
  3. use "format"
  4. use "itertools"
  5. class Orbit
  6. let _name: String
  7. var _orbits: Array[Orbit ref]
  8. new create(n: String) =>
  9. _name = n
  10. _orbits = Array[Orbit]()
  11. fun ref add(o: Orbit ref) =>
  12. _orbits.push(o)
  13. fun name(): String => _name
  14. fun print(env: Env) =>
  15. env.out.write(_name + ":")
  16. for o in _orbits.values() do
  17. env.out.write(" " + o.name())
  18. end
  19. env.out.print("")
  20. fun checksum(path_len: USize): USize =>
  21. var sum = path_len
  22. for o in _orbits.values() do
  23. sum = sum + o.checksum(path_len + 1)
  24. end
  25. sum
  26. fun ref contains(n: String): Bool =>
  27. (n == _name) or (Iter[Orbit](_orbits.values()).any({(o) => o.contains(n)}))
  28. fun ref closest_parent(l: String, r: String): String ? =>
  29. for o in _orbits.values() do
  30. try
  31. return o.closest_parent(l, r)?
  32. end
  33. end
  34. if contains(l) and contains(r) then
  35. return _name
  36. end
  37. error
  38. fun ref find_distance(n: String, dist: USize = 0): USize ? =>
  39. if n == _name then
  40. return dist
  41. end
  42. for o in _orbits.values() do
  43. try
  44. return o.find_distance(n, dist + 1)?
  45. end
  46. end
  47. error
  48. class System
  49. var orbits: Map[String, Orbit]
  50. new create(mapping: Array[(String, String)]) =>
  51. orbits = Map[String, Orbit]()
  52. orbits.insert("COM", Orbit("COM"))
  53. for (inner_name, outer_name) in mapping.values() do
  54. let outer = orbits.insert_if_absent(outer_name, Orbit(outer_name))
  55. let inner = orbits.insert_if_absent(inner_name, Orbit(inner_name))
  56. inner.add(outer)
  57. end
  58. fun print(env: Env) =>
  59. for o in orbits.values() do
  60. o.print(env)
  61. end
  62. fun checksum(): USize =>
  63. try
  64. orbits("COM")?.checksum(0)
  65. else
  66. 0
  67. end
  68. fun ref closest_parent(l: String, r: String): (String | None) =>
  69. try
  70. orbits("COM")?.closest_parent(l, r)?
  71. else
  72. None
  73. end
  74. fun ref distance(parent: String, child: String): USize =>
  75. try
  76. orbits(parent)?.find_distance(child)?
  77. else
  78. 0
  79. end
  80. actor Main
  81. new create(env: Env) =>
  82. let caps = recover val FileCaps.>set(FileRead).>set(FileStat) end
  83. let target_file = try env.args(1)? else "input.txt" end
  84. try
  85. with
  86. file = OpenFile(FilePath(env.root as AmbientAuth, target_file, caps)?) as File
  87. do
  88. let mapping = Array[(String, String)]()
  89. for line in file.lines() do
  90. try
  91. let sline = line.split(")")
  92. mapping.push((sline(0)?, sline(1)?))
  93. else
  94. env.out.write("Failed to parse line: " + line.clone())
  95. end
  96. end
  97. let s = System(mapping)
  98. env.out.print("Checksum: " + Format.int[USize](s.checksum()))
  99. s.print(env)
  100. match s.closest_parent("YOU", "SAN")
  101. | None => env.out.print("No connection between the two somehow?")
  102. | let o: String =>
  103. env.out.print("Closest parent between YOU and SAN is " + o)
  104. let d1 = s.distance(o, "YOU")
  105. let d2 = s.distance(o, "SAN")
  106. env.out.print("Distance is " + Format.int[USize]((d1 + d2) - 2))
  107. end
  108. end
  109. end