121 lines
2.9 KiB
Nim
121 lines
2.9 KiB
Nim
import std/[options, strutils]
|
|
import lib/loader
|
|
|
|
|
|
type Passport = object
|
|
byr, iyr, eyr, hgt, hcl, ecl, pid, cid: Option[string]
|
|
|
|
|
|
proc addField(p: var Passport, field: string) =
|
|
let kv = field.split(':')
|
|
case kv[0]
|
|
of "byr": p.byr = some(kv[1])
|
|
of "iyr": p.iyr = some(kv[1])
|
|
of "eyr": p.eyr = some(kv[1])
|
|
of "hgt": p.hgt = some(kv[1])
|
|
of "hcl": p.hcl = some(kv[1])
|
|
of "ecl": p.ecl = some(kv[1])
|
|
of "pid": p.pid = some(kv[1])
|
|
of "cid": p.cid = some(kv[1])
|
|
else: discard
|
|
|
|
|
|
var data = @[Passport()] # start with one empty passport
|
|
for line in loadStrings(4):
|
|
let pairs = line.splitWhitespace()
|
|
if pairs.len == 0:
|
|
data.add(Passport())
|
|
else:
|
|
for pair in pairs:
|
|
data[^1].addField(pair)
|
|
|
|
|
|
proc partOne(data: seq[Passport]): int =
|
|
for p in data:
|
|
if (
|
|
p.byr.isSome() and
|
|
p.iyr.isSome() and
|
|
p.eyr.isSome() and
|
|
p.hgt.isSome() and
|
|
p.hcl.isSome() and
|
|
p.ecl.isSome() and
|
|
p.pid.isSome()
|
|
):
|
|
inc result
|
|
|
|
|
|
func validateYr(year: string; min, max: int): bool =
|
|
if year.len != 4:
|
|
return false
|
|
try:
|
|
let n = parseInt(year)
|
|
result = (n >= min and n <= max)
|
|
except ValueError:
|
|
result = false
|
|
|
|
|
|
func validateHgt(hgt: string): bool =
|
|
if hgt.len < 3: # need both value and unit
|
|
return false
|
|
|
|
let value = try:
|
|
parseInt(hgt[0 .. ^3])
|
|
except ValueError:
|
|
return false
|
|
|
|
let unit = hgt[^2 .. ^1]
|
|
if unit == "in":
|
|
return value >= 59 and value <= 76
|
|
elif unit == "cm":
|
|
return value >= 150 and value <= 193
|
|
else:
|
|
return false
|
|
|
|
|
|
func validateHcl(hcl: string): bool =
|
|
if hcl.len != 7 or hcl[0] != '#':
|
|
return false
|
|
for c in hcl[2 .. ^1]:
|
|
if c notin {
|
|
'0', '1', '2', '3', '4', '5', '6', '7',
|
|
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
|
}:
|
|
return false
|
|
return true
|
|
|
|
|
|
func validateEcl(ecl: string): bool =
|
|
case ecl:
|
|
of "amb", "blu", "brn", "gry", "grn", "hzl", "oth":
|
|
return true
|
|
else:
|
|
return false
|
|
|
|
|
|
func validatePid(pid: string): bool =
|
|
if pid.len != 9:
|
|
return false
|
|
for c in pid:
|
|
if c notin {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}:
|
|
return false
|
|
return true
|
|
|
|
|
|
proc partTwo(data: seq[Passport]): int =
|
|
for p in data:
|
|
if (
|
|
validateYr(p.byr.get(""), 1920, 2002) and
|
|
validateYr(p.iyr.get(""), 2010, 2020) and
|
|
validateYr(p.eyr.get(""), 2020, 2030) and
|
|
validateHgt(p.hgt.get("")) and
|
|
validateHcl(p.hcl.get("")) and
|
|
validateEcl(p.ecl.get("")) and
|
|
validatePid(p.pid.get(""))
|
|
):
|
|
inc result
|
|
|
|
|
|
when isMainModule:
|
|
echo "One: ", partOne(data)
|
|
echo "Two: ", partTwo(data)
|