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.