My solutions to 2018's advent of code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

day18.nim 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import sequtils, strutils
  2. type
  3. GroundType = enum
  4. gtVoid, gtOpen, gtTrees, gtLumberYard
  5. Ground = array[-1..50, array[-1..50, GroundType]]
  6. iterator around(x, y: int): tuple[x,y: int] =
  7. for i in -1..1:
  8. for j in -1..1:
  9. if i != 0 or j != 0:
  10. yield (x + i, y + j)
  11. func hasAtLeastThree(ground: Ground, groundType: GroundType, x,y: int): bool =
  12. var count = 0
  13. for point in around(x, y):
  14. if ground[point.y][point.x] == groundType:
  15. count.inc
  16. if count == 3:
  17. return true
  18. return false
  19. func resourceValue(ground: Ground): int =
  20. # Multiplying the number of wooded acres by the number of lumberyards gives
  21. # the total resource value
  22. var trees, yards: int
  23. for row in ground:
  24. for cell in row:
  25. if cell == gtLumberYard:
  26. yards.inc
  27. elif cell == gtTrees:
  28. trees.inc
  29. trees * yards
  30. func turnToTrees(ground: Ground, x,y: int): bool =
  31. # An open acre will become filled with trees if three or more adjacent
  32. # acres contained trees.
  33. ground.hasAtLeastThree(gtTrees, x, y)
  34. func turnToLumberYard(ground: Ground, x,y: int): bool =
  35. # An acre filled with trees will become a lumberyard if three or more
  36. # adjacent acres were lumberyards.
  37. ground.hasAtLeastThree(gtLumberYard, x, y)
  38. func remainLumberYard(ground: Ground, x,y: int): bool =
  39. # An acre containing a lumberyard will remain a lumberyard if it was
  40. # adjacent to at least one other lumberyard and at least one acre
  41. # containing trees.
  42. var foundYard, foundTrees: bool
  43. for point in around(x,y):
  44. if ground[point.y][point.x] == gtLumberYard:
  45. foundYard = true
  46. if ground[point.y][point.x] == gtTrees:
  47. foundTrees = true
  48. if foundTrees and foundYard:
  49. return true
  50. return false
  51. proc load(dest: var Ground) =
  52. var y: int
  53. for line in readFile("data/18.txt").strip.splitlines:
  54. for x, c in line:
  55. dest[y][x] = case c:
  56. of '.': gtOpen
  57. of '|': gtTrees
  58. of '#': gtLumberYard
  59. else: gtVoid
  60. y.inc
  61. proc step(source: Ground, dest: var Ground) =
  62. for y, row in source:
  63. for x, cell in row:
  64. dest[y][x] = case cell:
  65. of gtVoid: gtVoid
  66. of gtOpen:
  67. if source.turnToTrees(x, y):
  68. gtTrees
  69. else:
  70. gtOpen
  71. of gtTrees:
  72. if source.turnToLumberYard(x, y):
  73. gtLumberYard
  74. else:
  75. gtTrees
  76. of gtLumberYard:
  77. if source.remainLumberYard(x, y):
  78. gtLumberYard
  79. else:
  80. gtOpen
  81. const loops = 1_000_000_000
  82. var
  83. grounds: array[100, Ground] # Arbitrary guess for maximum loop size
  84. activeGround, t: int
  85. grounds[0].load
  86. while t < loops:
  87. t.inc
  88. let nextGround = (activeGround + 1) mod grounds.len
  89. grounds[activeGround].step(grounds[nextGround])
  90. activeGround = nextGround
  91. if t == 10:
  92. echo grounds[activeGround].resourceValue
  93. # This isn't solvable by brute force, so assume that at some point the
  94. # state will repeat itself. If we find a loop, just jump the time ahead
  95. # by as many loops as we can, and carry on evaluating for the last few.
  96. for i, o in grounds:
  97. if i != activeGround and o == grounds[activeGround]:
  98. let
  99. loopLength = (grounds.len + activeGround - i) mod grounds.len
  100. remaining = (loops - t) mod loopLength
  101. t = loops
  102. activeGround = (i + remaining) mod grounds.len
  103. break
  104. echo grounds[activeGround].resourceValue