'''
--- Day 4: Passport Processing ---

You arrive at the airport only to realize that you grabbed your North Pole Credentials instead of your passport. While these documents are extremely similar, North Pole Credentials aren't issued by a country and therefore aren't actually valid documentation for travel in most of the world.

It seems like you're not the only one having problems, though; a very long line has formed for the automatic passport scanners, and the delay could upset your travel itinerary.

Due to some questionable network security, you realize you might be able to solve both of these problems at the same time.

The automatic passport scanners are slow because they're having trouble detecting which passports have all required fields. The expected fields are as follows:

    byr (Birth Year)
    iyr (Issue Year)
    eyr (Expiration Year)
    hgt (Height)
    hcl (Hair Color)
    ecl (Eye Color)
    pid (Passport ID)
    cid (Country ID)

Passport data is validated in batch files (your puzzle input). Each passport is represented as a sequence of key:value pairs separated by spaces or newlines. Passports are separated by blank lines.

Here is an example batch file containing four passports:

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

hcl:#ae17e1 iyr:2013
eyr:2024
ecl:brn pid:760753108 byr:1931
hgt:179cm

hcl:#cfa07d eyr:2025 pid:166559648
iyr:2011 ecl:brn hgt:59in

The first passport is valid - all eight fields are present. The second passport is invalid - it is missing hgt (the Height field).

The third passport is interesting; the only missing field is cid, so it looks like data from North Pole Credentials, not a passport at all! Surely, nobody would mind if you made the system temporarily ignore missing cid fields. Treat this "passport" as valid.

The fourth passport is missing two fields, cid and byr. Missing cid is fine, but missing any other field is not, so this passport is invalid.

According to the above rules, your improved system would report 2 valid passports.

Count the number of valid passports - those that have all required fields. Treat cid as optional. In your batch file, how many passports are valid?

'''

sample = """
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

hcl:#ae17e1 iyr:2013
eyr:2024
ecl:brn pid:760753108 byr:1931
hgt:179cm

hcl:#cfa07d eyr:2025 pid:166559648
iyr:2011 ecl:brn hgt:59in
"""


input = """
byr:1971
ecl:hzl pid:112040163
eyr:2023 iyr:2019
hcl:#b6652a hgt:167cm

pid:108667812 eyr:2023 hcl:#623a2f hgt:171cm iyr:2018 ecl:amb byr:1993

hcl:#cfa07d iyr:2014 ecl:blu eyr:2023 cid:304 hgt:70in byr:1961

byr:1977
hcl:#b6652a
iyr:2017 ecl:oth pid:703877876 hgt:185cm

byr:1972
cid:271
iyr:2016 pid:876104259 hgt:173cm eyr:2028 ecl:brn hcl:#733820

hgt:174cm ecl:gry iyr:2014 eyr:2029 hcl:#c0946f
byr:1967 pid:406306240

hcl:#6b5442
iyr:2011
pid:040592028 eyr:2026
ecl:amb
byr:1923

pid:293598838 byr:1960 cid:87
iyr:2018
ecl:blu eyr:2029
hcl:#7d3b0c
hgt:62in

iyr:2018 cid:137
hcl:1c7db1 ecl:#38812e byr:2006 eyr:2038 pid:1239811353 hgt:84

hcl:#888785 pid:308480529
iyr:2010 byr:1988
eyr:2025 hgt:176cm ecl:amb

cid:79 ecl:lzr
iyr:2013 byr:1991 hcl:2f49ef
hgt:191cm
pid:378428551

iyr:2005
hgt:64in hcl:89c369
ecl:gry byr:1932
eyr:2029 pid:753055776

ecl:amb iyr:2017
byr:1969 hcl:#fffffd
pid:305746470
hgt:173cm

pid:081972188 iyr:2011
hcl:9bb154
eyr:2024 byr:1966 ecl:oth cid:185 hgt:171cm

pid:522553186 hgt:171cm ecl:grn hcl:#7d3b0c
byr:1955
eyr:2025 iyr:1999

iyr:2015
byr:1941 pid:140123640 ecl:amb hgt:153cm hcl:#ceb3a1 eyr:2020

ecl:grn
cid:202 hcl:#602927
eyr:2029
hgt:180cm byr:1974
pid:658341964
iyr:2017

pid:2037156813 eyr:1978 ecl:grn hcl:519b45 iyr:2011 byr:2017

hcl:#fffffd ecl:hzl
pid:658716289 byr:2001 hgt:154cm cid:234 eyr:2031 iyr:2010

byr:2013 pid:#eb519e eyr:2026
hgt:157cm iyr:2030 hcl:7e9d5a ecl:oth

byr:2002
ecl:brn iyr:1998 hgt:60cm
hcl:#7d3b0c pid:#90286d
eyr:1938

byr:1956 hcl:#efcc98
hgt:190cm
iyr:2010 eyr:2023
ecl:amb
cid:342 pid:278521396

hgt:67cm
cid:98 eyr:2036 byr:2028 ecl:grt hcl:08b5ad iyr:2029 pid:187cm

ecl:dne hcl:fca461 hgt:129 iyr:2020 eyr:2027 byr:2022 pid:5014208295

hgt:169cm ecl:gry iyr:2015 eyr:2025 hcl:#733820 pid:240085824 byr:1920

iyr:2020 eyr:2033
pid:#3f8e9d hgt:190in ecl:brn hcl:#efcc98 byr:2004

iyr:2018 hcl:#18171d ecl:brn byr:1933
pid:514517439 hgt:171cm eyr:2028

eyr:2030 pid:053251865
byr:2028 hgt:174cm iyr:2015 hcl:5a0da9 ecl:hzl

hgt:169cm iyr:2014 ecl:oth eyr:2029 pid:348737413 hcl:#b6652a byr:1997

hgt:181cm cid:315
eyr:2021 iyr:2016 byr:1966 ecl:oth pid:779435812 hcl:#733820

pid:5052579 cid:268 hgt:193in
hcl:z
iyr:1942 eyr:1977

eyr:2039 hgt:69cm cid:337
iyr:2023 pid:568948965
byr:2018 hcl:z ecl:amb

byr:2014 eyr:2028
cid:311
pid:158cm ecl:#946399 hgt:99
hcl:z
iyr:1978

pid:474742310 iyr:2015 eyr:2021 hcl:#14f5da
hgt:163cm ecl:oth

hcl:#efcc98
ecl:blu
hgt:178cm pid:815309025 byr:2024
iyr:2008 eyr:1922

byr:1946 eyr:2028 pid:364439229 iyr:2011 hgt:186cm cid:79 ecl:blu

eyr:2028 hgt:157cm
cid:59 iyr:2010 byr:1927
ecl:brn
pid:893074368

hcl:#18171d ecl:#2defe4 hgt:128 byr:1940
pid:181904523 iyr:2022 eyr:1937

eyr:2023 hgt:172cm iyr:2012 hcl:#a97842 ecl:hzl byr:1982 pid:638759541

cid:91 hcl:#623a2f
byr:1996 eyr:2028 pid:181384347 hgt:175cm
iyr:2020

iyr:2017 eyr:2021 ecl:gry
byr:1979 hgt:168cm hcl:#6b5442 pid:950995084

ecl:blu iyr:2012 byr:1972
hcl:#888785 eyr:2022 hgt:179cm pid:293827532

hgt:179cm
ecl:hzl iyr:2011
byr:1982 eyr:2020 hcl:#efcc98 cid:209 pid:626732917

byr:1989
hcl:#6b5442 pid:679850983 iyr:2020
hgt:192cm ecl:blu

pid:333485773 hgt:167in ecl:zzz iyr:1945
eyr:2035 cid:319 hcl:#341e13

hgt:64in
cid:202 eyr:2023 ecl:gry hcl:#c0946f pid:212611149 byr:1928 iyr:2010

hgt:183cm hcl:#e8fa30 ecl:oth eyr:2021
byr:1943 pid:667658434
iyr:2010

cid:117
byr:2022 hcl:z ecl:#c6ae1f iyr:2028
hgt:188cm
pid:0883366415
eyr:2030

hcl:z
pid:99347800 iyr:2030 eyr:2032 ecl:#cd1fd7 hgt:192cm byr:2019

hgt:178cm byr:2013
iyr:2026 hcl:ad3da1
eyr:2020 pid:1626818790

hgt:63cm
iyr:1964
eyr:2032
cid:135 byr:2017 hcl:#a97842 pid:#1b83f5 ecl:gmt

hcl:c352d2 byr:1927 ecl:gmt hgt:187cm
eyr:2031 pid:170cm

byr:2022 eyr:1958 ecl:zzz pid:3692521800 hcl:8b2b50 iyr:1946 hgt:155in

ecl:#43f305 hcl:z byr:2028
pid:63518738 cid:243 eyr:2037
hgt:67cm iyr:1929

ecl:brn hcl:#888785
pid:495215177 byr:1962 eyr:2021
cid:192
hgt:151cm iyr:2012

ecl:#dcca8e cid:64 eyr:2030 pid:380057616
hcl:z iyr:2026 byr:1962

hcl:z
ecl:hzl eyr:2027 byr:2015 pid:302526406 hgt:175cm iyr:2017

byr:1966
cid:133 pid:9953651821 ecl:gry iyr:2020 hgt:152cm
hcl:#fffffd eyr:2026

hgt:191cm byr:1960 pid:752655640 hcl:#888785
cid:249 ecl:blu
iyr:2012 eyr:2028

pid:#c8c988 eyr:2027 hgt:157in hcl:z iyr:2025 byr:2019 ecl:zzz cid:195

hgt:96 pid:95381813 iyr:1950
hcl:#fffffd eyr:2026
byr:2010 cid:318
ecl:#48a819

eyr:2020
ecl:oth byr:1951 pid:080392492
iyr:2015 hcl:#6b5442 hgt:176cm

hgt:162cm pid:897792747 byr:1968
hcl:#ceb3a1 ecl:grn eyr:2026 iyr:2014

eyr:2038 hcl:cc324a byr:1983 ecl:brn
hgt:161 pid:#adf47f cid:208

iyr:2013 ecl:blu hcl:#866857 byr:1981 hgt:157cm eyr:2025 pid:216910202

hgt:152in byr:1990
iyr:2027 hcl:a4a3ae
ecl:#058ae2 eyr:2037 pid:646420120

ecl:oth byr:1982 eyr:2027 hgt:65in iyr:2019
hcl:#efcc98 cid:224
pid:854228141

pid:772612093
iyr:2027
hgt:175in byr:1981 hcl:c0b5a9 ecl:utc

hcl:#888785 iyr:2014 byr:1975
ecl:blu
pid:461319017 cid:229 eyr:2030 hgt:154cm

hgt:179cm eyr:2024
pid:192cm
iyr:2017 ecl:grt byr:1934 hcl:z cid:92

hcl:9c9409 iyr:2020 eyr:2030 hgt:156in
cid:189 pid:732321495
byr:1937 ecl:xry

eyr:2026 pid:092259220 byr:1943
iyr:2010 hgt:153cm hcl:#602927

byr:1925 hgt:180cm hcl:#888785 iyr:2014
pid:402548656 eyr:2023 ecl:hzl
cid:188

eyr:2020 pid:874307939 hcl:#3f85a4
ecl:gry hgt:167cm byr:1959 iyr:2014

eyr:2026 hgt:183cm iyr:2011 byr:1940 ecl:blu pid:810026000
cid:226 hcl:#866857

cid:292 ecl:grt hgt:72cm
byr:2009
iyr:2000 eyr:1946 hcl:7be409 pid:996363336

eyr:2027
iyr:2021
pid:632405666
byr:2027
ecl:#d83a36 hcl:z hgt:190in

cid:80
hgt:173cm
pid:735853952 ecl:gry hcl:#fffffd eyr:2025 iyr:2020 byr:1923

byr:1977
hcl:#733820
iyr:2020 ecl:#698d72 hgt:186cm pid:678869986 cid:67
eyr:2021

hgt:61cm iyr:2022 eyr:1972 hcl:979bcf byr:2023 pid:44037388 ecl:xry

eyr:2032 pid:193cm hcl:z
hgt:68cm byr:2016

byr:2008 cid:239
hcl:ddc745 eyr:2033 ecl:#6858b5 hgt:64cm iyr:2023
pid:89867524

iyr:2016 hgt:74in hcl:#18171d
byr:1959
ecl:blu
pid:848487392
eyr:2027

hgt:165in ecl:grn
byr:1960 eyr:2029
iyr:2017
hcl:#b6652a pid:096349067

eyr:2025 ecl:brn
pid:634481064 iyr:2015
hcl:#7d3b0c
byr:1943

ecl:grn eyr:2021
pid:34753212 cid:51 hgt:184 iyr:1970 byr:2012

eyr:1973 iyr:2014 cid:225
byr:2028 ecl:gmt
hgt:158cm
pid:#74f9b8 hcl:f6932a

hgt:168cm
hcl:#602927
pid:622067991 ecl:amb eyr:2025 iyr:2018

pid:791399958 byr:1956 eyr:2027 hcl:#602927
ecl:brn
iyr:2016 hgt:192cm

hgt:168cm iyr:2015 cid:115 ecl:#3fa48b eyr:2037 hcl:#1bf77b byr:1980 pid:947370470

iyr:2008
byr:2021 ecl:zzz
hcl:z hgt:109 pid:#fc2a91 cid:268 eyr:1957

byr:2018 hcl:fef19c iyr:2014 ecl:blu eyr:2023 cid:259 pid:193cm hgt:156

hcl:#b6652a
iyr:2023 byr:2021 hgt:153cm pid:934391984 eyr:2021 ecl:brn

pid:168cm hcl:b13f1e eyr:2038 iyr:2020 ecl:#7c0a6d hgt:169in

ecl:amb cid:170
pid:300188824 eyr:2024 byr:1954 hcl:#b6652a hgt:166cm
iyr:2013

ecl:brn
eyr:2023
hcl:#b6652a byr:1948 hgt:71in iyr:2015
pid:575973478

eyr:2026 hgt:180cm hcl:#866857 ecl:grn iyr:2013
byr:1997 pid:864648034

ecl:hzl
iyr:2013 eyr:2024 hcl:#02e17f byr:1960
hgt:163cm cid:338 pid:972201795

iyr:1994 eyr:2035 ecl:xry
hcl:z hgt:167in pid:159cm

ecl:hzl
byr:1952
eyr:2024 hgt:191cm pid:229400637 iyr:2011 hcl:#122db6

eyr:2022
pid:467667316 iyr:2019 hcl:#623a2f
hgt:161cm
ecl:oth

ecl:hzl eyr:2030 hcl:#733820 byr:1944
hgt:193cm pid:819137596

cid:321 hgt:184in ecl:hzl iyr:2018 byr:2010 eyr:2020 pid:171cm

ecl:amb eyr:2025 hcl:#c0946f pid:360891963 byr:1925
iyr:2017
hgt:180cm

hcl:#cfa07d byr:1949
eyr:1931 cid:350
ecl:#ff9943
pid:7550350393 hgt:75

eyr:2026 ecl:amb hcl:z pid:746919391 iyr:2014 hgt:179cm byr:1997

pid:157cm iyr:2030
hgt:152cm
hcl:ce8aa7 eyr:1976 ecl:grt cid:160 byr:2011

eyr:2022
hgt:183cm
byr:2000 iyr:2016 hcl:#a97842 ecl:blu pid:500935725

cid:245 eyr:2026 iyr:2015 ecl:gry hcl:#cfa07d
byr:1946

eyr:2022 hgt:168cm
pid:786361311 iyr:2013 hcl:#c0946f byr:1988 cid:244 ecl:hzl

byr:2014 hgt:176in iyr:2021
hcl:z pid:6361650130
eyr:2039 cid:300
ecl:#76310d

ecl:amb hgt:170in byr:2013
iyr:2024 eyr:2033 hcl:#888785

eyr:2025
iyr:1957 cid:182
ecl:blu pid:253552114
hgt:188cm hcl:z

cid:83 ecl:amb
eyr:2022 byr:1947
iyr:2013 hcl:#cfa07d
hgt:188cm pid:447734900

iyr:2013 hcl:#602927 byr:1979 hgt:167cm cid:321 pid:978238277 eyr:2020
ecl:grn

hgt:73cm
cid:199 ecl:amb iyr:2019
hcl:#733820 eyr:2021
byr:1939 pid:364966395

hgt:168in ecl:lzr eyr:2031
pid:#ff10ac byr:2014 iyr:2006

hgt:164cm eyr:1994 iyr:2010
ecl:amb hcl:#7d3b0c cid:240 pid:191cm
byr:2025

ecl:grn
eyr:2029
hcl:#7d3b0c hgt:158cm
byr:1939 iyr:2012 pid:855145518

iyr:2013 hcl:#ceb3a1
hgt:163cm eyr:2023 pid:761215570

hgt:154cm ecl:grn
iyr:2019 byr:1981 eyr:2021 hcl:#602927
cid:80 pid:427938374

eyr:2026 hgt:154cm cid:102 iyr:2012 pid:6632346648 ecl:amb
byr:2010 hcl:z

cid:302 iyr:2014
pid:161cm eyr:2037 byr:2026 ecl:gry hgt:60 hcl:9fb9e0

ecl:brn iyr:2015 pid:041582949 cid:180 byr:1938
hgt:158cm
hcl:#602927 eyr:2026

ecl:xry pid:#546891 hcl:#18171d hgt:71cm byr:1974
iyr:2018 eyr:2026

iyr:2015 eyr:2025 ecl:brn hgt:180cm hcl:#b6652a
byr:1938
pid:752379523

iyr:2020 ecl:grn hgt:179cm byr:1929
cid:103 hcl:#602927
pid:212212232

pid:262917603 ecl:gry iyr:2012 hcl:#fffffd hgt:165cm eyr:2022 byr:1965

byr:1960
eyr:2031 hgt:184in
pid:#ac1606 iyr:2013 hcl:#888785
cid:260 ecl:#7b2c3b

byr:1987
eyr:2025 cid:102
hgt:74in ecl:brn hcl:#4a6c75 pid:20220733 iyr:2028

eyr:2031 pid:823539963
iyr:1957
hgt:159cm byr:1953 ecl:oth cid:186 hcl:26d85f

ecl:gry iyr:2011
hgt:167cm hcl:#fffffd pid:001642707 eyr:2030 byr:1952

iyr:2029 ecl:grt
hcl:z byr:2011 hgt:64cm pid:37027672
eyr:1923

pid:021102096
eyr:2024 hgt:66 hcl:#a97842 byr:1922 ecl:gry iyr:2013

pid:166477382 ecl:oth byr:1982 iyr:2010 eyr:2020
hcl:#866857 hgt:60in

hcl:#7d3b0c
iyr:2018 pid:065652921 byr:1939
ecl:blu
hgt:180cm eyr:2028

ecl:amb iyr:2020 byr:1967 hcl:#fffffd eyr:2028 hgt:157cm

eyr:2029 hgt:185cm cid:85 hcl:z iyr:2014 pid:#1f4787 ecl:grn byr:2010

byr:1987 hcl:d397d9 iyr:2028
hgt:158cm pid:686994921 ecl:hzl

ecl:oth
byr:2008
pid:#db73d9 hgt:174cm hcl:#6b5442 iyr:1955 eyr:2028

eyr:2020 ecl:amb pid:490866828 hcl:#cfa07d cid:113
hgt:165cm

iyr:2011
pid:320518492
eyr:2028 byr:1940 hgt:164cm cid:84
hcl:#341e13 ecl:grn

hgt:142
hcl:z pid:152cm iyr:1953 eyr:2040 ecl:#e44f11 byr:2024

ecl:gmt hcl:be7483 eyr:2027
iyr:2026
pid:396722617 hgt:153cm

ecl:dne byr:2015
pid:330208482
hcl:#7d3b0c iyr:2014 eyr:2022 hgt:95

byr:1925 hcl:#7d3b0c
ecl:gry
eyr:2024
pid:694714722 hgt:158cm iyr:2015 cid:283

eyr:2023
hgt:183cm cid:345
hcl:#6b5442 ecl:hzl iyr:2019 byr:1971 pid:458416257

ecl:#dcae8b
iyr:2027 eyr:1940 byr:2009 hcl:f024de pid:20713584
hgt:169in

hcl:#888785 eyr:2026
byr:1984 iyr:2013 pid:935837461
hgt:193cm
ecl:gry

pid:7343429 byr:2002
hgt:191cm
ecl:lzr iyr:1983
eyr:1966 hcl:#623a2f
cid:302

hcl:#888785 iyr:2014 hgt:173cm
byr:2002 pid:005350165 eyr:2022

byr:2013 iyr:2028
ecl:lzr pid:5426915565 eyr:2018 hcl:z hgt:70cm cid:142

eyr:2021 hgt:157cm ecl:utc iyr:2014
byr:1934 cid:348 hcl:#623a2f pid:607329117

iyr:2015 hgt:167cm ecl:hzl
pid:088516395 hcl:#efcc98 byr:1968 eyr:2029

eyr:2028
iyr:2019
cid:199
ecl:amb
hgt:152cm byr:1928 pid:547112666 hcl:#623a2f

pid:406202463
byr:1950 cid:214
eyr:2021 hcl:#fffffd hgt:177cm
ecl:brn

eyr:2029
cid:210 byr:1982 pid:578085789 ecl:brn
hgt:187cm iyr:2010 hcl:#c0946f

byr:1980 hcl:#c0946f hgt:159cm pid:177650318 eyr:2024 ecl:amb iyr:2019

pid:923359071 byr:1997 ecl:#faa530
eyr:2028 iyr:2013 hcl:e6c902 hgt:177cm

eyr:2040
cid:98 hgt:156in
ecl:oth
iyr:1996 pid:81500971
hcl:#6b5442
byr:2017

byr:2004 iyr:1941
hcl:e1e4bb hgt:67cm pid:1143915351 ecl:#0d3e5d eyr:1972

hgt:184cm hcl:#623a2f
eyr:2028 pid:680951513 ecl:grn iyr:2014 byr:2001

hcl:#866857 hgt:156cm
eyr:2020
ecl:grn iyr:2010 pid:589945116

pid:599795227 iyr:2016 ecl:grn
hcl:#cfa07d hgt:157cm byr:1967 eyr:2029

hcl:#b6652a
byr:1966 iyr:2017 pid:117232314 ecl:oth hgt:186cm eyr:2029

pid:605019880
iyr:2020
hgt:169cm byr:1980 hcl:#623a2f
ecl:hzl eyr:2030

eyr:2019 hcl:#ceb3a1 pid:988269284
iyr:2015 byr:1989 hgt:171cm ecl:oth

cid:311 byr:1998 ecl:hzl
eyr:2027 hgt:152cm pid:734870801 hcl:#7d3b0c
iyr:2013

hcl:#efcc98
hgt:180cm iyr:2020
pid:202682423 byr:2027 ecl:grn eyr:2030

hcl:f0701f pid:161cm cid:291 hgt:160in iyr:2030
ecl:#e12345

cid:248 byr:1943 eyr:2024 hgt:181cm ecl:brn iyr:2010 hcl:#bf813e

byr:2005 hgt:187in eyr:2034 iyr:2025 hcl:z ecl:gmt
pid:78691465

byr:2000
hcl:#574f4e eyr:2024 iyr:2017 pid:#fec795 hgt:185cm ecl:gry

hcl:#a97842 byr:1959
iyr:2019 pid:690444949
hgt:160in eyr:1978

cid:236
iyr:2010 eyr:2025 byr:1976 pid:398376853
hcl:#341e13
hgt:150cm

hgt:182cm iyr:2019 hcl:#866857
ecl:grn
byr:1926 eyr:2029 pid:307880154 cid:94

ecl:blu
hgt:182cm pid:178cm byr:2019 eyr:2025
iyr:2022 hcl:#a2117d

eyr:2020 hcl:#c0946f ecl:amb pid:135511825 byr:1954 hgt:68in iyr:2017

hgt:188cm ecl:amb iyr:2011
pid:949021029 eyr:2028 hcl:#fffffd byr:1986

iyr:1949 pid:#8a8d94 ecl:#922a92 byr:1925 hcl:#63c4a5

hcl:#c0946f
ecl:grn iyr:2013 eyr:2024 pid:420295283 hgt:181cm
byr:1977

byr:1941 pid:299186098 hcl:#f1fa72
iyr:2013 ecl:amb eyr:2022 hgt:152cm
cid:150

ecl:blu eyr:2021 hgt:60in hcl:#623a2f
byr:1930 iyr:2018

eyr:2028 pid:663108638
hgt:75in cid:217
byr:1962 ecl:brn hcl:#733820

hcl:#341e13 hgt:188cm ecl:blu
pid:868930517
eyr:2029
iyr:2010 byr:1938

pid:194376910 byr:1956
hcl:#cd4ab4
eyr:1940 iyr:2012 ecl:#396cc3

pid:#c5da2a hgt:162cm
hcl:#866857
cid:95 ecl:#fa1f85
iyr:1965 byr:1963 eyr:2039

pid:44063430 hcl:289b20
ecl:#77ddd9 eyr:1953
iyr:1924 byr:2026 cid:267 hgt:180in

ecl:brn pid:990171473
eyr:2028 byr:1937
hgt:165cm iyr:2015
hcl:#fffffd cid:68

iyr:1968 ecl:lzr pid:#05a4ab eyr:1944 hcl:z

hgt:185cm hcl:#7d3b0c eyr:2029 ecl:oth
iyr:2016 byr:1997 pid:349316183

hcl:z
ecl:gry
hgt:192in pid:542996841 iyr:2019 cid:144 eyr:2028
byr:2026

eyr:2024
hcl:#18171d
ecl:grn hgt:160cm pid:399767457 byr:1979 iyr:2015

ecl:#924147 pid:665314 cid:216 iyr:2026 hcl:z
byr:2023 hgt:157
eyr:1987

eyr:1989 hcl:4f8779 ecl:#05ff52 iyr:1943 pid:3693010880 hgt:72cm
byr:2009

hcl:#c0946f eyr:2022
iyr:2015 hgt:157cm byr:1928 ecl:grn pid:243566446

eyr:2030
hcl:#733820 byr:1988 iyr:2017 cid:125 hgt:193cm ecl:amb pid:939550667

cid:161 hgt:157in
hcl:#cfa07d eyr:2036 ecl:#4efa35
iyr:2012 pid:3943280550 byr:1979

ecl:lzr hcl:#341e13 hgt:69cm eyr:2026 cid:322 byr:2006 pid:827964469

ecl:amb iyr:2012
eyr:2020 hgt:178cm pid:590705772 cid:218
hcl:#c0946f byr:1922

hcl:632b01 cid:252 byr:1933 ecl:hzl
iyr:2025 eyr:2040 hgt:191cm
pid:406010613

pid:711656819 ecl:blu eyr:2030 hgt:151cm
byr:1999 cid:319
hcl:#efcc98

pid:294223216 iyr:2012
hgt:171cm
eyr:2027
hcl:#ceb3a1 ecl:oth
byr:1952 cid:58

hcl:#888785 pid:457433756 eyr:2022 hgt:186cm
cid:336
byr:1923 iyr:2013 ecl:oth

byr:2014 hcl:6ce7d6 eyr:2030 pid:190cm iyr:2018 hgt:63cm ecl:#5063b9

cid:267 hgt:189cm
eyr:2020 hcl:#ffeffd iyr:2014 byr:1989
ecl:grn
pid:571696542

iyr:1953 hgt:160in
ecl:grt cid:188 eyr:2034
pid:179cm byr:2007
hcl:6895eb

hgt:165cm ecl:oth
iyr:2020
eyr:2028
hcl:#18171d pid:111506895

eyr:1957 cid:133 ecl:hzl pid:#e56ca2 byr:2003 hcl:8a9d65

hcl:6c4ecd byr:1930 hgt:179cm
eyr:2007 iyr:2028 ecl:#3d8705
pid:#dbfeec

eyr:2036
byr:1991 ecl:#2202d0 hcl:#341e13 pid:85636989 hgt:61cm
iyr:1930

byr:1996 iyr:2027 hcl:z
pid:780164868 ecl:zzz eyr:2026 hgt:73cm

byr:1940
iyr:1992 pid:132016954 eyr:2021
cid:147 hcl:#d78bfd ecl:xry

hgt:174cm
byr:1970
eyr:2021 hcl:#341e13 pid:086579106 iyr:2017 ecl:oth

ecl:oth cid:207 byr:1998 pid:479696359
hgt:174cm iyr:2017 eyr:2020 hcl:#6b5442

ecl:hzl iyr:2014
hcl:#cfa07d hgt:163cm eyr:2025
byr:1951 pid:563337128

ecl:gry hgt:172cm iyr:2013 hcl:#efcc98
byr:1970
pid:848996674
eyr:2027

hgt:163cm pid:583600660 iyr:2015 hcl:#18171d byr:1959 ecl:brn

hcl:#efcc98 pid:353178375 cid:145
iyr:2018 byr:1988 ecl:oth eyr:2029

hgt:62in
byr:1921 pid:125944934 hcl:#b6652a
eyr:2025 cid:71 iyr:2018 ecl:blu

iyr:2017 ecl:brn hcl:#602927 hgt:172cm pid:932690969 byr:1957 eyr:2026

hcl:#efcc98 pid:709772213 cid:146 ecl:oth byr:1998 iyr:2010 hgt:74in
eyr:2029

byr:1965
iyr:2011 hcl:#6b5442 cid:325 hgt:68in eyr:2028 pid:813272708 ecl:hzl

pid:57223084 hcl:#602927 ecl:grn
hgt:156cm eyr:1972 iyr:2017

pid:21573000 byr:2030 cid:168
hcl:baee61 eyr:2021 hgt:150cm
iyr:1950 ecl:#acdd7e

ecl:gry hgt:150cm hcl:#6b5442
byr:1927
iyr:2018 pid:161cm eyr:2021

hgt:153cm
iyr:2030 ecl:grn pid:575037626 byr:1921 eyr:2021 hcl:#866857

hgt:175cm iyr:2014
byr:1946 eyr:2025
cid:159 hcl:#18171d
ecl:oth pid:129913905

pid:566885568
hgt:157cm eyr:2021 ecl:gry byr:1933
hcl:#623a2f cid:223

ecl:blu byr:1981 cid:160
iyr:2014
hcl:#a97842 eyr:2021 hgt:172cm pid:714902414

hcl:#b6652a eyr:2021
hgt:168cm byr:1921 iyr:2018 ecl:oth pid:021318713

hgt:168 pid:222439573
cid:209
hcl:z byr:2016 ecl:#26a0fb
eyr:2031

hgt:181cm
byr:1970 eyr:2024
pid:476171876 ecl:hzl
hcl:#efcc98
iyr:2019

hcl:#18171d ecl:oth iyr:2018 byr:1949 hgt:165cm
eyr:2029 pid:078204562

byr:2021 ecl:blu iyr:1963
pid:2911597977 hcl:#ceb3a1 eyr:2020
hgt:154cm

pid:159642237
hcl:#81e94d ecl:gry eyr:2028 byr:1958

hgt:90 hcl:#a97842 pid:#db1158
iyr:1928 ecl:#c82a43 byr:1971 eyr:2036

eyr:2020
hgt:177cm iyr:2013
cid:347 ecl:grn
byr:1998 pid:455369144

byr:1936
pid:444305229 iyr:2013 eyr:2025 hcl:#733820
ecl:gry
hgt:175cm

byr:2027 hcl:z
hgt:61cm ecl:brn pid:836686228 eyr:2023 iyr:2030

byr:1931
ecl:hzl hgt:168cm eyr:2023 pid:956562488 hcl:#fffffd

ecl:#4126e5 pid:182cm iyr:2021
hgt:144 eyr:2039 hcl:z

pid:321400085 hcl:#733820 hgt:189cm
ecl:hzl byr:1923 eyr:2023 iyr:2016

iyr:2011 hgt:192cm hcl:#b6652a byr:1988 pid:998875769
ecl:#e612d9 eyr:2015

eyr:2021 iyr:2011 pid:265966660
byr:1934 hgt:180cm
hcl:#7d3b0c
ecl:gry cid:225

pid:550612542 ecl:oth byr:1931
iyr:2014 cid:99
hcl:#cfa07d hgt:163cm eyr:2026

ecl:gry hgt:156cm iyr:2018 hcl:#5d9d64 pid:295386055 byr:1996
eyr:2025

ecl:gry iyr:2013 pid:855457285 cid:309 eyr:2030
hcl:#733820 byr:1973

eyr:2030 pid:86472746 ecl:blu
hgt:192cm
iyr:2013 byr:1939 hcl:#b6652a

hcl:#888785
byr:1935
iyr:2018
hgt:155cm ecl:grn
pid:612879095 cid:108 eyr:2027

eyr:2016 hcl:z pid:025915371 iyr:2010 hgt:183cm ecl:gry
byr:2010
cid:228

hcl:#38dbf4
byr:1925 ecl:amb eyr:2020 pid:065102805 iyr:2018

cid:244 hgt:171cm
hcl:#cfa07d pid:466737179 eyr:2025
byr:1937 iyr:2020 ecl:oth

ecl:brn byr:1993 hgt:179cm hcl:#341e13 pid:855375268 eyr:2028
iyr:2018

pid:809135189 iyr:2020 hgt:162cm eyr:2027
hcl:#888785 byr:1988 ecl:grn

byr:2003 pid:4446708453
hgt:188cm iyr:2013 hcl:#888785 ecl:blu eyr:2008

hgt:165in ecl:#db642f iyr:2014
eyr:2020
byr:1955 hcl:371f72 pid:756089060

ecl:lzr
hgt:177in eyr:2037 pid:175cm
byr:2023 hcl:03b398 iyr:2026

iyr:2017 ecl:blu byr:1942 hcl:#733820 eyr:2023 hgt:151cm pid:289923625
"""


'''PART 2 Rules
You can continue to ignore the cid field, but each other field has strict rules about what values are valid for automatic validation:

    byr (Birth Year) - four digits; at least 1920 and at most 2002.
    iyr (Issue Year) - four digits; at least 2010 and at most 2020.
    eyr (Expiration Year) - four digits; at least 2020 and at most 2030.
    hgt (Height) - a number followed by either cm or in:
        If cm, the number must be at least 150 and at most 193.
        If in, the number must be at least 59 and at most 76.
    hcl (Hair Color) - a # followed by exactly six characters 0-9 or a-f.
    ecl (Eye Color) - exactly one of: amb blu brn gry grn hzl oth.
    pid (Passport ID) - a nine-digit number, including leading zeroes.
    cid (Country ID) - ignored, missing or not.

Your job is to count the passports where all required fields are both present and valid according to the above rules.
'''


def format_data(input:str):
    # get passport data in one line
    return [
        line.replace('\n',' ')
        for line in input.split('\n\n')
    ]

def get_keys(passport:str):
    # collect keys in a set
    keys =  {
        entry.strip().split(':')[0]
        for entry in passport.strip().split()
    }
    if 'cid' in keys:
        keys.remove('cid') # remove cid as it is optional
    return keys

# set of valid keys
VALID_KEYS = {
    'byr', # (Birth Year)
    'iyr', # (Issue Year)
    'eyr', # (Expiration Year)
    'hgt', # (Height)
    'hcl', # (Hair Color)
    'ecl', # (Eye Color)
    'pid', # (Passport ID)
    # 'cid', # (Country ID) -- optional 
}


