using System.Collections.Generic;
using System.Text.RegularExpressions;
public string BirthYear {get;set;}
public string IssueYear {get;set;}
public string ExpirationYear {get;set;}
public string Height {get;set;}
public string HairColor {get;set;}
public string EyeColor {get;set;}
public string PassportId {get;set;}
public string CountryId {get;set;}
public static void Main()
string input = @"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
ecl:brn pid:760753108 byr:1931
hcl:#cfa07d eyr:2025 pid:166559648
iyr:2011 ecl:brn hgt:59in";
string[] lines = input.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
var passports = new List<Passport>();
string passportDetails = string.Empty;
foreach (string line in lines) {
passports.Add(ParsePassport(passportDetails));
passportDetails = string.Empty;
passportDetails = $"{passportDetails} {line.TrimEnd('\n')}".TrimStart(' ');
var passportsWithRequiredFields = passports.Where(p => HasRequiredFields(p));
Console.WriteLine($"Part 1 Result: {passportsWithRequiredFields.Count()}");
var validPassports = passportsWithRequiredFields.Where(p => HasValidFields(p));
Console.WriteLine($"Part 2 Result: {validPassports.Count()}");
private static Passport ParsePassport(string details) {
string[] parts = details.Split(' ');
var passport = new Passport();
foreach (string part in parts) {
string label = part.Split(':')[0];
string val = part.Split(':')[1];
passport.BirthYear = val;
passport.IssueYear = val;
passport.ExpirationYear = val;
passport.HairColor = val;
passport.PassportId = val;
passport.CountryId = val;
private static bool HasRequiredFields(Passport passport) {
return !string.IsNullOrEmpty(passport.BirthYear) &&
!string.IsNullOrEmpty(passport.IssueYear) &&
!string.IsNullOrEmpty(passport.ExpirationYear) &&
!string.IsNullOrEmpty(passport.Height) &&
!string.IsNullOrEmpty(passport.HairColor) &&
!string.IsNullOrEmpty(passport.EyeColor) &&
!string.IsNullOrEmpty(passport.PassportId);
private static bool HasValidFields(Passport passport) {
return IsValidYear(1920, 2002, passport.BirthYear) &&
IsValidYear(2010, 2020, passport.IssueYear) &&
IsValidYear(2020, 2030, passport.ExpirationYear) &&
IsValidHeight(passport.Height) &&
IsValidHairColor(passport.HairColor) &&
IsValidEyeColor(passport.EyeColor) &&
IsValidPassportId(passport.PassportId);
private static bool IsValidYear(int min, int max, string val) {
if (val.Length == 4 && int.TryParse(val, out int i)) {
return min <= i && i <= max;
private static bool IsValidHeight(string height) {
if (height.Substring(height.Length - 2).Equals("cm")) {
if (int.TryParse(height.Substring(0, height.Length - 2), out int cms)) {
return 150 <= cms && cms <= 193;
if (height.Substring(height.Length - 2).Equals("in")) {
if (int.TryParse(height.Substring(0, height.Length - 2), out int inches)) {
return 59 <= inches && inches <= 76;
private static bool IsValidHairColor(string color) {
var r = new Regex("^[a-zA-Z0-9]*$");
return color.StartsWith('#') && color.Length == 7 && r.IsMatch(color.Substring(1));
private static bool IsValidEyeColor(string color) {
var validValues = new List<string> { "amb", "blu", "brn", "gry", "grn", "hzl", "oth" };
return validValues.Contains(color);
private static bool IsValidPassportId(string passportId) {
return passportId.Length == 9 && int.TryParse(passportId, out int _);