Add solutions from AOC 2016-2020
This commit is contained in:
parent
d5a29d41e2
commit
7daf307f21
205 changed files with 10423 additions and 0 deletions
4
2015-elixir/.formatter.exs
Normal file
4
2015-elixir/.formatter.exs
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Used by "mix format"
|
||||||
|
[
|
||||||
|
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||||
|
]
|
||||||
1
2015-elixir/.tool-versions
Normal file
1
2015-elixir/.tool-versions
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
elixir 1.11.1
|
||||||
29
2015-elixir/README.md
Normal file
29
2015-elixir/README.md
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
# Aoc
|
||||||
|
|
||||||
|
Solutions for [Advent of Code 2020][1], this year in Elixir.
|
||||||
|
|
||||||
|
[Elixir 1.11.1][2] preferred.
|
||||||
|
|
||||||
|
## Help scripts
|
||||||
|
|
||||||
|
Run tests using `mix test` as usual.
|
||||||
|
|
||||||
|
Create input file, test file and solution file for a day,
|
||||||
|
using day 1 as example:
|
||||||
|
|
||||||
|
mix Aoc.new 1 "Name of the puzzle"
|
||||||
|
|
||||||
|
Solve a single puzzle, using puzzle from day 3 as example:
|
||||||
|
|
||||||
|
mix Aoc.solve 3
|
||||||
|
|
||||||
|
Solve all puzzles, starting at the first:
|
||||||
|
|
||||||
|
mix Aoc.solve_all
|
||||||
|
|
||||||
|
## Log
|
||||||
|
|
||||||
|
_Advent of Code has not started yet. See you in December!_
|
||||||
|
|
||||||
|
[1]: https://adventofcode.com/
|
||||||
|
[2]: https://hexdocs.pm/elixir/Kernel.html
|
||||||
61
2015-elixir/lib/aoc.ex
Normal file
61
2015-elixir/lib/aoc.ex
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
defmodule Aoc do
|
||||||
|
@moduledoc """
|
||||||
|
Solutions for Advent of Code 2020, written in Elixir 1.11.1.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def solve_all() do
|
||||||
|
"""
|
||||||
|
|
||||||
|
ADVENT OF CODE 2020
|
||||||
|
===================
|
||||||
|
"""
|
||||||
|
|> IO.puts()
|
||||||
|
|
||||||
|
1..25 |> Enum.map(&solve/1)
|
||||||
|
end
|
||||||
|
|
||||||
|
def solve(n) do
|
||||||
|
id = n |> Integer.to_string() |> String.pad_leading(2, "0")
|
||||||
|
|
||||||
|
case File.read("./inputs/" <> id <> ".in") do
|
||||||
|
{:error, _} ->
|
||||||
|
nil
|
||||||
|
|
||||||
|
{:ok, input} ->
|
||||||
|
input
|
||||||
|
|> run(id)
|
||||||
|
|> present
|
||||||
|
|> IO.puts()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def run(input, id) do
|
||||||
|
solution_module = Module.concat(["Aoc.Solution", "Day" <> id])
|
||||||
|
|
||||||
|
data = apply(solution_module, :parse!, [input])
|
||||||
|
name = apply(solution_module, :get_name, [])
|
||||||
|
first_solution = apply(solution_module, :solve_first_part, [data])
|
||||||
|
second_solution = apply(solution_module, :solve_second_part, [data])
|
||||||
|
|
||||||
|
[name, first_solution, second_solution]
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Generates a CLI-friendly presentation of the solutions.
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
iex> Aoc.present(["Day 1: tomten kommer", "10", "20"])
|
||||||
|
"Day 1: tomten kommer\\n--------------------\\n\\n1. 10\\n2. 20\\n"
|
||||||
|
|
||||||
|
"""
|
||||||
|
def present([name, first_solution, second_solution]) do
|
||||||
|
"""
|
||||||
|
#{name}
|
||||||
|
#{1..String.length(name) |> Enum.map_join(fn _x -> "-" end)}
|
||||||
|
|
||||||
|
1. #{first_solution}
|
||||||
|
2. #{second_solution}
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
end
|
||||||
89
2015-elixir/lib/mix/tasks/bootstrap.ex
Normal file
89
2015-elixir/lib/mix/tasks/bootstrap.ex
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
defmodule Mix.Tasks.Aoc.New do
|
||||||
|
use Mix.Task
|
||||||
|
|
||||||
|
@shortdoc "Bootstrap new solution"
|
||||||
|
@impl Mix.Task
|
||||||
|
def run([n, name]) do
|
||||||
|
id = n |> String.pad_leading(2, "0")
|
||||||
|
|
||||||
|
input_file = "./inputs/" <> id <> ".in"
|
||||||
|
test_file = "./test/day_" <> id <> "_test.exs"
|
||||||
|
solution_file = "./lib/solutions/day_" <> id <> ".ex"
|
||||||
|
|
||||||
|
IO.puts("Creating " <> input_file)
|
||||||
|
File.touch(input_file)
|
||||||
|
|
||||||
|
IO.puts("Creating " <> test_file)
|
||||||
|
File.write!(test_file, test_file_content(id))
|
||||||
|
|
||||||
|
IO.puts("Creating " <> solution_file)
|
||||||
|
File.write!(solution_file, solution_file_content(name, id))
|
||||||
|
|
||||||
|
"""
|
||||||
|
\nDone! Start coding.
|
||||||
|
|
||||||
|
Get your puzzle input here:
|
||||||
|
https://adventofcode.com/2015/day/#{id}/input
|
||||||
|
|
||||||
|
mix test -- run tests.
|
||||||
|
mix Aoc.solve_all -- run all puzzles, starting with 1
|
||||||
|
mix Aoc.solve #{id} -- run single puzzle, 1-25
|
||||||
|
"""
|
||||||
|
|> IO.puts()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp test_file_content(id) do
|
||||||
|
"""
|
||||||
|
defmodule Day#{id}Test do
|
||||||
|
use ExUnit.Case
|
||||||
|
doctest Aoc.Solution.Day#{id}
|
||||||
|
import Aoc.Solution.Day#{id}
|
||||||
|
|
||||||
|
test "parses the input" do
|
||||||
|
expected = 10
|
||||||
|
|
||||||
|
assert parse!("10") == expected
|
||||||
|
end
|
||||||
|
|
||||||
|
test "solves first part" do
|
||||||
|
a = "something" |> parse!() |> solve_first_part()
|
||||||
|
|
||||||
|
expect a == :something
|
||||||
|
end
|
||||||
|
|
||||||
|
test "solves second part" do
|
||||||
|
a = "something" |> parse!() |> solve_second_part()
|
||||||
|
|
||||||
|
expect a == :something
|
||||||
|
end
|
||||||
|
end
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
|
||||||
|
defp solution_file_content(name, id) do
|
||||||
|
~s"""
|
||||||
|
defmodule Aoc.Solution.Day#{id} do
|
||||||
|
@name "#{name}"
|
||||||
|
@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
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
end
|
||||||
11
2015-elixir/lib/mix/tasks/solve.ex
Normal file
11
2015-elixir/lib/mix/tasks/solve.ex
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
defmodule Mix.Tasks.Aoc.Solve do
|
||||||
|
use Mix.Task
|
||||||
|
|
||||||
|
@shortdoc "Solve single puzzle"
|
||||||
|
@impl Mix.Task
|
||||||
|
def run([id]) do
|
||||||
|
id
|
||||||
|
|> String.to_integer()
|
||||||
|
|> Aoc.solve()
|
||||||
|
end
|
||||||
|
end
|
||||||
9
2015-elixir/lib/mix/tasks/solve_all.ex
Normal file
9
2015-elixir/lib/mix/tasks/solve_all.ex
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
defmodule Mix.Tasks.Aoc.SolveAll do
|
||||||
|
use Mix.Task
|
||||||
|
|
||||||
|
@shortdoc "Solve all puzzles"
|
||||||
|
@impl Mix.Task
|
||||||
|
def run(_) do
|
||||||
|
Aoc.solve_all()
|
||||||
|
end
|
||||||
|
end
|
||||||
6
2015-elixir/lib/solution.ex
Normal file
6
2015-elixir/lib/solution.ex
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
defmodule Solution do
|
||||||
|
@callback parse!(String.t()) :: Any
|
||||||
|
@callback get_name() :: String.t()
|
||||||
|
@callback solve_first_part(Any) :: String.t()
|
||||||
|
@callback solve_second_part(Any) :: String.t()
|
||||||
|
end
|
||||||
57
2015-elixir/lib/solutions/day_01.ex
Normal file
57
2015-elixir/lib/solutions/day_01.ex
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
defmodule Aoc.Solution.Day01 do
|
||||||
|
@name "Day 1: Not Quite Lisp"
|
||||||
|
@behaviour Solution
|
||||||
|
|
||||||
|
@basement -1
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def get_name, do: @name
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def parse!(raw) do
|
||||||
|
raw
|
||||||
|
|> String.split("", trim: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def solve_first_part(input) do
|
||||||
|
input
|
||||||
|
|> Enum.map(fn d ->
|
||||||
|
case d do
|
||||||
|
"(" -> 1
|
||||||
|
")" -> -1
|
||||||
|
_ -> 0
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|> Enum.sum()
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def solve_second_part(input) do
|
||||||
|
[change | changes] =
|
||||||
|
input
|
||||||
|
|> Enum.map(fn d ->
|
||||||
|
case d do
|
||||||
|
"(" -> 1
|
||||||
|
")" -> -1
|
||||||
|
_ -> 0
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
move(change, 1, 0, changes)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp move(change, pos, current, []) do
|
||||||
|
case current + change do
|
||||||
|
@basement -> pos
|
||||||
|
_ -> :basement_never_reached
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp move(change, pos, current, [next | changes]) do
|
||||||
|
case current + change do
|
||||||
|
@basement -> pos
|
||||||
|
_ -> move(next, pos + 1, current + change, changes)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
42
2015-elixir/lib/solutions/day_02.ex
Normal file
42
2015-elixir/lib/solutions/day_02.ex
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
defmodule Aoc.Solution.Day02 do
|
||||||
|
@name "I Was Told There Would Be No Math"
|
||||||
|
@behaviour Solution
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def get_name, do: @name
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def parse!(raw) do
|
||||||
|
raw
|
||||||
|
|> String.split()
|
||||||
|
|> Enum.map(fn p -> p |> String.split("x") |> Enum.map(&String.to_integer/1) end)
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def solve_first_part(input) do
|
||||||
|
input
|
||||||
|
|> Enum.map(fn p -> area(p) end)
|
||||||
|
|> Enum.sum()
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def solve_second_part(input) do
|
||||||
|
input
|
||||||
|
|> Enum.map(fn p -> ribbon(p) end)
|
||||||
|
|> Enum.sum()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp area(p) do
|
||||||
|
[l, w, h] = p
|
||||||
|
extra = Enum.min([l * w, w * h, h * l])
|
||||||
|
2 * l * w + 2 * w * h + 2 * h * l + extra
|
||||||
|
end
|
||||||
|
|
||||||
|
defp ribbon(p) do
|
||||||
|
[l, w, h] = p
|
||||||
|
[x, y | _] = Enum.sort(p)
|
||||||
|
ribbon = 2 * x + 2 * y
|
||||||
|
bow = l * w * h
|
||||||
|
bow + ribbon
|
||||||
|
end
|
||||||
|
end
|
||||||
53
2015-elixir/lib/solutions/day_03.ex
Normal file
53
2015-elixir/lib/solutions/day_03.ex
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
defmodule Aoc.Solution.Day03 do
|
||||||
|
@name "Perfectly Spherical Houses in a Vacuum"
|
||||||
|
@behaviour Solution
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def get_name, do: @name
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def parse!(raw) do
|
||||||
|
String.split(raw, "", trim: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def solve_first_part(input) do
|
||||||
|
input |> deliver() |> MapSet.size()
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def solve_second_part(input) do
|
||||||
|
santa = Enum.take_every(input, 2) |> deliver()
|
||||||
|
|
||||||
|
robosanta =
|
||||||
|
input
|
||||||
|
|> Enum.with_index()
|
||||||
|
|> Enum.reject(fn {_k, v} -> rem(v, 2) == 0 end)
|
||||||
|
|> Enum.map(fn {k, _v} -> k end)
|
||||||
|
|> deliver()
|
||||||
|
|
||||||
|
MapSet.union(santa, robosanta) |> MapSet.size()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp move("<", {x, y}), do: {x - 1, y}
|
||||||
|
|
||||||
|
defp move(">", {x, y}), do: {x + 1, y}
|
||||||
|
|
||||||
|
defp move("v", {x, y}), do: {x, y + 1}
|
||||||
|
|
||||||
|
defp move("^", {x, y}), do: {x, y - 1}
|
||||||
|
|
||||||
|
defp deliver(input) do
|
||||||
|
{_, seen} =
|
||||||
|
input
|
||||||
|
|> Enum.reduce(
|
||||||
|
{{0, 0}, MapSet.new([{0, 0}])},
|
||||||
|
fn d, {pos, seen} ->
|
||||||
|
next = move(d, pos)
|
||||||
|
{next, MapSet.put(seen, next)}
|
||||||
|
end
|
||||||
|
)
|
||||||
|
|
||||||
|
seen
|
||||||
|
end
|
||||||
|
end
|
||||||
35
2015-elixir/lib/solutions/day_04.ex
Normal file
35
2015-elixir/lib/solutions/day_04.ex
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
defmodule Aoc.Solution.Day04 do
|
||||||
|
@name "Day 4: The Ideal Stocking Stuffer"
|
||||||
|
@behaviour Solution
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def get_name, do: @name
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def parse!(raw) do
|
||||||
|
String.trim(raw)
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def solve_first_part(input) do
|
||||||
|
find_number(input, 0, "00000")
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def solve_second_part(input) do
|
||||||
|
find_number(input, 0, "000000")
|
||||||
|
end
|
||||||
|
|
||||||
|
defp find_number(a, b, prefix) do
|
||||||
|
case valid_checksum?(a, b, prefix) do
|
||||||
|
true -> b
|
||||||
|
false -> find_number(a, b + 1, prefix)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp valid_checksum?(a, b, prefix) do
|
||||||
|
:crypto.hash(:md5, "#{a}#{b}")
|
||||||
|
|> Base.encode16()
|
||||||
|
|> String.starts_with?(prefix)
|
||||||
|
end
|
||||||
|
end
|
||||||
73
2015-elixir/lib/solutions/day_05.ex
Normal file
73
2015-elixir/lib/solutions/day_05.ex
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
defmodule Aoc.Solution.Day05 do
|
||||||
|
@name "Day 5: Doesn't He Have Intern-Elves For This?"
|
||||||
|
@behaviour Solution
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def get_name, do: @name
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def parse!(raw) do
|
||||||
|
raw
|
||||||
|
|> String.split()
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def solve_first_part(strings) do
|
||||||
|
strings
|
||||||
|
|> Enum.map(fn s -> nice?(s) end)
|
||||||
|
|> Enum.map(fn b ->
|
||||||
|
if b, do: 1, else: 0
|
||||||
|
end)
|
||||||
|
|> Enum.sum()
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl Solution
|
||||||
|
def solve_second_part(strings) do
|
||||||
|
strings
|
||||||
|
|> Enum.map(fn s -> still_nice?(s) end)
|
||||||
|
|> Enum.map(fn b ->
|
||||||
|
if b, do: 1, else: 0
|
||||||
|
end)
|
||||||
|
|> Enum.sum()
|
||||||
|
end
|
||||||
|
|
||||||
|
defp nice?(subject) do
|
||||||
|
Enum.all?([
|
||||||
|
does_not_contain_the_strings(subject),
|
||||||
|
contains_at_least_three_vowels(subject),
|
||||||
|
contains_at_least_one_letter_pair(subject)
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
defp still_nice?(subject) do
|
||||||
|
Enum.all?([
|
||||||
|
contains_a_letter_pair_without_overlapping(subject),
|
||||||
|
contains_one_letter_pair_which_repeats_with_exactly_one_letter_between_them(subject)
|
||||||
|
])
|
||||||
|
end
|
||||||
|
|
||||||
|
defp contains_at_least_three_vowels(subject) do
|
||||||
|
r = ~r/[aeiou].*[aeiou].*[aeiou].*/
|
||||||
|
String.match?(subject, r)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp contains_at_least_one_letter_pair(subject) do
|
||||||
|
r = ~r/(\w)\1/
|
||||||
|
String.match?(subject, r)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp does_not_contain_the_strings(subject) do
|
||||||
|
r = ~r/ab|cd|pq|xy/
|
||||||
|
not String.match?(subject, r)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp contains_a_letter_pair_without_overlapping(subject) do
|
||||||
|
r = ~r/(\w{2}).*\1/
|
||||||
|
String.match?(subject, r)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp contains_one_letter_pair_which_repeats_with_exactly_one_letter_between_them(subject) do
|
||||||
|
r = ~r/(\w)\w\1/
|
||||||
|
String.match?(subject, r)
|
||||||
|
end
|
||||||
|
end
|
||||||
28
2015-elixir/mix.exs
Normal file
28
2015-elixir/mix.exs
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
defmodule Aoc.MixProject do
|
||||||
|
use Mix.Project
|
||||||
|
|
||||||
|
def project do
|
||||||
|
[
|
||||||
|
app: :Aoc,
|
||||||
|
version: "0.1.0",
|
||||||
|
elixir: "~> 1.10",
|
||||||
|
start_permanent: Mix.env() == :prod,
|
||||||
|
deps: deps()
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Run "mix help compile.app" to learn about applications.
|
||||||
|
def application do
|
||||||
|
[
|
||||||
|
extra_applications: [:logger, :crypto]
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Run "mix help deps" to learn about dependencies.
|
||||||
|
defp deps do
|
||||||
|
[
|
||||||
|
# {:dep_from_hexpm, "~> 0.3.0"},
|
||||||
|
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
4
2015-elixir/test/aoc_test.exs
Normal file
4
2015-elixir/test/aoc_test.exs
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
defmodule AocTest do
|
||||||
|
use ExUnit.Case
|
||||||
|
doctest Aoc
|
||||||
|
end
|
||||||
51
2015-elixir/test/day_01_test.exs
Normal file
51
2015-elixir/test/day_01_test.exs
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
defmodule Day01Test do
|
||||||
|
use ExUnit.Case
|
||||||
|
doctest Aoc.Solution.Day01
|
||||||
|
import Aoc.Solution.Day01
|
||||||
|
|
||||||
|
test "parses the input" do
|
||||||
|
expected = ["(", "(", ")", ")"]
|
||||||
|
|
||||||
|
result = parse!("(())")
|
||||||
|
|
||||||
|
assert result == expected
|
||||||
|
end
|
||||||
|
|
||||||
|
test "solves first part" do
|
||||||
|
a = "(())" |> parse!() |> solve_first_part()
|
||||||
|
b = "()()" |> parse!() |> solve_first_part()
|
||||||
|
c = "(((" |> parse!() |> solve_first_part()
|
||||||
|
d = "(()(()(" |> parse!() |> solve_first_part()
|
||||||
|
e = "))(((((" |> parse!() |> solve_first_part()
|
||||||
|
f = "())" |> parse!() |> solve_first_part()
|
||||||
|
g = "))(" |> parse!() |> solve_first_part()
|
||||||
|
h = ")))" |> parse!() |> solve_first_part()
|
||||||
|
i = ")())())" |> parse!() |> solve_first_part()
|
||||||
|
|
||||||
|
assert a == 0
|
||||||
|
assert b == 0
|
||||||
|
assert c == 3
|
||||||
|
assert d == 3
|
||||||
|
assert e == 3
|
||||||
|
assert f == -1
|
||||||
|
assert g == -1
|
||||||
|
assert h == -3
|
||||||
|
assert i == -3
|
||||||
|
end
|
||||||
|
|
||||||
|
test "solves second part" do
|
||||||
|
a = ")" |> parse!() |> solve_second_part()
|
||||||
|
b = "()())" |> parse!() |> solve_second_part()
|
||||||
|
c = "()())()" |> parse!() |> solve_second_part()
|
||||||
|
|
||||||
|
assert a == 1
|
||||||
|
assert b == 5
|
||||||
|
assert c == 5
|
||||||
|
end
|
||||||
|
|
||||||
|
test "solves second part with examples of no-last chars" do
|
||||||
|
a = "()())()" |> parse!() |> solve_second_part()
|
||||||
|
|
||||||
|
assert a == 5
|
||||||
|
end
|
||||||
|
end
|
||||||
45
2015-elixir/test/day_02_test.exs
Normal file
45
2015-elixir/test/day_02_test.exs
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
defmodule Day02Test do
|
||||||
|
use ExUnit.Case
|
||||||
|
doctest Aoc.Solution.Day02
|
||||||
|
import Aoc.Solution.Day02
|
||||||
|
|
||||||
|
test "parses the input" do
|
||||||
|
input = """
|
||||||
|
2x3x4
|
||||||
|
1x1x10
|
||||||
|
"""
|
||||||
|
|
||||||
|
assert parse!(input) == [
|
||||||
|
[2, 3, 4],
|
||||||
|
[1, 1, 10]
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "solves first part" do
|
||||||
|
a = "2x3x4" |> parse!() |> solve_first_part()
|
||||||
|
b = "1x1x10" |> parse!() |> solve_first_part()
|
||||||
|
|
||||||
|
assert a == 58
|
||||||
|
assert b == 43
|
||||||
|
end
|
||||||
|
|
||||||
|
test "solves first part using multiple packages" do
|
||||||
|
a = "2x3x4\n1x1x10" |> parse!() |> solve_first_part()
|
||||||
|
|
||||||
|
assert a == 58 + 43
|
||||||
|
end
|
||||||
|
|
||||||
|
test "solves second part" do
|
||||||
|
a = "2x3x4" |> parse!() |> solve_second_part()
|
||||||
|
b = "1x1x10" |> parse!() |> solve_second_part()
|
||||||
|
|
||||||
|
assert a == 34
|
||||||
|
assert b == 14
|
||||||
|
end
|
||||||
|
|
||||||
|
test "solves second part using multiple packages" do
|
||||||
|
a = "2x3x4\n1x1x10" |> parse!() |> solve_second_part()
|
||||||
|
|
||||||
|
assert a == 34 + 14
|
||||||
|
end
|
||||||
|
end
|
||||||
31
2015-elixir/test/day_03_test.exs
Normal file
31
2015-elixir/test/day_03_test.exs
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
defmodule Day03Test do
|
||||||
|
use ExUnit.Case
|
||||||
|
doctest Aoc.Solution.Day03
|
||||||
|
import Aoc.Solution.Day03
|
||||||
|
|
||||||
|
test "parses the input" do
|
||||||
|
expected = ["<", ">"]
|
||||||
|
|
||||||
|
assert parse!("<>") == expected
|
||||||
|
end
|
||||||
|
|
||||||
|
test "solves first part" do
|
||||||
|
a = ">" |> parse!() |> solve_first_part()
|
||||||
|
b = "^>v<" |> parse!() |> solve_first_part()
|
||||||
|
c = "^v^v^v^v^v" |> parse!() |> solve_first_part()
|
||||||
|
|
||||||
|
assert a == 2
|
||||||
|
assert b == 4
|
||||||
|
assert c == 2
|
||||||
|
end
|
||||||
|
|
||||||
|
test "solves second part" do
|
||||||
|
a = "^v" |> parse!() |> solve_second_part()
|
||||||
|
b = "^>v<" |> parse!() |> solve_second_part()
|
||||||
|
c = "^v^v^v^v^v" |> parse!() |> solve_second_part()
|
||||||
|
|
||||||
|
assert a == 3
|
||||||
|
assert b == 3
|
||||||
|
assert c == 11
|
||||||
|
end
|
||||||
|
end
|
||||||
20
2015-elixir/test/day_04_test.exs
Normal file
20
2015-elixir/test/day_04_test.exs
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
defmodule Day04Test do
|
||||||
|
use ExUnit.Case
|
||||||
|
doctest Aoc.Solution.Day04
|
||||||
|
import Aoc.Solution.Day04
|
||||||
|
|
||||||
|
test "parses the input" do
|
||||||
|
i = "\n ab \n"
|
||||||
|
expected = "ab"
|
||||||
|
|
||||||
|
assert parse!(i) == expected
|
||||||
|
end
|
||||||
|
|
||||||
|
test "solves first part" do
|
||||||
|
a = "abcdef" |> parse!() |> solve_first_part()
|
||||||
|
b = "pqrstuv" |> parse!() |> solve_first_part()
|
||||||
|
|
||||||
|
assert a == 609_043
|
||||||
|
assert b == 1_048_970
|
||||||
|
end
|
||||||
|
end
|
||||||
43
2015-elixir/test/day_05_test.exs
Normal file
43
2015-elixir/test/day_05_test.exs
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
defmodule Day05Test do
|
||||||
|
use ExUnit.Case
|
||||||
|
doctest Aoc.Solution.Day05
|
||||||
|
import Aoc.Solution.Day05
|
||||||
|
|
||||||
|
test "parses the input" do
|
||||||
|
input = """
|
||||||
|
a
|
||||||
|
b
|
||||||
|
c
|
||||||
|
"""
|
||||||
|
|
||||||
|
expected = ["a", "b", "c"]
|
||||||
|
|
||||||
|
assert parse!(input) == expected
|
||||||
|
end
|
||||||
|
|
||||||
|
test "solves first part" do
|
||||||
|
a = "ugknbfddgicrmopn" |> parse!() |> solve_first_part()
|
||||||
|
b = "aaa" |> parse!() |> solve_first_part()
|
||||||
|
c = "jchzalrnumimnmhp" |> parse!() |> solve_first_part()
|
||||||
|
d = "haegwjzuvuyypxyu" |> parse!() |> solve_first_part()
|
||||||
|
e = "dvszwmarrgswjxmb" |> parse!() |> solve_first_part()
|
||||||
|
|
||||||
|
assert a == 1
|
||||||
|
assert b == 1
|
||||||
|
assert c == 0
|
||||||
|
assert d == 0
|
||||||
|
assert e == 0
|
||||||
|
end
|
||||||
|
|
||||||
|
test "solves second part" do
|
||||||
|
a = "qjhvhtzxzqqjkmpb" |> parse!() |> solve_second_part()
|
||||||
|
b = "xxyxx" |> parse!() |> solve_second_part()
|
||||||
|
c = "uurcxstgmygtbstg" |> parse!() |> solve_second_part()
|
||||||
|
d = "ieodomkazucvgmuy" |> parse!() |> solve_second_part()
|
||||||
|
|
||||||
|
assert a == 1
|
||||||
|
assert b == 1
|
||||||
|
assert c == 0
|
||||||
|
assert d == 0
|
||||||
|
end
|
||||||
|
end
|
||||||
1
2015-elixir/test/test_helper.exs
Normal file
1
2015-elixir/test/test_helper.exs
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
ExUnit.start()
|
||||||
22
2016-python/README.md
Normal file
22
2016-python/README.md
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
# Lösningar till Advent of Code 2016
|
||||||
|
|
||||||
|
För Python 3. För att köra alla lösningarna i ett svep,
|
||||||
|
kör `python aoc2016.py`. Ingen virtualenv krävs: alla lösningar
|
||||||
|
använder inget utöver standardbiblioteket.
|
||||||
|
|
||||||
|
För att köra en enstaka lösning, skicka med pusselfilen
|
||||||
|
som första programargument, t ex såhär: `python day_03.py puzzles/03.txt`
|
||||||
|
|
||||||
|
## Noteringar / logg
|
||||||
|
|
||||||
|
* Koden i `Day 1: No Time for a Taxicab` är rejält överdriven vad gäller
|
||||||
|
läsbarhet och en (ill-)vilja för att ha fyndiga variabelnamn.
|
||||||
|
* För `Day 3: Squares With Three Sides` fanns ett osunt behov av att lösa
|
||||||
|
allt med en rad. Förlåt ...
|
||||||
|
* Latmasken hämtade [en befintlig algoritm](https://www.reddit.com/r/adventofcode/comments/5hbygy/2016_day_9_solutions/)
|
||||||
|
för andra delen av `Day 9: Explosives in Cyberspace` på grund av tidsbrist.
|
||||||
|
|
||||||
|
## Förtydligande
|
||||||
|
|
||||||
|
Det är ok att nämna mig vid namn i podden om ni hittar något värt
|
||||||
|
att nämna i min kod. :)
|
||||||
17
2016-python/aoc2016.py
Executable file
17
2016-python/aoc2016.py
Executable file
|
|
@ -0,0 +1,17 @@
|
||||||
|
print("""
|
||||||
|
_ _ ____ ___ _ __
|
||||||
|
_| || |_ __ _ ___ ___|___ \ / _ \/ |/ /_
|
||||||
|
|_ .. _|/ _` |/ _ \ / __| __) | | | | | '_ \\
|
||||||
|
|_ _| (_| | (_) | (__ / __/| |_| | | (_) |
|
||||||
|
|_||_| \__,_|\___/ \___|_____|\___/|_|\___/
|
||||||
|
""")
|
||||||
|
for i in [str(n).zfill(2) for n in range(1, 26)]:
|
||||||
|
try:
|
||||||
|
with open('inputs/%s.txt' % i, 'r') as puzzle_input:
|
||||||
|
puzzle = puzzle_input.read()
|
||||||
|
print('\n--- %s ---' % __import__('day_%s' % i).run.__doc__)
|
||||||
|
__import__('day_%s' % i).run(puzzle)
|
||||||
|
except IOError:
|
||||||
|
pass
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
108
2016-python/day_01.py
Normal file
108
2016-python/day_01.py
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
import sys
|
||||||
|
from random import randint
|
||||||
|
|
||||||
|
|
||||||
|
def run(pinput):
|
||||||
|
"""Day 1: No Time for a Taxicab"""
|
||||||
|
santa_starting_position = (randint(-1024, 1024), randint(-1024, 1024))
|
||||||
|
head_quarters, first_recurrence = direct_santa(santa_starting_position, pinput)
|
||||||
|
|
||||||
|
print('Distance to Easter Bunny HQ: %s' % head_quarters)
|
||||||
|
print('Distance to first recurrence: %s' % first_recurrence)
|
||||||
|
|
||||||
|
|
||||||
|
def get_distance(start, current):
|
||||||
|
return abs(abs(start[0] - current[0]) + abs(start[1] - current[1]))
|
||||||
|
|
||||||
|
|
||||||
|
def go_north(current_block, distance):
|
||||||
|
return (current_block[0] - distance, current_block[1]), 'N'
|
||||||
|
|
||||||
|
|
||||||
|
def go_south(current_block, distance):
|
||||||
|
return (current_block[0] + distance, current_block[1]), 'S'
|
||||||
|
|
||||||
|
|
||||||
|
def go_west(current_block, distance):
|
||||||
|
return (current_block[0], current_block[1] - distance), 'W'
|
||||||
|
|
||||||
|
|
||||||
|
def go_east(current_block, distance):
|
||||||
|
return (current_block[0], current_block[1] + distance), 'E'
|
||||||
|
|
||||||
|
|
||||||
|
def go_left(current_block, facing_direction, distance):
|
||||||
|
if facing_direction == 'N':
|
||||||
|
return go_west(current_block, distance)
|
||||||
|
if facing_direction == 'W':
|
||||||
|
return go_south(current_block, distance)
|
||||||
|
if facing_direction == 'S':
|
||||||
|
return go_east(current_block, distance)
|
||||||
|
if facing_direction == 'E':
|
||||||
|
return go_north(current_block, distance)
|
||||||
|
|
||||||
|
|
||||||
|
def go_right(current_block, facing_direction, distance):
|
||||||
|
if facing_direction == 'N':
|
||||||
|
return go_east(current_block, distance)
|
||||||
|
if facing_direction == 'E':
|
||||||
|
return go_south(current_block, distance)
|
||||||
|
if facing_direction == 'S':
|
||||||
|
return go_west(current_block, distance)
|
||||||
|
if facing_direction == 'W':
|
||||||
|
return go_north(current_block, distance)
|
||||||
|
|
||||||
|
|
||||||
|
def track_santa(tracks, direction, distance):
|
||||||
|
pos = tracks[-1]
|
||||||
|
recurrence = None
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
while i < distance:
|
||||||
|
if direction == 'N':
|
||||||
|
pos, f = go_north(pos, 1)
|
||||||
|
if direction == 'W':
|
||||||
|
pos, f = go_west(pos, 1)
|
||||||
|
if direction == 'S':
|
||||||
|
pos, f = go_south(pos, 1)
|
||||||
|
if direction == 'E':
|
||||||
|
pos, f = go_east(pos, 1)
|
||||||
|
|
||||||
|
if not recurrence and pos in tracks:
|
||||||
|
recurrence = pos
|
||||||
|
|
||||||
|
tracks.append(pos)
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
return tracks, recurrence
|
||||||
|
|
||||||
|
|
||||||
|
def direct_santa(starting_block, directions):
|
||||||
|
gone_in_circle_at = None
|
||||||
|
current_block = starting_block
|
||||||
|
facing = 'N'
|
||||||
|
tracks = [starting_block]
|
||||||
|
|
||||||
|
for d in directions.split(', '):
|
||||||
|
distance = int(d[1:])
|
||||||
|
current_block, facing = go_left(current_block, facing, distance) if d.startswith('L') else go_right(
|
||||||
|
current_block, facing, distance)
|
||||||
|
tracks, recurrence = track_santa(tracks, facing, distance)
|
||||||
|
|
||||||
|
if not gone_in_circle_at and recurrence:
|
||||||
|
gone_in_circle_at = recurrence
|
||||||
|
|
||||||
|
head_quarters_pos = get_distance(starting_block, current_block)
|
||||||
|
first_recurrence_pos = get_distance(starting_block, gone_in_circle_at)
|
||||||
|
|
||||||
|
return head_quarters_pos, first_recurrence_pos
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
with open(sys.argv[1], 'r') as f:
|
||||||
|
run(f.read())
|
||||||
|
except IOError:
|
||||||
|
print('please provide a file path to puzzle file, example: ./puzzle.txt')
|
||||||
|
except IndexError:
|
||||||
|
print('please provide a file path to puzzle file, example: ./puzzle.txt')
|
||||||
70
2016-python/day_02.py
Normal file
70
2016-python/day_02.py
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def run(pinput):
|
||||||
|
"""Day 2: Bathroom Security"""
|
||||||
|
imaginary_code = break_code_imaginary(5, pinput)
|
||||||
|
real_code = break_code_real(5, pinput)
|
||||||
|
|
||||||
|
print('Code using imaginary pad: %s' % imaginary_code)
|
||||||
|
print('Code using real pad: %s' % real_code)
|
||||||
|
|
||||||
|
|
||||||
|
def break_code_real(start, instructions):
|
||||||
|
"""
|
||||||
|
real pad:
|
||||||
|
|
||||||
|
1
|
||||||
|
2 3 4
|
||||||
|
5 6 7 8 9
|
||||||
|
A B C
|
||||||
|
D
|
||||||
|
"""
|
||||||
|
pos = start
|
||||||
|
code = ''
|
||||||
|
for l in instructions.split('\n'):
|
||||||
|
for g in l.strip():
|
||||||
|
if g == 'U' and pos not in [1, 2, 4, 5, 9]:
|
||||||
|
pos -= 2 if pos in [13, 3] else 4
|
||||||
|
if g == 'D' and pos not in [5, 9, 10, 12, 13]:
|
||||||
|
pos += 2 if pos in [1, 11] else 4
|
||||||
|
if g == 'L' and pos not in [1, 2, 5, 10, 13]:
|
||||||
|
pos -= 1
|
||||||
|
if g == 'R' and pos not in [1, 4, 9, 12, 13]:
|
||||||
|
pos += 1
|
||||||
|
code += format(pos, 'X')
|
||||||
|
return code
|
||||||
|
|
||||||
|
|
||||||
|
def break_code_imaginary(start, instructions):
|
||||||
|
"""
|
||||||
|
imaginary pad:
|
||||||
|
|
||||||
|
1 2 3
|
||||||
|
4 5 6
|
||||||
|
7 8 9
|
||||||
|
"""
|
||||||
|
pos = start
|
||||||
|
code = ''
|
||||||
|
for l in instructions.split('\n'):
|
||||||
|
for g in l.strip():
|
||||||
|
if g == 'U' and pos > 3:
|
||||||
|
pos -= 3
|
||||||
|
if g == 'D' and pos < 7:
|
||||||
|
pos += 3
|
||||||
|
if g == 'L' and pos not in [1, 4, 7]:
|
||||||
|
pos -= 1
|
||||||
|
if g == 'R' and pos not in [3, 6, 9]:
|
||||||
|
pos += 1
|
||||||
|
code += str(pos)
|
||||||
|
return code
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
with open(sys.argv[1], 'r') as f:
|
||||||
|
run(f.read())
|
||||||
|
except IOError:
|
||||||
|
print('please provide a file path to puzzle file, example: ./puzzle.txt')
|
||||||
|
except IndexError:
|
||||||
|
print('please provide a file path to puzzle file, example: ./puzzle.txt')
|
||||||
35
2016-python/day_03.py
Normal file
35
2016-python/day_03.py
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def run(pinput):
|
||||||
|
"""Day 3: Squares With Three Sides"""
|
||||||
|
h = find_fake_triangles_hor(pinput)
|
||||||
|
v = find_fake_triangles_ver(pinput)
|
||||||
|
|
||||||
|
print('Fake triangles count, horizontal: %s' % h)
|
||||||
|
print('Fake triangles count, vertical: %s' % v)
|
||||||
|
|
||||||
|
|
||||||
|
def find_fake_triangles_hor(pinput):
|
||||||
|
# see commit 8fd8787 for the more readable edition
|
||||||
|
return sum(map(lambda t: t[0] + t[1] > t[2], map(lambda l: sorted(map(int, l.split())), pinput.split('\n'))))
|
||||||
|
|
||||||
|
|
||||||
|
def find_fake_triangles_ver(pinput):
|
||||||
|
# do it in 1 loc? challenge accepted! also, I'm sorry.
|
||||||
|
return sum([map(lambda t: t[0] + t[1] > t[2],
|
||||||
|
[sorted(x[i:i + 3]) for i in range(0, len(x), 3)]) for x in
|
||||||
|
[(list(map(int, re.findall(r'^\s+(\d+)', pinput, flags=re.MULTILINE))) + list(
|
||||||
|
map(int, re.findall(r'^\s+\d+\s+(\d+)', pinput, flags=re.MULTILINE))) + list(
|
||||||
|
map(int, re.findall(r'^\s+\d+\s+\d+\s+(\d+)', pinput, flags=re.MULTILINE))))]][0])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
with open(sys.argv[1], 'r') as f:
|
||||||
|
run(f.read())
|
||||||
|
except IOError:
|
||||||
|
print('please provide a file path to puzzle file, example: ./puzzle.txt')
|
||||||
|
except IndexError:
|
||||||
|
print('please provide a file path to puzzle file, example: ./puzzle.txt')
|
||||||
56
2016-python/day_04.py
Normal file
56
2016-python/day_04.py
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from collections import Counter
|
||||||
|
|
||||||
|
|
||||||
|
def get_valid_rooms(pinput):
|
||||||
|
def only_valid_rooms(l):
|
||||||
|
code, id, checksum = re.match(r'^(\D+)(\d+)\[(\D+?)\]$', l.translate({ord('-'): None})).groups()
|
||||||
|
mc = Counter(code).most_common()
|
||||||
|
mc_sorted = sorted(mc, key=lambda e: (-e[1], e[0])) # because FU, Counter default sort ...
|
||||||
|
return ''.join(map(lambda x: x[0], mc_sorted)).startswith(checksum)
|
||||||
|
|
||||||
|
return filter(only_valid_rooms, pinput.splitlines())
|
||||||
|
|
||||||
|
|
||||||
|
def sum_sector_ids(puzzle):
|
||||||
|
return sum(map(int, map(lambda l: re.match(r'.+-(\d+)\[', l).group(1),
|
||||||
|
get_valid_rooms(puzzle))))
|
||||||
|
|
||||||
|
|
||||||
|
def decrypt_name(ciphered, id):
|
||||||
|
v = ''
|
||||||
|
for c in ciphered:
|
||||||
|
dec = ord(c) + (id % 26)
|
||||||
|
if dec > 122:
|
||||||
|
dec -= 26
|
||||||
|
v += ' ' if c == '-' else chr(dec)
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
|
def find_np_room(pinput):
|
||||||
|
rooms = get_valid_rooms(pinput)
|
||||||
|
for r in rooms:
|
||||||
|
code, sid = re.match(r'^(\D+)-(\d+)\[', r).groups()
|
||||||
|
decrypted = decrypt_name(code, int(sid))
|
||||||
|
if decrypted == 'northpole object storage':
|
||||||
|
return sid
|
||||||
|
|
||||||
|
|
||||||
|
def run(pinput):
|
||||||
|
"""Day 4: Security Through Obscurity"""
|
||||||
|
s = sum_sector_ids(pinput)
|
||||||
|
np = find_np_room(pinput)
|
||||||
|
|
||||||
|
print('Sum of sector IDs, real rooms: %s' % s)
|
||||||
|
print('Section ID for North Pole storage: %s' % np)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
with open(sys.argv[1], 'r') as f:
|
||||||
|
run(f.read())
|
||||||
|
except IOError:
|
||||||
|
print('please provide a file path to puzzle file, example: ./puzzle.txt')
|
||||||
|
except IndexError:
|
||||||
|
print('please provide a file path to puzzle file, example: ./puzzle.txt')
|
||||||
47
2016-python/day_05.py
Normal file
47
2016-python/day_05.py
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
import hashlib
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def hack_password(pinput):
|
||||||
|
passwd = ''
|
||||||
|
i = 0
|
||||||
|
while len(passwd) < 8:
|
||||||
|
s = hashlib.md5(bytes('%s%d' % (pinput, i), 'ascii')).hexdigest()
|
||||||
|
if s.startswith('00000'):
|
||||||
|
passwd += s[5]
|
||||||
|
i += 1
|
||||||
|
return passwd
|
||||||
|
|
||||||
|
|
||||||
|
def hack_password_again(pinput):
|
||||||
|
passwd = [' ' for n in range(0, 8)]
|
||||||
|
i = 0
|
||||||
|
while ' ' in passwd:
|
||||||
|
s = hashlib.md5(bytes('%s%d' % (pinput, i), 'ascii')).hexdigest()
|
||||||
|
try:
|
||||||
|
pos = int(s[5])
|
||||||
|
if s.startswith('00000') and pos < 8:
|
||||||
|
passwd[pos] = s[6] if passwd[pos] == ' ' else passwd[pos]
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
i += 1
|
||||||
|
return ''.join(passwd)
|
||||||
|
|
||||||
|
|
||||||
|
def run(pinput):
|
||||||
|
"""Day 5: How About a Nice Game of Chess?"""
|
||||||
|
p = hack_password(pinput)
|
||||||
|
q = hack_password_again(pinput)
|
||||||
|
|
||||||
|
print('Password, first door: %s' % p)
|
||||||
|
print('Password, second door: %s' % q)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
with open(sys.argv[1], 'r') as f:
|
||||||
|
run(f.read().strip())
|
||||||
|
except IOError:
|
||||||
|
print('please provide a file path to puzzle file, example: ./puzzle.txt')
|
||||||
|
except IndexError:
|
||||||
|
print('please provide a file path to puzzle file, example: ./puzzle.txt')
|
||||||
29
2016-python/day_06.py
Normal file
29
2016-python/day_06.py
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import sys
|
||||||
|
from collections import Counter
|
||||||
|
|
||||||
|
|
||||||
|
def get_message(pinput):
|
||||||
|
return ''.join(map(lambda l: Counter(l).most_common()[0][0], zip(*pinput.split('\n'))))
|
||||||
|
|
||||||
|
|
||||||
|
def get_real_message(pinput):
|
||||||
|
return ''.join(map(lambda l: Counter(l).most_common()[-1][0], zip(*pinput.split('\n'))))
|
||||||
|
|
||||||
|
|
||||||
|
def run(pinput):
|
||||||
|
"""Day 6: Signals and Noise"""
|
||||||
|
m = get_message(pinput)
|
||||||
|
n = get_real_message(pinput)
|
||||||
|
|
||||||
|
print('Corrected message, most common char: %s' % m)
|
||||||
|
print('Corrected message, least common char: %s' % n)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
with open(sys.argv[1], 'r') as f:
|
||||||
|
run(f.read().strip())
|
||||||
|
except IOError:
|
||||||
|
print('please provide a file path to puzzle file, example: ./puzzle.txt')
|
||||||
|
except IndexError:
|
||||||
|
print('please provide a file path to puzzle file, example: ./puzzle.txt')
|
||||||
44
2016-python/day_07.py
Normal file
44
2016-python/day_07.py
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def count_ips(pinput):
|
||||||
|
def tls(l):
|
||||||
|
a = re.sub(r'\[.+?\]', lambda x: ' ', l)
|
||||||
|
abbas = sum(map(lambda i: a[i:i + 4] == a[i:i + 4][::-1] and a[i:i + 1] != a[i + 1:i + 2],
|
||||||
|
range(0, len(a) - 3)))
|
||||||
|
total = sum(map(lambda i: l[i:i + 4] == l[i:i + 4][::-1] and l[i:i + 1] != l[i + 1:i + 2],
|
||||||
|
range(0, len(l) - 3)))
|
||||||
|
return abbas == total and abbas > 0
|
||||||
|
|
||||||
|
def ssl(l):
|
||||||
|
a = re.sub(r'\[.+?\]', lambda x: ' ', l)
|
||||||
|
b = ' '.join(re.findall(r'\[(.+?)\]', l))
|
||||||
|
|
||||||
|
abas = set(filter(lambda v: v, map(
|
||||||
|
lambda i: a[i:i + 3] if a[i:i + 3] == a[i:i + 3][::-1] and a[i:i + 1] != a[i + 1:i + 2] else None,
|
||||||
|
range(0, len(a) - 2))))
|
||||||
|
babs = set(filter(lambda v: v, map(
|
||||||
|
lambda i: b[i + 1:i + 3] + b[i + 1] if b[i:i + 3] == b[i:i + 3][::-1] and b[i:i + 1] != b[i + 1:i + 2] else None,
|
||||||
|
range(0, len(b) - 2))))
|
||||||
|
return len(abas.intersection(babs)) > 0
|
||||||
|
|
||||||
|
return sum(map(tls, pinput.split('\n'))), sum(map(ssl, pinput.split('\n')))
|
||||||
|
|
||||||
|
|
||||||
|
def run(pinput):
|
||||||
|
"""Day 7: Internet Protocol Version 7"""
|
||||||
|
tls, ssl = count_ips(pinput)
|
||||||
|
|
||||||
|
print('IPs supporting TLS: %s' % tls)
|
||||||
|
print('IPs supporting SSL: %s' % ssl)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
with open(sys.argv[1], 'r') as f:
|
||||||
|
run(f.read().strip())
|
||||||
|
except IOError:
|
||||||
|
print('please provide a file path to puzzle file, example: ./puzzle.txt')
|
||||||
|
except IndexError:
|
||||||
|
print('please provide a file path to puzzle file, example: ./puzzle.txt')
|
||||||
75
2016-python/day_08.py
Normal file
75
2016-python/day_08.py
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def rotate(o, w, h, matrix):
|
||||||
|
e = re.match(r'rotate.+([x|y])=(\d+) by (\d+)', o)
|
||||||
|
if e:
|
||||||
|
t, s, d = e.groups()
|
||||||
|
lit = list()
|
||||||
|
m = list()
|
||||||
|
if t == 'x':
|
||||||
|
for c in range(0, w):
|
||||||
|
lit.append(matrix[c::w])
|
||||||
|
for r in range(0, int(d)):
|
||||||
|
lit[int(s)] = lit[int(s)][h - 1:] + lit[int(s)][0:h - 1]
|
||||||
|
for c in zip(*lit):
|
||||||
|
m.extend(c)
|
||||||
|
if t == 'y':
|
||||||
|
for c in range(0, w):
|
||||||
|
lit.append(matrix[c::w])
|
||||||
|
lit = list(zip(*lit))
|
||||||
|
for r in range(0, int(d)):
|
||||||
|
lit[int(s)] = lit[int(s)][w - 1:] + lit[int(s)][0:w - 1]
|
||||||
|
for c in lit:
|
||||||
|
m.extend(c)
|
||||||
|
return m
|
||||||
|
else:
|
||||||
|
return matrix
|
||||||
|
|
||||||
|
|
||||||
|
def rect(o, w, h, matrix):
|
||||||
|
e = re.match(r'rect (\d+)x(\d+)', o)
|
||||||
|
if e:
|
||||||
|
x, y = e.groups()
|
||||||
|
lit = list()
|
||||||
|
r = list(range(0, w * h))
|
||||||
|
for c in range(0, int(x)):
|
||||||
|
lit += r[c::w][:int(y)]
|
||||||
|
for n in lit:
|
||||||
|
matrix[n] = True
|
||||||
|
return matrix
|
||||||
|
else:
|
||||||
|
return matrix
|
||||||
|
|
||||||
|
|
||||||
|
def lit_screen(w, h, pinput):
|
||||||
|
matrix = [False for i in range(0, w * h)]
|
||||||
|
|
||||||
|
for o in pinput:
|
||||||
|
matrix = rect(o, w, h, matrix)
|
||||||
|
matrix = rotate(o, w, h, matrix)
|
||||||
|
|
||||||
|
out = list()
|
||||||
|
for l in range(0, w * h, w):
|
||||||
|
out.append(''.join(map(lambda l: '#' if l else ' ', matrix[l:l+w])))
|
||||||
|
|
||||||
|
return sum(matrix), '\n'.join(out)
|
||||||
|
|
||||||
|
|
||||||
|
def run(pinput):
|
||||||
|
"""Day 8: Two-Factor Authentication"""
|
||||||
|
pl, out = lit_screen(50, 6, pinput.strip().split('\n'))
|
||||||
|
|
||||||
|
print('\n%s\n' % out)
|
||||||
|
print('Pixels lit: %s' % pl)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
with open(sys.argv[1], 'r') as f:
|
||||||
|
run(f.read().strip())
|
||||||
|
except IOError:
|
||||||
|
print('please provide a file path to puzzle file, example: ./puzzle.txt')
|
||||||
|
except IndexError:
|
||||||
|
print('please provide a file path to puzzle file, example: ./puzzle.txt')
|
||||||
52
2016-python/day_09.py
Normal file
52
2016-python/day_09.py
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def decompress(pinput):
|
||||||
|
parts = list()
|
||||||
|
m = re.match(r'.*\((\d+)x(\d+)\)', pinput)
|
||||||
|
if m:
|
||||||
|
while re.match(r'.*\((\d+)x(\d+)\)', pinput):
|
||||||
|
a, c, r, b = re.split(r'\((\d+)x(\d+)\)', pinput, maxsplit=1)
|
||||||
|
parts.append(a)
|
||||||
|
parts.append(''.join([b[0:int(c)] for i in range(0, int(r))]))
|
||||||
|
pinput = b[int(c):]
|
||||||
|
return sum(map(lambda s: len(s), parts)) + len(pinput)
|
||||||
|
else:
|
||||||
|
return len(pinput)
|
||||||
|
|
||||||
|
|
||||||
|
def decompress_V2(pinput):
|
||||||
|
# Algorithm found at:
|
||||||
|
# https://www.reddit.com/r/adventofcode/comments/5hbygy/2016_day_9_solutions/
|
||||||
|
l = 0
|
||||||
|
w = [1 for c in pinput]
|
||||||
|
cur = 0
|
||||||
|
while cur < len(pinput):
|
||||||
|
if pinput[cur] == '(':
|
||||||
|
s, r = re.match(r'\((\d+)x(\d+)\)', pinput[cur:]).groups()
|
||||||
|
cur += len('(%sx%s)' % (s, r))
|
||||||
|
for i in range(cur, cur + int(s)):
|
||||||
|
w[i] *= int(r)
|
||||||
|
else:
|
||||||
|
l += w[cur]
|
||||||
|
cur += 1
|
||||||
|
return l
|
||||||
|
|
||||||
|
|
||||||
|
def run(pinput):
|
||||||
|
"""Day 9: Explosives in Cyberspace"""
|
||||||
|
v1 = decompress(pinput)
|
||||||
|
v2 = decompress_V2(pinput)
|
||||||
|
print('Decrompressed length, v1: %s' % v1)
|
||||||
|
print('Decrompressed length, v2: %s' % v2)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
with open(sys.argv[1], 'r') as f:
|
||||||
|
run(f.read().strip())
|
||||||
|
except IOError:
|
||||||
|
print('please provide a file path to puzzle file, example: ./puzzle.txt')
|
||||||
|
except IndexError:
|
||||||
|
print('please provide a file path to puzzle file, example: ./puzzle.txt')
|
||||||
65
2016-python/day_10.py
Normal file
65
2016-python/day_10.py
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
value_delegate = re.compile(r'value (\d+) goes to bot (\d+)')
|
||||||
|
bot_delegate = re.compile(r'bot (\d+) gives low to \b(bot|output) (\d+) and high to \b(bot|output) (\d+)')
|
||||||
|
|
||||||
|
|
||||||
|
def delegate(pinput, x, y):
|
||||||
|
bots = dict()
|
||||||
|
outputs = dict()
|
||||||
|
for l in pinput:
|
||||||
|
if value_delegate.match(l):
|
||||||
|
fv, b = map(int, value_delegate.match(l).groups())
|
||||||
|
bots[b] = bots[b] + [fv] if b in bots else [fv]
|
||||||
|
|
||||||
|
bot = ''
|
||||||
|
go = True
|
||||||
|
while go:
|
||||||
|
botz = bots.copy().items()
|
||||||
|
for bid, bvs in botz:
|
||||||
|
if len(bvs) == 2:
|
||||||
|
for l in pinput:
|
||||||
|
if l.startswith('bot %d ' % bid) and bot_delegate.match(l):
|
||||||
|
fv, l, li, h, hi = bot_delegate.match(l).groups()
|
||||||
|
fv, li, hi = map(int, (fv, li, hi))
|
||||||
|
try:
|
||||||
|
if l == 'output':
|
||||||
|
outputs[li] = outputs[li] + [min(bots[fv])] if li in outputs else [min(bots[fv])]
|
||||||
|
bots[fv] = list(filter(lambda x: x != min(bots[fv]), bots[fv]))
|
||||||
|
else:
|
||||||
|
bots[li] = bots[li] + [min(bots[fv])] if li in bots else [min(bots[fv])]
|
||||||
|
bots[fv] = list(filter(lambda x: x != min(bots[fv]), bots[fv]))
|
||||||
|
|
||||||
|
if h == 'output':
|
||||||
|
outputs[hi] = outputs[hi] + [max(bots[fv])] if hi in outputs else [max(bots[fv])]
|
||||||
|
bots[fv] = list(filter(lambda x: x != max(bots[fv]), bots[fv]))
|
||||||
|
else:
|
||||||
|
bots[hi] = bots[hi] + [max(bots[fv])] if hi in bots else [max(bots[fv])]
|
||||||
|
bots[fv] = list(filter(lambda x: x != max(bots[fv]), bots[fv]))
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
break
|
||||||
|
go = len(list(filter(lambda b: len(b[1]) == 2, bots.items()))) != 0
|
||||||
|
bt = ''.join([str(z[0]) for z in filter(lambda z: x in z[1] and y in z[1], bots.items())])
|
||||||
|
if len(bt) > 0:
|
||||||
|
bot = bt
|
||||||
|
return bot, outputs[0][0] * outputs[2][0] * outputs[1][0]
|
||||||
|
|
||||||
|
|
||||||
|
def run(pinput):
|
||||||
|
"""Day 10: Balance Bots"""
|
||||||
|
bot, m = delegate(pinput.strip().splitlines(), 61, 17)
|
||||||
|
|
||||||
|
print('Bot that deals with %s and %s: %s' % (61, 17, bot))
|
||||||
|
print('Multiple the values of 0-2: %s' % m)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
try:
|
||||||
|
with open(sys.argv[1], 'r') as f:
|
||||||
|
run(f.read().strip())
|
||||||
|
except IOError:
|
||||||
|
print('please provide a file path to puzzle file, example: ./puzzle.txt')
|
||||||
|
except IndexError:
|
||||||
|
print('please provide a file path to puzzle file, example: ./puzzle.txt')
|
||||||
3
2017-python/.gitignore
vendored
Normal file
3
2017-python/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
.idea
|
||||||
|
*.pyc
|
||||||
|
__pycache__
|
||||||
54
2017-python/README.md
Normal file
54
2017-python/README.md
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
Advent of Code 2017
|
||||||
|
===================
|
||||||
|
|
||||||
|
Lösningar för #aoc2017 i Python 3 (testat mot 3.5.2).
|
||||||
|
|
||||||
|
|
||||||
|
Logg
|
||||||
|
----
|
||||||
|
|
||||||
|
* Särskilt svåra dagar (tidsåtgång mer än 60 min) vid kodtillfället:
|
||||||
|
* Dag 3,
|
||||||
|
* Dag 6,
|
||||||
|
* Dag 7,
|
||||||
|
* Dag 14,
|
||||||
|
* Dag 18 och
|
||||||
|
* Dag 21.
|
||||||
|
* Dag 3: del 2 kopierades från en [färdig sekvens](https://oeis.org/A141481). Restpunkt är att faktiskt
|
||||||
|
implementera den.
|
||||||
|
* Dag 5: del 2 tar väldigt lång tid att exekvera. Restpunkt är att optimera denna!
|
||||||
|
* Dag 11: Allt som behövs finns beskrivet på
|
||||||
|
[Hexagonal Grids](https://www.redblobgames.com/grids/hexagons/).
|
||||||
|
* Dag 13: del 2 misslyckande att hitta något som var snabbt nog att exekvera.
|
||||||
|
Restpunkt är skriva något som inte tar en timme att köra!
|
||||||
|
* Dag 14 del 2: Läs på om [Union-find algoritmen](https://en.wikipedia.org/wiki/Disjoint-set_data_structure)
|
||||||
|
* Dag 15: borde skrivas om att använda generatorer för att snabbas upp.
|
||||||
|
* Dag 18 del 2: ["värdet av" kan betyda flera saker](https://www.reddit.com/r/adventofcode/comments/7kj35s/2017_day_18_solutions/dreth75/) ... jävla etta.
|
||||||
|
* Dag 21: Blocken ska divergera och ska därmed testas separat mot reglerna. Detta missade jag, och antog istället att samma regel applicerade på alla block ...
|
||||||
|
|
||||||
|
|
||||||
|
Hjälpscript
|
||||||
|
-----------
|
||||||
|
|
||||||
|
För att köra alla lösningar:
|
||||||
|
|
||||||
|
python aoc.py
|
||||||
|
|
||||||
|
|
||||||
|
För att starta en ny dag (skapar och populerar filerna `inputs/<dagnummer>.txt`, `solutions/day_<dagnummer>.py` och
|
||||||
|
`tests/day_<dagnummer>_tests.py`):
|
||||||
|
|
||||||
|
python aoc.py <dagnummer> "<namn på dag>"
|
||||||
|
|
||||||
|
Öppna puzzle input manuellt och kopiera innehållet till `inputs/<dagnummer>.txt` som ett sista manuellt steg.
|
||||||
|
|
||||||
|
|
||||||
|
För att köra separat lösning (ersätt `XX` med dagens nummer):
|
||||||
|
|
||||||
|
PYTHONPATH=$(pwd) python solutions/day_XX.py
|
||||||
|
|
||||||
|
|
||||||
|
Starta automatisk testkörare (ersätt `XX` med dagens nummer):
|
||||||
|
|
||||||
|
export PYTHONPATH=$(pwd)
|
||||||
|
ls solutions/**/*.py | entr -c -r python tests/day_XX_tests.py
|
||||||
65
2017-python/aoc.py
Normal file
65
2017-python/aoc.py
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
_, day_no, name = sys.argv
|
||||||
|
except ValueError:
|
||||||
|
day_no = None
|
||||||
|
name = None
|
||||||
|
|
||||||
|
if day_no and name:
|
||||||
|
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 solve(self, puzzle_input):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
|
'''.strip().format(day=day_no, day_no=day_no.zfill(2), name=name) + '\n')
|
||||||
|
with open('tests/day_{}_tests.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()
|
||||||
|
|
||||||
|
def test_something(self):
|
||||||
|
assert self.solution.solve('puzzle_input') == True
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
'''.strip().format(day_no=day_no.zfill(2)) + '\n')
|
||||||
|
with open('inputs/{}.txt'.format(day_no.zfill(2)), 'w') as i:
|
||||||
|
i.write('')
|
||||||
|
exit(0)
|
||||||
|
|
||||||
|
print('\nAdvent of Code 2017'
|
||||||
|
'\n###################'
|
||||||
|
'\n\nby Anders Ytterström (@madr)')
|
||||||
|
|
||||||
|
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
|
||||||
26
2017-python/solutions/__init__.py
Normal file
26
2017-python/solutions/__init__.py
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
class BaseSolution:
|
||||||
|
puzzle_input = ""
|
||||||
|
input_file = None
|
||||||
|
trim_input = True
|
||||||
|
|
||||||
|
def parse_input(self, filename):
|
||||||
|
filepath = './inputs/{}'.format(filename)
|
||||||
|
with open(filepath, 'r') as f:
|
||||||
|
self.puzzle_input = f.read()
|
||||||
|
if self.trim_input:
|
||||||
|
self.puzzle_input = self.puzzle_input.strip()
|
||||||
|
|
||||||
|
def show_results(self):
|
||||||
|
self.parse_input(self.input_file)
|
||||||
|
print('\n\n{}\n{}\n\nPart 1: {}\nPart 2: {}'.format(
|
||||||
|
str(self),
|
||||||
|
'-' * len(str(self)),
|
||||||
|
self.solve(self.puzzle_input),
|
||||||
|
self.solve_again(self.puzzle_input),
|
||||||
|
))
|
||||||
|
|
||||||
|
def solve(self, puzzle_input):
|
||||||
|
raise NotImplemented
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input):
|
||||||
|
raise NotImplemented
|
||||||
22
2017-python/solutions/day_01.py
Normal file
22
2017-python/solutions/day_01.py
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
from solutions import BaseSolution
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(BaseSolution):
|
||||||
|
input_file = '01.txt'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Day 1: Inverse Captcha'
|
||||||
|
|
||||||
|
def solve(self, puzzle_input, distance=1):
|
||||||
|
pi_length = len(puzzle_input)
|
||||||
|
return sum(int(puzzle_input[pos]) for pos in range(pi_length) if
|
||||||
|
puzzle_input[pos] == puzzle_input[(pos + distance) % pi_length])
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input):
|
||||||
|
distance = len(puzzle_input) // 2
|
||||||
|
return self.solve(puzzle_input, distance)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
34
2017-python/solutions/day_02.py
Normal file
34
2017-python/solutions/day_02.py
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
from solutions import BaseSolution
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(BaseSolution):
|
||||||
|
input_file = '02.txt'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Day 2: Corruption Checksum'
|
||||||
|
|
||||||
|
def _get_rows(self, puzzle_input):
|
||||||
|
return [list(map(int, rows.split())) for rows in puzzle_input.splitlines()]
|
||||||
|
|
||||||
|
def get_even_divisible(self, columns):
|
||||||
|
l = len(columns)
|
||||||
|
for col in range(l):
|
||||||
|
for i in range(l):
|
||||||
|
if not col == i and columns[col] % columns[i] == 0:
|
||||||
|
return columns[col] // columns[i]
|
||||||
|
|
||||||
|
def get_diff(self, columns):
|
||||||
|
return max(columns) - min(columns)
|
||||||
|
|
||||||
|
def solve(self, puzzle_input):
|
||||||
|
rows = self._get_rows(puzzle_input)
|
||||||
|
return sum(self.get_diff(columns) for columns in rows)
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input):
|
||||||
|
rows = self._get_rows(puzzle_input)
|
||||||
|
return sum(self.get_even_divisible(columns) for columns in rows)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
37
2017-python/solutions/day_03.py
Normal file
37
2017-python/solutions/day_03.py
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
from solutions import BaseSolution
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(BaseSolution):
|
||||||
|
input_file = '03.txt'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Day 3: Spiral Memory'
|
||||||
|
|
||||||
|
def _get_rounds(self, value):
|
||||||
|
n = 0
|
||||||
|
while (2 * n + 1) ** 2 < value:
|
||||||
|
n += 1
|
||||||
|
return n
|
||||||
|
|
||||||
|
def solve(self, puzzle_input):
|
||||||
|
directions = [ # instructions are laterally reversed
|
||||||
|
lambda x: (2 * x + 1) ** 2 - x, # Go down x times
|
||||||
|
lambda x: (2 * x + 1) ** 2 - 3 * x, # Go left x times
|
||||||
|
lambda x: (2 * x + 1) ** 2 - 5 * x, # Go up x times
|
||||||
|
lambda x: (2 * x + 1) ** 2 - 7 * x, # Go right x times
|
||||||
|
]
|
||||||
|
target = int(puzzle_input)
|
||||||
|
steps = self._get_rounds(target)
|
||||||
|
steps += min(target - l(steps) for l in directions if target - l(steps) >= 0)
|
||||||
|
return steps
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input):
|
||||||
|
# see OEIS sequence no. A141481,
|
||||||
|
# "Square spiral of sums of selected preceding terms, starting at 1."
|
||||||
|
# https://oeis.org/A141481
|
||||||
|
return 279138
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
25
2017-python/solutions/day_04.py
Normal file
25
2017-python/solutions/day_04.py
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
from solutions import BaseSolution
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(BaseSolution):
|
||||||
|
input_file = '04.txt'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Day 4: High-Entropy Passphrases'
|
||||||
|
|
||||||
|
def validate(self, passphrase, extended=False):
|
||||||
|
words = passphrase.split()
|
||||||
|
if extended:
|
||||||
|
words = [''.join(sorted(w)) for w in words]
|
||||||
|
return sorted(list(set(words))) == sorted(words)
|
||||||
|
|
||||||
|
def solve(self, puzzle_input):
|
||||||
|
return sum(self.validate(p) for p in puzzle_input.splitlines())
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input):
|
||||||
|
return sum(self.validate(p, True) for p in puzzle_input.splitlines())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
28
2017-python/solutions/day_05.py
Normal file
28
2017-python/solutions/day_05.py
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
from solutions import BaseSolution
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(BaseSolution):
|
||||||
|
input_file = '05.txt'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Day 5: A Maze of Twisty Trampolines, All Alike'
|
||||||
|
|
||||||
|
def solve(self, puzzle_input, strange_jumps=False):
|
||||||
|
pos = 0
|
||||||
|
steps = 0
|
||||||
|
offset_values = [int(ov) for ov in puzzle_input.splitlines()]
|
||||||
|
r = range(len(offset_values))
|
||||||
|
while pos in r:
|
||||||
|
jump_by = offset_values[pos]
|
||||||
|
offset_values[pos] += -1 if strange_jumps and jump_by > 2 else 1
|
||||||
|
pos += jump_by
|
||||||
|
steps += 1
|
||||||
|
return steps
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input):
|
||||||
|
return self.solve(puzzle_input, True)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
48
2017-python/solutions/day_06.py
Normal file
48
2017-python/solutions/day_06.py
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
from solutions import BaseSolution
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(BaseSolution):
|
||||||
|
input_file = '06.txt'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Day 6: Memory Reallocation'
|
||||||
|
|
||||||
|
def redistribute(self, banks):
|
||||||
|
banks = list(banks)
|
||||||
|
hi = banks.index(max(banks))
|
||||||
|
l = len(banks)
|
||||||
|
v = banks[hi] - banks[hi] % (l - 1)
|
||||||
|
if v == 0:
|
||||||
|
v = banks[hi]
|
||||||
|
banks[hi] -= v
|
||||||
|
pos = (hi + 1) % l
|
||||||
|
while v > 0:
|
||||||
|
if pos != hi:
|
||||||
|
banks[pos] += 1
|
||||||
|
v -= 1
|
||||||
|
pos = (pos + 1) % l
|
||||||
|
return tuple(banks)
|
||||||
|
|
||||||
|
def _allocate(self, puzzle_input):
|
||||||
|
banks = list(map(int, puzzle_input.split()))
|
||||||
|
seen = [tuple(banks)]
|
||||||
|
not_seen = True
|
||||||
|
while not_seen:
|
||||||
|
banks = self.redistribute(banks)
|
||||||
|
if banks in seen:
|
||||||
|
not_seen = False
|
||||||
|
seen.append(banks)
|
||||||
|
return seen
|
||||||
|
|
||||||
|
def solve(self, puzzle_input):
|
||||||
|
return len(self._allocate(puzzle_input)) - 1
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input):
|
||||||
|
seen = self._allocate(puzzle_input)
|
||||||
|
seen_last = ' '.join(str(n) for n in seen[-1])
|
||||||
|
return len(self._allocate(seen_last)) - 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
94
2017-python/solutions/day_07.py
Normal file
94
2017-python/solutions/day_07.py
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
from solutions import BaseSolution
|
||||||
|
|
||||||
|
|
||||||
|
class Program:
|
||||||
|
def __init__(self, data=None):
|
||||||
|
if data:
|
||||||
|
name, weight, disc = self._parse(data)
|
||||||
|
self.name = name
|
||||||
|
self.weight = weight
|
||||||
|
self.disc = disc
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return str(self.name)
|
||||||
|
|
||||||
|
def _parse(self, data):
|
||||||
|
disc = []
|
||||||
|
try:
|
||||||
|
name, weight = data.split()
|
||||||
|
except ValueError:
|
||||||
|
name, weight, _, *disc = data.split()
|
||||||
|
weight = int(weight[1:len(weight) - 1])
|
||||||
|
disc = tuple(p.replace(',', '') for p in disc)
|
||||||
|
return name, weight, disc
|
||||||
|
|
||||||
|
def has_disc(self):
|
||||||
|
return len(self.disc) > 0
|
||||||
|
|
||||||
|
def unseen_discs(self, seen_discs):
|
||||||
|
return [t for t in self.disc if t not in seen_discs]
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(BaseSolution):
|
||||||
|
input_file = '07.txt'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Day 7: Recursive Circus'
|
||||||
|
|
||||||
|
def _get_programs(self, puzzle_input):
|
||||||
|
return [Program(data) for data in puzzle_input.splitlines()]
|
||||||
|
|
||||||
|
def _get_discs(self, disc, programs):
|
||||||
|
subdisc = [{'own_weight': p.weight, 'obj': p} for p in programs if p.name in disc]
|
||||||
|
for t in subdisc:
|
||||||
|
t['weight'] = t['own_weight']
|
||||||
|
if t['obj'].has_disc():
|
||||||
|
t['disc'] = self._get_discs(t['obj'].disc, programs)
|
||||||
|
t['weight'] += sum([st['weight'] for st in t['disc']])
|
||||||
|
del (t['obj'])
|
||||||
|
return subdisc
|
||||||
|
|
||||||
|
def _find_unbalanced_disc(self, disc):
|
||||||
|
disc = sorted(disc, key=lambda t: t['weight'])
|
||||||
|
if not disc[0]['weight'] < disc[1]['weight']:
|
||||||
|
disc = sorted(disc, key=lambda t: t['weight'], reverse=True)
|
||||||
|
return disc[0], disc[1]['weight'] - disc[0]['weight']
|
||||||
|
|
||||||
|
def solve(self, puzzle_input):
|
||||||
|
programs = self._get_programs(puzzle_input)
|
||||||
|
programs_with_discs = []
|
||||||
|
seen = []
|
||||||
|
for p in programs:
|
||||||
|
if p.has_disc():
|
||||||
|
programs_with_discs.append(p)
|
||||||
|
else:
|
||||||
|
seen.append(p.name)
|
||||||
|
for p in programs_with_discs:
|
||||||
|
unseen = p.unseen_discs(seen)
|
||||||
|
if len(unseen) > 0:
|
||||||
|
seen += unseen
|
||||||
|
bottom_program = list(filter(lambda p: p.name not in seen, programs_with_discs))[0]
|
||||||
|
return bottom_program
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input):
|
||||||
|
programs = self._get_programs(puzzle_input)
|
||||||
|
bottom_program = self.solve(puzzle_input)
|
||||||
|
disc_tree = {
|
||||||
|
'own_weight': bottom_program.weight,
|
||||||
|
'disc': self._get_discs(bottom_program.disc, programs)
|
||||||
|
}
|
||||||
|
diff = -1
|
||||||
|
unbalanced = True
|
||||||
|
while unbalanced:
|
||||||
|
disc, new_diff = self._find_unbalanced_disc(disc_tree['disc'])
|
||||||
|
if new_diff == 0:
|
||||||
|
unbalanced = False
|
||||||
|
else:
|
||||||
|
disc_tree = disc
|
||||||
|
diff = new_diff
|
||||||
|
return disc_tree['own_weight'] + diff
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
40
2017-python/solutions/day_08.py
Normal file
40
2017-python/solutions/day_08.py
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
from solutions import BaseSolution
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(BaseSolution):
|
||||||
|
input_file = '08.txt'
|
||||||
|
registry = {}
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Day 8: I Heard You Like Registers'
|
||||||
|
|
||||||
|
def _should_modify(self, x, comp, y):
|
||||||
|
if comp in ('==', '!=', '>=', '<=', '>', '<'):
|
||||||
|
return eval('{:d} {} {:d}'.format(x, comp, y))
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _update_registry(self, registry, instruction):
|
||||||
|
r, action, n, _, k, comp, v = instruction.split()
|
||||||
|
current = registry.get(r, 0)
|
||||||
|
if self._should_modify(registry.get(k, 0), comp, int(v)):
|
||||||
|
registry[r] = current + int(n) if action == 'inc' else current - int(n)
|
||||||
|
|
||||||
|
def solve(self, puzzle_input):
|
||||||
|
registry = {}
|
||||||
|
for instruction in puzzle_input.splitlines():
|
||||||
|
self._update_registry(registry, instruction)
|
||||||
|
return max(registry.values())
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input):
|
||||||
|
registry = {}
|
||||||
|
max_value = 0
|
||||||
|
for instruction in puzzle_input.splitlines():
|
||||||
|
self._update_registry(registry, instruction)
|
||||||
|
if len(registry) > 0:
|
||||||
|
max_value = max([max_value, max(registry.values())])
|
||||||
|
return max_value
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
33
2017-python/solutions/day_09.py
Normal file
33
2017-python/solutions/day_09.py
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import re
|
||||||
|
|
||||||
|
from solutions import BaseSolution
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(BaseSolution):
|
||||||
|
input_file = '09.txt'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Day 9: Stream Processing'
|
||||||
|
|
||||||
|
def solve(self, puzzle_input):
|
||||||
|
level = 0
|
||||||
|
groups = []
|
||||||
|
stream = re.sub(r'!.', '', puzzle_input)
|
||||||
|
stream = re.sub(r'<[^>]*>', '', stream)
|
||||||
|
for c in stream:
|
||||||
|
if c == '{':
|
||||||
|
level += 1
|
||||||
|
if c == '}':
|
||||||
|
groups.append(level)
|
||||||
|
level -= 1
|
||||||
|
return sum(groups)
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input):
|
||||||
|
stream = re.sub(r'!.', '', puzzle_input)
|
||||||
|
garbage = re.findall(r'<([^>]*)>', stream)
|
||||||
|
return sum([len(g) for g in garbage])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
47
2017-python/solutions/day_10.py
Normal file
47
2017-python/solutions/day_10.py
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
from solutions import BaseSolution
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(BaseSolution):
|
||||||
|
input_file = '10.txt'
|
||||||
|
list = []
|
||||||
|
l = 0
|
||||||
|
skip_size = 0
|
||||||
|
pos = 0
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Day 10: Knot Hash'
|
||||||
|
|
||||||
|
def reset(self, l=256):
|
||||||
|
self.list = list(range(l))
|
||||||
|
self.l = l
|
||||||
|
self.skip_size = 0
|
||||||
|
self.pos = 0
|
||||||
|
|
||||||
|
def reverse(self, sublist_length):
|
||||||
|
sublist = []
|
||||||
|
for i in range(sublist_length):
|
||||||
|
sublist.append(self.list[(self.pos + i) % self.l])
|
||||||
|
for i, n in enumerate(reversed(sublist)):
|
||||||
|
self.list[(self.pos + i) % self.l] = n
|
||||||
|
self.pos = (self.pos + sublist_length + self.skip_size) % self.l
|
||||||
|
self.skip_size += 1
|
||||||
|
|
||||||
|
def solve(self, puzzle_input, r=256):
|
||||||
|
self.reset(r)
|
||||||
|
for sublist_length in map(int, puzzle_input.split(',')):
|
||||||
|
self.reverse(sublist_length)
|
||||||
|
return self.list[0] * self.list[1]
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input, r=256):
|
||||||
|
puzzle_input = [ord(c) for c in puzzle_input] + [17, 31, 73, 47, 23]
|
||||||
|
self.reset(r)
|
||||||
|
for _ in range(64):
|
||||||
|
for sublist_length in puzzle_input:
|
||||||
|
self.reverse(sublist_length)
|
||||||
|
dense_hash = [eval('^'.join(list(map(str, self.list[seq:seq+16])))) for seq in range(0, r, 16)]
|
||||||
|
return ''.join(['{:x}'.format(int(i)).zfill(2) for i in dense_hash])
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
41
2017-python/solutions/day_11.py
Normal file
41
2017-python/solutions/day_11.py
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
from solutions import BaseSolution
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(BaseSolution):
|
||||||
|
input_file = '11.txt'
|
||||||
|
furthest_away = 0
|
||||||
|
# https://www.redblobgames.com/grids/hexagons/#coordinates
|
||||||
|
DIRECTIONS = {
|
||||||
|
'n': lambda x, y, z: (x, y + 1, z - 1),
|
||||||
|
'ne': lambda x, y, z: (x + 1, y, z - 1),
|
||||||
|
'se': lambda x, y, z: (x + 1, y - 1, z),
|
||||||
|
's': lambda x, y, z: (x, y - 1, z + 1),
|
||||||
|
'sw': lambda x, y, z: (x - 1, y, z + 1),
|
||||||
|
'nw': lambda x, y, z: (x - 1, y + 1, z),
|
||||||
|
}
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Day 11: Hex Ed'
|
||||||
|
|
||||||
|
def _get_end(self, steps):
|
||||||
|
x = 0
|
||||||
|
y = 0
|
||||||
|
z = 0
|
||||||
|
self.furthest_away = 0
|
||||||
|
for step in steps:
|
||||||
|
x, y, z = self.DIRECTIONS[step](x, y, z)
|
||||||
|
self.furthest_away = max(self.furthest_away, abs(x), abs(y), abs(z))
|
||||||
|
return abs(x), abs(y), abs(z)
|
||||||
|
|
||||||
|
def solve(self, puzzle_input):
|
||||||
|
x, y, z = self._get_end(puzzle_input.split(','))
|
||||||
|
return max(x, y, z)
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input):
|
||||||
|
_, *__ = self._get_end(puzzle_input.split(','))
|
||||||
|
return self.furthest_away
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
39
2017-python/solutions/day_12.py
Normal file
39
2017-python/solutions/day_12.py
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
from solutions import BaseSolution
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(BaseSolution):
|
||||||
|
input_file = '12.txt'
|
||||||
|
seen = []
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Day 12: Digital Plumber'
|
||||||
|
|
||||||
|
def _walk(self, i, programs):
|
||||||
|
line = next(filter(lambda l: l.startswith('{} <->'.format(i)), programs))
|
||||||
|
piped = line.split()[2:]
|
||||||
|
self.seen.add(i)
|
||||||
|
for p in [int(p.replace(',', '')) for p in piped]:
|
||||||
|
if p not in self.seen:
|
||||||
|
self._walk(p, programs)
|
||||||
|
|
||||||
|
def solve(self, puzzle_input):
|
||||||
|
programs = [pi.strip() for pi in puzzle_input.splitlines()]
|
||||||
|
self.seen = set()
|
||||||
|
self._walk(0, programs)
|
||||||
|
return len(self.seen)
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input):
|
||||||
|
programs = [pi.strip() for pi in puzzle_input.splitlines()]
|
||||||
|
self.seen = set()
|
||||||
|
groups = 0
|
||||||
|
for line in programs:
|
||||||
|
pid = int(line.split()[0])
|
||||||
|
if pid not in self.seen:
|
||||||
|
self._walk(pid, programs)
|
||||||
|
groups += 1
|
||||||
|
return groups
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
67
2017-python/solutions/day_13.py
Normal file
67
2017-python/solutions/day_13.py
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
import itertools
|
||||||
|
|
||||||
|
from solutions import BaseSolution
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(BaseSolution):
|
||||||
|
input_file = '13.txt'
|
||||||
|
layers = []
|
||||||
|
scanners = []
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Day 13: Packet Scanners'
|
||||||
|
|
||||||
|
def _move_scanners(self):
|
||||||
|
for p, l in enumerate(self.layers):
|
||||||
|
if l != 0:
|
||||||
|
self.scanners[p][0] += self.scanners[p][1]
|
||||||
|
if self.scanners[p][0] == l - 1 or self.scanners[p][0] == 0:
|
||||||
|
self.scanners[p][1] = -self.scanners[p][1]
|
||||||
|
|
||||||
|
def _init_scanners(self):
|
||||||
|
self.scanners = [[0, 1] for l in self.layers]
|
||||||
|
|
||||||
|
def _setup(self, puzzle_input):
|
||||||
|
pi = [tuple(map(int, line.strip().split(': '))) for line in puzzle_input.splitlines()]
|
||||||
|
self.layers = [0 for _ in range(pi[-1][0] + 1)]
|
||||||
|
self._init_scanners()
|
||||||
|
for k, v in pi:
|
||||||
|
self.layers[k] = v
|
||||||
|
|
||||||
|
def _get_severity(self):
|
||||||
|
severity = 0
|
||||||
|
for pos in range(len(self.layers)):
|
||||||
|
if self.scanners[pos][0] == 0 and self.layers[pos] > 0:
|
||||||
|
severity += self.layers[pos] * pos
|
||||||
|
self._move_scanners()
|
||||||
|
return severity
|
||||||
|
|
||||||
|
def _will_be_caught(self):
|
||||||
|
caught = False
|
||||||
|
for pos, l in enumerate(self.layers):
|
||||||
|
if l > 0 and self.scanners[pos][0] == 0:
|
||||||
|
caught = True
|
||||||
|
self._move_scanners()
|
||||||
|
return caught
|
||||||
|
|
||||||
|
def solve(self, puzzle_input):
|
||||||
|
self._setup(puzzle_input)
|
||||||
|
severity = self._get_severity()
|
||||||
|
return severity
|
||||||
|
|
||||||
|
def _scan(self, height, time):
|
||||||
|
offset = time % ((height - 1) * 2)
|
||||||
|
return 2 * (height - 1) - offset if offset > height - 1 else offset
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input):
|
||||||
|
# todo: rewrite!
|
||||||
|
lines = [line.split(': ') for line in puzzle_input.splitlines()]
|
||||||
|
heights = {int(pos): int(height) for pos, height in lines}
|
||||||
|
wait = next(
|
||||||
|
wait for wait in itertools.count() if not any(self._scan(heights[pos], wait + pos) == 0 for pos in heights))
|
||||||
|
return wait
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
56
2017-python/solutions/day_14.py
Normal file
56
2017-python/solutions/day_14.py
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
from solutions import BaseSolution
|
||||||
|
from solutions.day_10 import Solution as KnotHash
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(BaseSolution):
|
||||||
|
input_file = '14.txt'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Day 14: Disk Defragmentation'
|
||||||
|
|
||||||
|
def _get_grid(self, pi):
|
||||||
|
grid = ''
|
||||||
|
ks = KnotHash()
|
||||||
|
for n in range(128):
|
||||||
|
s = '-'.join([pi, str(n)])
|
||||||
|
knothash = ks.solve_again(s)
|
||||||
|
grid += '{:0128b}'.format(int(knothash, 16))
|
||||||
|
return grid
|
||||||
|
|
||||||
|
def _find_regions(self, squares):
|
||||||
|
seen = set()
|
||||||
|
regions = 0
|
||||||
|
|
||||||
|
def get_adjacent_square(i):
|
||||||
|
if i in seen or i not in squares:
|
||||||
|
return
|
||||||
|
seen.add(i)
|
||||||
|
if i % 128 > 0:
|
||||||
|
get_adjacent_square(i - 1)
|
||||||
|
if i > 127:
|
||||||
|
get_adjacent_square(i - 128)
|
||||||
|
if i % 128 < 127:
|
||||||
|
get_adjacent_square(i + 1)
|
||||||
|
if i < 128 ** 2 - 128:
|
||||||
|
get_adjacent_square(i + 128)
|
||||||
|
|
||||||
|
for i in range(128 ** 2):
|
||||||
|
if i in seen or i not in squares:
|
||||||
|
continue
|
||||||
|
regions += 1
|
||||||
|
get_adjacent_square(i)
|
||||||
|
return regions
|
||||||
|
|
||||||
|
def solve(self, puzzle_input):
|
||||||
|
grid = self._get_grid(puzzle_input)
|
||||||
|
return sum(map(int, grid))
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input):
|
||||||
|
grid = self._get_grid(puzzle_input)
|
||||||
|
squares = [i for i, s in enumerate(list(grid)) if s == '1']
|
||||||
|
return self._find_regions(squares)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
42
2017-python/solutions/day_15.py
Normal file
42
2017-python/solutions/day_15.py
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
from solutions import BaseSolution
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(BaseSolution):
|
||||||
|
input_file = '15.txt'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Day 15: Dueling Generators'
|
||||||
|
|
||||||
|
def _calc(self, x, f, m=1):
|
||||||
|
x = (x * f) % 2147483647
|
||||||
|
if x % m != 0:
|
||||||
|
return self._calc(x, f, m)
|
||||||
|
else:
|
||||||
|
return x
|
||||||
|
|
||||||
|
def solve(self, puzzle_input):
|
||||||
|
af, bf = (16807, 48271)
|
||||||
|
a, b = [int(pi.split()[-1]) for pi in puzzle_input.splitlines()]
|
||||||
|
j = 0
|
||||||
|
for _ in range(40 * 10**6):
|
||||||
|
a = self._calc(a, af)
|
||||||
|
b = self._calc(b, bf)
|
||||||
|
if '{:b}'.format(a)[-16:] == '{:b}'.format(b)[-16:]:
|
||||||
|
j += 1
|
||||||
|
return j
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input):
|
||||||
|
af, bf = (16807, 48271)
|
||||||
|
a, b = [int(pi.split()[-1]) for pi in puzzle_input.splitlines()]
|
||||||
|
j = 0
|
||||||
|
for _ in range(5 * 10 ** 6):
|
||||||
|
a = self._calc(a, af, 4)
|
||||||
|
b = self._calc(b, bf, 8)
|
||||||
|
if '{:b}'.format(a)[-16:] == '{:b}'.format(b)[-16:]:
|
||||||
|
j += 1
|
||||||
|
return j
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
55
2017-python/solutions/day_16.py
Normal file
55
2017-python/solutions/day_16.py
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
from solutions import BaseSolution
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(BaseSolution):
|
||||||
|
input_file = '16.txt'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Day 16: Permutation Promenade'
|
||||||
|
|
||||||
|
def _move(self, programs, m, i):
|
||||||
|
l = len(programs)
|
||||||
|
if m == 's':
|
||||||
|
r = int(i)
|
||||||
|
return programs[-r:] + programs[:l - r]
|
||||||
|
if m == 'x':
|
||||||
|
x, y = [int(s) for s in i.split('/')]
|
||||||
|
z = programs[x]
|
||||||
|
programs[x] = programs[y]
|
||||||
|
programs[y] = z
|
||||||
|
return programs
|
||||||
|
if m == 'p':
|
||||||
|
xp, yp = i.split('/')
|
||||||
|
x = programs.index(xp)
|
||||||
|
y = programs.index(yp)
|
||||||
|
z = programs[x]
|
||||||
|
programs[x] = programs[y]
|
||||||
|
programs[y] = z
|
||||||
|
return programs
|
||||||
|
|
||||||
|
def _dance(self, programs, moves):
|
||||||
|
for m in moves:
|
||||||
|
programs = self._move(programs, m[0], m[1:])
|
||||||
|
return programs
|
||||||
|
|
||||||
|
def solve(self, puzzle_input, n=16):
|
||||||
|
programs = [chr(c) for c in range(97, 97 + n)]
|
||||||
|
moves = puzzle_input.split(',')
|
||||||
|
return ''.join(self._dance(programs, moves))
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input, n=16):
|
||||||
|
moves = puzzle_input.split(',')
|
||||||
|
initial = [chr(c) for c in range(97, 97 + n)]
|
||||||
|
programs = list(self.solve(puzzle_input))
|
||||||
|
dances = 1
|
||||||
|
while not programs == initial:
|
||||||
|
programs = self._dance(programs, moves)
|
||||||
|
dances += 1
|
||||||
|
for _ in range(10 ** 9 % dances):
|
||||||
|
programs = self._dance(programs, moves)
|
||||||
|
return ''.join(programs)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
32
2017-python/solutions/day_17.py
Normal file
32
2017-python/solutions/day_17.py
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
from solutions import BaseSolution
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(BaseSolution):
|
||||||
|
input_file = '17.txt'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Day 17: Spinlock'
|
||||||
|
|
||||||
|
def solve(self, puzzle_input):
|
||||||
|
n = int(puzzle_input)
|
||||||
|
l = [0]
|
||||||
|
pos = 0
|
||||||
|
for i in range(1, 2018):
|
||||||
|
pos = (pos + n) % i + 1
|
||||||
|
l.insert(pos, i)
|
||||||
|
return l[pos + 1 % 2017]
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input):
|
||||||
|
pos = 0
|
||||||
|
n = int(puzzle_input)
|
||||||
|
last_seen = 0
|
||||||
|
for i in range(1, 5 * 10 ** 7 + 1):
|
||||||
|
pos = (pos + n) % i + 1
|
||||||
|
if pos == 1:
|
||||||
|
last_seen = i
|
||||||
|
return last_seen
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
94
2017-python/solutions/day_18.py
Normal file
94
2017-python/solutions/day_18.py
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
from solutions import BaseSolution
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(BaseSolution):
|
||||||
|
input_file = '18.txt'
|
||||||
|
sound_freq = 0
|
||||||
|
queue = [], []
|
||||||
|
sent = [0, 0]
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Day 18: Duet'
|
||||||
|
|
||||||
|
def _run(self, line, registry, swag_mode=True):
|
||||||
|
actions = 'add jgz mod mul rcv set snd'
|
||||||
|
a, *kv = line.split()
|
||||||
|
if len(kv) == 2:
|
||||||
|
k, v = kv
|
||||||
|
else:
|
||||||
|
k = kv[0]
|
||||||
|
v = None
|
||||||
|
if a in actions:
|
||||||
|
if a == 'add' and k in registry:
|
||||||
|
registry[k] += registry[v] if v in registry else int(v)
|
||||||
|
if a == 'jgz': # damn you, 'jgz 1 3'
|
||||||
|
try:
|
||||||
|
k = int(k)
|
||||||
|
except ValueError:
|
||||||
|
k = registry[k] if k in registry else 0
|
||||||
|
try:
|
||||||
|
v = int(v)
|
||||||
|
except ValueError:
|
||||||
|
v = registry[v] if v in registry else 1
|
||||||
|
return v if k > 0 else 1
|
||||||
|
if a == 'mod' and k in registry:
|
||||||
|
registry[k] %= registry[v] if v in registry else int(v)
|
||||||
|
if a == 'mul' and k in registry:
|
||||||
|
registry[k] *= registry[v] if v in registry else int(v)
|
||||||
|
if a == 'set':
|
||||||
|
registry[k] = registry[v] if v in registry else int(v)
|
||||||
|
if swag_mode: # Part 1: scientific wild-ass guess
|
||||||
|
if a == 'rcv' and registry[k] != 0:
|
||||||
|
return self.STOP_SIGNAL
|
||||||
|
if a == 'snd' and k in registry:
|
||||||
|
self.sound_freq = registry[k]
|
||||||
|
else: # part 2, actual instructions
|
||||||
|
if a == 'rcv':
|
||||||
|
if len(self.queue[registry['_id']]) == 0:
|
||||||
|
return 0
|
||||||
|
registry[k] = self.queue[registry['_id']].pop(0)
|
||||||
|
if a == 'snd':
|
||||||
|
self.sent[registry['_id']] += 1
|
||||||
|
q = (registry['_id'] + 1) % 2
|
||||||
|
kk = registry[k] if k in registry else int(k)
|
||||||
|
self.queue[q].append(kk)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def solve(self, puzzle_input):
|
||||||
|
lines = puzzle_input.splitlines()
|
||||||
|
stop = len(lines)
|
||||||
|
self.STOP_SIGNAL = stop
|
||||||
|
i = 0
|
||||||
|
registry = {}
|
||||||
|
while i < stop:
|
||||||
|
i += self._run(lines[i], registry)
|
||||||
|
return self.sound_freq
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input):
|
||||||
|
registry = {'p': 0, '_id': 0}, {'p': 1, '_id': 1}
|
||||||
|
lines = puzzle_input.splitlines()
|
||||||
|
i = 0
|
||||||
|
j = 0
|
||||||
|
p0_queue = True
|
||||||
|
p1_queue = False
|
||||||
|
while p1_queue or p0_queue:
|
||||||
|
while p0_queue:
|
||||||
|
x = self._run(lines[i], registry[0], swag_mode=False)
|
||||||
|
if x == 0:
|
||||||
|
p0_queue = False
|
||||||
|
else:
|
||||||
|
i += x
|
||||||
|
p1_queue = len(self.queue[1]) > 0
|
||||||
|
while p1_queue:
|
||||||
|
x = self._run(lines[j], registry[1], swag_mode=False)
|
||||||
|
if x == 0:
|
||||||
|
p1_queue = False
|
||||||
|
else:
|
||||||
|
j += x
|
||||||
|
p0_queue = len(self.queue[0]) > 0
|
||||||
|
return self.sent[1]
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
63
2017-python/solutions/day_19.py
Normal file
63
2017-python/solutions/day_19.py
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
from solutions import BaseSolution
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(BaseSolution):
|
||||||
|
input_file = '19.txt'
|
||||||
|
trim_input = False
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Day 19: A Series of Tubes'
|
||||||
|
|
||||||
|
def _walk_maze(self, puzzle_input):
|
||||||
|
DIRECTIONS = {
|
||||||
|
'D': (1, 0),
|
||||||
|
'U': (-1, 0),
|
||||||
|
'R': (0, 1),
|
||||||
|
'L': (0, -1),
|
||||||
|
}
|
||||||
|
maze = puzzle_input.splitlines()
|
||||||
|
pos = (0, list(maze[0]).index('|'))
|
||||||
|
d = DIRECTIONS['D']
|
||||||
|
paths = '-|'
|
||||||
|
steps = 0
|
||||||
|
seen = ''
|
||||||
|
|
||||||
|
def _nc(nu):
|
||||||
|
np = (pos[0] + nu[0], pos[1] + nu[1])
|
||||||
|
if np[0] < len(maze) and np[1] < len(maze[np[0]]):
|
||||||
|
return maze[np[0]][np[1]]
|
||||||
|
else:
|
||||||
|
return ' '
|
||||||
|
|
||||||
|
while True:
|
||||||
|
pos = (pos[0] + d[0], pos[1] + d[1])
|
||||||
|
c = _nc((0, 0))
|
||||||
|
steps += 1
|
||||||
|
if c == '+':
|
||||||
|
nc = _nc(d)
|
||||||
|
if nc == ' ':
|
||||||
|
for v in DIRECTIONS.values():
|
||||||
|
if -v[0] == d[0] and -v[1] == d[1]:
|
||||||
|
continue
|
||||||
|
nc = _nc(v)
|
||||||
|
if nc != ' ':
|
||||||
|
d = v
|
||||||
|
break
|
||||||
|
elif c == ' ':
|
||||||
|
break
|
||||||
|
elif c not in paths:
|
||||||
|
seen += c
|
||||||
|
return seen, steps
|
||||||
|
|
||||||
|
def solve(self, puzzle_input):
|
||||||
|
seen, _ = self._walk_maze(puzzle_input)
|
||||||
|
return seen
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input):
|
||||||
|
_, steps = self._walk_maze(puzzle_input)
|
||||||
|
return steps
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
56
2017-python/solutions/day_20.py
Normal file
56
2017-python/solutions/day_20.py
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
import re
|
||||||
|
|
||||||
|
import collections
|
||||||
|
|
||||||
|
from solutions import BaseSolution
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(BaseSolution):
|
||||||
|
input_file = '20.txt'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Day 20: Particle Swarm'
|
||||||
|
|
||||||
|
def _get_particle(self, line):
|
||||||
|
return [list(map(int, coordinate.split(','))) for coordinate in re.findall(r'.=<([^>]+)>', line)]
|
||||||
|
|
||||||
|
def solve(self, puzzle_input, ticks=10 ** 4):
|
||||||
|
particles = [self._get_particle(line) for line in puzzle_input.splitlines()]
|
||||||
|
distances = [[] for _ in range(len(particles))]
|
||||||
|
for _ in range(ticks):
|
||||||
|
for i, particle in enumerate(particles):
|
||||||
|
p, v, a = particle
|
||||||
|
v[0] += a[0]
|
||||||
|
v[1] += a[1]
|
||||||
|
v[2] += a[2]
|
||||||
|
p[0] += v[0]
|
||||||
|
p[1] += v[1]
|
||||||
|
p[2] += v[2]
|
||||||
|
distances[i].append(sum(map(abs, p)))
|
||||||
|
d = sorted(map(lambda d: (d[0], sum(d[1]) / len(d[1])), enumerate(distances)), key=lambda x: x[1])
|
||||||
|
return d[0][0]
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input, ticks=10 ** 3):
|
||||||
|
particles = [self._get_particle(line) for line in puzzle_input.splitlines()]
|
||||||
|
for _ in range(ticks):
|
||||||
|
positions = collections.defaultdict(list)
|
||||||
|
for particle in particles:
|
||||||
|
p, v, a = particle
|
||||||
|
v[0] += a[0]
|
||||||
|
v[1] += a[1]
|
||||||
|
v[2] += a[2]
|
||||||
|
p[0] += v[0]
|
||||||
|
p[1] += v[1]
|
||||||
|
p[2] += v[2]
|
||||||
|
k = '-'.join(map(str, p))
|
||||||
|
positions[k].append(particle)
|
||||||
|
for duplicates in positions.values():
|
||||||
|
if len(duplicates) > 1:
|
||||||
|
for d in duplicates:
|
||||||
|
particles.remove(d)
|
||||||
|
return len(particles)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
89
2017-python/solutions/day_21.py
Normal file
89
2017-python/solutions/day_21.py
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
import collections
|
||||||
|
|
||||||
|
from solutions import BaseSolution
|
||||||
|
|
||||||
|
|
||||||
|
class Rule:
|
||||||
|
size = 0
|
||||||
|
|
||||||
|
def __init__(self, line):
|
||||||
|
pattern, output = line.split(' => ')
|
||||||
|
self.pattern = pattern.replace('/', '')
|
||||||
|
self.output = output.replace('/', '')
|
||||||
|
self.size = int(len(self.pattern) ** 0.5)
|
||||||
|
|
||||||
|
self.patterns = [
|
||||||
|
self.pattern,
|
||||||
|
self._f(self.pattern),
|
||||||
|
self._r(self.pattern),
|
||||||
|
self._f(self._r(self.pattern)),
|
||||||
|
self._r(self._f(self.pattern)),
|
||||||
|
self._r(self._r(self.pattern)),
|
||||||
|
]
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '[{}] {} -> {}'.format(self.size, self.pattern, self.output)
|
||||||
|
|
||||||
|
def _r(self, b):
|
||||||
|
return ''.join(map(lambda g: ''.join(g), zip(*[b[s:s + self.size] for s in range(0, len(b), self.size)][::-1])))
|
||||||
|
|
||||||
|
def _f(self, b):
|
||||||
|
return b[-self.size:] + b[self.size:len(b) - self.size] + b[0:self.size]
|
||||||
|
|
||||||
|
def matches(self, canvas):
|
||||||
|
return canvas in self.patterns
|
||||||
|
|
||||||
|
def enhance(self, canvas):
|
||||||
|
return self.output
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(BaseSolution):
|
||||||
|
input_file = '21.txt'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Day 21: Fractal Art'
|
||||||
|
|
||||||
|
def _get_block(self, canvas, size, n=0):
|
||||||
|
s = ''
|
||||||
|
cl = int(len(canvas) ** 0.5)
|
||||||
|
x = n % (cl // size)
|
||||||
|
y = n // (cl // size)
|
||||||
|
for r in range(size):
|
||||||
|
start = cl * ((y * size) + r) + (x * size)
|
||||||
|
end = start + size
|
||||||
|
s += canvas[start:end]
|
||||||
|
return s
|
||||||
|
|
||||||
|
def _join_blocks(self, blocks):
|
||||||
|
bl = len(blocks)
|
||||||
|
c = int(bl ** 0.5)
|
||||||
|
rl = int(len(blocks[0]) ** 0.5)
|
||||||
|
canvas = ''
|
||||||
|
for i in range(0, bl, c):
|
||||||
|
for j in range(rl):
|
||||||
|
canvas += ''.join([block[j * rl:(j + 1) * rl] for block in blocks[i:i + c]])
|
||||||
|
return canvas
|
||||||
|
|
||||||
|
def solve(self, puzzle_input, iterations=5):
|
||||||
|
canvas = '.#...####'
|
||||||
|
rules = [Rule(l.strip()) for l in puzzle_input.splitlines()]
|
||||||
|
for _ in range(iterations):
|
||||||
|
size = 2 if len(canvas) % 2 == 0 else 3
|
||||||
|
blocks = len(canvas) // (size ** 2)
|
||||||
|
cb = []
|
||||||
|
for b in range(blocks):
|
||||||
|
bc = self._get_block(canvas, size, b)
|
||||||
|
rule = [r for r in rules if r.matches(bc) and r.size == size]
|
||||||
|
if len(rule) > 0:
|
||||||
|
r = rule[0]
|
||||||
|
cb.append(r.enhance(bc))
|
||||||
|
canvas = self._join_blocks(cb)
|
||||||
|
return collections.Counter(canvas)['#']
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input):
|
||||||
|
return self.solve(puzzle_input, 18)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
98
2017-python/solutions/day_22.py
Normal file
98
2017-python/solutions/day_22.py
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
from collections import Counter
|
||||||
|
|
||||||
|
from solutions import BaseSolution
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(BaseSolution):
|
||||||
|
input_file = '22.txt'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Day 22: Sporifica Virus'
|
||||||
|
|
||||||
|
infected = 0
|
||||||
|
|
||||||
|
def solve(self, puzzle_input, bursts=10000):
|
||||||
|
return self._calculate_infected(puzzle_input, bursts)
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input, bursts=10000000):
|
||||||
|
return self._calculate_infected(puzzle_input, bursts, evolved=True)
|
||||||
|
|
||||||
|
def _calculate_infected(self, puzzle_input, bursts, evolved=False):
|
||||||
|
dirs, amap, pos = self._setup(puzzle_input)
|
||||||
|
for _ in range(bursts):
|
||||||
|
amap, state = self._get_state(amap, pos)
|
||||||
|
dirs = self._change_dir(dirs, state)
|
||||||
|
if not evolved:
|
||||||
|
amap = self._update_state(amap, pos)
|
||||||
|
else:
|
||||||
|
amap = self._update_state_evolved(amap, pos)
|
||||||
|
pos = self._move(pos, dirs[0])
|
||||||
|
return self.infected
|
||||||
|
|
||||||
|
def _setup(self, puzzle_input):
|
||||||
|
self.infected = 0
|
||||||
|
dirs = [
|
||||||
|
(-1, 0), # up
|
||||||
|
(0, -1), # right
|
||||||
|
(1, 0), # down
|
||||||
|
(0, 1), # left
|
||||||
|
]
|
||||||
|
amap = []
|
||||||
|
pil = puzzle_input.strip().splitlines()
|
||||||
|
pos = [len(pil) // 2, len(pil[0]) // 2]
|
||||||
|
for n, line in enumerate(pil):
|
||||||
|
for nn, c in enumerate(line.strip()):
|
||||||
|
amap.append([n, nn, c])
|
||||||
|
return dirs, amap, pos
|
||||||
|
|
||||||
|
def _change_dir(self, dirs, state):
|
||||||
|
if state == ".":
|
||||||
|
dirs = dirs[1:] + [dirs[0]]
|
||||||
|
elif state == "#":
|
||||||
|
dirs = [dirs[3]] + dirs[:3]
|
||||||
|
elif state == 'F':
|
||||||
|
dirs = dirs[2:] + dirs[:2]
|
||||||
|
return dirs
|
||||||
|
|
||||||
|
def _get_state(self, amap, pos):
|
||||||
|
t = lambda x: x[1][0] == pos[0] and x[1][1] == pos[1]
|
||||||
|
existing = next(filter(t, enumerate(amap)), None)
|
||||||
|
if existing:
|
||||||
|
i, p = existing
|
||||||
|
return amap, p[2]
|
||||||
|
else:
|
||||||
|
amap.append([pos[0], pos[1], '.'])
|
||||||
|
return amap, '.'
|
||||||
|
|
||||||
|
def _update_state(self, amap, pos):
|
||||||
|
t = lambda x: x[1][0] == pos[0] and x[1][1] == pos[1]
|
||||||
|
existing = next(filter(t, enumerate(amap)))
|
||||||
|
i, p = existing
|
||||||
|
if p[2] == '.':
|
||||||
|
self.infected += 1
|
||||||
|
amap[i][2] = '.' if p[2] == '#' else '#'
|
||||||
|
return amap
|
||||||
|
|
||||||
|
def _move(self, pos, d):
|
||||||
|
return [pos[0] + d[0], pos[1] + d[1]]
|
||||||
|
|
||||||
|
def _update_state_evolved(self, amap, pos):
|
||||||
|
t = lambda x: x[1][0] == pos[0] and x[1][1] == pos[1]
|
||||||
|
existing = next(filter(t, enumerate(amap)))
|
||||||
|
i, p = existing
|
||||||
|
if p[2] == '.':
|
||||||
|
ns = 'W'
|
||||||
|
elif p[2] == 'W':
|
||||||
|
self.infected += 1
|
||||||
|
ns = "#"
|
||||||
|
elif p[2] == '#':
|
||||||
|
ns = "F"
|
||||||
|
else:
|
||||||
|
ns = "."
|
||||||
|
amap[i][2] = ns
|
||||||
|
return amap
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
0
2017-python/tests/__init__.py
Normal file
0
2017-python/tests/__init__.py
Normal file
25
2017-python/tests/day_01_tests.py
Normal file
25
2017-python/tests/day_01_tests.py
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from solutions.day_01 import Solution
|
||||||
|
|
||||||
|
|
||||||
|
class Day1TestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.solution = Solution()
|
||||||
|
|
||||||
|
def test_sums_equal_pairs(self):
|
||||||
|
assert self.solution.solve('1122') == 3
|
||||||
|
assert self.solution.solve('1111') == 4
|
||||||
|
assert self.solution.solve('1234') == 0
|
||||||
|
assert self.solution.solve('91212129') == 9
|
||||||
|
|
||||||
|
def test_sums_equal_pairs_halvway_around(self):
|
||||||
|
assert self.solution.solve_again('1212') == 6
|
||||||
|
assert self.solution.solve_again('1221') == 0
|
||||||
|
assert self.solution.solve_again('123425') == 4
|
||||||
|
assert self.solution.solve_again('123123') == 12
|
||||||
|
assert self.solution.solve_again('12131415') == 4
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
31
2017-python/tests/day_02_tests.py
Normal file
31
2017-python/tests/day_02_tests.py
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from solutions.day_02 import Solution
|
||||||
|
|
||||||
|
|
||||||
|
class Day2TestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.solution = Solution()
|
||||||
|
|
||||||
|
def test_calculates_row_difference(self):
|
||||||
|
assert self.solution.get_diff([5, 1, 9, 5]) == 8
|
||||||
|
assert self.solution.get_diff([7, 5, 3]) == 4
|
||||||
|
assert self.solution.get_diff([2, 4, 6, 8]) == 6
|
||||||
|
|
||||||
|
def test_calculates_checksum(self):
|
||||||
|
puzzle_input = '\n'.join(['5 1 9 5', '7 5 3', '2 4 6 8'])
|
||||||
|
assert self.solution.solve(puzzle_input) == 18
|
||||||
|
|
||||||
|
def test_calculates_row_even_divisible(self):
|
||||||
|
puzzle_input = '\n'.join(['5 9 2 8', '9 4 7 3', '3 8 6 5'])
|
||||||
|
assert self.solution.get_even_divisible([5, 9, 2, 8]) == 4
|
||||||
|
assert self.solution.get_even_divisible([9, 4, 7, 3]) == 3
|
||||||
|
assert self.solution.get_even_divisible([3, 8, 6, 5]) == 2
|
||||||
|
|
||||||
|
def test_calculates_row_result_sum(self):
|
||||||
|
puzzle_input = '\n'.join(['5 9 2 8', '9 4 7 3', '3 8 6 5'])
|
||||||
|
assert self.solution.solve_again(puzzle_input) == 9
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
18
2017-python/tests/day_03_tests.py
Normal file
18
2017-python/tests/day_03_tests.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from solutions.day_03 import Solution
|
||||||
|
|
||||||
|
|
||||||
|
class Day3TestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.solution = Solution()
|
||||||
|
|
||||||
|
def test_shortest_manhattan_distance(self):
|
||||||
|
assert self.solution.solve('1') == 0
|
||||||
|
assert self.solution.solve('12') == 3
|
||||||
|
assert self.solution.solve('23') == 2
|
||||||
|
assert self.solution.solve('1024') == 31
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
37
2017-python/tests/day_04_tests.py
Normal file
37
2017-python/tests/day_04_tests.py
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from solutions.day_04 import Solution
|
||||||
|
|
||||||
|
|
||||||
|
class Day4TestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.solution = Solution()
|
||||||
|
|
||||||
|
def test_passphrase_has_only_unique_words(self):
|
||||||
|
passphrases = [
|
||||||
|
'aa bb cc dd ee',
|
||||||
|
'aa bb cc dd aa',
|
||||||
|
'aa bb cc dd aaa',
|
||||||
|
]
|
||||||
|
assert self.solution.validate(passphrases[0]) == True
|
||||||
|
assert self.solution.validate(passphrases[1]) == False
|
||||||
|
assert self.solution.validate(passphrases[2]) == True
|
||||||
|
assert self.solution.solve('\n'.join(passphrases)) == 2
|
||||||
|
|
||||||
|
def test_passphrase_has_no_anagrams(self):
|
||||||
|
passphrases = [
|
||||||
|
'abcde fghij',
|
||||||
|
'abcde xyz ecdab',
|
||||||
|
'a ab abc abd abf abj',
|
||||||
|
'iiii oiii ooii oooi oooo',
|
||||||
|
'oiii ioii iioi iiio',
|
||||||
|
]
|
||||||
|
assert self.solution.validate(passphrases[0], True) == True
|
||||||
|
assert self.solution.validate(passphrases[1], True) == False
|
||||||
|
assert self.solution.validate(passphrases[2], True) == True
|
||||||
|
assert self.solution.validate(passphrases[3], True) == True
|
||||||
|
assert self.solution.validate(passphrases[4], True) == False
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
20
2017-python/tests/day_05_tests.py
Normal file
20
2017-python/tests/day_05_tests.py
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from solutions.day_05 import Solution
|
||||||
|
|
||||||
|
|
||||||
|
class Day5TestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.solution = Solution()
|
||||||
|
|
||||||
|
def test_calculate_exit_distance(self):
|
||||||
|
puzzle_input = '\n'.join(['0', '3', '0', '1', '-3',])
|
||||||
|
assert self.solution.solve(puzzle_input) == 5
|
||||||
|
|
||||||
|
def test_calculate_stranger_exit_distance(self):
|
||||||
|
puzzle_input = '\n'.join(['0', '3', '0', '1', '-3',])
|
||||||
|
assert self.solution.solve_again(puzzle_input) == 10
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
26
2017-python/tests/day_06_tests.py
Normal file
26
2017-python/tests/day_06_tests.py
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from solutions.day_06 import Solution
|
||||||
|
|
||||||
|
|
||||||
|
class Day6TestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.solution = Solution()
|
||||||
|
|
||||||
|
def test_count_redistribution_cycles(self):
|
||||||
|
puzzle_input = '0 2 7 0'
|
||||||
|
banks = list(map(int, puzzle_input.split()))
|
||||||
|
assert self.solution.redistribute(banks) == (2, 4, 1, 2)
|
||||||
|
assert self.solution.redistribute((2, 4, 1, 2)) == (3, 1, 2, 3)
|
||||||
|
assert self.solution.redistribute((3, 1, 2, 3)) == (0, 2, 3, 4)
|
||||||
|
assert self.solution.redistribute((0, 2, 3, 4)) == (1, 3, 4, 1)
|
||||||
|
assert self.solution.redistribute((1, 3, 4, 1)) == (2, 4, 1, 2)
|
||||||
|
assert self.solution.solve(puzzle_input) == 5
|
||||||
|
|
||||||
|
def test_count_redistribution_cycles_again(self):
|
||||||
|
puzzle_input = '0 2 7 0'
|
||||||
|
assert self.solution.solve_again(puzzle_input) == 4
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
42
2017-python/tests/day_07_tests.py
Normal file
42
2017-python/tests/day_07_tests.py
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from solutions.day_07 import Solution, Program
|
||||||
|
|
||||||
|
|
||||||
|
class Day7TestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.puzzle_input = '''
|
||||||
|
pbga (66)
|
||||||
|
xhth (57)
|
||||||
|
ebii (61)
|
||||||
|
havc (66)
|
||||||
|
ktlj (57)
|
||||||
|
fwft (72) -> ktlj, cntj, xhth
|
||||||
|
qoyq (66)
|
||||||
|
padx (45) -> pbga, havc, qoyq
|
||||||
|
tknk (41) -> ugml, padx, fwft
|
||||||
|
jptl (61)
|
||||||
|
ugml (68) -> gyxo, ebii, jptl
|
||||||
|
gyxo (61)
|
||||||
|
cntj (57)
|
||||||
|
'''.strip()
|
||||||
|
self.solution = Solution()
|
||||||
|
|
||||||
|
def test_find_bottom_tower(self):
|
||||||
|
p = Program('ugml (68) -> gyxo, ebii, jptl')
|
||||||
|
assert p.name == 'ugml'
|
||||||
|
assert p.weight == 68
|
||||||
|
assert p.disc == ('gyxo', 'ebii', 'jptl')
|
||||||
|
p = Program('jptl (61)')
|
||||||
|
assert p.name == 'jptl'
|
||||||
|
assert p.weight == 61
|
||||||
|
assert p.disc == ()
|
||||||
|
assert self.solution.solve(self.puzzle_input).name == 'tknk'
|
||||||
|
|
||||||
|
def test_find_weight_correction(self):
|
||||||
|
corrected = self.solution.solve_again(self.puzzle_input)
|
||||||
|
assert corrected == 60
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
30
2017-python/tests/day_08_tests.py
Normal file
30
2017-python/tests/day_08_tests.py
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from solutions.day_08 import Solution
|
||||||
|
|
||||||
|
|
||||||
|
class Day8TestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.solution = Solution()
|
||||||
|
|
||||||
|
def test_largest_registry_value(self):
|
||||||
|
puzzle_input = '''
|
||||||
|
b inc 5 if a > 1
|
||||||
|
a inc 1 if b < 5
|
||||||
|
c dec -10 if a >= 1
|
||||||
|
c inc -20 if c == 10
|
||||||
|
'''.strip()
|
||||||
|
assert self.solution.solve(puzzle_input) == 1
|
||||||
|
|
||||||
|
def test_largest_ath_registry_value(self):
|
||||||
|
puzzle_input = '''
|
||||||
|
b inc 5 if a > 1
|
||||||
|
a inc 1 if b < 5
|
||||||
|
c dec -10 if a >= 1
|
||||||
|
c inc -20 if c == 10
|
||||||
|
'''.strip()
|
||||||
|
assert self.solution.solve_again(puzzle_input) == 10
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
31
2017-python/tests/day_09_tests.py
Normal file
31
2017-python/tests/day_09_tests.py
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from solutions.day_09 import Solution
|
||||||
|
|
||||||
|
|
||||||
|
class Day9TestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.solution = Solution()
|
||||||
|
|
||||||
|
def test_calculates_score(self):
|
||||||
|
assert self.solution.solve('{}') == 1
|
||||||
|
assert self.solution.solve('{{{}}}') == 6
|
||||||
|
assert self.solution.solve('{{},{}}') == 5
|
||||||
|
assert self.solution.solve('{{{},{},{{}}}}') == 16
|
||||||
|
assert self.solution.solve('{<a>,<a>,<a>,<a>}') == 1
|
||||||
|
assert self.solution.solve('{{<ab>},{<ab>},{<ab>},{<ab>}}') == 9
|
||||||
|
assert self.solution.solve('{{<!!>},{<!!>},{<!!>},{<!!>}}') == 9
|
||||||
|
assert self.solution.solve('{{<a!>},{<a!>},{<a!>},{<ab>}}') == 3
|
||||||
|
|
||||||
|
def test_count_garbage(self):
|
||||||
|
assert self.solution.solve_again('<>') == 0
|
||||||
|
assert self.solution.solve_again('<random characters>') == 17
|
||||||
|
assert self.solution.solve_again('<<<<>') == 3
|
||||||
|
assert self.solution.solve_again('<{!>}>') == 2
|
||||||
|
assert self.solution.solve_again('<!!>') == 0
|
||||||
|
assert self.solution.solve_again('<!!!>>') == 0
|
||||||
|
assert self.solution.solve_again('<{o"i!a,<{i<a>') == 10
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
38
2017-python/tests/day_10_tests.py
Normal file
38
2017-python/tests/day_10_tests.py
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from solutions.day_10 import Solution
|
||||||
|
|
||||||
|
|
||||||
|
class Day10TestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.solution = Solution()
|
||||||
|
|
||||||
|
def test_process_and_check(self):
|
||||||
|
self.solution.reset(5)
|
||||||
|
self.solution.reverse(3)
|
||||||
|
assert self.solution.list == [2, 1, 0, 3, 4]
|
||||||
|
assert self.solution.skip_size == 1
|
||||||
|
assert self.solution.pos == 3
|
||||||
|
self.solution.reverse(4)
|
||||||
|
assert self.solution.list == [4, 3, 0, 1, 2]
|
||||||
|
assert self.solution.skip_size == 2
|
||||||
|
assert self.solution.pos == 3
|
||||||
|
self.solution.reverse(1)
|
||||||
|
assert self.solution.list == [4, 3, 0, 1, 2]
|
||||||
|
assert self.solution.skip_size == 3
|
||||||
|
assert self.solution.pos == 1
|
||||||
|
self.solution.reverse(5)
|
||||||
|
assert self.solution.list == [3, 4, 2, 1, 0]
|
||||||
|
assert self.solution.skip_size == 4
|
||||||
|
assert self.solution.pos == 4
|
||||||
|
assert self.solution.solve('3,4,1,5', r=5) == 12
|
||||||
|
|
||||||
|
def test_dense_hash(self):
|
||||||
|
assert self.solution.solve_again('') == 'a2582a3a0e66e6e86e3812dcb672a272'
|
||||||
|
assert self.solution.solve_again('AoC 2017') == '33efeb34ea91902bb2f59c9920caa6cd'
|
||||||
|
assert self.solution.solve_again('1,2,3') == '3efbe78a8d82f29979031a4aa0b16a9d'
|
||||||
|
assert self.solution.solve_again('1,2,4') == '63960835bcdc130f0b66d7ff4f6a5a8e'
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
22
2017-python/tests/day_11_tests.py
Normal file
22
2017-python/tests/day_11_tests.py
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from solutions.day_11 import Solution
|
||||||
|
|
||||||
|
|
||||||
|
class Day11TestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.solution = Solution()
|
||||||
|
|
||||||
|
def test_distance(self):
|
||||||
|
assert self.solution.solve('ne,ne,ne') == 3
|
||||||
|
assert self.solution.solve('ne,ne,sw,sw') == 0
|
||||||
|
assert self.solution.solve('ne,ne,s,s') == 2
|
||||||
|
assert self.solution.solve('se,sw,se,sw,sw') == 3
|
||||||
|
|
||||||
|
def test_furthest_away(self):
|
||||||
|
assert self.solution.solve_again('ne,ne,sw,sw') == 2
|
||||||
|
assert self.solution.solve_again('se,sw,se,sw,sw') == 3
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
36
2017-python/tests/day_12_tests.py
Normal file
36
2017-python/tests/day_12_tests.py
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from solutions.day_12 import Solution
|
||||||
|
|
||||||
|
|
||||||
|
class Day12TestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.solution = Solution()
|
||||||
|
|
||||||
|
def test_connected_to_program0(self):
|
||||||
|
puzzle_input = '''
|
||||||
|
0 <-> 2
|
||||||
|
1 <-> 1
|
||||||
|
2 <-> 0, 3, 4
|
||||||
|
3 <-> 2, 4
|
||||||
|
4 <-> 2, 3, 6
|
||||||
|
5 <-> 6
|
||||||
|
6 <-> 4, 5
|
||||||
|
'''.strip()
|
||||||
|
assert self.solution.solve(puzzle_input) == 6
|
||||||
|
|
||||||
|
def test_group_coun(self):
|
||||||
|
puzzle_input = '''
|
||||||
|
0 <-> 2
|
||||||
|
1 <-> 1
|
||||||
|
2 <-> 0, 3, 4
|
||||||
|
3 <-> 2, 4
|
||||||
|
4 <-> 2, 3, 6
|
||||||
|
5 <-> 6
|
||||||
|
6 <-> 4, 5
|
||||||
|
'''.strip()
|
||||||
|
assert self.solution.solve_again(puzzle_input) == 2
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
30
2017-python/tests/day_13_tests.py
Normal file
30
2017-python/tests/day_13_tests.py
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from solutions.day_13 import Solution
|
||||||
|
|
||||||
|
|
||||||
|
class Day13TestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.solution = Solution()
|
||||||
|
|
||||||
|
def test_get_through_firewall(self):
|
||||||
|
puzzle_input = '''
|
||||||
|
0: 3
|
||||||
|
1: 2
|
||||||
|
4: 4
|
||||||
|
6: 4
|
||||||
|
'''.strip()
|
||||||
|
assert self.solution.solve(puzzle_input) == 24
|
||||||
|
|
||||||
|
def test_wait(self):
|
||||||
|
puzzle_input = '''
|
||||||
|
0: 3
|
||||||
|
1: 2
|
||||||
|
4: 4
|
||||||
|
6: 4
|
||||||
|
'''.strip()
|
||||||
|
assert self.solution.solve_again(puzzle_input) == 10
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
18
2017-python/tests/day_14_tests.py
Normal file
18
2017-python/tests/day_14_tests.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from solutions.day_14 import Solution
|
||||||
|
|
||||||
|
|
||||||
|
class Day14TestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.solution = Solution()
|
||||||
|
|
||||||
|
def test_used_squares(self):
|
||||||
|
assert self.solution.solve('flqrgnkx') == 8108
|
||||||
|
|
||||||
|
def test_regions(self):
|
||||||
|
assert self.solution.solve_again('flqrgnkx') == 1242
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
26
2017-python/tests/day_15_tests.py
Normal file
26
2017-python/tests/day_15_tests.py
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from solutions.day_15 import Solution
|
||||||
|
|
||||||
|
|
||||||
|
class Day15TestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.solution = Solution()
|
||||||
|
|
||||||
|
def test_40m_pairs(self):
|
||||||
|
puzzle_input = '''
|
||||||
|
Generator A starts with 65
|
||||||
|
Generator B starts with 8921
|
||||||
|
'''.strip()
|
||||||
|
#assert self.solution.solve(puzzle_input) == 588
|
||||||
|
|
||||||
|
def test_5k_pairs(self):
|
||||||
|
puzzle_input = '''
|
||||||
|
Generator A starts with 65
|
||||||
|
Generator B starts with 8921
|
||||||
|
'''.strip()
|
||||||
|
assert self.solution.solve_again(puzzle_input) == 309
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
16
2017-python/tests/day_16_tests.py
Normal file
16
2017-python/tests/day_16_tests.py
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from solutions.day_16 import Solution
|
||||||
|
|
||||||
|
|
||||||
|
class Day16TestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.solution = Solution()
|
||||||
|
|
||||||
|
def test_something(self):
|
||||||
|
puzzle_input = '''s1,x3/4,pe/b'''.strip()
|
||||||
|
assert self.solution.solve(puzzle_input, 5) == 'baedc'
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
15
2017-python/tests/day_17_tests.py
Normal file
15
2017-python/tests/day_17_tests.py
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from solutions.day_17 import Solution
|
||||||
|
|
||||||
|
|
||||||
|
class Day17TestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.solution = Solution()
|
||||||
|
|
||||||
|
def test_something(self):
|
||||||
|
assert self.solution.solve('3') == 638
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
39
2017-python/tests/day_18_tests.py
Normal file
39
2017-python/tests/day_18_tests.py
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from solutions.day_18 import Solution
|
||||||
|
|
||||||
|
|
||||||
|
class Day18TestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.solution = Solution()
|
||||||
|
|
||||||
|
def test_something(self):
|
||||||
|
puzzle_input = '''
|
||||||
|
set a 1
|
||||||
|
add a 2
|
||||||
|
mul a a
|
||||||
|
mod a 5
|
||||||
|
snd a
|
||||||
|
set a 0
|
||||||
|
rcv a
|
||||||
|
jgz a -1
|
||||||
|
set a 1
|
||||||
|
jgz a -2
|
||||||
|
'''.strip()
|
||||||
|
assert self.solution.solve(puzzle_input) == 4
|
||||||
|
|
||||||
|
def test_something_else(self):
|
||||||
|
puzzle_input = '''
|
||||||
|
snd 1
|
||||||
|
snd 2
|
||||||
|
snd p
|
||||||
|
rcv a
|
||||||
|
rcv b
|
||||||
|
rcv c
|
||||||
|
rcv d
|
||||||
|
'''.strip()
|
||||||
|
assert self.solution.solve_again(puzzle_input) == 3
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
34
2017-python/tests/day_19_tests.py
Normal file
34
2017-python/tests/day_19_tests.py
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from solutions.day_19 import Solution
|
||||||
|
|
||||||
|
|
||||||
|
class Day19TestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.solution = Solution()
|
||||||
|
|
||||||
|
def test_seen(self):
|
||||||
|
puzzle_input = ''' |
|
||||||
|
| +--+
|
||||||
|
A | C
|
||||||
|
F---|----E|--+
|
||||||
|
| | | D
|
||||||
|
+B-+ +--+
|
||||||
|
|
||||||
|
'''
|
||||||
|
assert self.solution.solve(puzzle_input) == 'ABCDEF'
|
||||||
|
|
||||||
|
def test_steps(self):
|
||||||
|
puzzle_input = ''' |
|
||||||
|
| +--+
|
||||||
|
A | C
|
||||||
|
F---|----E|--+
|
||||||
|
| | | D
|
||||||
|
+B-+ +--+
|
||||||
|
|
||||||
|
'''
|
||||||
|
assert self.solution.solve_again(puzzle_input) == 38
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
28
2017-python/tests/day_20_tests.py
Normal file
28
2017-python/tests/day_20_tests.py
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from solutions.day_20 import Solution
|
||||||
|
|
||||||
|
|
||||||
|
class Day20TestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.solution = Solution()
|
||||||
|
|
||||||
|
def test_shortest_distance_over_time(self):
|
||||||
|
puzzle_input = '''
|
||||||
|
p=< 3,0,0>, v=< 2,0,0>, a=<-1,0,0>
|
||||||
|
p=< 4,0,0>, v=< 0,0,0>, a=<-2,0,0>
|
||||||
|
'''.strip()
|
||||||
|
assert self.solution.solve(puzzle_input, 4) == 0
|
||||||
|
|
||||||
|
def test_something(self):
|
||||||
|
puzzle_input = '''
|
||||||
|
p=<-6,0,0>, v=< 3,0,0>, a=< 0,0,0>
|
||||||
|
p=<-4,0,0>, v=< 2,0,0>, a=< 0,0,0>
|
||||||
|
p=<-2,0,0>, v=< 1,0,0>, a=< 0,0,0>
|
||||||
|
p=< 3,0,0>, v=<-1,0,0>, a=< 0,0,0>
|
||||||
|
'''.strip()
|
||||||
|
assert self.solution.solve_again(puzzle_input, 4) == 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
19
2017-python/tests/day_21_tests.py
Normal file
19
2017-python/tests/day_21_tests.py
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from solutions.day_21 import Solution
|
||||||
|
|
||||||
|
|
||||||
|
class Day21TestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.solution = Solution()
|
||||||
|
|
||||||
|
def test_something(self):
|
||||||
|
puzzle_input = '''
|
||||||
|
../.# => ##./#../...
|
||||||
|
.#./..#/### => #..#/..../..../#..#
|
||||||
|
'''.strip()
|
||||||
|
assert self.solution.solve(puzzle_input, 2) == 12
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
30
2017-python/tests/day_22_tests.py
Normal file
30
2017-python/tests/day_22_tests.py
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from solutions.day_22 import Solution
|
||||||
|
|
||||||
|
|
||||||
|
class Day22TestCase(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.solution = Solution()
|
||||||
|
|
||||||
|
def test_infected(self):
|
||||||
|
puzzle_input = """
|
||||||
|
..#
|
||||||
|
#..
|
||||||
|
...
|
||||||
|
"""
|
||||||
|
assert self.solution.solve(puzzle_input, 7) == 5
|
||||||
|
assert self.solution.solve(puzzle_input, 70) == 41
|
||||||
|
assert self.solution.solve(puzzle_input, 10000) == 5587
|
||||||
|
|
||||||
|
def test_evolved_infected(self):
|
||||||
|
puzzle_input = """
|
||||||
|
..#
|
||||||
|
#..
|
||||||
|
...
|
||||||
|
"""
|
||||||
|
assert self.solution.solve_again(puzzle_input, 100) == 26
|
||||||
|
assert self.solution.solve_again(puzzle_input, 10000000) == 2511944
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
4
2018-elixir/.formatter.exs
Normal file
4
2018-elixir/.formatter.exs
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Used by "mix format"
|
||||||
|
[
|
||||||
|
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
|
||||||
|
]
|
||||||
25
2018-elixir/.gitignore
vendored
Normal file
25
2018-elixir/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
# The directory Mix will write compiled artifacts to.
|
||||||
|
/_build/
|
||||||
|
|
||||||
|
# If you run "mix test --cover", coverage assets end up here.
|
||||||
|
/cover/
|
||||||
|
|
||||||
|
# The directory Mix downloads your dependencies sources to.
|
||||||
|
/deps/
|
||||||
|
|
||||||
|
# Where 3rd-party dependencies like ExDoc output generated docs.
|
||||||
|
/doc/
|
||||||
|
|
||||||
|
# Ignore .fetch files in case you like to edit your project deps locally.
|
||||||
|
/.fetch
|
||||||
|
|
||||||
|
# If the VM crashes, it generates a dump, let's ignore it too.
|
||||||
|
erl_crash.dump
|
||||||
|
|
||||||
|
# Also ignore archive artifacts (built via "mix archive.build").
|
||||||
|
*.ez
|
||||||
|
|
||||||
|
# Ignore package tarball (built via "mix hex.build").
|
||||||
|
aoc2018e-*.tar
|
||||||
|
|
||||||
|
.idea
|
||||||
21
2018-elixir/README.md
Normal file
21
2018-elixir/README.md
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
# Aoc2018e
|
||||||
|
|
||||||
|
**TODO: Add description**
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
If [available in Hex](https://hex.pm/docs/publish), the package can be installed
|
||||||
|
by adding `aoc2018e` to your list of dependencies in `mix.exs`:
|
||||||
|
|
||||||
|
```elixir
|
||||||
|
def deps do
|
||||||
|
[
|
||||||
|
{:aoc2018e, "~> 0.1.0"}
|
||||||
|
]
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
|
||||||
|
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
|
||||||
|
be found at [https://hexdocs.pm/aoc2018e](https://hexdocs.pm/aoc2018e).
|
||||||
|
|
||||||
30
2018-elixir/config/config.exs
Normal file
30
2018-elixir/config/config.exs
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
# This file is responsible for configuring your application
|
||||||
|
# and its dependencies with the aid of the Mix.Config module.
|
||||||
|
use Mix.Config
|
||||||
|
|
||||||
|
# This configuration is loaded before any dependency and is restricted
|
||||||
|
# to this project. If another project depends on this project, this
|
||||||
|
# file won't be loaded nor affect the parent project. For this reason,
|
||||||
|
# if you want to provide default values for your application for
|
||||||
|
# 3rd-party users, it should be done in your "mix.exs" file.
|
||||||
|
|
||||||
|
# You can configure your application as:
|
||||||
|
#
|
||||||
|
# config :aoc2018e, key: :value
|
||||||
|
#
|
||||||
|
# and access this configuration in your application as:
|
||||||
|
#
|
||||||
|
# Application.get_env(:aoc2018e, :key)
|
||||||
|
#
|
||||||
|
# You can also configure a 3rd-party app:
|
||||||
|
#
|
||||||
|
# config :logger, level: :info
|
||||||
|
#
|
||||||
|
|
||||||
|
# It is also possible to import configuration files, relative to this
|
||||||
|
# directory. For example, you can emulate configuration per environment
|
||||||
|
# by uncommenting the line below and defining dev.exs, test.exs and such.
|
||||||
|
# Configuration from the imported file will override the ones defined
|
||||||
|
# here (which is why it is important to import them last).
|
||||||
|
#
|
||||||
|
# import_config "#{Mix.env()}.exs"
|
||||||
993
2018-elixir/data/01.in
Normal file
993
2018-elixir/data/01.in
Normal file
|
|
@ -0,0 +1,993 @@
|
||||||
|
+3
|
||||||
|
+15
|
||||||
|
-1
|
||||||
|
-18
|
||||||
|
+3
|
||||||
|
-10
|
||||||
|
+3
|
||||||
|
+10
|
||||||
|
-8
|
||||||
|
-20
|
||||||
|
+13
|
||||||
|
+11
|
||||||
|
-21
|
||||||
|
-10
|
||||||
|
-16
|
||||||
|
-2
|
||||||
|
-6
|
||||||
|
+19
|
||||||
|
-8
|
||||||
|
+12
|
||||||
|
-13
|
||||||
|
+4
|
||||||
|
-9
|
||||||
|
-20
|
||||||
|
+12
|
||||||
|
+15
|
||||||
|
-17
|
||||||
|
-18
|
||||||
|
+11
|
||||||
|
-17
|
||||||
|
-9
|
||||||
|
-12
|
||||||
|
-9
|
||||||
|
+3
|
||||||
|
+9
|
||||||
|
-6
|
||||||
|
+18
|
||||||
|
+16
|
||||||
|
+9
|
||||||
|
-11
|
||||||
|
-1
|
||||||
|
+8
|
||||||
|
-20
|
||||||
|
+17
|
||||||
|
-3
|
||||||
|
-16
|
||||||
|
-7
|
||||||
|
+10
|
||||||
|
+6
|
||||||
|
+3
|
||||||
|
+15
|
||||||
|
+3
|
||||||
|
-2
|
||||||
|
+9
|
||||||
|
-8
|
||||||
|
-6
|
||||||
|
+11
|
||||||
|
+5
|
||||||
|
+24
|
||||||
|
+10
|
||||||
|
+4
|
||||||
|
-8
|
||||||
|
+2
|
||||||
|
+13
|
||||||
|
-16
|
||||||
|
+13
|
||||||
|
-16
|
||||||
|
+11
|
||||||
|
+7
|
||||||
|
-9
|
||||||
|
-13
|
||||||
|
-12
|
||||||
|
+17
|
||||||
|
-4
|
||||||
|
-5
|
||||||
|
-1
|
||||||
|
+16
|
||||||
|
+22
|
||||||
|
+8
|
||||||
|
+12
|
||||||
|
+9
|
||||||
|
+2
|
||||||
|
-3
|
||||||
|
-5
|
||||||
|
+12
|
||||||
|
+4
|
||||||
|
+4
|
||||||
|
+8
|
||||||
|
+18
|
||||||
|
+9
|
||||||
|
-14
|
||||||
|
-11
|
||||||
|
-5
|
||||||
|
-11
|
||||||
|
+15
|
||||||
|
-18
|
||||||
|
-7
|
||||||
|
-12
|
||||||
|
+1
|
||||||
|
+5
|
||||||
|
-18
|
||||||
|
+14
|
||||||
|
-13
|
||||||
|
-10
|
||||||
|
+17
|
||||||
|
+8
|
||||||
|
+11
|
||||||
|
-12
|
||||||
|
+20
|
||||||
|
-16
|
||||||
|
+22
|
||||||
|
+5
|
||||||
|
+1
|
||||||
|
-9
|
||||||
|
+16
|
||||||
|
+13
|
||||||
|
+6
|
||||||
|
+5
|
||||||
|
+7
|
||||||
|
-4
|
||||||
|
-4
|
||||||
|
-7
|
||||||
|
+16
|
||||||
|
+4
|
||||||
|
-1
|
||||||
|
-15
|
||||||
|
-11
|
||||||
|
+19
|
||||||
|
+9
|
||||||
|
+17
|
||||||
|
-15
|
||||||
|
+21
|
||||||
|
-7
|
||||||
|
+4
|
||||||
|
-16
|
||||||
|
-3
|
||||||
|
-9
|
||||||
|
+4
|
||||||
|
+11
|
||||||
|
+12
|
||||||
|
+11
|
||||||
|
+7
|
||||||
|
+12
|
||||||
|
+14
|
||||||
|
-6
|
||||||
|
-1
|
||||||
|
-18
|
||||||
|
-3
|
||||||
|
-13
|
||||||
|
+4
|
||||||
|
+10
|
||||||
|
-15
|
||||||
|
-10
|
||||||
|
-8
|
||||||
|
+15
|
||||||
|
+15
|
||||||
|
+19
|
||||||
|
+16
|
||||||
|
-3
|
||||||
|
-14
|
||||||
|
+13
|
||||||
|
+16
|
||||||
|
+1
|
||||||
|
+10
|
||||||
|
+9
|
||||||
|
+7
|
||||||
|
-11
|
||||||
|
-19
|
||||||
|
+2
|
||||||
|
-3
|
||||||
|
+10
|
||||||
|
-2
|
||||||
|
+13
|
||||||
|
-19
|
||||||
|
-7
|
||||||
|
+3
|
||||||
|
+18
|
||||||
|
+1
|
||||||
|
+9
|
||||||
|
+2
|
||||||
|
+12
|
||||||
|
-13
|
||||||
|
-9
|
||||||
|
-7
|
||||||
|
-15
|
||||||
|
-18
|
||||||
|
-6
|
||||||
|
-1
|
||||||
|
-8
|
||||||
|
-12
|
||||||
|
+19
|
||||||
|
-1
|
||||||
|
-14
|
||||||
|
-6
|
||||||
|
-16
|
||||||
|
-4
|
||||||
|
+1
|
||||||
|
+4
|
||||||
|
-22
|
||||||
|
-19
|
||||||
|
-2
|
||||||
|
+4
|
||||||
|
+18
|
||||||
|
-8
|
||||||
|
-19
|
||||||
|
-16
|
||||||
|
+6
|
||||||
|
+16
|
||||||
|
-7
|
||||||
|
+4
|
||||||
|
+8
|
||||||
|
-20
|
||||||
|
-11
|
||||||
|
-11
|
||||||
|
+20
|
||||||
|
+15
|
||||||
|
+19
|
||||||
|
+30
|
||||||
|
+19
|
||||||
|
+19
|
||||||
|
-11
|
||||||
|
-18
|
||||||
|
+4
|
||||||
|
+1
|
||||||
|
+21
|
||||||
|
-9
|
||||||
|
-9
|
||||||
|
+12
|
||||||
|
+18
|
||||||
|
-1
|
||||||
|
-6
|
||||||
|
+12
|
||||||
|
+16
|
||||||
|
+12
|
||||||
|
+3
|
||||||
|
+1
|
||||||
|
-9
|
||||||
|
-15
|
||||||
|
-15
|
||||||
|
-1
|
||||||
|
-1
|
||||||
|
-18
|
||||||
|
-32
|
||||||
|
-11
|
||||||
|
-17
|
||||||
|
-20
|
||||||
|
+4
|
||||||
|
+14
|
||||||
|
-1
|
||||||
|
+16
|
||||||
|
+20
|
||||||
|
+53
|
||||||
|
+19
|
||||||
|
+16
|
||||||
|
+14
|
||||||
|
+14
|
||||||
|
+6
|
||||||
|
-8
|
||||||
|
+14
|
||||||
|
-17
|
||||||
|
-5
|
||||||
|
+3
|
||||||
|
+14
|
||||||
|
-3
|
||||||
|
-15
|
||||||
|
-10
|
||||||
|
-19
|
||||||
|
+17
|
||||||
|
+3
|
||||||
|
+17
|
||||||
|
+5
|
||||||
|
+14
|
||||||
|
-7
|
||||||
|
+5
|
||||||
|
+14
|
||||||
|
+18
|
||||||
|
-2
|
||||||
|
-19
|
||||||
|
+8
|
||||||
|
+10
|
||||||
|
+15
|
||||||
|
-6
|
||||||
|
+13
|
||||||
|
-11
|
||||||
|
+19
|
||||||
|
+10
|
||||||
|
-15
|
||||||
|
-15
|
||||||
|
+2
|
||||||
|
-4
|
||||||
|
-3
|
||||||
|
+11
|
||||||
|
+2
|
||||||
|
+18
|
||||||
|
+3
|
||||||
|
+17
|
||||||
|
+9
|
||||||
|
-16
|
||||||
|
-8
|
||||||
|
+6
|
||||||
|
+15
|
||||||
|
-11
|
||||||
|
-3
|
||||||
|
+20
|
||||||
|
-1
|
||||||
|
+12
|
||||||
|
+1
|
||||||
|
+8
|
||||||
|
+11
|
||||||
|
-8
|
||||||
|
+6
|
||||||
|
+7
|
||||||
|
+17
|
||||||
|
-12
|
||||||
|
+13
|
||||||
|
-8
|
||||||
|
+16
|
||||||
|
+15
|
||||||
|
-8
|
||||||
|
-12
|
||||||
|
+7
|
||||||
|
-12
|
||||||
|
-18
|
||||||
|
+5
|
||||||
|
+5
|
||||||
|
+7
|
||||||
|
-8
|
||||||
|
+6
|
||||||
|
-4
|
||||||
|
-15
|
||||||
|
+17
|
||||||
|
-15
|
||||||
|
-10
|
||||||
|
-1
|
||||||
|
+17
|
||||||
|
+18
|
||||||
|
-21
|
||||||
|
-19
|
||||||
|
-9
|
||||||
|
+19
|
||||||
|
+16
|
||||||
|
+18
|
||||||
|
-5
|
||||||
|
-15
|
||||||
|
+19
|
||||||
|
-11
|
||||||
|
+10
|
||||||
|
+9
|
||||||
|
-1
|
||||||
|
+4
|
||||||
|
+4
|
||||||
|
+9
|
||||||
|
-5
|
||||||
|
+20
|
||||||
|
+4
|
||||||
|
-18
|
||||||
|
+17
|
||||||
|
+12
|
||||||
|
-18
|
||||||
|
+14
|
||||||
|
-21
|
||||||
|
-15
|
||||||
|
-5
|
||||||
|
-18
|
||||||
|
-17
|
||||||
|
-19
|
||||||
|
+11
|
||||||
|
+12
|
||||||
|
-20
|
||||||
|
-19
|
||||||
|
+12
|
||||||
|
-9
|
||||||
|
+8
|
||||||
|
-1
|
||||||
|
-22
|
||||||
|
+4
|
||||||
|
+15
|
||||||
|
+14
|
||||||
|
+9
|
||||||
|
-10
|
||||||
|
-26
|
||||||
|
-22
|
||||||
|
-10
|
||||||
|
+7
|
||||||
|
+9
|
||||||
|
-1
|
||||||
|
-16
|
||||||
|
-21
|
||||||
|
-18
|
||||||
|
+8
|
||||||
|
+6
|
||||||
|
+18
|
||||||
|
+1
|
||||||
|
+5
|
||||||
|
+11
|
||||||
|
+18
|
||||||
|
+6
|
||||||
|
+20
|
||||||
|
-7
|
||||||
|
-10
|
||||||
|
-5
|
||||||
|
+33
|
||||||
|
-21
|
||||||
|
-8
|
||||||
|
-13
|
||||||
|
-5
|
||||||
|
+7
|
||||||
|
+1
|
||||||
|
-7
|
||||||
|
-39
|
||||||
|
-14
|
||||||
|
-12
|
||||||
|
+16
|
||||||
|
-14
|
||||||
|
-15
|
||||||
|
+4
|
||||||
|
+2
|
||||||
|
+12
|
||||||
|
-11
|
||||||
|
+16
|
||||||
|
+8
|
||||||
|
+15
|
||||||
|
-1
|
||||||
|
+21
|
||||||
|
-5
|
||||||
|
+13
|
||||||
|
-18
|
||||||
|
-7
|
||||||
|
+2
|
||||||
|
-15
|
||||||
|
+19
|
||||||
|
+8
|
||||||
|
+26
|
||||||
|
-24
|
||||||
|
+37
|
||||||
|
+59
|
||||||
|
+21
|
||||||
|
-19
|
||||||
|
+18
|
||||||
|
+6
|
||||||
|
-11
|
||||||
|
+15
|
||||||
|
-2
|
||||||
|
+5
|
||||||
|
-2
|
||||||
|
+20
|
||||||
|
+8
|
||||||
|
+2
|
||||||
|
-7
|
||||||
|
+18
|
||||||
|
-8
|
||||||
|
-1
|
||||||
|
-8
|
||||||
|
+3
|
||||||
|
+17
|
||||||
|
+12
|
||||||
|
+18
|
||||||
|
+2
|
||||||
|
-8
|
||||||
|
+3
|
||||||
|
+40
|
||||||
|
+3
|
||||||
|
+21
|
||||||
|
+5
|
||||||
|
-1
|
||||||
|
+15
|
||||||
|
+2
|
||||||
|
+16
|
||||||
|
-50
|
||||||
|
+15
|
||||||
|
+5
|
||||||
|
+21
|
||||||
|
-31
|
||||||
|
-17
|
||||||
|
-15
|
||||||
|
-10
|
||||||
|
-9
|
||||||
|
-2
|
||||||
|
-18
|
||||||
|
-14
|
||||||
|
+7
|
||||||
|
-14
|
||||||
|
+6
|
||||||
|
-20
|
||||||
|
-8
|
||||||
|
+13
|
||||||
|
-27
|
||||||
|
+8
|
||||||
|
+2
|
||||||
|
-16
|
||||||
|
+3
|
||||||
|
-7
|
||||||
|
-6
|
||||||
|
+23
|
||||||
|
+31
|
||||||
|
+52
|
||||||
|
-6
|
||||||
|
-1
|
||||||
|
+2
|
||||||
|
-54
|
||||||
|
-42
|
||||||
|
-6
|
||||||
|
+18
|
||||||
|
+2
|
||||||
|
+1
|
||||||
|
-29
|
||||||
|
+36
|
||||||
|
-42
|
||||||
|
+7
|
||||||
|
-146
|
||||||
|
-2
|
||||||
|
-14
|
||||||
|
-13
|
||||||
|
+19
|
||||||
|
-8
|
||||||
|
+19
|
||||||
|
-15
|
||||||
|
-18
|
||||||
|
-4
|
||||||
|
-18
|
||||||
|
-1
|
||||||
|
+2
|
||||||
|
-3
|
||||||
|
+11
|
||||||
|
-16
|
||||||
|
-23
|
||||||
|
-9
|
||||||
|
-30
|
||||||
|
-31
|
||||||
|
+58
|
||||||
|
+18
|
||||||
|
-19
|
||||||
|
+45
|
||||||
|
+11
|
||||||
|
+14
|
||||||
|
-16
|
||||||
|
+19
|
||||||
|
-10
|
||||||
|
+17
|
||||||
|
+12
|
||||||
|
-2
|
||||||
|
-8
|
||||||
|
+19
|
||||||
|
-50
|
||||||
|
+8
|
||||||
|
-114
|
||||||
|
-40
|
||||||
|
-62
|
||||||
|
-153
|
||||||
|
-60
|
||||||
|
+12
|
||||||
|
-23
|
||||||
|
-40
|
||||||
|
-87
|
||||||
|
+377
|
||||||
|
-79652
|
||||||
|
-12
|
||||||
|
+1
|
||||||
|
-9
|
||||||
|
-5
|
||||||
|
-12
|
||||||
|
-14
|
||||||
|
+9
|
||||||
|
-3
|
||||||
|
-2
|
||||||
|
+8
|
||||||
|
-15
|
||||||
|
-18
|
||||||
|
+19
|
||||||
|
-6
|
||||||
|
+4
|
||||||
|
-14
|
||||||
|
-2
|
||||||
|
-18
|
||||||
|
-19
|
||||||
|
-8
|
||||||
|
+2
|
||||||
|
+11
|
||||||
|
-19
|
||||||
|
-11
|
||||||
|
+5
|
||||||
|
-3
|
||||||
|
+4
|
||||||
|
+1
|
||||||
|
-3
|
||||||
|
+9
|
||||||
|
+7
|
||||||
|
+15
|
||||||
|
-9
|
||||||
|
-2
|
||||||
|
-6
|
||||||
|
+3
|
||||||
|
+2
|
||||||
|
+10
|
||||||
|
+9
|
||||||
|
+3
|
||||||
|
-5
|
||||||
|
-4
|
||||||
|
+12
|
||||||
|
+15
|
||||||
|
-6
|
||||||
|
-11
|
||||||
|
-9
|
||||||
|
-15
|
||||||
|
+9
|
||||||
|
-19
|
||||||
|
-15
|
||||||
|
+4
|
||||||
|
+7
|
||||||
|
+7
|
||||||
|
-16
|
||||||
|
+15
|
||||||
|
-4
|
||||||
|
-19
|
||||||
|
-8
|
||||||
|
-11
|
||||||
|
-18
|
||||||
|
-14
|
||||||
|
-18
|
||||||
|
-16
|
||||||
|
+5
|
||||||
|
+5
|
||||||
|
+12
|
||||||
|
-9
|
||||||
|
-16
|
||||||
|
+2
|
||||||
|
-6
|
||||||
|
-2
|
||||||
|
+20
|
||||||
|
-13
|
||||||
|
-9
|
||||||
|
-16
|
||||||
|
+4
|
||||||
|
-1
|
||||||
|
+2
|
||||||
|
-3
|
||||||
|
-17
|
||||||
|
-2
|
||||||
|
-11
|
||||||
|
+1
|
||||||
|
+6
|
||||||
|
+17
|
||||||
|
-4
|
||||||
|
-15
|
||||||
|
-3
|
||||||
|
-19
|
||||||
|
+6
|
||||||
|
-16
|
||||||
|
-18
|
||||||
|
-6
|
||||||
|
+2
|
||||||
|
+12
|
||||||
|
-9
|
||||||
|
+6
|
||||||
|
+7
|
||||||
|
-6
|
||||||
|
+7
|
||||||
|
-9
|
||||||
|
-18
|
||||||
|
-3
|
||||||
|
+10
|
||||||
|
-17
|
||||||
|
+11
|
||||||
|
+16
|
||||||
|
+16
|
||||||
|
+6
|
||||||
|
+13
|
||||||
|
-17
|
||||||
|
+2
|
||||||
|
+3
|
||||||
|
+17
|
||||||
|
-10
|
||||||
|
+8
|
||||||
|
-1
|
||||||
|
-9
|
||||||
|
-15
|
||||||
|
+11
|
||||||
|
+2
|
||||||
|
-14
|
||||||
|
+7
|
||||||
|
-12
|
||||||
|
-19
|
||||||
|
-3
|
||||||
|
-7
|
||||||
|
-7
|
||||||
|
-15
|
||||||
|
-17
|
||||||
|
+5
|
||||||
|
+3
|
||||||
|
+14
|
||||||
|
+6
|
||||||
|
-5
|
||||||
|
+17
|
||||||
|
-9
|
||||||
|
-5
|
||||||
|
+1
|
||||||
|
-8
|
||||||
|
-13
|
||||||
|
+7
|
||||||
|
+17
|
||||||
|
-12
|
||||||
|
-14
|
||||||
|
-18
|
||||||
|
+10
|
||||||
|
+16
|
||||||
|
-3
|
||||||
|
-19
|
||||||
|
+7
|
||||||
|
+14
|
||||||
|
+14
|
||||||
|
+11
|
||||||
|
-1
|
||||||
|
+18
|
||||||
|
-16
|
||||||
|
-4
|
||||||
|
+10
|
||||||
|
-14
|
||||||
|
+9
|
||||||
|
-17
|
||||||
|
-1
|
||||||
|
+4
|
||||||
|
-14
|
||||||
|
-16
|
||||||
|
+1
|
||||||
|
-14
|
||||||
|
-7
|
||||||
|
+1
|
||||||
|
+7
|
||||||
|
-11
|
||||||
|
-4
|
||||||
|
-14
|
||||||
|
+19
|
||||||
|
-11
|
||||||
|
+8
|
||||||
|
+14
|
||||||
|
+8
|
||||||
|
-15
|
||||||
|
-18
|
||||||
|
+2
|
||||||
|
-17
|
||||||
|
-19
|
||||||
|
+13
|
||||||
|
+3
|
||||||
|
+6
|
||||||
|
+8
|
||||||
|
-10
|
||||||
|
+7
|
||||||
|
-3
|
||||||
|
-9
|
||||||
|
+8
|
||||||
|
+12
|
||||||
|
-4
|
||||||
|
+15
|
||||||
|
+7
|
||||||
|
+10
|
||||||
|
+11
|
||||||
|
-10
|
||||||
|
-20
|
||||||
|
-16
|
||||||
|
+11
|
||||||
|
-1
|
||||||
|
-21
|
||||||
|
-13
|
||||||
|
-19
|
||||||
|
-15
|
||||||
|
-15
|
||||||
|
-7
|
||||||
|
+10
|
||||||
|
+19
|
||||||
|
-17
|
||||||
|
-6
|
||||||
|
-10
|
||||||
|
-13
|
||||||
|
+12
|
||||||
|
-18
|
||||||
|
+16
|
||||||
|
+10
|
||||||
|
-13
|
||||||
|
+12
|
||||||
|
-1
|
||||||
|
+12
|
||||||
|
+12
|
||||||
|
+10
|
||||||
|
+16
|
||||||
|
-18
|
||||||
|
-5
|
||||||
|
-10
|
||||||
|
-13
|
||||||
|
-7
|
||||||
|
+19
|
||||||
|
+14
|
||||||
|
+18
|
||||||
|
-2
|
||||||
|
-4
|
||||||
|
-13
|
||||||
|
+14
|
||||||
|
+18
|
||||||
|
-7
|
||||||
|
+11
|
||||||
|
-13
|
||||||
|
-21
|
||||||
|
-12
|
||||||
|
+14
|
||||||
|
+16
|
||||||
|
+7
|
||||||
|
-19
|
||||||
|
+16
|
||||||
|
+7
|
||||||
|
+2
|
||||||
|
-5
|
||||||
|
+1
|
||||||
|
+19
|
||||||
|
+16
|
||||||
|
+14
|
||||||
|
+9
|
||||||
|
+12
|
||||||
|
+14
|
||||||
|
-8
|
||||||
|
-28
|
||||||
|
+13
|
||||||
|
+11
|
||||||
|
+13
|
||||||
|
-17
|
||||||
|
-21
|
||||||
|
+15
|
||||||
|
-37
|
||||||
|
-11
|
||||||
|
+19
|
||||||
|
+1
|
||||||
|
+8
|
||||||
|
+12
|
||||||
|
-1
|
||||||
|
-27
|
||||||
|
-21
|
||||||
|
-19
|
||||||
|
-21
|
||||||
|
+15
|
||||||
|
-24
|
||||||
|
-7
|
||||||
|
-11
|
||||||
|
-17
|
||||||
|
-15
|
||||||
|
-11
|
||||||
|
-11
|
||||||
|
+8
|
||||||
|
-9
|
||||||
|
-9
|
||||||
|
-4
|
||||||
|
-6
|
||||||
|
+15
|
||||||
|
-10
|
||||||
|
-3
|
||||||
|
+19
|
||||||
|
+9
|
||||||
|
+8
|
||||||
|
+6
|
||||||
|
+11
|
||||||
|
-4
|
||||||
|
-14
|
||||||
|
-1
|
||||||
|
+3
|
||||||
|
-15
|
||||||
|
+17
|
||||||
|
+18
|
||||||
|
-10
|
||||||
|
-22
|
||||||
|
-15
|
||||||
|
+14
|
||||||
|
+6
|
||||||
|
-14
|
||||||
|
-11
|
||||||
|
+4
|
||||||
|
-18
|
||||||
|
+5
|
||||||
|
-16
|
||||||
|
-9
|
||||||
|
-13
|
||||||
|
+14
|
||||||
|
+3
|
||||||
|
+9
|
||||||
|
+17
|
||||||
|
-9
|
||||||
|
+22
|
||||||
|
-12
|
||||||
|
-8
|
||||||
|
-5
|
||||||
|
-1
|
||||||
|
-6
|
||||||
|
-6
|
||||||
|
-19
|
||||||
|
+17
|
||||||
|
+9
|
||||||
|
+28
|
||||||
|
+20
|
||||||
|
+14
|
||||||
|
+11
|
||||||
|
+6
|
||||||
|
+7
|
||||||
|
-2
|
||||||
|
+17
|
||||||
|
+17
|
||||||
|
-12
|
||||||
|
+7
|
||||||
|
+21
|
||||||
|
-2
|
||||||
|
-4
|
||||||
|
+10
|
||||||
|
+2
|
||||||
|
+12
|
||||||
|
-19
|
||||||
|
-22
|
||||||
|
-8
|
||||||
|
-20
|
||||||
|
+25
|
||||||
|
-17
|
||||||
|
-15
|
||||||
|
-8
|
||||||
|
-1
|
||||||
|
+13
|
||||||
|
-15
|
||||||
|
+16
|
||||||
|
+15
|
||||||
|
+19
|
||||||
|
-128
|
||||||
|
-4
|
||||||
|
-16
|
||||||
|
-4
|
||||||
|
+13
|
||||||
|
-10
|
||||||
|
+20
|
||||||
|
-16
|
||||||
|
-13
|
||||||
|
+15
|
||||||
|
+9
|
||||||
|
+1
|
||||||
|
-11
|
||||||
|
-16
|
||||||
|
+13
|
||||||
|
+1
|
||||||
|
+15
|
||||||
|
+1
|
||||||
|
-31
|
||||||
|
+11
|
||||||
|
-53
|
||||||
|
-11
|
||||||
|
-9
|
||||||
|
-16
|
||||||
|
-11
|
||||||
|
+7
|
||||||
|
+6
|
||||||
|
+13
|
||||||
|
+6
|
||||||
|
-12
|
||||||
|
-3
|
||||||
|
+16
|
||||||
|
+2
|
||||||
|
-5
|
||||||
|
+7
|
||||||
|
-16
|
||||||
|
+17
|
||||||
|
-13
|
||||||
|
-9
|
||||||
|
+15
|
||||||
|
-3
|
||||||
|
+13
|
||||||
|
+8
|
||||||
|
+5
|
||||||
|
-8
|
||||||
|
-1
|
||||||
|
-5
|
||||||
|
-21
|
||||||
|
+25
|
||||||
|
+23
|
||||||
|
+12
|
||||||
|
+1
|
||||||
|
-2
|
||||||
|
+7
|
||||||
|
-25
|
||||||
|
-51
|
||||||
|
-5
|
||||||
|
+4
|
||||||
|
+14
|
||||||
|
-8
|
||||||
|
+4
|
||||||
|
+11
|
||||||
|
-5
|
||||||
|
-21
|
||||||
|
-14
|
||||||
|
+9
|
||||||
|
+8
|
||||||
|
-13
|
||||||
|
+4
|
||||||
|
+80915
|
||||||
250
2018-elixir/data/02.in
Normal file
250
2018-elixir/data/02.in
Normal file
|
|
@ -0,0 +1,250 @@
|
||||||
|
crruafyzloguvxwctqmphenbkd
|
||||||
|
srcjafyzlcguvrwctqmphenbkd
|
||||||
|
srijafyzlogbpxwctgmphenbkd
|
||||||
|
zrijafyzloguvxrctqmphendkd
|
||||||
|
srijabyzloguvowcqqmphenbkd
|
||||||
|
srijafyzsoguvxwctbmpienbkd
|
||||||
|
srirtfyzlognvxwctqmphenbkd
|
||||||
|
srijafyzloguvxwctgmphenbmq
|
||||||
|
senjafyzloguvxectqmphenbkd
|
||||||
|
srijafyeloguvxwwtqmphembkd
|
||||||
|
srijafyzlogurxtctqmpkenbkd
|
||||||
|
srijafyzlkguvxictqhphenbkd
|
||||||
|
srijafgzlogunxwctqophenbkd
|
||||||
|
shijabyzloguvxwctqmqhenbkd
|
||||||
|
srjoafyzloguvxwctqmphenbwd
|
||||||
|
srijafyhloguvxwmtqmphenkkd
|
||||||
|
srijadyzlogwvxwctqmphenbed
|
||||||
|
brijafyzloguvmwctqmphenhkd
|
||||||
|
smijafyzlhguvxwctqmphjnbkd
|
||||||
|
sriqafvzloguvxwctqmpheebkd
|
||||||
|
srijafyzloguvxwisqmpuenbkd
|
||||||
|
mrijakyuloguvxwctqmphenbkd
|
||||||
|
srnfafyzloguvxwctqmphgnbkd
|
||||||
|
srijadyzloguvxwhfqmphenbkd
|
||||||
|
srijafhzloguvxwctdmlhenbkd
|
||||||
|
srijafyzloguvxwcsqmphykbkd
|
||||||
|
srijafyzlogwvxwatqmphhnbkd
|
||||||
|
srijafyzlozqvxwctqmphenbku
|
||||||
|
srijafyzloguvxwcbamphenbgd
|
||||||
|
srijafyzlfguvxwctqmphzybkd
|
||||||
|
srijafyzloguqxwetqmphenkkd
|
||||||
|
srijafyylogubxwttqmphenbkd
|
||||||
|
srijafyzloguvxzctadphenbkd
|
||||||
|
srijafyzloguoxwhtqmchenbkd
|
||||||
|
srijafyzloguvxwcvqmzhenbko
|
||||||
|
srijnfyzloguvxwctqmchenjkd
|
||||||
|
srijaryzloggvxwctqzphenbkd
|
||||||
|
srijafhzleguvxwcxqmphenbkd
|
||||||
|
ssijafyzllguvxfctqmphenbkd
|
||||||
|
srijafyzloguvxdctqmfhenbcd
|
||||||
|
srijafyzloguvxfctqmplynbkd
|
||||||
|
srijaftzlogavxwcrqmphenbkd
|
||||||
|
sriwaoyzloguvxwctqmphenbtd
|
||||||
|
srijahyzlogunxwctqmphenbvd
|
||||||
|
srjjafyzloguzxwctumphenbkd
|
||||||
|
nrijafyzlxguvxwctqmphanbkd
|
||||||
|
srijafezlqguyxwctqmphenbkd
|
||||||
|
srijafygloguvxwjtqcphenbkd
|
||||||
|
erijafyzloguvxoctqmnhenbkd
|
||||||
|
ssijafyzllguvxwbtqmphenbkd
|
||||||
|
sriaafyzloguvxwctqqphenbkv
|
||||||
|
frijafyzloguvswctwmphenbkd
|
||||||
|
srijafyzyogkvxwctqmprenbkd
|
||||||
|
syijafyzuoguvxwctqmkhenbkd
|
||||||
|
srijafyzloganxwctqmphenbkf
|
||||||
|
srijafyzloguvxwftqmxhenbkq
|
||||||
|
srijafyflogxvxwctqmghenbkd
|
||||||
|
srijafyzsoguvxwctqmpjenwkd
|
||||||
|
srujafylloguvxwctqmphenckd
|
||||||
|
srijafyzlpzuvxwctqmphenbud
|
||||||
|
srijafyzlogfvxwctqmhhenbwd
|
||||||
|
srijafjzlogusxwctqmphepbkd
|
||||||
|
srijlfyzloguvxwctqfphenzkd
|
||||||
|
srijafyzlogwvxwctqyphenbqd
|
||||||
|
srijafyzloluvxwctqtphenukd
|
||||||
|
srizafyzlowuvxwctqmphqnbkd
|
||||||
|
sritafkzlkguvxwctqmphenbkd
|
||||||
|
sbijafdzloguvxgctqmphenbkd
|
||||||
|
crijafyeloguvxwctqmpsenbkd
|
||||||
|
srijafyvlogulxwctqmphenbkk
|
||||||
|
srijafyologuvxwctqmehegbkd
|
||||||
|
siijafyzloguvxwctjmphenbmd
|
||||||
|
srijafyzlupuvxwctqmpheabkd
|
||||||
|
srijafyzlogumxwctqqphanbkd
|
||||||
|
srijxfyzlogujxwcqqmphenbkd
|
||||||
|
irijafizeoguvxwctqmphenbkd
|
||||||
|
sgijafyzloguvtwctqmpfenbkd
|
||||||
|
srijzfyzloguvmwctnmphenbkd
|
||||||
|
srijafyzwohuvxwctqmthenbkd
|
||||||
|
srijafyzlhguvxoctqwphenbkd
|
||||||
|
srgjafyplogxvxwctqmphenbkd
|
||||||
|
srijafyqlogovxwctqzphenbkd
|
||||||
|
srijafjzloguvlnvtqmphenbkd
|
||||||
|
srijafyzooguvxwctqmphenvud
|
||||||
|
srijafyzgoguvxwctumphgnbkd
|
||||||
|
srijaffzloguvxwdqqmphenbkd
|
||||||
|
srijafyzlogugxwctqxphenbkr
|
||||||
|
srijafyzlogutxwctqmmcenbkd
|
||||||
|
srifafyzlhguwxwctqmphenbkd
|
||||||
|
mrimajyzloguvxwctqmphenbkd
|
||||||
|
sriyafyzloguvxwcthmphejbkd
|
||||||
|
srieakyzlokuvxwctqmphenbkd
|
||||||
|
srisafyzloguhxwctqmphecbkd
|
||||||
|
srijanyzloguvxcctqmxhenbkd
|
||||||
|
srijafyzypguvxwctqmqhenbkd
|
||||||
|
sryjtfyzlvguvxwctqmphenbkd
|
||||||
|
srijafyzlsguvxwctqmqfenbkd
|
||||||
|
srijafyzlogudxwbtqwphenbkd
|
||||||
|
srijysyzloguvxwctqmpvenbkd
|
||||||
|
srijafyzloggvxwjtqmphegbkd
|
||||||
|
srijgfyzloguvxwctqmbhdnbkd
|
||||||
|
ssijufyzloguvawctqmphenbkd
|
||||||
|
skojafyzloguvxwctqmphenbnd
|
||||||
|
srijafylloguvxwcqqmpienbkd
|
||||||
|
trioafyzloguvqwctqmphenbkd
|
||||||
|
srijafydloguvxwctqmpzjnbkd
|
||||||
|
saijafvzloguvxwcqqmphenbkd
|
||||||
|
srhjapyzloguvxwctqmbhenbkd
|
||||||
|
srijafyzlfguvxwcsqmpwenbkd
|
||||||
|
shijafyzboguvxwctqmphenbmd
|
||||||
|
srizafysloguvxwrtqmphenbkd
|
||||||
|
srijafyzloguvxwciqmwhenbkj
|
||||||
|
qrijafyzloduvxwctqmphenbko
|
||||||
|
srijefyuloguvxwctqmphenbed
|
||||||
|
srijafyzlobuvxwctqmphenhbd
|
||||||
|
srijafyzloxuvxwctqmpheabkq
|
||||||
|
srijafyzloguvrwctqmghenkkd
|
||||||
|
sfisafywloguvxwctqmphenbkd
|
||||||
|
srgjafyzlogurxwctqmphenbkp
|
||||||
|
srijafhzloguvxwcjqmphenhkd
|
||||||
|
srijafyylogufxwrtqmphenbkd
|
||||||
|
srijafyzvoguvxwzkqmphenbkd
|
||||||
|
sqijafyzloguvxwctqmpheqbxd
|
||||||
|
srijafyvloguvxwctqzpherbkd
|
||||||
|
srijufyzloguvxlcsqmphenbkd
|
||||||
|
srijafykloguvxlccqmphenbkd
|
||||||
|
srijafyzloguexwcrqmphenzkd
|
||||||
|
sridifyzloguyxwctqmphenbkd
|
||||||
|
srijafyzlogfvxwctqlphenbkl
|
||||||
|
srijafyzlodqdxwctqmphenbkd
|
||||||
|
srijafyzloruvxactqmphenekd
|
||||||
|
grijafyzloguvxpctmmphenbkd
|
||||||
|
srsjakyzloguvxwctqmphvnbkd
|
||||||
|
srikafyvloguvxwrtqmphenbkd
|
||||||
|
srijafyzloguvxwctqjpserbkd
|
||||||
|
jrijafyzloguvxwctqmpgesbkd
|
||||||
|
swijafyzluguvxwctqmfhenbkd
|
||||||
|
srijanynlogovxwctqmphenbkd
|
||||||
|
jrijafyzloguvxwctymphrnbkd
|
||||||
|
srinafyzloguvewctqmphenbzd
|
||||||
|
srijakyzloguvxwctqmphcnbka
|
||||||
|
srijafyhlobuvxwctqmphenbka
|
||||||
|
srijafyzcogusxwctqmphwnbkd
|
||||||
|
srijavyzlosuvxwctqmphjnbkd
|
||||||
|
orijafyzxoguvxwcnqmphenbkd
|
||||||
|
srijafyzlogcvxwvtqmthenbkd
|
||||||
|
srijapyzloauvxwctqmphenvkd
|
||||||
|
srijaflzloguhxwctqmphenbwd
|
||||||
|
smijafyzlonuvxwctqmphenbkw
|
||||||
|
jrijafyzloguvxwclqmnhenbkd
|
||||||
|
srijaqyzloguvqwctqmphenskd
|
||||||
|
srijasyzloguvxwctqmvhenbku
|
||||||
|
crijtfyzloguvxwctqmthenbkd
|
||||||
|
srrkafyzvoguvxwctqmphenbkd
|
||||||
|
srijatyzloguvewctqmphenbld
|
||||||
|
srfjafyyloguvnwctqmphenbkd
|
||||||
|
srijafyzloguvxwctqjpbenbkt
|
||||||
|
hrijafyzooguvxwctqmphenbld
|
||||||
|
srijafbzlogscxwctqmphenbkd
|
||||||
|
srinafyzlogxvxwctqqphenbkd
|
||||||
|
slijafyzloglvxwctqmphenbdd
|
||||||
|
srijafyzlogjvxwcsqmphenbld
|
||||||
|
sryjcfyzloguvewctqmphenbkd
|
||||||
|
srijafyzloguexwctqmohknbkd
|
||||||
|
jaijafyzlogevxwctqmphenbkd
|
||||||
|
srijafbzlogavxwctqmphenbki
|
||||||
|
srijafozlogpvxwctqmphgnbkd
|
||||||
|
srijdfyzloguvxwczqmphenbkm
|
||||||
|
srijafyzlobuvxwctqmphxndkd
|
||||||
|
mrijifyzlhguvxwctqmphenbkd
|
||||||
|
srijafyzloguvxbctumphjnbkd
|
||||||
|
srijafyzloyuvxwptqmphlnbkd
|
||||||
|
arijafyzloguvxwcsqmohenbkd
|
||||||
|
srijaftzioguvxwttqmphenbkd
|
||||||
|
srijafyzlqsuvxwctqmphxnbkd
|
||||||
|
srijafyzioguvxwctqnphetbkd
|
||||||
|
prijafbzloguvxdctqmphenbkd
|
||||||
|
srijaeyzlnguvxwmtqmphenbkd
|
||||||
|
srijofyzloguvqwctqmphonbkd
|
||||||
|
srixaryzpoguvxwctqmphenbkd
|
||||||
|
srijafyzlowuvxwcwhmphenbkd
|
||||||
|
srijafydloguvxwctqmptenikd
|
||||||
|
srijqfyzlogtvfwctqmphenbkd
|
||||||
|
srijafyzloguvxlctqmpvenbgd
|
||||||
|
srijafyzlbguvxwjtqgphenbkd
|
||||||
|
srijafyzlohuqxwctqmphenbka
|
||||||
|
srijafyzroguvxictqmphynbkd
|
||||||
|
srijafyzloguvxdctjmphenjkd
|
||||||
|
srijaoczloguvxwctqmphenbjd
|
||||||
|
srajafhzloguvxwctqmphenbke
|
||||||
|
srijofyzloduvxwctqmphanbkd
|
||||||
|
srijafytloguvxwmtnmphenbkd
|
||||||
|
srijafyzuoguvxwceqmpgenbkd
|
||||||
|
rrijafyzloyuvxwctqmphlnbkd
|
||||||
|
srljafyzloguvxictqmohenbkd
|
||||||
|
srijafyzlogulxwcrqrphenbkd
|
||||||
|
srajafyzloguvxwctqmphanbke
|
||||||
|
srijafyzlhguvxwxtqmpheabkd
|
||||||
|
sxijafyzloggwxwctqmphenbkd
|
||||||
|
srijafyultguvxwctqmphinbkd
|
||||||
|
srijafyzloguvtwctqmfhvnbkd
|
||||||
|
srijafwzloruvxwctquphenbkd
|
||||||
|
srbjafyzxoguuxwctqmphenbkd
|
||||||
|
erijafyzlxguvxbctqmphenbkd
|
||||||
|
srijagyzlojubxwctqmphenbkd
|
||||||
|
srijafyzloguvxwdtqmchenakd
|
||||||
|
srijafkzlogukxwctqiphenbkd
|
||||||
|
mridafyzloguvxwctqmphenrkd
|
||||||
|
szqjafyzloguvxwctqmpheibkd
|
||||||
|
srijahyzloguvxwctcmphenekd
|
||||||
|
srijafyzloguvxwczpuphenbkd
|
||||||
|
srijafyzcoguvfwctqmphenbkq
|
||||||
|
qriiafyzloguvxwctqmpheebkd
|
||||||
|
srijpfyzloguvxlctqmphenokd
|
||||||
|
srijzfyzlotuvxwcjqmphenbkd
|
||||||
|
srinafyqloguvxwctfmphenbkd
|
||||||
|
srijafyzlogjvxpltqmphenbkd
|
||||||
|
srijafyzlotuvxwutqmphenbtd
|
||||||
|
sridafyzloguvxwctqmpyenokd
|
||||||
|
srxjafyzqogyvxwctqmphenbkd
|
||||||
|
ssijafyzzoguvxwctqmphenbad
|
||||||
|
srijafrzloguvxwctqmphekpkd
|
||||||
|
srijafyzlfgrvxactqmphenbkd
|
||||||
|
srijafyzroguvxwttqmphekbkd
|
||||||
|
srijefyzloguvxwctqmpqenbrd
|
||||||
|
srijefycloguvxwctqmchenbkd
|
||||||
|
srzjafyzloguvxwcqqmphanbkd
|
||||||
|
srijauyzlhguvxwctqmphenbgd
|
||||||
|
srijafyzloguvmwvnqmphenbkd
|
||||||
|
srihafyzloguvlwotqmphenbkd
|
||||||
|
srigafyzloguvxwctqmphennsd
|
||||||
|
sriuafzzloguvxwcuqmphenbkd
|
||||||
|
srijavuzllguvxwctqmphenbkd
|
||||||
|
srijafjzloguvlnctqmphenbkd
|
||||||
|
lrirafyzloguvxwctqmphenbld
|
||||||
|
soijarxzloguvxwctqmphenbkd
|
||||||
|
srijapyzlnguvxwctqmdhenbkd
|
||||||
|
srijafyzkogujxmctqmphenbkd
|
||||||
|
srijafuzloguvxwcsqvphenbkd
|
||||||
|
srijagyzzoguvxwctqmpvenbkd
|
||||||
|
srijafyzlovuvxwctqmrhenbxd
|
||||||
|
srijafyzqoguvxwctwmpienbkd
|
||||||
|
sxijafyzloguvxwutqmphenlkd
|
||||||
|
srijafyzlhgzvxwctqmphqnbkd
|
||||||
|
srijajyzloguvxwcbwmphenbkd
|
||||||
|
srijazyzloguvxwhtqmphenbkx
|
||||||
|
srgjafyzloguvvwctqmphdnbkd
|
||||||
|
rrivafyzloguvxjctqmphenbkd
|
||||||
|
srijifyzdoguvxwctqmphenbka
|
||||||
|
hrijafyzloguvxectqmpheybkd
|
||||||
7
2018-elixir/lib/aoc2018e.ex
Normal file
7
2018-elixir/lib/aoc2018e.ex
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
defmodule Aoc2018e do
|
||||||
|
alias Day01
|
||||||
|
def show_all do
|
||||||
|
Day01.show
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Aoc2018e.show_all
|
||||||
44
2018-elixir/lib/day01.ex
Normal file
44
2018-elixir/lib/day01.ex
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
defmodule Day01 do
|
||||||
|
defp find_recurring(data) do
|
||||||
|
Enum.reduce_while(data, {0, MapSet.new([0])}, fn term, {prev, known} ->
|
||||||
|
freq = prev + term
|
||||||
|
if MapSet.member?(known, freq) do
|
||||||
|
{:halt, freq}
|
||||||
|
else
|
||||||
|
{:cont, {freq, MapSet.put(known, freq)}}
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp parse(data) do
|
||||||
|
String.split(data, "\n")
|
||||||
|
|> Enum.map(&String.trim/1)
|
||||||
|
|> Enum.map(&String.to_integer/1)
|
||||||
|
end
|
||||||
|
|
||||||
|
def solve(data) do
|
||||||
|
data
|
||||||
|
|> parse
|
||||||
|
|> Enum.sum
|
||||||
|
end
|
||||||
|
|
||||||
|
def solve_again(data) do
|
||||||
|
data
|
||||||
|
|> parse
|
||||||
|
|> Stream.cycle
|
||||||
|
|> find_recurring
|
||||||
|
end
|
||||||
|
|
||||||
|
def show do
|
||||||
|
data = File.read!("data/01.in")
|
||||||
|
:timer.tc(fn -> solve(data) end)
|
||||||
|
|> elem(0)
|
||||||
|
|> Kernel./(1_000_000)
|
||||||
|
|> IO.inspect
|
||||||
|
:timer.tc(fn -> solve_again(data) end)
|
||||||
|
|> elem(0)
|
||||||
|
|> Kernel./(1_000_000)
|
||||||
|
|> IO.inspect
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Day01.show()
|
||||||
40
2018-elixir/lib/day02.ex
Normal file
40
2018-elixir/lib/day02.ex
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
defmodule Day02 do
|
||||||
|
defp parse(data) do
|
||||||
|
data
|
||||||
|
|> String.split("\n", trim: true)
|
||||||
|
|> Enum.map(&String.trim/1)
|
||||||
|
end
|
||||||
|
|
||||||
|
def countn(data, n) do
|
||||||
|
data
|
||||||
|
|> Enum.filter(fn s -> MapSet.size(MapSet.new(String.to_charlist(s))) != String.length(s) - n + 1 end)
|
||||||
|
|> Enum.count
|
||||||
|
end
|
||||||
|
|
||||||
|
def solve(data) do
|
||||||
|
parsed = data
|
||||||
|
|> parse
|
||||||
|
f2 = parsed
|
||||||
|
|> countn(2)
|
||||||
|
f3 = parsed
|
||||||
|
|> countn(3)
|
||||||
|
f2 * f3
|
||||||
|
end
|
||||||
|
|
||||||
|
def solve_again(data) do
|
||||||
|
data
|
||||||
|
|> parse
|
||||||
|
end
|
||||||
|
|
||||||
|
def show do
|
||||||
|
data = File.read!("data/02.in")
|
||||||
|
:timer.tc(fn -> solve(data) end)
|
||||||
|
|> elem(0)
|
||||||
|
|> Kernel./(1_000_000)
|
||||||
|
|> IO.inspect
|
||||||
|
:timer.tc(fn -> solve_again(data) end)
|
||||||
|
|> elem(0)
|
||||||
|
|> Kernel./(1_000_000)
|
||||||
|
|> IO.inspect
|
||||||
|
end
|
||||||
|
end
|
||||||
28
2018-elixir/mix.exs
Normal file
28
2018-elixir/mix.exs
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
defmodule Aoc2018e.MixProject do
|
||||||
|
use Mix.Project
|
||||||
|
|
||||||
|
def project do
|
||||||
|
[
|
||||||
|
app: :aoc2018e,
|
||||||
|
version: "0.1.0",
|
||||||
|
elixir: "~> 1.7",
|
||||||
|
start_permanent: Mix.env() == :prod,
|
||||||
|
deps: deps()
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Run "mix help compile.app" to learn about applications.
|
||||||
|
def application do
|
||||||
|
[
|
||||||
|
extra_applications: [:logger]
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Run "mix help deps" to learn about dependencies.
|
||||||
|
defp deps do
|
||||||
|
[
|
||||||
|
# {:dep_from_hexpm, "~> 0.3.0"},
|
||||||
|
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"},
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
||||||
17
2018-elixir/test/day01_test.exs
Normal file
17
2018-elixir/test/day01_test.exs
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
defmodule Day01Test do
|
||||||
|
use ExUnit.Case
|
||||||
|
doctest Day01
|
||||||
|
|
||||||
|
test "adjust frequency" do
|
||||||
|
assert Day01.solve("+1\n+1\n+1") == 3
|
||||||
|
assert Day01.solve("+1\n+1\n-2") == 0
|
||||||
|
assert Day01.solve("-1\n-2\n-3") == -6
|
||||||
|
end
|
||||||
|
|
||||||
|
test "finds recurring frequency" do
|
||||||
|
assert Day01.solve_again("+1\n-1") == 0
|
||||||
|
assert Day01.solve_again("+3\n+3\n+4\n-2\n-4") == 10
|
||||||
|
assert Day01.solve_again("-6\n+3\n+8\n+5\n-6") == 5
|
||||||
|
assert Day01.solve_again("+7\n+7\n-2\n-7\n-4") == 14
|
||||||
|
end
|
||||||
|
end
|
||||||
38
2018-elixir/test/day02_test.exs
Normal file
38
2018-elixir/test/day02_test.exs
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
defmodule Day02Test do
|
||||||
|
use ExUnit.Case
|
||||||
|
doctest Day02
|
||||||
|
|
||||||
|
setup do
|
||||||
|
puzzle_input = [
|
||||||
|
'abcdef',
|
||||||
|
'bababc',
|
||||||
|
'abbcde',
|
||||||
|
'abcccd',
|
||||||
|
'aabcdd',
|
||||||
|
'abcdee',
|
||||||
|
'ababab'
|
||||||
|
]
|
||||||
|
|> Enum.join("\n")
|
||||||
|
{:ok, puzzle_input: puzzle_input }
|
||||||
|
end
|
||||||
|
|
||||||
|
test "box id checksum", meta do
|
||||||
|
puzzle_input = [
|
||||||
|
"abcdef",
|
||||||
|
"bababc",
|
||||||
|
"abbcde",
|
||||||
|
"abcccd",
|
||||||
|
"aabcdd",
|
||||||
|
"abcdee",
|
||||||
|
"ababab"
|
||||||
|
]
|
||||||
|
assert Day02.countn(puzzle_input, 2) == 3
|
||||||
|
assert Day02.countn(puzzle_input, 3) == 4
|
||||||
|
#assert Day02.solve(puzzle_input) == 12
|
||||||
|
end
|
||||||
|
|
||||||
|
test "finds recurring frequency", meta do
|
||||||
|
puzzle_input = meta[:puzzle_input]
|
||||||
|
#assert Day02.solve_again(puzzle_input) == "fgij"
|
||||||
|
end
|
||||||
|
end
|
||||||
1
2018-elixir/test/test_helper.exs
Normal file
1
2018-elixir/test/test_helper.exs
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
ExUnit.start()
|
||||||
3
2018-python/.gitignore
vendored
Normal file
3
2018-python/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
.idea
|
||||||
|
*.pyc
|
||||||
|
__pycache__
|
||||||
52
2018-python/README.md
Normal file
52
2018-python/README.md
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
Advent of Code 2018
|
||||||
|
===================
|
||||||
|
|
||||||
|
Lösningar för #aoc2018 i Python 3 (testat mot 3.7.1).
|
||||||
|
|
||||||
|
Hjälpscript
|
||||||
|
-----------
|
||||||
|
|
||||||
|
För att köra alla lösningar:
|
||||||
|
|
||||||
|
python aoc.py
|
||||||
|
|
||||||
|
För att starta en ny dag (skapar och populerar filerna `inputs/<dagnummer>.txt`, `solutions/day_<dagnummer>.py` och
|
||||||
|
`tests/day_<dagnummer>_tests.py`):
|
||||||
|
|
||||||
|
python aoc.py <dagnummer_utan_nolla> "<namn på dag>"
|
||||||
|
|
||||||
|
Öppna puzzle input manuellt och kopiera innehållet till `inputs/<dagnummer>.txt` som ett sista manuellt steg.
|
||||||
|
|
||||||
|
För att köra separat lösning (ersätt `XX` med dagens nummer):
|
||||||
|
|
||||||
|
PYTHONPATH=$(pwd) python solutions/day_XX.py
|
||||||
|
|
||||||
|
Starta automatisk testkörare (ersätt `XX` med dagens nummer):
|
||||||
|
|
||||||
|
export PYTHONPATH=$(pwd)
|
||||||
|
ls solutions/**/*.py | entr -c -r python tests/day_XX_tests.py
|
||||||
|
|
||||||
|
Logg
|
||||||
|
----
|
||||||
|
|
||||||
|
* Dag 1: Insikten när en for-loop kan ersättas med en `sum`. xD Dagens `itertools`: `cycle()`
|
||||||
|
* Dag 2: Dagens `itertools`: `combinations()`, efter många försök att vara för smart med `zip()`.
|
||||||
|
* Dag 3: Dagens `itertools` (ja, det verkar vara ett tema!): `product()`. Två nästlade for-loopar kändes trist.
|
||||||
|
* Dag 4: Mycket text och mycket kod. Dagens `itertools`: `chain()`.
|
||||||
|
* Dag 5: Krånglade till saker genom att köra listor istället för strängar, skrev om till att istället använda en
|
||||||
|
`reduce`. Inga `itertools`. :(
|
||||||
|
* Dag 6: Längsta körtiden hittills och kan högst troligtvis optimeras.
|
||||||
|
* Dag 7: Svårtolkad uppgift. Otäckt med workers. Rant i [kodkommentar om icke hjälpsamt
|
||||||
|
exempel](https://github.com/madr/redesigned-system/blob/master/solutions/day_07.py#L63-L70).
|
||||||
|
* Dag 8: Rekursion! Invigning av `sys.setrecursionlimit()`.
|
||||||
|
* Dag 9: Harakiri.
|
||||||
|
* Dag 10: Kult med visualisering! Fick tipset att leta efter minsta bounds, och kom då fram till den magiska siffran
|
||||||
|
`10391`. Det krävdes en hel del optimering, då första versionen var slö.
|
||||||
|
* Dag 11: [Summed-area table](https://en.wikipedia.org/wiki/Summed-area_table). Lösning 2 behöver refaktoriseras för
|
||||||
|
att använda partial sum och summed-area table, den tar 8-12h att köra med brute force.
|
||||||
|
* Dag 12: Otydliga instruktioner. [Inte bara enligt mig](https://www.reddit.com/r/adventofcode/comments/a5gt7h/day12_part_1_explanation_for_the_example/),
|
||||||
|
[vad det verkar](https://www.reddit.com/r/adventofcode/comments/a5eztl/2018_day_12_solutions/).
|
||||||
|
* Day 13: Ännu en dag med ett exempel som var vilseledande för att testa ens kod.
|
||||||
|
[Rant i kodkommentar](https://github.com/madr/redesigned-system/blob/master/solutions/day_13.py#L108-L141).
|
||||||
|
* Day 14:
|
||||||
|
* Dag 15:
|
||||||
66
2018-python/aoc.py
Normal file
66
2018-python/aoc.py
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
_, day_no, name = sys.argv
|
||||||
|
except ValueError:
|
||||||
|
day_no = None
|
||||||
|
name = None
|
||||||
|
|
||||||
|
if day_no and name:
|
||||||
|
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}.in'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Day {day}: {name}'
|
||||||
|
|
||||||
|
def solve(self, puzzle_input):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
|
'''.strip().format(day=day_no, day_no=day_no.zfill(2), name=name) + '\n')
|
||||||
|
with open('tests/day_{}_tests.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()
|
||||||
|
|
||||||
|
def test_something(self):
|
||||||
|
puzzle_input = ''
|
||||||
|
assert self.solution.solve(puzzle_input) == True
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
|
'''.strip().format(day_no=day_no.zfill(2)) + '\n')
|
||||||
|
with open('inputs/{}.in'.format(day_no.zfill(2)), 'w') as i:
|
||||||
|
i.write('')
|
||||||
|
exit(0)
|
||||||
|
|
||||||
|
print('\nAdvent of Code 2018'
|
||||||
|
'\n###################'
|
||||||
|
'\n\nby Anders Ytterström (@madr)')
|
||||||
|
|
||||||
|
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
|
||||||
36
2018-python/solutions/__init__.py
Normal file
36
2018-python/solutions/__init__.py
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
import time
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
|
||||||
|
class BaseSolution:
|
||||||
|
puzzle_input = ""
|
||||||
|
input_file = None
|
||||||
|
trim_input = True
|
||||||
|
|
||||||
|
def parse_input(self, filename):
|
||||||
|
filepath = './inputs/{}'.format(filename)
|
||||||
|
with open(filepath, 'r') as f:
|
||||||
|
self.puzzle_input = f.read()
|
||||||
|
if self.trim_input:
|
||||||
|
self.puzzle_input = self.puzzle_input.strip()
|
||||||
|
|
||||||
|
def show_results(self):
|
||||||
|
self.parse_input(self.input_file)
|
||||||
|
start_time = time.monotonic()
|
||||||
|
p1 = self.solve(self.puzzle_input)
|
||||||
|
p2 = self.solve_again(self.puzzle_input)
|
||||||
|
end_time = time.monotonic()
|
||||||
|
duration = timedelta(seconds=end_time - start_time)
|
||||||
|
print('\n\n{}\n{}\n\nPart 1: {}\nPart 2: {}\n\nDuration: {}'.format(
|
||||||
|
str(self),
|
||||||
|
'-' * len(str(self)),
|
||||||
|
p1,
|
||||||
|
p2,
|
||||||
|
duration,
|
||||||
|
))
|
||||||
|
|
||||||
|
def solve(self, puzzle_input):
|
||||||
|
raise NotImplemented
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input):
|
||||||
|
raise NotImplemented
|
||||||
28
2018-python/solutions/day_01.py
Normal file
28
2018-python/solutions/day_01.py
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import itertools
|
||||||
|
|
||||||
|
from solutions import BaseSolution
|
||||||
|
|
||||||
|
|
||||||
|
class Solution(BaseSolution):
|
||||||
|
input_file = '01.in'
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return 'Day 1: Chronal Calibration'
|
||||||
|
|
||||||
|
def solve(self, puzzle_input, freq=0):
|
||||||
|
return sum(map(int, puzzle_input.splitlines()))
|
||||||
|
|
||||||
|
def solve_again(self, puzzle_input, freq=0):
|
||||||
|
freq_changes = map(int, puzzle_input.splitlines())
|
||||||
|
known = {0}
|
||||||
|
for n in itertools.cycle(freq_changes):
|
||||||
|
freq += n
|
||||||
|
if freq in known:
|
||||||
|
break
|
||||||
|
known.add(freq)
|
||||||
|
return freq
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
solution = Solution()
|
||||||
|
solution.show_results()
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue