Day 4 Parts 1 and 2

This commit is contained in:
Adam Millerchip 2020-12-04 15:21:20 +09:00
parent 7483608460
commit ace4184758
5 changed files with 1163 additions and 1 deletions

View file

@ -2,7 +2,7 @@
My (attempted) solutions to [Advent of Code 2020](https://adventofcode.com/2020) in Elixir.
<img width="973" alt="image" src="https://user-images.githubusercontent.com/498229/100967992-db331000-3573-11eb-8a48-aa73d01f1a53.png">
<img width="970" alt="image" src="https://user-images.githubusercontent.com/498229/101128533-397af400-3643-11eb-8555-c78113d57aa5.png">
## Strategy

47
day4/README Normal file
View file

@ -0,0 +1,47 @@
Day 4 Notes
+--------+
| Part 1 |
+--------+
$ elixir day4part1.exs
210
Thoughts:
Parse each passport into a list of key-value pairs, and extract the keys.
Not sure if there will be extra keys, so store required keys in a Mapset, which means I can use
MapSet.subset to make sure all the required keys are present.
Embedded enums are kind of ugly.
Nice usage of Enum.into, IMO 🍠.
+--------+
| Part 2 |
+--------+
$ elixir day4part2.exs
131
Thoughts:
Need the values too now, so refactor a bit to preserve them, storing each passport at a map.
Can still use part 1 logic to filter out passports that have missing keys.
- just pull out the keys and convert to a MapSet as before.
Delete the cid key if present, since needs to be ignored.
Validation code:
Mostly just implementing the spec.
Use regex for fiddly requirements.
hgt was a bit annoying, really wanted to fail-fast if the regex failed to match the units,
maybe will come back to that and think of a nicer way later.
For valid?: Is there a nicer way to call a bunch of functions with the same argument and
aggregate their results? 🤔
+------------------+
| Overall Thoughts |
+------------------+
Starting to take me longer now, about an hour for this one.
Ended up not using Enum.reduce here, but every time I do use it I forget the order of the
acc/item pair in the reducer function... 😩

19
day4/day4part1.exs Normal file
View file

@ -0,0 +1,19 @@
defmodule Day4Part1 do
@required MapSet.new(["byr", "ecl", "eyr", "hcl", "hgt", "iyr", "pid"])
def run do
File.read!("input")
|> String.trim()
|> String.split("\n\n")
|> Enum.map(fn passport ->
passport
|> String.split([" ", "\n"])
|> Enum.map(&String.split(&1, ":"))
|> Enum.into(MapSet.new(), fn [k, _] -> k end)
end)
|> Enum.count(&MapSet.subset?(@required, &1))
|> IO.puts()
end
end
Day4Part1.run()

67
day4/day4part2.exs Normal file
View file

@ -0,0 +1,67 @@
defmodule Day4Part2 do
@required MapSet.new(["byr", "ecl", "eyr", "hcl", "hgt", "iyr", "pid"])
def run do
File.read!("input")
|> String.trim()
|> String.split("\n\n")
|> Enum.map(fn passport ->
passport
|> String.split([" ", "\n"])
|> Enum.map(&String.split(&1, ":"))
|> Map.new(fn [k, v] -> {k, v} end)
end)
|> Enum.map(&Map.delete(&1, "cid"))
|> Enum.filter(&MapSet.subset?(@required, &1 |> Map.keys() |> MapSet.new()))
|> Enum.count(&valid?/1)
|> IO.puts()
end
def valid?(passport) do
byr?(passport) && iyr?(passport) && eyr?(passport) && hgt?(passport) && hcl?(passport) &&
ecl?(passport) && pid?(passport)
end
def byr?(%{"byr" => byr}) do
date = String.to_integer(byr)
1920 <= date && date <= 2002
end
def iyr?(%{"iyr" => iyr}) do
date = String.to_integer(iyr)
2010 <= date && date <= 2020
end
def eyr?(%{"eyr" => eyr}) do
date = String.to_integer(eyr)
2020 <= date && date <= 2030
end
def hgt?(%{"hgt" => hgt}) do
{hgt, unit} =
case Regex.run(~r/\A(\d+)([^\d]+)\z/, hgt, capture: :all_but_first) do
[hgt, unit] -> {String.to_integer(hgt), unit}
nil -> {0, nil}
end
case unit do
"cm" -> 150 <= hgt && hgt <= 193
"in" -> 59 <= hgt && hgt <= 76
nil -> false
end
end
def hcl?(%{"hcl" => hcl}) do
Regex.match?(~r/\A#[0-9a-f]{6}\z/, hcl)
end
def ecl?(%{"ecl" => ecl}) do
ecl in ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"]
end
def pid?(%{"pid" => pid}) do
Regex.match?(~r/\A\d{9}\z/, pid)
end
end
Day4Part2.run()

1029
day4/input Normal file

File diff suppressed because it is too large Load diff