def validate_passports(passports):
    return sum(
        [
            #  set <= other - Test whether every element in the set is in other.
            VALID_KEYS <= get_keys(passport)
            for passport in format_data(passports)
        ]
    )

print(f'sample result = {validate_passports(sample)}')

print(f'input result = {validate_passports(input)}')



# sample result = 2
# input result = 192

def validate_min_max(min, max, value):
    return int(min) <= int(value) <= int(max)

def validate_yr(min, max, year):
    if re.match(r'(\d{4})', year):
        return validate_min_max(min, max, year)
    return False

def validate_byr(byr):
    # byr (Birth Year) - four digits; at least 1920 and at most 2002.
    return validate_yr(1920, 2002, byr)

def validate_iyr(iyr):
    # iyr (Issue Year) - four digits; at least 2010 and at most 2020.
    return validate_yr(2010, 2020, iyr)

def validate_eyr(eyr):
    # eyr (Expiration Year) - four digits; at least 2020 and at most 2030.
    return validate_yr(2020, 2030, eyr)





import re

def validate_hgt(height):
    # hgt (Height) - a number followed by either cm or in:
    #   If cm, the number must be at least 150 and at most 193.
    #   If in, the number must be at least 59 and at most 76.
    if re.match(r'(\d+(cm|in)$)', height):
        _, value, unit = re.split(r'(\d+)', height)
        if unit == 'cm':
            return validate_min_max(150, 193, value)
        else:
            return validate_min_max(59, 76, value)
    return False



