1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
FIELDS = {
  byr: ->(s) { s =~ /^\d{4}$/ && (1920..2002).cover?(s.to_i) },
  iyr: ->(s) { s =~ /^\d{4}$/ && (2010..2020).cover?(s.to_i) },
  eyr: ->(s) { s =~ /^\d{4}$/ && (2020..2030).cover?(s.to_i) },
  hgt: ->(s) {
    s =~ /^(\d+)(cm|in)$/
    case $2
    when "cm"
      (150..193).cover?($1.to_i)
    when "in"
      (59..76).cover?($1.to_i)
    else
      false
    end
  },
  hcl: ->(s) { s =~ /^#[0-9a-f]{6}$/ },
  ecl: ->(s) { s =~ /^(amb|blu|brn|gry|grn|hzl|oth)$/ },
  pid: ->(s) { s =~ /^\d{9}$/ },
  cid: ->(s) { true },
}

puts ARGF.read.split("\n\n").map {|line| line.scan(/(\w+):(\S+)/).to_h }
  .count {|passport|
    FIELDS.map {|k,v| v[passport.fetch(k.to_s, "")] }.all?
  }