puzzle-01.scm 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. (import
  2. (except (rnrs base) let-values map error)
  3. (only (guile) lambda* λ command-line string-null?)
  4. (ice-9 peg)
  5. (srfi srfi-1)
  6. (fileio))
  7. ;; GRAMMAR
  8. (define-peg-pattern ALPHA-NUMERIC body
  9. (or (range #\0 #\9) (range #\a #\z) (range #\A #\Z)))
  10. (define-peg-pattern KEY-VALUE-SEP none ":")
  11. (define-peg-pattern PAIR-SEP body " ")
  12. (define-peg-pattern VALUE-CHARS body
  13. (or (range #\0 #\9) (range #\a #\z) (range #\A #\Z) "#")
  14. #;(and (* (and peg-any (not-followed-by PAIR-SEP)))
  15. (and peg-any (followed-by PAIR-SEP))))
  16. (define-peg-pattern VALUE all (+ VALUE-CHARS))
  17. (define-peg-pattern BIRTH-YEAR body "byr")
  18. (define-peg-pattern ISSUE-YEAR body "iyr")
  19. (define-peg-pattern EXPIRATION-YEAR body "eyr")
  20. (define-peg-pattern HEIGHT body "hgt")
  21. (define-peg-pattern HAIR-COLOR body "hcl")
  22. (define-peg-pattern EYE-COLOR body "ecl")
  23. (define-peg-pattern PASSPORT-ID body "pid")
  24. (define-peg-pattern COUNTRY-ID body "cid")
  25. (define-peg-pattern KNOWN-KEYS body
  26. (or BIRTH-YEAR
  27. ISSUE-YEAR
  28. EXPIRATION-YEAR
  29. HEIGHT
  30. HAIR-COLOR
  31. EYE-COLOR
  32. PASSPORT-ID
  33. COUNTRY-ID))
  34. (define-peg-pattern KEY body KNOWN-KEYS)
  35. (define-peg-pattern KEY-VALUE-PAIR body (and KEY KEY-VALUE-SEP VALUE))
  36. (define-peg-pattern PASSPORT body
  37. (and (* (and KEY-VALUE-PAIR PAIR-SEP))
  38. KEY-VALUE-PAIR))
  39. (define get-value-from-peg-tree
  40. (λ (peg-tree label)
  41. (cond
  42. [(null? peg-tree) #f]
  43. [(pair? (car peg-tree))
  44. (or (get-value-from-peg-tree (car peg-tree) label)
  45. (get-value-from-peg-tree (cdr peg-tree) label))]
  46. [(string? (car peg-tree))
  47. (cond
  48. [(string=? (car peg-tree) label)
  49. (cadadr peg-tree)]
  50. [else
  51. (get-value-from-peg-tree (cdr peg-tree) label)])]
  52. [else
  53. (get-value-from-peg-tree (cdr peg-tree) label)])))
  54. (define println
  55. (λ (thing)
  56. (simple-format (current-output-port) "~a\n" thing)))
  57. (define lines->passport-data
  58. (lambda* (lines #:key (passport-separator-test string-null?) (key-separator " "))
  59. (let next-line ([remaining-lines lines] [single-passport-data ""])
  60. (cond
  61. [(null? remaining-lines)
  62. (list (string-trim-both single-passport-data))]
  63. [else
  64. (let ([cur-line (car remaining-lines)])
  65. (cond
  66. ;; The passport-separator finishes an entry in
  67. ;; the lines. We cons the single passport data
  68. ;; onto the recursion and start collecting data
  69. ;; for the next single passport.
  70. [(passport-separator-test cur-line)
  71. (cons (string-trim-both single-passport-data)
  72. (next-line (cdr remaining-lines) ""))]
  73. ;; If more data for a single passport follows, we
  74. ;; append it onto the single passport data and
  75. ;; look at the next line.
  76. [else
  77. (next-line (cdr remaining-lines)
  78. (string-append single-passport-data
  79. key-separator
  80. cur-line))]))]))))
  81. (define valid-passport?
  82. (λ (passport)
  83. (let ([tree (peg:tree passport)]
  84. [mandatory-keys '("byr" "iyr" "eyr" "hgt" "hcl" "ecl" "pid")]
  85. [optional-keys '("cid")])
  86. (let ([key-containments
  87. (map (λ (key) (if tree (get-value-from-peg-tree tree key) #f))
  88. mandatory-keys)])
  89. ;; (simple-format (current-output-port) "key containments: ~a\n" key-containments)
  90. ;; (simple-format (current-output-port) "result: ~a\n" (reduce (λ (elem acc)
  91. ;; (and acc elem))
  92. ;; #f
  93. ;; key-containments))
  94. (reduce (λ (elem acc) (and acc elem))
  95. #f
  96. key-containments)))))
  97. (define main
  98. (λ (cmd-line-args)
  99. (let* ([lines (get-lines-from-file (second cmd-line-args))]
  100. [passport-data (lines->passport-data lines)]
  101. [passports (map (λ (datum) (match-pattern PASSPORT datum))
  102. passport-data)])
  103. (length (filter valid-passport? passports)))))
  104. (simple-format (current-output-port)
  105. "~a\n"
  106. (main (command-line)))