def validate_hcl(hair):
    # hcl (Hair Color) - a # followed by exactly six characters 0-9 or a-f.
    return bool(re.match(r'(^#([0-9]|[a-f]){6}$)', hair))

EYE_COLOR = {
    'amb',
    'blu',
    'brn',
    'gry',
    'grn',
    'hzl',
    'oth',
}

def validate_ecl(ecl):
    # ecl (Eye Color) - exactly one of: amb blu brn gry grn hzl oth.
    return ecl in EYE_COLOR

def validate_pid(pid):
    # pid (Passport ID) - a nine-digit number, including leading zeroes.
    return bool(re.match(r'(^\d{9}$)', pid))


def passport_dict(passport:str):
    # collect keys in a set
    result = dict(
        entry.strip().split(':')
        for entry in passport.strip().split()
        if entry.strip().split(':')[0] != 'cid'
    )
    return result

validate_dispatch = {
    'byr' : validate_byr,
    'iyr' : validate_iyr,
    'eyr' : validate_eyr,
    'hgt' : validate_hgt,
    'hcl' : validate_hcl,
    'ecl' : validate_ecl,
    'pid' : validate_pid,
}

def validate_passport_part_two(passport_str:str):
    passport = passport_dict(passport_str)
    if VALID_KEYS <= passport.keys():
        return all(
            [validate_dispatch[key](value) for key, value in passport.items()]
        )
    else:
        return False
        

def validate_part_two(passports):
    return sum(
        [
            validate_passport_part_two(passport)
            for passport in format_data(passports)
        ]
    )
        

print(f'part two result = {validate_part_two(input)}')

# part two result = 101