2.rkt 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. #lang racket
  2. (require "../lib/utils.rkt")
  3. (require "../lib/obj.rkt")
  4. (define (read-input)
  5. (call-with-input-file "input"
  6. (λ (fp)
  7. (list->vector (get-lines fp)))))
  8. (define schema (read-input))
  9. (define (char-at line col)
  10. (string-ref (vector-ref schema line) col))
  11. (define height (vector-length schema))
  12. (define width (string-length (vector-ref schema 0)))
  13. (define make-num (obj-maker 'line 'col 'value 'length))
  14. (define (scan-nums)
  15. (define nums '())
  16. (let loop ((i 0))
  17. (if (>= i height)
  18. (void)
  19. (let ()
  20. (let loop ((j 0))
  21. (define curline (vector-ref schema i))
  22. (if (>= j width)
  23. (void)
  24. (let ()
  25. (define next 1)
  26. (define (find-next)
  27. (if (or (>= (+ j next) 140)
  28. (not (char-numeric? (char-at i (+ j next)))))
  29. (void)
  30. (let ()
  31. (set! next (+ 1 next))
  32. (find-next))))
  33. (if (char-numeric? (char-at i j))
  34. (let ()
  35. (find-next)
  36. (define value (string->number (substring curline j (+ j next))))
  37. (set! nums (cons (make-num i j value next) nums)))
  38. (void))
  39. (loop (+ j next)))))
  40. (loop (+ 1 i)))))
  41. (reverse nums))
  42. (define nums (scan-nums))
  43. (define (collect-adjacent-positions num)
  44. (define (position-range line start end)
  45. (define delta (- end start))
  46. (map list (repeat delta line) (range start end)))
  47. (define left
  48. (if (= 0 (num 'col))
  49. '()
  50. (list (list (num 'line) (- (num 'col) 1)))))
  51. (define right
  52. (if (= width (+ (num 'col) (num 'length)))
  53. '()
  54. (list (list (num 'line) (+ (num 'col) (num 'length))))))
  55. (define up
  56. (if (= 0 (num 'line))
  57. '()
  58. (position-range (- (num 'line) 1)
  59. (max 0 (- (num 'col) 1))
  60. (min width (+ (num 'col) (num 'length) 1)))))
  61. (define down
  62. (if (= (- height 1) (num 'line))
  63. '()
  64. (position-range (+ (num 'line) 1)
  65. (max 0 (- (num 'col) 1))
  66. (min width (+ (num 'col) (num 'length) 1)))))
  67. (append left right up down))
  68. (define asterisks (make-hash))
  69. (define (mark-adj-asterisk num)
  70. (define adjs (collect-adjacent-positions num))
  71. (define (mark coord)
  72. (if (not (char=? #\* (char-at (car coord) (cadr coord))))
  73. (void)
  74. (let ()
  75. (when (not (hash-has-key? asterisks coord))
  76. (hash-set! asterisks coord '()))
  77. (hash-set! asterisks coord (cons (num 'value) (hash-ref asterisks coord))))))
  78. (for-each mark adjs))
  79. (for-each mark-adj-asterisk nums)
  80. (define aster-list (hash->list asterisks))
  81. (define (is-gear? aster)
  82. (define nums-list (cdr aster))
  83. (= 2 (length nums-list)))
  84. (define (power aster)
  85. (define nums-list (cdr aster))
  86. (* (car nums-list) (cadr nums-list)))
  87. (apply + (map power (filter is-gear? aster-list)))