part-01.scm 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. (import
  2. (except (rnrs base) let-values map error)
  3. (only (guile)
  4. lambda* λ
  5. current-output-port)
  6. (fileio)
  7. (math)
  8. (list-helpers)
  9. (array-helpers)
  10. ;; lists
  11. (srfi srfi-1)
  12. ;; let-values
  13. (srfi srfi-11)
  14. ;; hash tables
  15. (srfi srfi-69)
  16. ;; functional records
  17. (srfi srfi-9 gnu)
  18. (ice-9 pretty-print))
  19. (define lines (get-lines-from-file "input"))
  20. (define noop?
  21. (λ (line)
  22. (string=? line "noop")))
  23. (define addx?
  24. (λ (line)
  25. (string-prefix? "addx" line)))
  26. (define addx-get-number
  27. (λ (line)
  28. (string->number
  29. (second (string-split line #\space)))))
  30. (define signal-strength
  31. (λ (cycle register)
  32. (* cycle register)))
  33. (define-immutable-record-type <state>
  34. (make-state cycle register)
  35. state?
  36. (cycle state-cycle set-state-cycle)
  37. (register state-register set-state-register))
  38. (set-record-type-printer!
  39. <state>
  40. (lambda (record port)
  41. (simple-format port "<state: cycle:~a register:~a>"
  42. (state-cycle record)
  43. (state-register record))))
  44. (define initial-state (make-state 0 1))
  45. (define run-instruction
  46. (λ (state instruction)
  47. (cond
  48. [(noop? instruction)
  49. (set-state-cycle state (+ (state-cycle state) 1))]
  50. [(addx? instruction)
  51. (let ([register-increment (addx-get-number instruction)])
  52. (set-fields state
  53. ((state-cycle) (+ (state-cycle state) 1))
  54. ((state-register) (+ (state-register state) register-increment))))]
  55. [else
  56. (error "unrecognized instruction" instruction)])))
  57. ;; Idea: Translate addx <number> to 2 instructions, a noop
  58. ;; instruction and the actual adding instruction, both
  59. ;; taking 1 cycle. This should make it easier to write the
  60. ;; rest of the logic, because one does not have to consider
  61. ;; addx <number> taking 2 cycles.
  62. (define instructions
  63. (let iter-lines ([lines° lines])
  64. (cond
  65. [(null? lines°) '()]
  66. [else
  67. (let ([line (car lines°)])
  68. (cond
  69. [(noop? line)
  70. (cons line (iter-lines (cdr lines°)))]
  71. [(addx? line)
  72. (cons "noop"
  73. (cons line
  74. (iter-lines (cdr lines°))))]
  75. [else
  76. (error "unrecognized input line" line)]))])))
  77. (define significant-cycle?
  78. (λ (cycle)
  79. (= (remainder (+ cycle 20) 40) 0)))
  80. (define calc-score
  81. (λ (state instruction previous-score)
  82. (cond
  83. [(significant-cycle? (state-cycle state))
  84. (+ previous-score
  85. (signal-strength (state-cycle state)
  86. (state-register state)))]
  87. [else previous-score])))
  88. ;; Now we can act, as if every instruction merely takes 1
  89. ;; cycle.
  90. (define final-signal-strength
  91. (let iter ([state initial-state]
  92. [instructions° instructions]
  93. [score 0])
  94. (simple-format (current-output-port) "~a\n" state)
  95. (cond
  96. [(null? instructions°) score]
  97. [else
  98. (let ([instruction (car instructions°)])
  99. (iter (run-instruction state instruction)
  100. (cdr instructions°)
  101. (calc-score state instruction score)))])))
  102. (simple-format (current-output-port)
  103. "~a\n"
  104. final-signal-strength)