Advent of Code: Quick & Dirty Parsing
Password Philosophy
After a couple of AoCs I have an impression that quick and dirty parsing is usually the best approach: choosing correct separator for string splitting and converting strings to numbers covers most of the requirements.
(destructuring-bind (i j c password)
(cl-ppcre:split "[- ]" "17-18 z: bzzzzxtzcxzjvzzlzbn")
(list (parse-integer i) (parse-integer j) (char c 0) password))
(17 18 #\z "bzzzzxtzcxzjvzzlzbn")
Handy Haversacks
Even if input seems very human language like, I found regular expressions, or, even better, a well placed string split to be more than enough.
dark orange bags contain 3 bright white bags, 4 muted yellow bags. light red bags contain 1 bright white bag. faded blue bags contain no other bags.
When I saw this "chatty input", it was very tempting to use recursive pattern matching… So I did.
(defpackage :chatty-input-example
(:use :cl :str :trivia)
(:import-from :alexandria :compose))
(in-package :chatty-input-example)
(defun parse-chatty-words (words)
(match words
((list* a b "bags" "contain" rest)
(cons (list a b) (parse-chatty-words rest)))
((list* (read n) a b bags rest)
(cons (cons (list a b) n)
(when (ends-with-p "," bags)
(parse-chatty-words rest))))
;; "no" "bags." and nil cases skipped.
))
(mapcar (compose #'parse-chatty-words #'words)
(lines "dark orange bags contain 3 bright white bags, 4 muted yellow bags.
light red bags contain 1 bright white bag.
faded blue bags contain no other bags."))
((("dark" "orange") (("bright" "white") . 3) (("muted" "yellow") . 4))
(("light" "red") (("bright" "white") . 1)) (("faded" "blue")))
Unnecessary complicated. Recursion is too powerful here. A start of LL parsing? It's easier to split on "bags contain".
(in-package :chatty-input-example)
(defun parse-n-bags (text)
(multiple-value-bind (n end) (parse-integer text :junk-allowed t)
(cons (subseq text (1+ end)) n)))
(defun parse-chatty-line (line)
(destructuring-bind (l r) (split " bags contain " line)
(cons l (unless (starts-with-p "no" r)
(mapcar #'parse-n-bags (cl-ppcre:split " bags?(.|, )" r))))))
(mapcar #'parse-chatty-line
(lines "dark orange bags contain 3 bright white bags, 4 muted yellow bags.
light red bags contain 1 bright white bag.
faded blue bags contain no other bags."))
(("dark orange" ("bright white" . 3) ("muted yellow" . 4))
("light red" ("bright white" . 1)) ("faded blue"))
So let it be a reminder for myself to not overthink input parsing in online competitions.