Solve day 5-6 2015
This commit is contained in:
parent
93c3322770
commit
5ed6e5e8ce
14 changed files with 427 additions and 16 deletions
|
|
@ -1,8 +1,8 @@
|
|||
# Aoc
|
||||
|
||||
Solutions for [Advent of Code 2020][1], this year in Elixir.
|
||||
Solutions for [Advent of Code 2021][1], this year in Elixir.
|
||||
|
||||
[Elixir 1.11.1][2] preferred.
|
||||
[Elixir 1.12.3][2] preferred.
|
||||
|
||||
## Help scripts
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,9 @@
|
|||
defmodule Aoc do
|
||||
@moduledoc """
|
||||
Solutions for Advent of Code 2020, written in Elixir 1.11.1.
|
||||
"""
|
||||
|
||||
@year 2021
|
||||
def solve_all() do
|
||||
"""
|
||||
|
||||
ADVENT OF CODE 2020
|
||||
ADVENT OF CODE #{@year}
|
||||
===================
|
||||
"""
|
||||
|> IO.puts()
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@ defmodule Mix.Tasks.Aoc.New do
|
|||
|
||||
@shortdoc "Bootstrap new solution"
|
||||
@impl Mix.Task
|
||||
|
||||
@year 2021
|
||||
|
||||
def run([n, name]) do
|
||||
id = n |> String.pad_leading(2, "0")
|
||||
|
||||
|
|
@ -17,17 +20,17 @@ defmodule Mix.Tasks.Aoc.New do
|
|||
File.write!(test_file, test_file_content(id))
|
||||
|
||||
IO.puts("Creating " <> solution_file)
|
||||
File.write!(solution_file, solution_file_content(name, id))
|
||||
File.write!(solution_file, solution_file_content(name, id, n))
|
||||
|
||||
"""
|
||||
\nDone! Start coding.
|
||||
|
||||
Get your puzzle input here:
|
||||
https://adventofcode.com/2015/day/#{id}/input
|
||||
https://adventofcode.com/#{@year}/day/#{n}/input
|
||||
|
||||
mix test -- run tests.
|
||||
mix Aoc.solve_all -- run all puzzles, starting with 1
|
||||
mix Aoc.solve #{id} -- run single puzzle, 1-25
|
||||
mix aoc.solve_all -- run all puzzles, starting with 1
|
||||
mix aoc.solve #{id} -- run single puzzle, 1-25
|
||||
"""
|
||||
|> IO.puts()
|
||||
end
|
||||
|
|
@ -48,22 +51,22 @@ defmodule Mix.Tasks.Aoc.New do
|
|||
test "solves first part" do
|
||||
a = "something" |> parse!() |> solve_first_part()
|
||||
|
||||
expect a == :something
|
||||
assert a == :something
|
||||
end
|
||||
|
||||
test "solves second part" do
|
||||
a = "something" |> parse!() |> solve_second_part()
|
||||
|
||||
expect a == :something
|
||||
assert a == :something
|
||||
end
|
||||
end
|
||||
"""
|
||||
end
|
||||
|
||||
defp solution_file_content(name, id) do
|
||||
defp solution_file_content(name, id, n) do
|
||||
~s"""
|
||||
defmodule Aoc.Solution.Day#{id} do
|
||||
@name "#{name}"
|
||||
@name "Day #{n}: #{name}"
|
||||
@behaviour Solution
|
||||
|
||||
@impl Solution
|
||||
|
|
|
|||
96
2015-elixir/lib/solutions/day_06.ex
Normal file
96
2015-elixir/lib/solutions/day_06.ex
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
defmodule Aoc.Solution.Day06 do
|
||||
@name "Day 6: Probably a Fire Hazard"
|
||||
@behaviour Solution
|
||||
|
||||
@impl Solution
|
||||
def get_name, do: @name
|
||||
|
||||
@impl Solution
|
||||
def parse!(raw) do
|
||||
r = ~r/ ?(\S+) (\d+),(\d+) through (\d+),(\d+)/
|
||||
|
||||
raw
|
||||
|> String.split("\n")
|
||||
|> Enum.map(fn row ->
|
||||
[_, verb, x1, y1, x2, y2] = Regex.run(r, row)
|
||||
{verb, String.to_integer(x1)..String.to_integer(x2), String.to_integer(y1)..String.to_integer(y2)}
|
||||
end)
|
||||
end
|
||||
|
||||
@impl Solution
|
||||
def solve_first_part(input) do
|
||||
lit = MapSet.new()
|
||||
change_state(lit, input) |> MapSet.size()
|
||||
end
|
||||
|
||||
@impl Solution
|
||||
def solve_second_part(input) do
|
||||
lit = Map.new()
|
||||
adjust_brightness(lit, input)
|
||||
end
|
||||
|
||||
defp change_state(lit, []) do
|
||||
lit
|
||||
end
|
||||
|
||||
defp change_state(lit, [ {verb, xset, yset} | remaining]) do
|
||||
change = for x <- xset do
|
||||
for y <- yset do
|
||||
{x, y}
|
||||
end
|
||||
end |> List.flatten() |> MapSet.new()
|
||||
case verb do
|
||||
"on" ->
|
||||
change_state(MapSet.union(lit, change), remaining)
|
||||
|
||||
"off" ->
|
||||
change_state(MapSet.difference(lit, change), remaining)
|
||||
|
||||
"toggle" ->
|
||||
to_lit = MapSet.difference(change, lit)
|
||||
to_unlit = MapSet.difference(lit, change)
|
||||
change_state(MapSet.union(to_lit, to_unlit), remaining)
|
||||
end
|
||||
end
|
||||
|
||||
defp adjust_brightness(lit, []) do
|
||||
Map.values(lit) |> Enum.sum
|
||||
end
|
||||
|
||||
defp adjust_brightness(lit, [ {verb, xset, yset} | remaining]) do
|
||||
change = for x <- xset do
|
||||
for y <- yset do
|
||||
{x, y}
|
||||
end
|
||||
end |> List.flatten()
|
||||
updated = case verb do
|
||||
"on" ->
|
||||
Enum.reduce(change, lit, fn xy, acc ->
|
||||
if Map.has_key?(acc, xy) do
|
||||
%{acc | xy => Map.get(acc, xy) + 1}
|
||||
else
|
||||
Map.put(acc, xy, 1)
|
||||
end
|
||||
end)
|
||||
|
||||
"off" ->
|
||||
Enum.reduce(change, lit, fn xy, acc ->
|
||||
if Map.has_key?(acc, xy) do
|
||||
%{acc | xy => max(Map.get(acc, xy) - 1, 0)}
|
||||
else
|
||||
acc
|
||||
end
|
||||
end)
|
||||
|
||||
"toggle" ->
|
||||
Enum.reduce(change, lit, fn xy, acc ->
|
||||
if Map.has_key?(acc, xy) do
|
||||
%{acc | xy => Map.get(acc, xy) + 2}
|
||||
else
|
||||
Map.put(acc, xy, 2)
|
||||
end
|
||||
end)
|
||||
end
|
||||
adjust_brightness(updated, remaining)
|
||||
end
|
||||
end
|
||||
22
2015-elixir/lib/solutions/day_07.ex
Normal file
22
2015-elixir/lib/solutions/day_07.ex
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
defmodule Aoc.Solution.Day07 do
|
||||
@name "Day 7: Some Assembly Required"
|
||||
@behaviour Solution
|
||||
|
||||
@impl Solution
|
||||
def get_name, do: @name
|
||||
|
||||
@impl Solution
|
||||
def parse!(_raw) do
|
||||
"10"
|
||||
end
|
||||
|
||||
@impl Solution
|
||||
def solve_first_part(_input) do
|
||||
"(TBW)"
|
||||
end
|
||||
|
||||
@impl Solution
|
||||
def solve_second_part(_input) do
|
||||
"(TBW)"
|
||||
end
|
||||
end
|
||||
|
|
@ -14,7 +14,7 @@ defmodule Aoc.MixProject do
|
|||
# Run "mix help compile.app" to learn about applications.
|
||||
def application do
|
||||
[
|
||||
extra_applications: [:logger, :crypto]
|
||||
extra_applications: [:logger]
|
||||
]
|
||||
end
|
||||
|
||||
|
|
|
|||
45
2015-elixir/test/day_06_test.exs
Normal file
45
2015-elixir/test/day_06_test.exs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
defmodule Day06Test do
|
||||
use ExUnit.Case
|
||||
doctest Aoc.Solution.Day06
|
||||
import Aoc.Solution.Day06
|
||||
|
||||
test "parses the input" do
|
||||
input = """
|
||||
turn off 674,321 through 793,388
|
||||
toggle 749,672 through 973,965
|
||||
turn on 943,30 through 990,907
|
||||
""" |> String.trim()
|
||||
|
||||
expected = [
|
||||
{"off", 674..793, 321..388},
|
||||
{"toggle", 749..973, 672..965},
|
||||
{"on", 943..990, 30..907},
|
||||
]
|
||||
|
||||
assert parse!(input) == expected
|
||||
end
|
||||
|
||||
test "solves first part" do
|
||||
input = """
|
||||
turn on 0,0 through 999,999
|
||||
toggle 0,0 through 999,0
|
||||
turn off 499,499 through 500,500
|
||||
""" |> String.trim()
|
||||
|
||||
a = input |> parse!() |> solve_first_part()
|
||||
|
||||
assert a == 998996
|
||||
end
|
||||
|
||||
test "solves second part" do
|
||||
input = """
|
||||
turn on 0,0 through 999,999
|
||||
toggle 0,0 through 999,0
|
||||
turn off 499,499 through 500,500
|
||||
""" |> String.trim()
|
||||
|
||||
a = input |> parse!() |> solve_second_part()
|
||||
|
||||
assert a == 1000000 + 2000 - 4
|
||||
end
|
||||
end
|
||||
23
2015-elixir/test/day_07_test.exs
Normal file
23
2015-elixir/test/day_07_test.exs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
defmodule Day07Test do
|
||||
use ExUnit.Case
|
||||
doctest Aoc.Solution.Day07
|
||||
import Aoc.Solution.Day07
|
||||
|
||||
test "parses the input" do
|
||||
expected = 10
|
||||
|
||||
assert parse!("10") == expected
|
||||
end
|
||||
|
||||
test "solves first part" do
|
||||
a = "something" |> parse!() |> solve_first_part()
|
||||
|
||||
assert a == :something
|
||||
end
|
||||
|
||||
test "solves second part" do
|
||||
a = "something" |> parse!() |> solve_second_part()
|
||||
|
||||
assert a == :something
|
||||
end
|
||||
end
|
||||
29
2015-python/README.md
Normal file
29
2015-python/README.md
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
Advent of Code 2021
|
||||
===================
|
||||
|
||||
Solutions for #aoc2020 in Python 3 (3.8+).
|
||||
|
||||
Help scripts
|
||||
------------
|
||||
|
||||
Solve all puzzles:
|
||||
|
||||
python aoc.py
|
||||
|
||||
To bootstrap a new puzzle (creates `inputs/<day_no>.txt`, `solutions/day_<day_no>.py` och
|
||||
`tests/test_day_<day_no>.py`):
|
||||
|
||||
python aoc.py <dag_no> "<puzzle_name>"
|
||||
|
||||
Manually copy the puzzle input from https://adventofcode.com and paste it in `inputs/<day_no>.txt`
|
||||
to start coding.
|
||||
|
||||
Solve separate puzzle (replace `XX` with the puzzle number):
|
||||
|
||||
python -m solutions.day_XX
|
||||
|
||||
Run tests (replace `XX` with the puzzle number):
|
||||
|
||||
python -m unittest --locals -v
|
||||
# or, if `pytest` is preferred:
|
||||
pytest
|
||||
113
2015-python/aoc.py
Normal file
113
2015-python/aoc.py
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
import sys
|
||||
|
||||
year = 2021
|
||||
|
||||
try:
|
||||
_, day_no, name = sys.argv
|
||||
except ValueError:
|
||||
day_no = None
|
||||
name = None
|
||||
|
||||
print(
|
||||
f"\nAdvent of Code {year}"
|
||||
"\n###################"
|
||||
"\n\nby Anders Ytterström (@madr_se)"
|
||||
)
|
||||
|
||||
if day_no and name:
|
||||
print(f"\n- creating solutions/day_{day_no.zfill(2)}.py")
|
||||
with open("solutions/day_{}.py".format(day_no.zfill(2)), "w") as s:
|
||||
s.write(
|
||||
"""
|
||||
from solutions import BaseSolution
|
||||
|
||||
|
||||
class Solution(BaseSolution):
|
||||
input_file = "{day_no}.txt"
|
||||
|
||||
def __str__(self):
|
||||
return "Day {day}: {name}"
|
||||
|
||||
def parse_input(self, data):
|
||||
return data
|
||||
|
||||
def solve(self, puzzle_input):
|
||||
return True
|
||||
|
||||
def solve_again(self, puzzle_input):
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
solution = Solution()
|
||||
solution.show_results()
|
||||
""".strip().format(
|
||||
day=day_no, day_no=day_no.zfill(2), name=name
|
||||
)
|
||||
+ "\n"
|
||||
)
|
||||
print(f"- creating tests/test_day_{day_no.zfill(2)}.py")
|
||||
with open("tests/test_day_{}.py".format(day_no.zfill(2)), "w") as t:
|
||||
t.write(
|
||||
"""
|
||||
import unittest
|
||||
|
||||
from solutions.day_{day_no} import Solution
|
||||
|
||||
|
||||
class Day{day_no}TestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.solution = Solution()
|
||||
self.puzzle_input = self.solution.parse_input(
|
||||
\"\"\"
|
||||
<REPLACE ME>
|
||||
\"\"\"
|
||||
)
|
||||
|
||||
def test_parse_puzzle_input(self):
|
||||
data = \"\"\"
|
||||
<REPLACE ME>
|
||||
\"\"\"
|
||||
assert self.solution.parse_input(data) == "<REPLACE ME>"
|
||||
|
||||
# def test_solve_first_part(self):
|
||||
# assert self.solution.solve(self.puzzle_input) == True
|
||||
|
||||
# def test_solve_second_part(self):
|
||||
# assert self.solution.solve_again(self.puzzle_input) == True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
""".strip().format(
|
||||
day_no=day_no.zfill(2)
|
||||
)
|
||||
+ "\n"
|
||||
)
|
||||
print(f"- creating empty inputs/{day_no.zfill(2)}.txt")
|
||||
with open("inputs/{}.txt".format(day_no.zfill(2)), "w") as i:
|
||||
i.write("")
|
||||
|
||||
print(
|
||||
f"""
|
||||
Done! start coding.
|
||||
|
||||
Puzzle link:
|
||||
https://adventofcode.com/{year}/day/{day_no}
|
||||
|
||||
Puzzle input (copy and paste to inputs/{day_no.zfill(2)}.txt):
|
||||
https://adventofcode.com/{year}/day/{day_no}/input
|
||||
"""
|
||||
)
|
||||
exit(0)
|
||||
|
||||
for i in [str(n).zfill(2) for n in range(1, 26)]:
|
||||
try:
|
||||
solution = __import__(
|
||||
"solutions.day_{}".format(i), globals(), locals(), ["Solution"], 0
|
||||
).Solution()
|
||||
solution.show_results()
|
||||
except IOError:
|
||||
pass
|
||||
except ImportError:
|
||||
pass
|
||||
32
2015-python/solutions/__init__.py
Normal file
32
2015-python/solutions/__init__.py
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
class BaseSolution:
|
||||
input_file = None
|
||||
trim_input = True
|
||||
|
||||
def read_input(self, filename):
|
||||
filepath = "./inputs/{}".format(filename)
|
||||
with open(filepath, "r") as f:
|
||||
data = f.read()
|
||||
if self.trim_input:
|
||||
return data.strip()
|
||||
return data
|
||||
|
||||
def show_results(self):
|
||||
data = self.read_input(self.input_file)
|
||||
puzzle_input = self.parse_input(data)
|
||||
print(
|
||||
"\n\n{}\n{}\n\nPart 1: {}\nPart 2: {}".format(
|
||||
str(self),
|
||||
"-" * len(str(self)),
|
||||
self.solve(puzzle_input),
|
||||
self.solve_again(puzzle_input),
|
||||
)
|
||||
)
|
||||
|
||||
def solve(self, puzzle_input):
|
||||
raise NotImplemented
|
||||
|
||||
def solve_again(self, puzzle_input):
|
||||
raise NotImplemented
|
||||
|
||||
def parse_input(self, data):
|
||||
raise NotImplemented
|
||||
22
2015-python/solutions/day_06.py
Normal file
22
2015-python/solutions/day_06.py
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
from solutions import BaseSolution
|
||||
|
||||
|
||||
class Solution(BaseSolution):
|
||||
input_file = "06.txt"
|
||||
|
||||
def __str__(self):
|
||||
return "Day 6: Probably a Fire Hazard"
|
||||
|
||||
def parse_input(self, data):
|
||||
return data
|
||||
|
||||
def solve(self, puzzle_input):
|
||||
return True
|
||||
|
||||
def solve_again(self, puzzle_input):
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
solution = Solution()
|
||||
solution.show_results()
|
||||
0
2015-python/tests/__init__.py
Normal file
0
2015-python/tests/__init__.py
Normal file
29
2015-python/tests/test_day_06.py
Normal file
29
2015-python/tests/test_day_06.py
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import unittest
|
||||
|
||||
from solutions.day_06 import Solution
|
||||
|
||||
|
||||
class Day06TestCase(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.solution = Solution()
|
||||
self.puzzle_input = self.solution.parse_input(
|
||||
"""
|
||||
<REPLACE ME>
|
||||
"""
|
||||
)
|
||||
|
||||
def test_parse_puzzle_input(self):
|
||||
data = """
|
||||
<REPLACE ME>
|
||||
"""
|
||||
assert self.solution.parse_input(data) == "<REPLACE ME>"
|
||||
|
||||
# def test_solve_first_part(self):
|
||||
# assert self.solution.solve(self.puzzle_input) == True
|
||||
|
||||
# def test_solve_second_part(self):
|
||||
# assert self.solution.solve_again(self.puzzle_input) == True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Loading…
Add table
Reference in a new issue