:- use_module(library(clpfd)). :- use_module(library(dcg/basics)). :- set_prolog_flag(double_quotes, codes). info(Prop) --> [A, B, C], ":", !, nonblanks(Value), { atom_codes(Name, [A, B, C]), Prop =.. [Name, Value] }. passport([I]) --> info(I). passport([I|Info]) --> info(I), blank, passport(Info). passports([P]) --> passport(P), blanks. passports([P|Passports]) --> passport(P), "\n\n" , passports(Passports). valid(Info) :- maplist(functor, Info, Names, _), subtract([byr, iyr, eyr, hgt, hcl, ecl, pid], Names, []). check(byr(Byr)) :- integer(Y, Byr, []), Y #>= 1920, Y #=< 2002. check(iyr(Iyr)) :- integer(Y, Iyr, []), Y #>= 2010, Y #=< 2020. check(eyr(Eyr)) :- integer(Y, Eyr, []), Y #>= 2020, Y #=< 2030. check(hgt(Hgt)) :- integer(H, Hgt, "cm"), H #>= 150, H #=< 193. check(hgt(Hgt)) :- integer(H, Hgt, "in"), H #>= 59, H #=< 76. check(hcl(Hcl)) :- phrase(("#", xinteger(_)), Hcl). check(ecl(Ecl)) :- atom_codes(E, Ecl), memberchk(E, [amb, blu, brn, gry, grn, hzl, oth]). check(pid(Pid)) :- length(Pid, 9), integer(_, Pid, []). check(cid(_)). main(Step1, Step2) :- phrase_from_file(passports(Passports), 'advent_4_inp.txt'), include(valid, Passports, Valid), length(Valid, Step1), include(maplist(check), Valid, Checked), length(Checked, Step2).