Folders and files
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Repository files navigation
* Tackling Advent of Code 2020 in emacs lisp ** Resources [[https://adventofcode.com][Advent of code]] *** Utility functions **** Read data Utility functions for loading the input data. ~read-lines~ adapted from an example by [[http://ergoemacs.org/emacs/elisp_read_file_content.html][Xah Lee]]. #+begin_src emacs-lisp (defun read-lines (filePath) "Return a list of lines of a file at filePath." (with-temp-buffer (insert-file-contents filePath) (split-string (buffer-string) "\n" nil))) (defun line-to-numbers (line) "Convert a whitespace separated list of strings into numbers" (apply 'string-to-number (split-string line)) ) (defun read-numbers (filePath) "Return a list of all the numbers in a file at filePath." (let ( (lines (read-lines filePath)) ) (mapcar 'line-to-numbers lines)) ) #+end_src #+RESULTS: : read-numbers ** Day 01 [[https://adventofcode.com/2020/day/1][Instructions]] *** Part 1 **** Requirements 1. Load puzzle input 2. Find which 2 values in puzzle input sum to 2020 3. Return product of those 2 values **** Load data #+begin_src emacs-lisp (setq data (read-numbers '"inputs/day1.txt")) #+end_src #+RESULTS: | 997 | 1582 | 1790 | 1798 | 1094 | 1831 | 1879 | 1730 | 1995 | 1702 | 1680 | 1869 | 1964 | 1777 | 1862 | 1928 | 1997 | 1741 | 1604 | 1691 | 1219 | 1458 | 1749 | 1717 | 1786 | 1665 | 1724 | 1998 | 1589 | 1828 | 1953 | 1848 | 1500 | 1590 | 1968 | 1948 | 1323 | 1800 | 1986 | 679 | 1907 | 1916 | 1820 | 1661 | 1479 | 1808 | 1824 | 1825 | 1952 | 1666 | 1541 | 1791 | 1906 | 1638 | 1557 | 1999 | 1710 | 1549 | 1912 | 1974 | 1628 | 1748 | 1411 | 1978 | 1865 | 1932 | 1839 | 1892 | 1981 | 1807 | 357 | 912 | 1443 | 1972 | 1816 | 1890 | 1029 | 1175 | 1522 | 1750 | 2001 | 1655 | 1955 | 1949 | 1660 | 233 | 1891 | 1994 | 1934 | 1908 | 1573 | 1712 | 1622 | 1770 | 1574 | 1778 | 1851 | 2004 | 1818 | 1200 | 1229 | 1110 | 1005 | 1716 | 1765 | 1835 | 1773 | 15 | 1914 | 1833 | 1689 | 1843 | 1718 | 1872 | 390 | 1941 | 1178 | 1670 | 1899 | 1864 | 1913 | 2010 | 1855 | 1797 | 1767 | 1673 | 1657 | 1607 | 1305 | 1341 | 1662 | 1845 | 1980 | 1534 | 1789 | 1876 | 1849 | 1926 | 1958 | 977 | 1709 | 1647 | 1832 | 1785 | 1854 | 1667 | 1679 | 1970 | 1186 | 2000 | 1681 | 1684 | 1614 | 1988 | 1561 | 1594 | 1636 | 1327 | 1696 | 1915 | 1045 | 1829 | 1079 | 1295 | 1213 | 1714 | 1992 | 1984 | 1951 | 1687 | 1842 | 1792 | 87 | 1732 | 428 | 1799 | 1850 | 1962 | 1629 | 1965 | 1142 | 1040 | 131 | 1844 | 1454 | 1779 | 1369 | 1960 | 1887 | 1725 | 1893 | 1465 | 1676 | 1826 | 1462 | 1408 | 1937 | 1643 | 1069 | 1759 | **** Processing Loop over each value, and return the values where ~2020 - value~ is in the list of all values. Return those two values (since we'll find both halves in a pass through the full list). #+begin_src emacs-lisp (defun inverse-in-list (sequence item) (if (member (- 2020 item) sequence) t nil)) (setq result (seq-filter (apply-partially 'inverse-in-list data) data)) #+end_src #+RESULTS: | 679 | 1341 | And the final result is the product of those two values: #+begin_src emacs-lisp (setq result_part1 (eval (cons '* result))) #+end_src #+RESULTS: : 910539 I think this approach of inserting the operator into the start of the list, and then evaluating the list, is the "lisp-ish" way to multiply the list together. But I'm not certain there isn't a better method. *** Part 2 **** Requirements 1. Find product of the three numbers that sum to 2020 **** Processing Already have processing for 2 numbers that sum to 2020. Can we loop over each value in the input data and calculate if two numbers in the input sum to ~(2020 - current loop value)~? First, can we change ~inverse-in-list~ to use an arbitrary value rather than 2020? #+begin_src emacs-lisp (defun inverse-in-list (sequence item reference) (if (member (- item reference) sequence) t nil)) (setq result (seq-filter (apply-partially 'inverse-in-list data 2020) data)) #+end_src #+RESULTS: | 679 | 1341 | And now loop over each value in the input, and call the new ~inverse-in-list~ with a reference of ~2020 - value~: #+begin_src emacs-lisp (setq result '()) (dolist (current-data data result) (setq interim_result (seq-filter (apply-partially 'inverse-in-list data (- 2020 current-data)) data)) (if interim_result (push current-data result)) ) #+end_src #+RESULTS: | 131 | 977 | 912 | In English, the above creates a ~result~ list to accumulate the values we want to multiply. Then, for each ~current-data~ in the ~data~ list, we check if any two values in the list add up to ~(2020 - current-data)~. If they do, we accumulate the ~current-data~. Notice that the third argument of ~do-list~ is the returned value, in this case the accumulated ~result~. Finally, a similar multiplication as for part 1: #+begin_src emacs-lisp (setq result_part2 (eval (cons '* result))) #+end_src #+RESULTS: : 116724144 ** Day 02 [[https://adventofcode.com/2020/day/2][Instructions]] *** Part 1 **** Requirements 1. Load puzzle input 2. Count valid passwords in input, where valid password defined as: #+begin_quote suppose you have the following list: 1-3 a: abcde 1-3 b: cdefg 2-9 c: ccccccccc Each line gives the password policy and then the password. The password policy indicates the lowest and highest number of times a given letter must appear for the password to be valid. For example, 1-3 a means that the password must contain a at least 1 time and at most 3 times. #+end_quote **** Processing So let's start with a function to validate a single line: #+begin_src emacs-lisp (defun password-break-line (line) "Breaks a line from the day 2 input in to the parts needed for validation" (let* ( (parts (split-string line)) (counts (split-string (elt parts 0) "-"))) (setq min-count (string-to-number (elt counts 0)) max-count (string-to-number (elt counts 1)) letter (substring (elt parts 1) 0 1) password (elt parts 2) ) ) ) (defun validate-password (line) "Checks if a password is valid according to the day 2 instructions." (message line) (password-break-line line) (let ( (letter-count (- (length (split-string password letter ) ) 1) ) ) (setq result (<= min-count letter-count max-count)) ) result ) (validate-password "2-9 c: ccccccccc") #+end_src #+RESULTS: : t And now apply across all lines: #+begin_src emacs-lisp (setq data (read-lines '"inputs/day2.txt")) (setq result (seq-filter 'validate-password data)) (length result) #+end_src #+RESULTS: : 434 Which is the right result for part 1 of day 2. *** Part 2 **** Requirements 1. Load puzzle input 2. Count valid passwords in input, where valid password defined as (note different to part 1): #+begin_quote Each policy actually describes two positions in the password, where 1 means the first character, 2 means the second character, and so on. (Be careful; Toboggan Corporate Policies have no concept of "index zero"!) Exactly one of these positions must contain the given letter. Other occurrences of the letter are irrelevant for the purposes of policy enforcement. Given the same example list from above: 1-3 a: abcde is valid: position 1 contains a and position 3 does not. 1-3 b: cdefg is invalid: neither position 1 nor position 3 contains b. 2-9 c: ccccccccc is invalid: both position 2 and position 9 contain c. #+end_quote **** Processing Need a different validation: #+begin_src emacs-lisp (defun get-letter (line index)) "Returns letter from line at (1-indexed) index." (let ((result (aref 'line (1+ 'index)))))) (defun validate-password (line) "Checks if a password is valid according to the day 2 instructions." (message line) (password-break-line line) (let ( (letter-count (- (length (split-string password letter ) ) 1) ) ) (setq result (<= min-count letter-count max-count)) ) result ) #+end_src and test cases: #+begin_src emacs-lisp (let ((test-result (list (validate-password "1-3 b: cdefg") (validate-password "2-9 c: ccccccccc")))) (equal 'test-result (list t nil)) ) #+end_src #+RESULTS: ** Day 04 Note that if you're using the github viewer for this file, the results are all hidden. Use the 'raw' button to see results (or download and view in the one true editor). *** Part 1 Skipping to day 4 for a python experiment. First, load the day 4 data with lisp. Loading the data isn't an interesting python problem, but combining lisp and python is an interesting problem: #+name: load-day4 #+begin_src emacs-lisp (setq day4-data (read-lines '"inputs/day4.txt")) #+end_src #+RESULTS: load-day4 | ecl:grn | cid:315 iyr:2012 hgt:192cm eyr:2023 pid:873355140 byr:1925 hcl:#cb2c03 | | byr:2027 hcl:ec0cfd ecl:blu cid:120 | eyr:1937 pid:106018766 iyr:2010 hgt:154cm | | byr:1965 eyr:2028 hgt:157cm | cid:236 iyr:2018 ecl:brn | hcl:#cfa07d pid:584111467 | | eyr:2029 ecl:hzl | iyr:1972 byr:1966 | pid:2898897192 | hgt:59cm hcl:z | | pid:231652013 hcl:#602927 hgt:166 | ecl:grn eyr:2025 | byr:2008 iyr:1986 | | byr:1928 hgt:167cm | hcl:#18171d iyr:2012 | ecl:oth pid:237657808 eyr:1944 | | hgt:73in ecl:grn byr:1931 pid:358388825 iyr:2020 | hcl:#602927 eyr:2020 | | hcl:#efcc98 eyr:2024 ecl:hzl | byr:2030 hgt:192cm | iyr:2013 pid:7479289410 | | pid:053467220 iyr:2012 hgt:169cm | cid:149 hcl:#866857 | eyr:2030 | byr:1995 ecl:oth | | hgt:162cm hcl:#efcc98 ecl:grn byr:1985 pid:419840766 | eyr:2022 | iyr:2020 | | pid:22086957 hcl:c69235 ecl:#c458c5 eyr:1986 byr:2014 hgt:72cm iyr:1934 | | hcl:#866857 | ecl:brn eyr:2024 | iyr:2017 | pid:505225484 cid:144 | byr:1980 | hgt:170cm | | hcl:#866857 ecl:gry | byr:1972 iyr:2019 eyr:2023 | cid:234 pid:721290041 hgt:191cm | | pid:346301363 | eyr:2020 | hcl:#733820 iyr:2019 hgt:177cm | byr:1998 | | hgt:157cm byr:1963 | pid:898055805 | hcl:#fffffd ecl:blu iyr:2017 cid:87 | eyr:2030 | | pid:605900764 iyr:2011 | hgt:73in ecl:hzl eyr:2024 | hcl:#888785 | cid:281 | | iyr:2010 eyr:2026 hcl:#4f7e76 pid:883386029 byr:1946 ecl:brn | | hcl:z | iyr:2020 pid:9121928466 byr:2014 ecl:zzz eyr:2025 | hgt:172in | | hgt:151cm cid:163 pid:670884417 iyr:2012 | ecl:oth hcl:#ceb3a1 | eyr:2028 | | hcl:z cid:92 hgt:69cm | byr:2008 pid:492284612 | eyr:2020 iyr:2023 | ecl:hzl | | byr:1933 | hcl:#7d3b0c eyr:2020 hgt:170cm | pid:949064511 iyr:2010 | ecl:oth | | eyr:2025 byr:1989 ecl:oth cid:100 hgt:182cm | pid:629190040 iyr:2017 hcl:#b6652a | | ecl:hzl cid:76 hcl:#e71392 eyr:2021 iyr:2013 byr:1995 | pid:762177473 | hgt:179cm | | pid:198500564 eyr:2029 hcl:#733820 cid:51 iyr:2012 | hgt:70in byr:1938 ecl:oth | | hgt:190cm ecl:brn byr:1952 iyr:2015 hcl:#623a2f | eyr:2023 | | hgt:169cm hcl:#602927 byr:2001 pid:823979592 iyr:2016 eyr:2029 | | iyr:2010 ecl:gry | eyr:2022 hgt:156cm byr:1953 pid:434063393 | hcl:#733820 | | pid:091724580 hcl:a7069e eyr:1984 ecl:#95d01e byr:2012 iyr:2005 | | eyr:2022 byr:1972 hcl:#866857 ecl:hzl pid:227453248 | hgt:153cm cid:324 iyr:2018 | | cid:195 pid:049871343 | eyr:2024 hgt:169cm | byr:1952 iyr:2010 ecl:grn | | eyr:2035 pid:189cm | hgt:77 iyr:1973 ecl:#dc83d5 | hcl:z byr:2004 | | byr:2027 | pid:89338932 hcl:1de39e ecl:grn hgt:159in eyr:2034 iyr:1937 | | pid:076534920 | hgt:152cm | byr:1969 | ecl:blu | hcl:#866857 iyr:2011 eyr:2024 | | iyr:2019 eyr:2028 | ecl:blu hgt:169cm | hcl:#888785 pid:332202163 byr:1923 | | hgt:65in byr:1964 iyr:2019 | pid:287612987 ecl:hzl cid:213 eyr:2023 hcl:#ceb3a1 | | hcl:#623a2f pid:182484027 | iyr:2016 ecl:brn byr:1943 | hgt:71in eyr:2021 cid:344 | | hcl:#cdee64 iyr:2011 ecl:brn eyr:2026 hgt:176cm | byr:1985 pid:978641227 | | eyr:2029 ecl:brn hgt:173cm byr:1920 cid:211 | hcl:#866857 | iyr:2016 pid:289769625 | | hcl:#7d3b0c pid:770938833 iyr:2010 byr:1941 ecl:oth eyr:2029 hgt:161cm | | hgt:172cm iyr:2015 ecl:gry byr:1948 | eyr:2029 | pid:466359109 hcl:#341e13 | | cid:74 pid:405199325 ecl:blu | hcl:#6b5442 | eyr:1980 byr:2024 hgt:174cm iyr:2011 | | hgt:183cm pid:075760048 cid:78 byr:1960 ecl:hzl eyr:2030 hcl:#6b5442 iyr:2014 | | cid:264 hcl:#7d3b0c | ecl:blu iyr:2011 eyr:2020 hgt:182cm | byr:1929 | | pid:435338286 byr:1931 | hcl:z ecl:amb iyr:2013 hgt:73in | cid:165 eyr:2027 | | pid:511898552 eyr:2025 hgt:184cm hcl:#602927 | iyr:2018 byr:1989 ecl:hzl | | iyr:2016 | hgt:168in | hcl:#623a2f | eyr:2025 pid:310738569 ecl:#0c3039 | byr:2027 | | pid:158cm byr:1946 ecl:grt | iyr:1920 cid:189 | hcl:389bce hgt:165cm | | pid:973732906 hcl:#cfa07d iyr:2010 eyr:2020 hgt:180cm | byr:1930 | ecl:brn | | pid:930994364 byr:1967 hgt:151cm | iyr:2011 eyr:2022 | | eyr:1968 hgt:75cm cid:241 | iyr:2011 pid:5493866745 | ecl:grt | byr:1976 hcl:#a97842 | | eyr:2026 ecl:oth | iyr:2016 hcl:#c0946f | byr:1929 | hgt:175cm | pid:9421898537 | | eyr:2028 iyr:2016 byr:1962 | ecl:grn hgt:186cm hcl:#cfa07d pid:432962396 | | iyr:2010 byr:1934 eyr:2023 hgt:180cm hcl:#cfa07d ecl:gry | | cid:168 | byr:1978 | eyr:2027 hgt:189cm pid:802710287 | hcl:#2f980b iyr:2014 | ecl:grn | | eyr:1970 | pid:576329104 | ecl:xry iyr:1954 hcl:#341e13 byr:2026 | hgt:74in | | eyr:2027 hgt:153cm | ecl:oth | hcl:#866857 | pid:290407832 byr:1956 iyr:2017 | | iyr:2011 | cid:128 | ecl:amb hcl:#7d3b0c hgt:68in pid:743606119 eyr:2020 | | ecl:oth hcl:#cfa07d | byr:2016 pid:#de98ae iyr:1984 cid:194 | hgt:170cm | eyr:2034 | | pid:526098672 hgt:168cm | hcl:#7d3b0c cid:167 byr:1923 ecl:blu iyr:2016 | eyr:2030 | | pid:495569197 hcl:#866857 hgt:193cm | iyr:2013 eyr:2021 byr:1921 ecl:amb | | ecl:amb | hcl:#a97842 pid:862249915 iyr:2012 byr:1964 | cid:325 | eyr:2021 | | iyr:1958 | byr:2003 | hgt:160 hcl:#18171d | ecl:hzl eyr:2020 | | iyr:2019 byr:1997 ecl:brn | pid:342735713 hcl:#efcc98 | hgt:181cm cid:307 | eyr:2027 | | pid:817121616 eyr:2020 | iyr:2012 | hgt:185cm | hcl:#18171d byr:1969 ecl:hzl | | pid:381399203 | ecl:oth byr:1930 | iyr:2014 hcl:#6b5442 hgt:71in cid:156 eyr:2025 | | byr:2002 hcl:#18171d iyr:2017 | pid:398245854 hgt:64in ecl:gry eyr:2025 cid:127 | | eyr:2028 hcl:#341e13 | ecl:amb iyr:2012 | pid:079796480 hgt:69cm | byr:1995 | | cid:315 iyr:2028 | pid:775929239 | hgt:162cm ecl:dne byr:1940 eyr:1952 hcl:#c0946f | | iyr:2015 | hgt:154cm byr:1997 | ecl:grn | cid:125 eyr:2024 pid:834780229 | hcl:#18171d | | ecl:hzl hcl:#a97842 pid:553710574 eyr:2028 | hgt:183cm cid:196 | iyr:2014 | | pid:377912488 hgt:159cm ecl:amb eyr:2024 byr:1974 | iyr:2014 | hcl:#ceb3a1 | | eyr:2024 | byr:1947 hgt:63in ecl:brn | cid:69 | pid:185228911 hcl:#b6652a iyr:2016 | | eyr:2024 | hgt:168cm hcl:#602927 | iyr:2013 | byr:1993 | pid:681091728 ecl:gry cid:203 | | pid:037922164 iyr:2020 | byr:1990 hgt:156cm eyr:2023 hcl:#866857 | cid:97 ecl:grn | | hgt:170cm pid:980455250 | iyr:2011 ecl:hzl byr:1957 | eyr:2030 hcl:#cfa07d | | hgt:158cm | hcl:#602927 | byr:2002 ecl:hzl iyr:2013 | cid:99 | eyr:2020 pid:48646993 | | byr:1955 pid:814033843 eyr:2030 hcl:#a97842 | hgt:191cm iyr:2019 | | pid:111196491 hgt:191cm iyr:2012 ecl:blu hcl:#a97842 | eyr:2026 cid:131 byr:1979 | | hcl:#fffffd hgt:68in | cid:121 ecl:oth eyr:2024 pid:343836937 | byr:1955 | iyr:2020 | | eyr:2025 byr:1954 | pid:737517118 | cid:343 hcl:#b6652a | iyr:2017 ecl:hzl | hgt:175cm | | ecl:brn | iyr:2011 hgt:171cm cid:102 pid:066348279 byr:1981 | | ecl:oth iyr:2018 byr:1975 | eyr:2029 | hgt:185cm cid:226 | pid:978243407 hcl:#341e13 | | iyr:2015 pid:918017915 hcl:#3e52b7 | byr:1999 ecl:brn cid:314 | eyr:2025 hgt:192cm | | hcl:#19d1fa byr:1984 ecl:dne hgt:76in | iyr:2015 cid:118 pid:417075672 | eyr:2020 | | iyr:2019 | cid:120 hgt:186cm | hcl:#733820 eyr:2024 pid:423238982 ecl:brn byr:1968 | | hgt:70cm cid:173 pid:767014975 | hcl:#866857 eyr:2039 ecl:brn byr:1985 | | pid:340424924 | eyr:2027 hcl:#7d3b0c | hgt:168cm ecl:hzl iyr:2016 | byr:1994 | | ecl:hzl byr:1933 pid:580425691 | iyr:2010 hcl:#c0946f eyr:2024 | hgt:64in | | hcl:#9fe6b0 pid:913184461 ecl:grn eyr:2030 | cid:262 iyr:2014 | | ecl:amb pid:640007768 eyr:2030 byr:2017 iyr:1988 hcl:z | | byr:1977 cid:54 | eyr:1939 pid:882762394 iyr:2030 hcl:#ceb3a1 ecl:blu | | iyr:2011 hcl:#7d3b0c byr:1928 | pid:340969354 cid:199 hgt:168cm eyr:2029 ecl:hzl | | pid:729464282 | iyr:2012 hcl:baae60 | eyr:2026 ecl:hzl hgt:166cm byr:2019 | | pid:930997801 iyr:2019 eyr:2030 | hcl:#866857 ecl:oth byr:1960 cid:235 hgt:73in | | ecl:brn | byr:1988 hgt:179cm iyr:2017 | pid:864768439 cid:305 hcl:#c0946f | eyr:2029 | | hcl:#7d3b0c ecl:grn | hgt:182cm eyr:2021 pid:719891314 | byr:1920 iyr:2017 | | hgt:62cm | cid:71 ecl:brn hcl:#fffffd iyr:2025 eyr:1997 | pid:175cm byr:2022 | | hcl:#cfa07d cid:239 eyr:2025 ecl:hzl hgt:189in byr:1980 iyr:2020 | pid:703047050 | | byr:1951 | eyr:2030 | ecl:hzl | pid:130992467 hgt:157cm hcl:#341e13 | | hgt:175cm | hcl:#623a2f | cid:68 eyr:2025 | byr:2001 ecl:oth pid:253618704 iyr:2016 | | hcl:#fffffd pid:379344553 ecl:grn | eyr:2026 | hgt:72in byr:1974 iyr:2013 | | ecl:#b4e952 byr:1970 hcl:z | eyr:2039 pid:6056894636 iyr:2021 hgt:165cm | cid:328 | | hcl:#602927 iyr:2014 pid:890429537 byr:1957 hgt:68in eyr:2020 ecl:hzl | | cid:265 byr:1961 hcl:#ceb3a1 eyr:2022 iyr:2016 hgt:184cm pid:921615309 | | byr:1951 eyr:2024 | hcl:#341e13 | ecl:amb pid:414644982 | iyr:2010 hgt:159cm | | iyr:2015 cid:319 | eyr:2029 ecl:brn pid:380237898 | hcl:#efcc98 hgt:157cm byr:1972 | | pid:237156579 ecl:#312a91 | hgt:167cm iyr:2011 hcl:#c0946f eyr:2021 byr:1953 | | ecl:hzl iyr:2015 pid:10160221 eyr:2025 hgt:175cm hcl:z byr:1939 | | hgt:59in hcl:#18171d byr:1962 ecl:hzl | iyr:2019 eyr:2025 | cid:337 pid:491938615 | | ecl:utc hgt:82 pid:51674655 byr:2020 | eyr:1954 iyr:2029 hcl:z | | pid:119530189 | cid:103 | iyr:2010 byr:1979 | hgt:168cm hcl:#a97842 ecl:brn eyr:2029 | | hgt:177cm ecl:brn | byr:1990 | pid:015089628 eyr:2028 hcl:#733820 iyr:2020 | | ecl:blu iyr:2020 hgt:189cm | hcl:#efcc98 byr:1982 pid:346500376 eyr:2021 cid:160 | | ecl:brn hgt:173cm iyr:2011 cid:259 hcl:#6b5442 eyr:2026 | byr:1995 | pid:654875035 | | ecl:grn eyr:2025 pid:147155222 byr:1942 | cid:341 hcl:#602927 | hgt:165cm | iyr:2016 | | pid:543171646 | hgt:153cm | iyr:2019 hcl:#fffffd byr:1985 cid:266 | eyr:2027 | ecl:hzl | | ecl:blu | eyr:2022 | pid:667939101 byr:1974 | cid:259 hcl:#888785 | | eyr:2030 byr:2016 iyr:2022 | pid:86902982 | ecl:zzz hgt:72 hcl:ceb867 | | hcl:#fffffd | ecl:grn pid:046978329 | byr:1924 | eyr:2025 hgt:158cm iyr:2011 | | hgt:150cm eyr:2028 byr:1985 ecl:gry hcl:#866857 pid:340615189 | iyr:2017 | cid:50 | | cid:171 hcl:#18171d pid:009562218 byr:1981 hgt:175cm eyr:2024 ecl:oth iyr:2017 | | iyr:2019 | eyr:2022 | ecl:brn hcl:#cfa07d pid:050270380 cid:159 | hgt:151cm | byr:1951 | | hcl:#7d3b0c hgt:176cm iyr:2015 byr:1923 pid:348188421 ecl:blu eyr:2029 | | byr:1997 hgt:162cm eyr:2023 pid:445685977 | iyr:2012 ecl:amb hcl:#efcc98 | | iyr:2017 ecl:oth eyr:2028 pid:791977055 hgt:170cm byr:1991 | hcl:#623a2f | | byr:1998 hcl:#fffffd | eyr:2020 | ecl:gry pid:039483695 hgt:163cm iyr:2020 | cid:165 | | ecl:hzl hgt:74in iyr:2016 pid:026214321 | cid:152 hcl:#a1f179 | eyr:2036 byr:2001 | | pid:257900949 cid:80 byr:1956 iyr:2012 hgt:165cm eyr:2030 | | pid:918371363 | ecl:xry | iyr:2012 | byr:2012 hgt:65cm | eyr:2029 | | pid:041789006 iyr:2018 byr:1945 eyr:2024 ecl:blu | hcl:#5ab31e hgt:171cm | | ecl:gry | byr:1956 cid:318 iyr:2020 hcl:#623a2f | eyr:2030 pid:020576506 hgt:184cm | | hgt:173cm iyr:2025 | eyr:2023 | ecl:amb pid:958983168 hcl:#866857 byr:1935 | | byr:1974 | eyr:2040 pid:57104308 iyr:1980 hcl:z | hgt:192in cid:295 ecl:amb | | pid:180cm hcl:1109f7 eyr:2039 byr:2020 | ecl:dne hgt:189in iyr:1921 | | iyr:2013 byr:1961 | hcl:#866857 | eyr:2025 hgt:158cm ecl:gry | | ecl:brn iyr:2013 eyr:2021 pid:978650418 byr:1980 | hcl:#ceb3a1 cid:110 | hgt:166cm | | pid:864880558 ecl:hzl hcl:#c0946f byr:1955 eyr:2027 hgt:169cm iyr:2011 | | eyr:2023 hgt:191cm hcl:#866857 | pid:454509887 | ecl:grn byr:1938 iyr:2015 | | pid:793008846 eyr:2025 ecl:grn hcl:#341e13 | hgt:187cm | byr:1973 cid:224 | iyr:2013 | | hcl:#866857 eyr:2022 pid:802335395 hgt:171cm ecl:amb | iyr:2015 byr:1991 | | hcl:#888785 pid:768625886 | hgt:180cm | eyr:2026 ecl:oth cid:178 byr:1958 | | pid:921387245 cid:82 hgt:190cm hcl:#c0946f ecl:grn | iyr:2015 eyr:2023 | | pid:0704550258 hcl:1ba8f6 iyr:2010 byr:1978 cid:130 | eyr:2030 ecl:dne hgt:66cm | | pid:626293279 hcl:#7d3b0c hgt:185cm ecl:oth | eyr:2020 byr:1937 iyr:2012 | | hgt:175 | eyr:1933 ecl:gry | hcl:#7d3b0c byr:2003 pid:#5d8fcc | iyr:2012 | | eyr:2027 | byr:1927 cid:154 | ecl:gry pid:683668809 hgt:164cm | hcl:#a97842 iyr:2011 | | byr:1940 iyr:2014 hgt:172cm eyr:2024 pid:033678324 hcl:#10fded | cid:292 ecl:oth | | iyr:1970 ecl:#201515 pid:#4cd485 eyr:2034 hgt:162 | byr:2005 cid:67 | hcl:#c0946f | | cid:306 | byr:1948 | hcl:#efcc98 | eyr:2024 hgt:171cm pid:440657854 iyr:2015 ecl:brn | | hgt:172cm ecl:brn byr:1958 pid:054926969 hcl:#4b8065 iyr:2019 | | pid:45977569 ecl:amb byr:2002 hgt:71cm hcl:z iyr:1983 | | pid:811407848 hcl:#866857 cid:112 hgt:180cm byr:1986 | ecl:brn eyr:2026 | | ecl:amb | byr:1992 | cid:288 pid:417117245 hcl:#623a2f | iyr:2011 hgt:181cm | eyr:2021 | | byr:1974 hgt:192cm cid:172 | eyr:2022 | ecl:blu | hcl:#cfa07d iyr:2014 | | eyr:2024 ecl:gry | pid:874569675 byr:1960 iyr:2017 hgt:186cm | hcl:#6b5442 | | byr:1988 eyr:2024 iyr:2020 ecl:oth hcl:#866857 pid:227304269 hgt:170cm | | ecl:grn iyr:2019 byr:2002 cid:150 hcl:#efcc98 | pid:600740993 | hgt:167cm eyr:2027 | | pid:553824537 iyr:2019 ecl:blu eyr:2025 hcl:#e21269 hgt:193cm | byr:1923 | | byr:2030 iyr:2019 ecl:#cb0911 | hcl:#cfa07d hgt:74in eyr:2012 | pid:7647207386 | | cid:289 hgt:128 pid:178cm iyr:2025 ecl:#4ad977 byr:2020 eyr:2036 hcl:#efcc98 | | cid:119 hgt:150in | hcl:z | iyr:2012 | ecl:brn eyr:1975 | byr:2007 pid:#0dcd32 | | hcl:8a1ce7 pid:0434291854 | eyr:2034 iyr:2005 | hgt:62cm byr:2029 ecl:utc | | ecl:gry hcl:#ceb3a1 byr:1976 eyr:2024 iyr:2010 hgt:188cm | pid:636312902 | | hcl:#888785 byr:2027 hgt:178in iyr:2017 pid:973095872 eyr:1952 | | hgt:179cm iyr:2015 hcl:#ceb3a1 | byr:1944 pid:182079308 cid:317 | eyr:2025 ecl:hzl | | hcl:#6b5442 ecl:grn eyr:2023 hgt:71in pid:829794667 byr:2000 | iyr:2014 cid:192 | | iyr:2014 pid:096659610 hcl:#c0946f ecl:oth byr:1991 cid:180 | hgt:177cm | eyr:2023 | | byr:2017 | eyr:2036 iyr:1933 | cid:225 ecl:gmt hgt:179in | hcl:b5c44d pid:99932231 | | hcl:#18171d | hgt:187cm eyr:2023 byr:1934 cid:286 pid:878541119 iyr:2020 ecl:amb | | hgt:185cm | pid:754207134 ecl:oth eyr:2023 | hcl:#a97842 cid:313 byr:1966 | iyr:2015 | | hcl:#ceb3a1 byr:1921 eyr:2022 pid:799265846 cid:285 | hgt:67in iyr:2015 | | iyr:2011 byr:1941 | hcl:#341e13 cid:65 pid:413556937 | hgt:169cm | ecl:amb eyr:2020 | | iyr:2016 | hgt:158cm ecl:grn byr:1931 hcl:#7d3b0c | | pid:574299170 iyr:2013 byr:1961 ecl:hzl hcl:#866857 hgt:168cm eyr:2022 | | eyr:2022 pid:245416405 | iyr:2019 hgt:173cm hcl:#c0946f | ecl:brn | byr:1965 | | byr:1980 hgt:162cm ecl:brn pid:239318191 | hcl:#fffffd | cid:58 eyr:2025 iyr:2020 | | pid:892646915 | iyr:2012 hcl:#733820 byr:1991 eyr:2021 | hgt:157cm ecl:oth | | pid:310597466 eyr:2025 | hcl:#cfa07d byr:1944 iyr:2018 ecl:oth | hgt:183cm | | iyr:2010 hgt:187cm ecl:oth | pid:975763328 | hcl:#866857 eyr:2023 cid:283 byr:1997 | | iyr:2020 cid:225 hcl:#efcc98 pid:424680047 ecl:blu | hgt:154cm | byr:1968 eyr:2027 | | ecl:oth eyr:2020 hgt:183cm hcl:#623a2f | pid:771851807 | byr:1990 | iyr:2017 | | hcl:#efcc98 ecl:blu byr:1991 hgt:191cm pid:266021118 | cid:124 | eyr:2025 | | byr:1993 | ecl:hzl eyr:2020 | hgt:163cm | iyr:2015 pid:831538073 hcl:#18171d | | hgt:74in hcl:#420afb eyr:2028 | ecl:grn pid:264469103 | byr:1993 | | eyr:2020 | cid:79 | byr:1972 | pid:084953331 hcl:#a97842 ecl:brn iyr:2010 | hgt:170cm | | iyr:2014 ecl:gry pid:094812116 eyr:2026 hgt:190cm byr:1965 hcl:#944667 | | hcl:#fffffd byr:1953 iyr:2014 ecl:hzl hgt:164cm | cid:123 eyr:2023 pid:546394433 | | iyr:2012 hgt:155cm byr:1998 pid:#2c9be6 eyr:2023 hcl:#ceb3a1 ecl:gry | | eyr:2029 ecl:gry pid:752489331 iyr:2015 hgt:167cm hcl:#18171d cid:70 byr:2002 | | byr:1938 | ecl:gry | pid:764937909 iyr:2014 | hcl:#7d3b0c | eyr:2022 cid:145 hgt:184cm | | cid:340 | byr:1924 hgt:169cm eyr:2026 | iyr:2013 ecl:amb | pid:499844992 hcl:#18171d | | pid:838417672 hgt:175cm | ecl:grt iyr:2017 eyr:2025 hcl:17aa1a | | eyr:2020 | byr:1925 hcl:#341e13 | ecl:brn cid:342 pid:047426814 hgt:156cm iyr:2012 | | iyr:2011 hcl:#341e13 byr:1959 | ecl:amb pid:969679865 | | byr:1978 cid:320 hgt:180cm hcl:#435ceb pid:363518544 eyr:2023 iyr:2016 ecl:blu | | iyr:2010 eyr:2028 | pid:183cm byr:1948 | ecl:oth cid:133 | hcl:#8d3298 hgt:190cm | | hcl:#6b5442 byr:1929 iyr:2019 pid:207713865 eyr:2029 | hgt:166cm ecl:gry | | ecl:blu iyr:2019 | byr:1985 eyr:2030 hcl:#866857 hgt:155cm pid:659180287 | | ecl:hzl | eyr:2020 iyr:2016 pid:440624039 | cid:147 | hgt:61in byr:1976 hcl:#733820 | | hcl:#341e13 pid:178082907 eyr:2023 | iyr:2015 byr:1956 | ecl:amb hgt:163cm | | eyr:2023 | iyr:2011 hcl:#cfa07d hgt:164cm | pid:291621559 byr:1960 ecl:gry | | hcl:#efcc98 byr:1976 | iyr:2017 pid:394566091 cid:248 | hgt:176cm ecl:hzl eyr:2026 | | iyr:2013 eyr:2029 hgt:152cm ecl:gry byr:1984 hcl:#623a2f pid:511780941 | | pid:953716819 iyr:2010 hgt:156cm ecl:amb | byr:1947 | hcl:#18171d eyr:2025 | | eyr:2025 ecl:amb | iyr:2016 | hcl:#cfa07d byr:1925 pid:322787273 hgt:168cm | | hgt:59in iyr:2012 | pid:916978929 byr:1959 | hcl:#c0946f eyr:2021 | ecl:brn | | byr:2018 eyr:1929 hgt:187in | hcl:z | iyr:2003 pid:0377361331 ecl:utc | | byr:1949 hcl:#fffffd pid:071791776 eyr:2030 iyr:2015 hgt:71in ecl:hzl | | hcl:#341e13 | hgt:154cm byr:1927 eyr:2023 ecl:blu iyr:2017 | pid:639867283 | | hcl:z pid:315276249 byr:2026 | hgt:151cm | iyr:2028 eyr:2020 | ecl:hzl | | hcl:#341e13 eyr:2027 byr:1981 cid:342 pid:999898177 hgt:187cm | ecl:blu iyr:2011 | | byr:2009 | hgt:73cm iyr:1921 hcl:z | pid:181cm | ecl:xry | | ecl:hzl | byr:1925 | pid:034183103 hcl:#341e13 hgt:158cm eyr:2029 iyr:2010 | | byr:1976 | iyr:2011 hgt:177cm pid:833479839 hcl:#dcab9d ecl:blu eyr:2020 | | cid:230 hcl:#7d3b0c byr:1954 | iyr:2014 eyr:2026 pid:122150889 | ecl:brn hgt:182cm | | hcl:#a97842 | ecl:brn hgt:187cm | eyr:2028 | pid:427631634 iyr:2002 byr:2004 | | pid:912516995 ecl:hzl iyr:2017 hcl:#ceb3a1 byr:1929 eyr:2028 | hgt:155cm | | pid:019809181 | cid:128 iyr:2013 hcl:#f5b9f7 byr:1931 | hgt:161cm | ecl:amb | | hgt:64in byr:1924 | iyr:2016 eyr:2029 ecl:hzl pid:474940085 hcl:#c0946f | | pid:172419213 | ecl:grn | hgt:193cm iyr:2010 byr:1973 hcl:#6b5442 | eyr:2027 | | ecl:#7b5cfd iyr:2019 | byr:2016 | eyr:2040 hgt:191in | cid:187 hcl:z pid:#c61084 | | eyr:2032 iyr:2014 pid:430247344 byr:1967 | hcl:#ceb3a1 | cid:241 | ecl:brn hgt:178in | | hcl:#623a2f iyr:2017 cid:235 | eyr:2020 byr:1978 ecl:blu hgt:175cm | | iyr:2013 ecl:amb hgt:174cm hcl:#866857 pid:285533942 byr:1954 | | hgt:152cm ecl:blu pid:952587262 eyr:2024 | iyr:2019 cid:268 hcl:#602927 byr:1947 | | hgt:176in cid:245 byr:2011 iyr:2018 | eyr:1987 | hcl:z | pid:346518170 | ecl:utc | | hgt:180cm | iyr:2015 ecl:brn eyr:2027 pid:807494368 cid:324 byr:1980 | | byr:1936 hcl:#866857 ecl:blu | eyr:2021 hgt:187cm | iyr:2016 pid:244556968 | | byr:1950 cid:125 | iyr:2020 hgt:168cm hcl:#c0946f eyr:2030 pid:758313758 ecl:blu | | eyr:2021 | pid:618915663 hcl:#cfa07d iyr:2018 byr:2002 | hgt:157cm ecl:blu | | byr:1967 | ecl:brn hcl:#c0946f pid:200495802 eyr:2021 iyr:2020 | cid:335 | hgt:181cm | | byr:1996 | ecl:brn iyr:2015 | eyr:2030 | hcl:#fffffd cid:207 | pid:022460311 hgt:158cm | | eyr:2022 hgt:59cm iyr:2023 | byr:1974 pid:354098699 hcl:b244f7 | ecl:#219505 | | hcl:#866857 eyr:2025 | pid:370874666 | byr:1947 | cid:162 ecl:oth hgt:186cm iyr:2011 | | ecl:hzl eyr:2029 | byr:1981 | iyr:2012 pid:433430792 cid:252 | hgt:171cm | | pid:512473844 hgt:186cm iyr:2012 eyr:2028 byr:1949 ecl:hzl hcl:#18171d | | hgt:60cm iyr:1934 | ecl:#4a4017 pid:3067366202 hcl:1161df | eyr:1938 byr:2008 | | pid:119509757 hcl:#cfa07d eyr:2022 hgt:174cm byr:1983 | iyr:2015 | ecl:blu | | byr:1955 eyr:2023 | cid:114 | hcl:f1aa8a pid:609049659 ecl:grn hgt:177cm | iyr:2015 | | eyr:2027 cid:284 | pid:654627982 byr:1964 iyr:2018 hgt:168cm | hcl:#fffffd ecl:oth | | iyr:1988 | hgt:191cm hcl:b87a62 byr:1990 ecl:xry | pid:996624367 eyr:1960 | | pid:641466821 eyr:2028 hcl:#7d3b0c | iyr:2010 hgt:175cm ecl:gry | | hcl:#b6652a | ecl:oth | byr:1926 eyr:2030 iyr:2019 hgt:183cm | pid:057196056 | | iyr:2017 | eyr:2022 pid:936841429 | ecl:blu hcl:#6b5442 cid:179 byr:1927 hgt:161cm | | eyr:2021 | cid:289 hgt:174cm iyr:2013 | ecl:grn pid:329574701 byr:1970 | | eyr:2021 byr:1939 ecl:gry pid:933505139 iyr:2014 hgt:173cm hcl:#7d3b0c | | cid:116 hcl:045bff eyr:2030 iyr:1920 | ecl:brn | byr:2030 | pid:#38f7f3 | hgt:155in | | eyr:2028 | pid:225829241 byr:1928 hcl:#cfa07d iyr:2019 | ecl:oth | hgt:166cm | | cid:80 byr:1936 | iyr:2017 | hgt:94 hcl:#2e7503 ecl:oth eyr:2030 | pid:597284996 | | ecl:oth | iyr:2019 hgt:76in | byr:1956 pid:821874039 | | eyr:2026 hgt:168cm | pid:019015588 | iyr:2010 | ecl:amb byr:2009 hcl:#623a2f cid:159 | | iyr:1980 hgt:167in | pid:380644909 eyr:1966 ecl:blu byr:2004 hcl:z | | eyr:2020 iyr:2013 | hcl:#08ad66 pid:540886868 | ecl:oth byr:1980 hgt:158cm | | eyr:2026 hgt:186cm byr:1995 | cid:275 | hcl:z iyr:1958 ecl:blu | | eyr:2026 iyr:2012 | hgt:61in byr:1936 pid:390833536 cid:298 ecl:grn hcl:#623a2f | | pid:393878498 eyr:2023 ecl:gry byr:1943 iyr:2010 hcl:#888785 hgt:158cm | | hgt:191cm cid:197 iyr:2014 byr:1945 | hcl:#fffffd | eyr:2020 | pid:183948344 ecl:amb | | ecl:gmt hgt:88 | cid:260 iyr:2024 byr:2022 eyr:2031 hcl:z pid:#532c6e | | hcl:#a97842 | hgt:160cm eyr:2024 ecl:blu iyr:2015 byr:1970 | | byr:1964 hgt:178cm | eyr:2025 | pid:813643223 ecl:brn iyr:2014 | hcl:#ceb3a1 | | byr:1965 eyr:2024 iyr:2018 | hgt:165cm hcl:#18171d ecl:grn pid:475669993 | | hgt:116 | iyr:2024 eyr:1974 hcl:504345 byr:2010 cid:206 pid:166cm ecl:zzz | | iyr:2014 eyr:2020 pid:096460673 byr:1948 | hgt:153cm | ecl:blu hcl:#341e13 | | hcl:#ceb3a1 | iyr:2017 hgt:67cm | pid:178cm byr:2028 ecl:brn | cid:293 | | hgt:157cm | hcl:#602927 byr:1941 | iyr:2012 pid:611003211 eyr:2029 | | iyr:2019 byr:2000 pid:083917767 eyr:2024 hgt:172cm | cid:248 hcl:#7e4d15 | | byr:1946 | hgt:160cm iyr:2020 hcl:#559278 pid:989139577 | ecl:amb eyr:2020 | | pid:165cm byr:1927 cid:178 hcl:#733820 iyr:2017 hgt:156in | eyr:2029 ecl:brn | | hcl:#18171d hgt:163cm eyr:2022 byr:1962 pid:639124940 cid:258 ecl:hzl | iyr:2015 | | cid:123 pid:4542006033 | eyr:1987 byr:2010 iyr:2029 ecl:amb | hgt:191cm hcl:#18171d | | hcl:z | byr:1928 iyr:1965 | eyr:2022 hgt:75 ecl:oth pid:400765046 | | hcl:#c0946f hgt:62in | ecl:blu byr:1978 iyr:1923 | cid:260 eyr:2021 pid:404628742 | | pid:#bf1611 ecl:grn | iyr:2018 cid:146 byr:1948 | eyr:2025 hcl:#fffffd hgt:87 | | pid:767547618 | iyr:2018 hcl:#b6652a eyr:2029 hgt:165cm ecl:hzl byr:1937 | | ecl:blu iyr:2019 pid:960083875 eyr:2027 hgt:71in hcl:#c0946f | byr:1921 | | iyr:2011 | pid:9562042482 | hcl:z hgt:59cm | eyr:1994 cid:258 ecl:#6c1bcc byr:2025 | | eyr:2028 pid:494999718 byr:1928 hgt:176cm | iyr:2015 ecl:oth hcl:#733820 | | cid:78 eyr:2020 hgt:160cm byr:1947 ecl:blu | hcl:#b6652a iyr:2016 pid:069457741 | | hcl:#6b5442 iyr:2010 | byr:1971 | eyr:2028 hgt:169cm ecl:brn pid:528961949 | | eyr:2028 | hcl:#7d3b0c | byr:1952 | ecl:hzl | cid:317 iyr:2016 | pid:832169844 | | hcl:#c0946f | ecl:brn | iyr:2017 eyr:2028 | pid:161390075 byr:1993 cid:50 | hgt:171cm | | ecl:#ae12d3 hgt:74cm cid:239 hcl:z pid:345439730 iyr:1924 byr:2029 eyr:2031 | | Now to use the data loaded with lisp in python. First, we'll set up a function to convert the data into a list of dicts: #+begin_src python :session day4 def generate_passports(data): """ Converts data into a list of dicts. Each dict represents a single passport. Passports are delineated in the data by a blank line. """ passports = [] passport = {} for line in data: if line == "": passports.append(passport) passport = {} continue for pairs in line.split(): items = pairs.split(':') try: passport[items[0]] = items[1] except IndexError: print(f"Parse error: {items}") passports.append(passport) # Need to include last passport since input # doesn't have a blank line at the end return passports #+end_src #+RESULTS: A quick test that ~generate_passports~ works roughly as expected: #+begin_src python :session day4 :results output data = ["ecl:gry pid:860033327 eyr:2020 hcl:#fffffd", "byr:1937 iyr:2017 cid:147 hgt:183cm", "", "iyr:2013 ecl:amb cid:350 eyr:2023 pid:028048884", "hcl:#cfa07d byr:1929",] test_result = generate_passports(data) import pprint pprint.pprint(test_result) #+end_src #+RESULTS: #+begin_example [{'byr': '1937', 'cid': '147', 'ecl': 'gry', 'eyr': '2020', 'hcl': '#fffffd', 'hgt': '183cm', 'iyr': '2017', 'pid': '860033327'}, {'byr': '1929', 'cid': '350', 'ecl': 'amb', 'eyr': '2023', 'hcl': '#cfa07d', 'iyr': '2013', 'pid': '028048884'}] #+end_example Now to call ~generate_passports~ with the lisp loaded data. Notice that the data variable being passed into the python session is defined as the name of the lisp code block, not the variable being set in the code block (with the implication that running the python block also re-runs the lisp block): #+begin_src python :session day4 :var data=load-day4 passports = generate_passports(data) #+end_src #+RESULTS: Now we need to validate the passports: #+begin_src python :session day4 def is_valid_passport(passport): """Returns True for valid passport, False otherwise. Valid passport defined as including the following keys: byr (Birth Year) iyr (Issue Year) eyr (Expiration Year) hgt (Height) hcl (Hair Color) ecl (Eye Color) pid (Passport ID) """ required_keys = ("byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid") result = True for key in required_keys: if key not in passport.keys(): result = False return result #+end_src #+RESULTS: Verify with the test data. From instructions, the first test data passport is valid while the second is not: #+begin_src python :session day4 [is_valid_passport(passport) for passport in test_result] #+end_src #+RESULTS: | True | False | Now run on full set of passports. Note we only want the total number of valid passports: #+begin_src python :session day4 len([passport for passport in passports if is_valid_passport(passport)]) #+end_src #+RESULTS: : 226 Which is the right answer for part 1. *** Part 2 This has a different validation: #+begin_src python :session day4 import re def is_in_range(number, minimum, maximum): try: result = minimum <= int(number) <= maximum except ValueError: result = False return result def is_valid_hcl(hcl): result = True if len(hcl) != 7: result = False if hcl.startswith("#") is False: result = False if hcl[1:].isalnum is False: result = False if re.search(r'g-z', hcl[1:]): result = False return result def is_valid_pid(pid): result = True if len(pid) != 9: result = False if pid.isalnum is False: result = False return result def is_valid_passport_part2(passport): """Returns True for valid passport, False otherwise. Valid passport defined as including the following keys and values: byr (Birth Year) 1920 to 2002 iyr (Issue Year) 2010 to 2020 eyr (Expiration Year) 2020 to 2030 hgt (Height) 150 to 193cm or 59 to 76in hcl (Hair Color) # followed by 6 characters, 0 to 9 or a to f ecl (Eye Color) exactly one of: amb blu brn gry grn hzl oth pid (Passport ID) 9 digit number, including leading zeroes """ result = True valid_ecls = ('amb', 'blu', 'brn', 'gry', 'grn', 'hzl', 'oth') try: result = result and is_in_range(passport['byr'], 1920, 2002) except KeyError: result = False try: result = result and is_in_range(passport['iyr'], 2010, 2020) except KeyError: result = False try: result = result and is_in_range(passport['eyr'], 2020, 2030) except KeyError: result = False try: height = passport['hgt'] min_height = 150 max_height = 193 if height[-2:] == 'in': min_height = 59 max_height = 76 result = result and is_in_range(height[:-2], min_height, max_height) except KeyError: result = False try: result = result and passport['ecl'] in valid_ecls except KeyError: result = False try: result = result and is_valid_hcl(passport['hcl']) except KeyError: result = False try: pid = passport['pid'] result = result and is_valid_pid(pid) except KeyError: result = False return result #+end_src #+RESULTS: 2 valid and 2 invalid passport tests from the instructions: #+begin_src python :session day4 :results output data_part2 = ["pid:087499704 hgt:74in ecl:grn iyr:2012 eyr:2030 byr:1980", "hcl:#623a2f", "", "eyr:2029 ecl:blu cid:129 byr:1989", "iyr:2014 pid:896056539 hcl:#a97842 hgt:165cm", "", "eyr:1972 cid:100", "hcl:#18171d ecl:amb hgt:170 pid:186cm iyr:2018 byr:1926", "", "iyr:2019", "hcl:#602927 eyr:1967 hgt:170cm", "ecl:grn pid:012533040 byr:1946", ] test_result_part2 = generate_passports(data_part2) import pprint pprint.pprint(test_result_part2) #+end_src #+RESULTS: #+begin_example [{'byr': '1980', 'ecl': 'grn', 'eyr': '2030', 'hcl': '#623a2f', 'hgt': '74in', 'iyr': '2012', 'pid': '087499704'}, {'byr': '1989', 'cid': '129', 'ecl': 'blu', 'eyr': '2029', 'hcl': '#a97842', 'hgt': '165cm', 'iyr': '2014', 'pid': '896056539'}, {'byr': '1926', 'cid': '100', 'ecl': 'amb', 'eyr': '1972', 'hcl': '#18171d', 'hgt': '170', 'iyr': '2018', 'pid': '186cm'}, {'byr': '1946', 'ecl': 'grn', 'eyr': '1967', 'hcl': '#602927', 'hgt': '170cm', 'iyr': '2019', 'pid': '012533040'}] #+end_example And check that we get 2 valid and 2 invalid results: #+begin_src python :session day4 [is_valid_passport_part2(passport) for passport in test_result_part2] #+end_src #+RESULTS: | True | True | False | False | #+begin_src python :session day4 len([passport for passport in passports if is_valid_passport_part2(passport)]) #+end_src #+RESULTS: : 160 Which is the right answer for part 2.