main.pony 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. use "collections"
  2. use "files"
  3. use "itertools"
  4. // A basic two-dimensional point class
  5. class val Point is Hashable
  6. let x: USize
  7. let y: USize
  8. new val create(_x: USize, _y: USize) =>
  9. x = _x
  10. y = _y
  11. // because we want to use this as a key in a hashmap
  12. fun hash(): USize =>
  13. // hey this is probably bad, huh?
  14. x.hash() + y.hash()
  15. fun eq(other: Point): Bool =>
  16. (x == other.x) and (y == other.y)
  17. fun ne(other: Point): Bool => not eq(other)
  18. class Layer
  19. let pixels: Map[Point, U8]
  20. let w: USize
  21. let h: USize
  22. new create(pixels': Map[Point, U8], w': USize, h': USize) =>
  23. pixels = pixels'
  24. w = w'
  25. h = h'
  26. fun ref string(): String =>
  27. var buf = String()
  28. for y in Range(0, h) do
  29. for x in Range(0, w) do
  30. try
  31. match pixels(Point(x, y))?
  32. | '0' => buf.push(' ')
  33. | '1' => buf.push('X')
  34. | '2' => buf.push('?')
  35. end
  36. else
  37. buf.push('.')
  38. end
  39. end
  40. buf.push('\n')
  41. end
  42. buf.clone()
  43. fun ref count(n: U8): USize =>
  44. Iter[U8](pixels.values()).filter({(x) => x == n}).count()
  45. class Image
  46. var layers: Array[Layer]
  47. new create(layers': Array[Layer]) =>
  48. layers = layers'
  49. fun ref string(): String =>
  50. var buf = ""
  51. buf = buf.add("image [\n")
  52. for (i, l) in Iter[Layer](layers.values()).enum[USize]() do
  53. buf = buf.add(" layer ")
  54. buf = buf.add(i.string())
  55. buf = buf.add(": ")
  56. buf = buf.add(l.string())
  57. buf = buf.add("\n")
  58. end
  59. buf = buf.add("]")
  60. buf.clone()
  61. fun ref composite(): Layer =>
  62. var result: Map[Point, U8] = Map[Point, U8]()
  63. for layer in layers.values() do
  64. for (p, v) in layer.pixels.pairs() do
  65. if result.get_or_else(p, '2') == '2' then
  66. if v != '2' then result(p) = v end
  67. end
  68. end
  69. end
  70. Layer(result, 25, 6)
  71. actor Main
  72. fun mk_image(env: Env, width: USize, height: USize, file: File): Image =>
  73. var layers = Array[Layer]()
  74. var pixels = Map[Point, U8]()
  75. try
  76. while true do
  77. for y in Range(0, height) do
  78. for x in Range(0, width) do
  79. pixels(Point(x, y)) = file.read(1)(0)?
  80. end
  81. end
  82. layers.push(Layer(pixels = Map[Point, U8](), width, height))
  83. end
  84. end
  85. Image(layers)
  86. new create(env: Env) =>
  87. let caps = recover val FileCaps.>set(FileRead).>set(FileStat) end
  88. let target_file = try env.args(1)? else "input.txt" end
  89. try
  90. with
  91. file = OpenFile(FilePath(env.root as AmbientAuth, target_file, caps)?) as File
  92. do
  93. let w: USize = 25
  94. let h: USize = 6
  95. let image = mk_image(env, w, h, file)
  96. env.out.print("image is " + image.string())
  97. var min: (USize | None) = None
  98. var min_idx: (USize | None) = None
  99. for (idx, layer) in Iter[Layer](image.layers.values()).enum() do
  100. let zeroes = layer.count('0')
  101. let is_min = try min as USize > zeroes else true end
  102. env.out.print("layer " + idx.string() + ": " + zeroes.string())
  103. if is_min then
  104. min = zeroes
  105. min_idx = idx
  106. end
  107. end
  108. env.out.print("min layer " + min_idx.string() + " had " + min.string() + " zeroes")
  109. try
  110. let tgt = image.layers(min_idx as USize)?
  111. env.out.print(" answer: " + (tgt.count('1') * tgt.count('2')).string())
  112. end
  113. let composite = image.composite()
  114. env.out.print("composite:\n" + composite.string())
  115. end
  116. end
  117. env.out.print(".")