aoc2020/day4/part2/main.d

139 lines
3.2 KiB
D
Raw Normal View History

2020-12-04 11:43:17 +01:00
module day4.part2.main;
import std;
void main()
{
readText("input").parsePassports.countValidPassports.writeln;
}
alias Passport = string[string];
auto parsePassports(string input)
{
return input.splitter("\n\n").map!(passport => passport.splitter().map!((entry) {
auto keyAndValue = entry.split(':');
return tuple(keyAndValue[0], keyAndValue[1]);
}).assocArray);
}
enum Field : string
{
birthYear = "byr",
issueYear = "iyr",
expirationYear = "eyr",
height = "hgt",
hairColor = "hcl",
eyeColor = "ecl",
passportID = "pid",
countryID = "cid",
}
bool isValidYear(int min, int max)(string yr)
{
if (yr.length != 4 || yr.canFind!(not!isDigit))
return false;
auto year = yr.to!int;
return year >= min && year <= max;
}
alias isValidBirthYear = isValidYear!(1920, 2002);
alias isValidIssueYear = isValidYear!(2010, 2020);
alias isValidExpirationYear = isValidYear!(2020, 2030);
bool isValidHeight(string hgt)
{
auto match = hgt.matchFirst(r"^(\d+)(cm|in)$");
if (!match || match.length != 3)
return false;
auto number = match[1].to!int;
switch (match[2])
{
case "cm":
return number >= 150 && number <= 193;
break;
case "in":
return number >= 59 && number <= 76;
default:
return false;
}
}
bool isValidHairColor(string hcl)
{
return hcl.matchFirst(r"^#[0-9a-f]{6}$").to!bool;
}
bool isValidEyeColor(string ecl)
{
return ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"].canFind(ecl);
}
bool isValidPassportID(string pid)
{
return pid.matchFirst(r"^\d{9}$").to!bool;
}
enum requiredFields = [
Field.birthYear, Field.issueYear, Field.expirationYear, Field.height,
Field.hairColor, Field.eyeColor, Field.passportID
];
bool isValidPassport(Passport passport)
{
return requiredFields.all!(field => field in passport)
&& isValidBirthYear(passport[Field.birthYear])
&& isValidIssueYear(passport[Field.issueYear])
&& isValidExpirationYear(passport[Field.expirationYear])
&& isValidHeight(passport[Field.height])
&& isValidHairColor(passport[Field.hairColor])
&& isValidEyeColor(passport[Field.eyeColor])
&& isValidPassportID(passport[Field.passportID]);
}
auto countValidPassports(R)(R r) if (isInputRange!R && is(ElementType!R == Passport))
{
return r.filter!isValidPassport.count;
}
unittest
{
auto input = `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
hcl:dab227 iyr:2012
ecl:brn hgt:182cm pid:021572410 eyr:2020 byr:1992 cid:277
hgt:59cm ecl:zzz
eyr:2038 hcl:74454a iyr:2023
pid:3556412378 byr:2007`;
auto passPorts = input.parsePassports;
assert(passPorts.countValidPassports == 0);
}
unittest
{
auto input = `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
hcl:#888785
hgt:164cm byr:2001 iyr:2015 cid:88
pid:545766238 ecl:hzl
eyr:2022
iyr:2010 hgt:158cm hcl:#b6652a ecl:blu byr:1944 eyr:2021 pid:093154719`;
auto passPorts = input.parsePassports;
assert(passPorts.countValidPassports == 4);
}