My solutions to 2018's advent of code
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
Ce dépôt est archivé. Vous pouvez voir les fichiers et le cloner, mais vous ne pouvez pas pousser ni ouvrir de ticket/demande d'ajout.

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