part-02.scm 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. (import
  2. (except (rnrs base)
  3. let-values
  4. map
  5. error
  6. vector-map)
  7. (only (guile)
  8. lambda* λ
  9. simple-format
  10. current-output-port)
  11. (fileio)
  12. (queue)
  13. (list-helpers)
  14. (math)
  15. ;; lists
  16. (srfi srfi-1)
  17. ;; vectors
  18. (srfi srfi-43)
  19. ;; let-values
  20. ;; (srfi srfi-11)
  21. ;; hash tables
  22. ;; (srfi srfi-69)
  23. ;; functional records
  24. (srfi srfi-9 gnu)
  25. (ice-9 pretty-print)
  26. (ice-9 peg)
  27. (prefix (peg-tree-utils) peg-tree:))
  28. ;; define parser
  29. (define-peg-pattern SPACE none " ")
  30. (define-peg-pattern NEWLINE none "\n")
  31. (define-peg-pattern COLON none ":")
  32. (define-peg-pattern KEY-VAL-SEP none (and COLON SPACE))
  33. (define-peg-pattern NUMBER body (+ (range #\0 #\9)))
  34. (define-peg-pattern ANYTHING-EXCEPT-NUMBER none
  35. (* (and (not-followed-by NUMBER) peg-any)))
  36. ;; 1. line
  37. (define-peg-pattern MONKEY-LABEL none "Monkey")
  38. (define-peg-pattern ID all NUMBER)
  39. ;; 2. line
  40. (define-peg-pattern NUMBER-LIST all (* (and NUMBER (? ",") (? SPACE))))
  41. (define-peg-pattern ITEMS-LINE all (and ANYTHING-EXCEPT-NUMBER NUMBER-LIST))
  42. ;; 3. line
  43. (define-peg-pattern OP-LABEL none "Operation")
  44. (define-peg-pattern OP-VAR-NEW none "new")
  45. (define-peg-pattern OP-EQUALS none "=")
  46. (define-peg-pattern OP-VAR-OLD none "old")
  47. (define-peg-pattern OPERATOR all (or "+" "*"))
  48. (define-peg-pattern OPERAND-OLD body "old")
  49. (define-peg-pattern OPERAND all (or NUMBER OPERAND-OLD))
  50. (define-peg-pattern OPERATION all
  51. (and OPERATOR SPACE OPERAND))
  52. (define-peg-pattern ID-LINE all
  53. (and MONKEY-LABEL SPACE ID COLON))
  54. (define-peg-pattern OP-LINE all
  55. (and (* SPACE) OP-LABEL KEY-VAL-SEP
  56. OP-VAR-NEW SPACE OP-EQUALS SPACE OP-VAR-OLD SPACE
  57. OPERATION))
  58. ;; 4. line
  59. (define-peg-pattern TEST-DIVISOR all NUMBER)
  60. (define-peg-pattern TEST-LINE all (and ANYTHING-EXCEPT-NUMBER TEST-DIVISOR))
  61. ;; 5. line
  62. (define-peg-pattern TEST-TRUE-NEXT-MONKEY all NUMBER)
  63. (define-peg-pattern TEST-TRUE-LINE all (and ANYTHING-EXCEPT-NUMBER TEST-TRUE-NEXT-MONKEY))
  64. ;; 6. line
  65. (define-peg-pattern TEST-FALSE-NEXT-MONKEY all NUMBER)
  66. (define-peg-pattern TEST-FALSE-LINE all (and ANYTHING-EXCEPT-NUMBER TEST-FALSE-NEXT-MONKEY))
  67. (define-peg-pattern MONKEY all
  68. (and ID-LINE NEWLINE
  69. ITEMS-LINE NEWLINE
  70. OP-LINE NEWLINE
  71. TEST-LINE NEWLINE
  72. TEST-TRUE-LINE NEWLINE
  73. TEST-FALSE-LINE))
  74. ;; define model
  75. (define-immutable-record-type <monkey>
  76. (make-monkey id items inspections operation test-divisor true-next false-next)
  77. monkey?
  78. (id monkey-id)
  79. (operation monkey-operation)
  80. (test-divisor monkey-test-divisor)
  81. (true-next monkey-true-next)
  82. (false-next monkey-false-next)
  83. (items monkey-items set-monkey-items)
  84. (inspections monkey-inspections set-monkey-inspections))
  85. (set-record-type-printer!
  86. <monkey>
  87. (lambda (record port)
  88. (simple-format port
  89. "<monkey: id:~a items:~a inspections:~a true-next:~a false-next:~a>"
  90. (monkey-id record)
  91. (monkey-items record)
  92. (monkey-inspections record)
  93. (monkey-true-next record)
  94. (monkey-false-next record))))
  95. (define-syntax ->
  96. (syntax-rules ()
  97. ;; first expression is left unchanged
  98. [(-> expr) expr]
  99. ;; take from the back, wrap other calls
  100. [(-> expr* ... (op args* ...))
  101. (op args* ... (-> expr* ...))]
  102. ;; make parens unnecessary in trivial case of no further arguments
  103. [(-> expr* ... op)
  104. (op (-> expr* ...))]))
  105. (define lines (get-lines-from-file "input"))
  106. (define monkey-lines
  107. (split-into-segments lines (λ (line) (string-null? line))))
  108. (define string-operator->operator
  109. (λ (str)
  110. (cond
  111. [(string=? str "+") +]
  112. [(string=? str "*") *]
  113. [else (error "unrecognized operator" str)])))
  114. (define monkey-lines->monkey
  115. (λ (lines)
  116. (let* ([monkey-str (string-join lines "\n")]
  117. [tree (peg:tree (match-pattern MONKEY monkey-str))])
  118. (let ([id (string->number (car (peg-tree:tree-refs tree '(ID))))]
  119. [items
  120. (map string->number
  121. (string-split (car (peg-tree:tree-refs tree '(ITEMS-LINE NUMBER-LIST)))
  122. #\,))]
  123. [inspections 0]
  124. ;; Operation is a function taking the previous
  125. ;; worry value as argument.
  126. [operation
  127. (let ([operand-str (car (peg-tree:tree-refs tree '(OPERATION OPERAND)))]
  128. [operator
  129. (string-operator->operator
  130. (car (peg-tree:tree-refs tree '(OPERATION OPERATOR))))])
  131. ;; Handling the annoying special case ...
  132. (cond
  133. [(string=? operand-str "old")
  134. (λ (worry)
  135. (operator worry worry))]
  136. [else
  137. (λ (worry)
  138. (operator worry (string->number operand-str)))]))]
  139. [test-divisor
  140. (string->number
  141. (car (peg-tree:tree-refs tree '(TEST-DIVISOR))))]
  142. [test-true-next-monkey
  143. (string->number
  144. (car (peg-tree:tree-refs tree '(TEST-TRUE-NEXT-MONKEY))))]
  145. [test-false-next-monkey
  146. (string->number
  147. (car (peg-tree:tree-refs tree '(TEST-FALSE-NEXT-MONKEY))))])
  148. ;; (make-monkey id items inspections operation test true-next false-next)
  149. (make-monkey id
  150. items
  151. 0 ; inspections so far
  152. operation
  153. test-divisor
  154. test-true-next-monkey
  155. test-false-next-monkey)))))
  156. (define monkeys
  157. (list->vector
  158. (map monkey-lines->monkey
  159. monkey-lines)))
  160. (define bored
  161. (λ (modulus item-worry)
  162. (remainder item-worry modulus)))
  163. (define calc-modulus
  164. (λ (monkeys)
  165. (product
  166. (vector->list
  167. (vector-map (λ (index monkey) (monkey-test-divisor monkey))
  168. monkeys)))))
  169. (define move-items
  170. (λ (monkeys ind modulus)
  171. (let iter ([items° (monkey-items (vector-ref monkeys ind))]
  172. [monkeys° monkeys])
  173. (let* ([monkey (vector-ref monkeys ind)]
  174. [monkey-op (monkey-operation monkey)])
  175. (cond
  176. [(null? items°) monkeys°]
  177. [else
  178. (let* ([new-item-worry (-> items° car monkey-op (bored modulus))])
  179. (let ([target-monkey-ind
  180. (if (divisible-by? new-item-worry (monkey-test-divisor monkey))
  181. (monkey-true-next monkey)
  182. (monkey-false-next monkey))])
  183. ;; (simple-format (current-output-port)
  184. ;; "moving item from index: ~a to index: ~a\n"
  185. ;; ind target-monkey-ind)
  186. ;; Remove item from current monkey's item list
  187. ;; and add to inspection counter.
  188. (vector-set! monkeys°
  189. ind
  190. (set-fields monkey
  191. ((monkey-inspections)
  192. (+ (monkey-inspections (vector-ref monkeys° ind)) 1))
  193. ((monkey-items) (drop items° 1))))
  194. ;; Append the item to the target monkey's item
  195. ;; list.
  196. (let* ([target-monkey (vector-ref monkeys° target-monkey-ind)]
  197. [target-monkey-items
  198. (append (monkey-items target-monkey)
  199. (list new-item-worry))]
  200. [updated
  201. (set-monkey-items target-monkey target-monkey-items)])
  202. (vector-set! monkeys° target-monkey-ind updated))
  203. (iter (cdr items°) monkeys°)))])))))
  204. (define calc-rounds
  205. (λ (monkeys num-rounds)
  206. ;; The mathematical trick to keep the integers low is to
  207. ;; calculate modulo. But what should the modulus be?
  208. ;; Each one of the monkeys' divisors alone would not
  209. ;; work. To calculate modulo one of them would change
  210. ;; the results with regards to another monkey's divisor,
  211. ;; when checking for divisibility. However, apparently
  212. ;; one can multiply all the divisors to get a bigger
  213. ;; modulus, which makes things work out for all monkeys'
  214. ;; divisibility tests.
  215. (define modulus (calc-modulus monkeys))
  216. (let iter ([round° 0] [monkeys° monkeys] [monkey-ind 0])
  217. (when (and (or (< round° 10) (= (remainder round° 100) 0)) (= monkey-ind 0))
  218. (simple-format (current-output-port) "state:\n")
  219. (pretty-print monkeys°))
  220. (cond
  221. [(>= round° num-rounds)
  222. ;; (simple-format (current-output-port) "done simulating rounds\n")
  223. monkeys°]
  224. [(>= monkey-ind (vector-length monkeys°))
  225. ;; (when (or (< round° 10)
  226. ;; (= (remainder round° 100) 0))
  227. ;; (simple-format (current-output-port) "simulate round ~a\n" round°))
  228. (iter (+ round° 1) monkeys° 0)]
  229. [else
  230. ;; (when (or (< round° 10)
  231. ;; (= (remainder round° 1000) 0))
  232. ;; (simple-format (current-output-port) "moving items of monkey ~a\n" monkey-ind))
  233. (iter round°
  234. (move-items monkeys° monkey-ind modulus)
  235. (+ monkey-ind 1))]))))
  236. (define monkey-business
  237. (λ (monkeys)
  238. (product
  239. (n-highest
  240. (vector->list
  241. (vector-map (λ (ind monkey) (monkey-inspections monkey))
  242. monkeys))
  243. 2))))
  244. (define after-10000-rounds (calc-rounds monkeys 10000))
  245. ;; (simple-format (current-output-port) "monkeys after 10000 rounds:\n")
  246. ;; (pretty-print after-10000-rounds)
  247. (define result (monkey-business after-10000-rounds))
  248. ;; (simple-format (current-output-port)
  249. ;; "~a\n"
  250. ;; (vector->list
  251. ;; (vector-map (λ (ind monkey) (monkey-inspections monkey))
  252. ;; monkeys)))
  253. (simple-format (current-output-port) "result: ~a\n" result)
  254. ;; (define apply-n-times
  255. ;; (λ (func thing n)
  256. ;; (let iter ([count 0] [result thing])
  257. ;; (cond
  258. ;; [(< count n)
  259. ;; (iter (+ count 1) (func result))]
  260. ;; [else
  261. ;; result]))))