aboutsummaryrefslogtreecommitdiff
path: root/racket/aoc2021/day-06
diff options
context:
space:
mode:
Diffstat (limited to 'racket/aoc2021/day-06')
-rw-r--r--racket/aoc2021/day-06/day-06.ex35
-rw-r--r--racket/aoc2021/day-06/day-06.livemd152
-rw-r--r--racket/aoc2021/day-06/day-06.rkt27
-rw-r--r--racket/aoc2021/day-06/input.txt1
4 files changed, 215 insertions, 0 deletions
diff --git a/racket/aoc2021/day-06/day-06.ex b/racket/aoc2021/day-06/day-06.ex
new file mode 100644
index 0000000..efe10e4
--- /dev/null
+++ b/racket/aoc2021/day-06/day-06.ex
@@ -0,0 +1,35 @@
+defmodule Day06 do
+ def next_day(state) do
+ with one_day_older <- Enum.into(state, %{}, fn {k, v} -> {k - 1, v} end),
+ {n, s} <- Map.pop(one_day_older, -1, 0) do
+ Map.update(s, 6, n, &(&1 + n))
+ |> Map.put(8, n)
+ end
+ end
+end
+
+school =
+ with {:ok, data} <- File.read("input.txt") do
+ data
+ |> String.trim()
+ |> String.split(",")
+ |> Enum.map(&String.to_integer/1)
+ end
+
+starting_state = Enum.frequencies(school)
+
+Enum.reduce(
+ Enum.to_list(1..80),
+ starting_state,
+ fn _, acc -> Day06.next_day(acc) end
+)
+|> Enum.reduce(0, fn {_, v}, acc -> v + acc end)
+|> IO.inspect()
+
+Enum.reduce(
+ Enum.to_list(1..256),
+ starting_state,
+ fn _, acc -> Day06.next_day(acc) end
+)
+|> Enum.reduce(0, fn {_, v}, acc -> v + acc end)
+|> IO.inspect()
diff --git a/racket/aoc2021/day-06/day-06.livemd b/racket/aoc2021/day-06/day-06.livemd
new file mode 100644
index 0000000..5ab794f
--- /dev/null
+++ b/racket/aoc2021/day-06/day-06.livemd
@@ -0,0 +1,152 @@
+<!-- vim: set syntax=markdown: -->
+<!-- livebook:{"persist_outputs":true} -->
+
+# Advent of Code 2021, Day 6
+
+## Short problem summary
+
+A school of fish reproduce according to the following rules:
+
+* Every fish has an "internal timer"
+* The timer decrements by one every day
+* If the timer is at 0, the timer is instead reset to 6,
+ and a new fish with an internal timer of 8 is added to the school
+
+Questions:
+
+1. How many fish are in the school after 80 days?
+2. How many fish are in the school after 256 days?
+
+## Setting up
+
+The initial input is a list of fish, represented by the initial value of their internal timer:
+
+```elixir
+school =
+ with {:ok, data} <- File.read("day-06/input.txt") do
+ data
+ |> String.trim()
+ |> String.split(",")
+ |> Enum.map(&String.to_integer/1)
+ end
+```
+
+```output
+[5, 4, 3, 5, 1, 1, 2, 1, 2, 1, 3, 2, 3, 4, 5, 1, 2, 4, 3, 2, 5, 1, 4, 2, 1, 1, 2, 5, 4, 4, 4, 1, 5,
+ 4, 5, 2, 1, 2, 5, 5, 4, 1, 3, 1, 4, 2, 4, 2, 5, 1, ...]
+```
+
+Every fish with the same starting internal timer will reproduce at the same time,
+as will all of the children of those fish and their children, and so forth,
+so we don't need to track individual fish; we just need to group the fish based on
+their starting internal timer and track those groups throughout the simulation.
+
+```elixir
+starting_state = Enum.frequencies(school)
+```
+
+```output
+%{1 => 88, 2 => 45, 3 => 54, 4 => 52, 5 => 61}
+```
+
+Every time a day passes, the following things happen:
+
+* All the internal timers decrement by 1
+* The group of fish with an internal timer of -1 is reset to 6
+ (added to any existing fish whose timers are already at 6),
+ and an equal-sized group of fish with internal timer 8 is added
+
+```elixir
+defmodule Day06 do
+ def next_day(state) do
+ with one_day_older <- Enum.into(state, %{}, fn {k, v} -> {k - 1, v} end),
+ {n, s} <- Map.pop(one_day_older, -1, 0) do
+ Map.update(s, 6, n, &(&1 + n))
+ |> Map.put(8, n)
+ end
+ end
+end
+
+day1 = Day06.next_day(starting_state)
+```
+
+```output
+%{0 => 88, 1 => 45, 2 => 54, 3 => 52, 4 => 61, 6 => 0, 8 => 0}
+```
+
+After the first day there's not any fish old enough to reproduce yet, but after the second day,
+
+```elixir
+day2 = Day06.next_day(day1)
+```
+
+```output
+%{0 => 45, 1 => 54, 2 => 52, 3 => 61, 5 => 0, 6 => 88, 7 => 0, 8 => 88}
+```
+
+The 88 fish whose timers were at 0 have rolled over to 6 and created 88 more fish with timers at 8.
+
+## Solution
+
+Now we just need to apply the transformation function the necessary number
+of times and sum up the total population in the end:
+
+```elixir
+part1_state =
+ Enum.reduce(
+ Enum.to_list(1..80),
+ starting_state,
+ fn _, acc -> Day06.next_day(acc) end
+ )
+ |> IO.inspect()
+ |> Enum.reduce(0, fn {_, v}, acc -> v + acc end)
+```
+
+```output
+%{
+ 0 => 24572,
+ 1 => 43660,
+ 2 => 30525,
+ 3 => 48458,
+ 4 => 41318,
+ 5 => 47697,
+ 6 => 57731,
+ 7 => 23218,
+ 8 => 33738
+}
+```
+
+```output
+350917
+```
+
+Identically for part 2,
+
+```elixir
+part2_state =
+ Enum.reduce(
+ Enum.to_list(1..256),
+ starting_state,
+ fn _, acc -> Day06.next_day(acc) end
+ )
+ |> IO.inspect()
+ |> Enum.reduce(0, fn {_, v}, acc -> v + acc end)
+```
+
+```output
+%{
+ 0 => 139170477178,
+ 1 => 162618979933,
+ 2 => 169389497028,
+ 3 => 188231720546,
+ 4 => 207908029672,
+ 5 => 217769615201,
+ 6 => 252681772250,
+ 7 => 117023886952,
+ 8 => 138124736869
+}
+```
+
+```output
+1592918715629
+```
diff --git a/racket/aoc2021/day-06/day-06.rkt b/racket/aoc2021/day-06/day-06.rkt
new file mode 100644
index 0000000..d8855ba
--- /dev/null
+++ b/racket/aoc2021/day-06/day-06.rkt
@@ -0,0 +1,27 @@
+#lang racket
+(require advent-of-code
+ list-utils
+ threading
+ racket/hash)
+
+(define fish-data
+ (~> (open-aoc-input (find-session) 2021 6 #:cache (string->path "./cache"))
+ port->string
+ string-trim
+ (string-split ",")
+ (map string->number _)))
+
+(define (simulate-fish time-period)
+ (for/fold ([state (frequencies fish-data)] #:result (~> state hash-values (apply + _)))
+ ([day (inclusive-range 1 time-period)])
+ (define day-older-fish
+ (for/hash ([(days pop) (in-hash state)])
+ (values (sub1 days) pop)))
+ (define breeding-fish (hash-ref day-older-fish -1 0))
+ (hash-union (hash-remove day-older-fish -1) (hash 8 breeding-fish 6 breeding-fish) #:combine +)))
+
+;; part 1
+(simulate-fish 80)
+
+;; part 2
+(simulate-fish 256)
diff --git a/racket/aoc2021/day-06/input.txt b/racket/aoc2021/day-06/input.txt
new file mode 100644
index 0000000..ba3c3cc
--- /dev/null
+++ b/racket/aoc2021/day-06/input.txt
@@ -0,0 +1 @@
+5,4,3,5,1,1,2,1,2,1,3,2,3,4,5,1,2,4,3,2,5,1,4,2,1,1,2,5,4,4,4,1,5,4,5,2,1,2,5,5,4,1,3,1,4,2,4,2,5,1,3,5,3,2,3,1,1,4,5,2,4,3,1,5,5,1,3,1,3,2,2,4,1,3,4,3,3,4,1,3,4,3,4,5,2,1,1,1,4,5,5,1,1,3,2,4,1,2,2,2,4,1,2,5,5,1,4,5,2,4,2,1,5,4,1,3,4,1,2,3,1,5,1,3,4,5,4,1,4,3,3,3,5,5,1,1,5,1,5,5,1,5,2,1,5,1,2,3,5,5,1,3,3,1,5,3,4,3,4,3,2,5,2,1,2,5,1,1,1,1,5,1,1,4,3,3,5,1,1,1,4,4,1,3,3,5,5,4,3,2,1,2,2,3,4,1,5,4,3,1,1,5,1,4,2,3,2,2,3,4,1,3,4,1,4,3,4,3,1,3,3,1,1,4,1,1,1,4,5,3,1,1,2,5,2,5,1,5,3,3,1,3,5,5,1,5,4,3,1,5,1,1,5,5,1,1,2,5,5,5,1,1,3,2,2,3,4,5,5,2,5,4,2,1,5,1,4,4,5,4,4,1,2,1,1,2,3,5,5,1,3,1,4,2,3,3,1,4,1,1