Day 4 Parts 1 and 2
This commit is contained in:
parent
7483608460
commit
ace4184758
5 changed files with 1163 additions and 1 deletions
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
My (attempted) solutions to [Advent of Code 2020](https://adventofcode.com/2020) in Elixir.
|
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
|
## Strategy
|
||||||
|
|
||||||
|
|
47
day4/README
Normal file
47
day4/README
Normal 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
19
day4/day4part1.exs
Normal 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
67
day4/day4part2.exs
Normal 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
1029
day4/input
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue