1. // Wrap in object, otherwise ammonite .par or Future would not work
  2. object Solution {
  3. val O = scala.io.Source.fromFile("input").getLines.map(_.toCharArray).toArray
  4. //FIXME: This M is global variable entangled in case class S for defining empty etc.
  5. // Also this is used in findStable which is sad.
  6. var M = O
  7. val R = M.length
  8. val C = M.head.length
  9. case class S(r: Int, c: Int) {
  10. def +(o: S) = S(r + o.r, c + o.c)
  11. def ok = r >= 0 && r < R && c >= 0 && c < C
  12. def empty = M(r)(c) == 'L'
  13. def occupied = M(r)(c) == '#'
  14. def floor = M(r)(c) == '.'
  15. def dbg = s"$r $c ${M(r)(c)}"
  16. def update(v: Char, n: Array[Array[Char]]) = n(r)(c) = v
  17. }
  18. val NB = List(
  19. S(-1, -1), S(-1, 0), S(-1, 1),
  20. S( 0, -1), S( 0, 1),
  21. S( 1, -1), S( 1, 0), S( 1, 1)
  22. )
  23. val coords = for (r <- 0 to R - 1; c <- 0 to C - 1) yield (r, c)
  24. // direct 8 neighbours
  25. def seen1(cur: S) = NB.map(_ + cur).filter(_.ok).filter(_.occupied).size
  26. // closest 8 direction neighbours
  27. def seen2(cur : S) = {
  28. var seen : List[S] = Nil
  29. NB.foreach{ dir =>
  30. var c = cur + dir
  31. while(c.ok && c.floor){
  32. c += dir
  33. }
  34. if(c.ok) seen = c :: seen
  35. }
  36. seen.filter(_.occupied).size
  37. }
  38. def evolve(fSeen : S => Int, minSeen : Int) = {
  39. var stable = true
  40. val N = M.map(_.clone)
  41. val updates = coords.par.map { case (r,c) =>
  42. val cur = S(r,c)
  43. val nSeen = fSeen(cur)
  44. if(cur.empty && nSeen == 0) {
  45. cur.update('#', N)
  46. stable = false
  47. }
  48. if(cur.occupied && nSeen >= minSeen) {
  49. cur.update('L', N)
  50. stable = false
  51. }
  52. }
  53. M = N
  54. stable
  55. }
  56. def findStable(fSeen : S => Int, minSeen : Int): Int = {
  57. M = O
  58. var stable = evolve(fSeen, minSeen)
  59. while(!stable){ stable = evolve(fSeen, minSeen) }
  60. M.flatten.filter(_ == '#').size
  61. }
  62. def solveAll() = {
  63. println(findStable(seen1, 4))
  64. println(findStable(seen2, 5))
  65. }
  66. }
  67. Solution.solveAll()