From 6a1a537ac8f0d4fab44b806aa8986dce4aab8f9e Mon Sep 17 00:00:00 2001 From: Neil Smith <neil.git@njae.me.uk> Date: Sun, 6 Dec 2020 14:24:41 +0000 Subject: [PATCH] Added problem, some tidying --- advent24/src/advent24b.hs | 40 +++-- advent24/src/advent24tape.hs | 89 ---------- advent24/src/advent24v.hs | 78 --------- problems/day24.html | 328 +++++++++++++++++++++++++++++++++++ 4 files changed, 354 insertions(+), 181 deletions(-) delete mode 100644 advent24/src/advent24tape.hs delete mode 100644 advent24/src/advent24v.hs create mode 100644 problems/day24.html diff --git a/advent24/src/advent24b.hs b/advent24/src/advent24b.hs index 1b173b7..a259df4 100644 --- a/advent24/src/advent24b.hs +++ b/advent24/src/advent24b.hs @@ -1,4 +1,4 @@ -import Debug.Trace +-- import Debug.Trace import qualified Data.Set as S @@ -14,7 +14,7 @@ gridSize = 5 main :: IO () main = do grid0 <- readGrid - print grid0 + -- print grid0 let finalGrid = head $ drop 200 $ iterate update grid0 print $ S.size finalGrid @@ -36,27 +36,39 @@ neighbourSpaces cell = neighbourSpacesLeft :: Cell -> Grid neighbourSpacesLeft (Cell {..}) - | column == 4 && row == 3 = S.fromList [ Cell { level = (level + 1), row = r, column = 5} | r <- [1..gridSize] ] - | column == 1 = S.singleton ( Cell { level = (level - 1), row = 3, column = 2}) - | otherwise = S.singleton ( Cell { level, row, column = (column - 1)}) + | column == 4 && row == 3 = S.fromList [ Cell { level = (level + 1), + row = r, column = 5} + | r <- [1..gridSize] ] + | column == 1 = S.singleton ( Cell { level = (level - 1), + row = 3, column = 2}) + | otherwise = S.singleton ( Cell { column = (column - 1), ..}) neighbourSpacesRight :: Cell -> Grid neighbourSpacesRight (Cell {..}) - | column == 2 && row == 3 = S.fromList [ Cell { level = (level + 1), row = r, column = 1} | r <- [1..gridSize] ] - | column == 5 = S.singleton ( Cell { level = (level - 1), row = 3, column = 4}) - | otherwise = S.singleton ( Cell { level, row, column = (column + 1)}) + | column == 2 && row == 3 = S.fromList [ Cell { level = (level + 1), + row = r, column = 1} + | r <- [1..gridSize] ] + | column == 5 = S.singleton ( Cell { level = (level - 1), + row = 3, column = 4}) + | otherwise = S.singleton ( Cell { column = (column + 1), ..}) neighbourSpacesAbove :: Cell -> Grid neighbourSpacesAbove (Cell {..}) - | row == 4 && column == 3 = S.fromList [ Cell { level = (level + 1), row = 5, column = c} | c <- [1..gridSize] ] - | row == 1 = S.singleton ( Cell { level = (level - 1), row = 2, column = 3}) - | otherwise = S.singleton ( Cell { level, row = (row - 1), column}) + | row == 4 && column == 3 = S.fromList [ Cell { level = (level + 1), + row = 5, column = c} + | c <- [1..gridSize] ] + | row == 1 = S.singleton ( Cell { level = (level - 1), + row = 2, column = 3}) + | otherwise = S.singleton ( Cell { row = (row - 1), ..}) neighbourSpacesBelow :: Cell -> Grid neighbourSpacesBelow (Cell {..}) - | row == 2 && column == 3 = S.fromList [ Cell { level = (level + 1), row = 1, column = c} | c <- [1..gridSize] ] - | row == 5 = S.singleton ( Cell { level = (level - 1), row = 4, column = 3}) - | otherwise = S.singleton ( Cell { level, row = (row + 1), column}) + | row == 2 && column == 3 = S.fromList [ Cell { level = (level + 1), + row = 1, column = c} + | c <- [1..gridSize] ] + | row == 5 = S.singleton ( Cell { level = (level - 1), + row = 4, column = 3}) + | otherwise = S.singleton ( Cell { row = (row + 1), ..}) countOccupiedNeighbours :: Cell -> Grid -> Int diff --git a/advent24/src/advent24tape.hs b/advent24/src/advent24tape.hs deleted file mode 100644 index 8f6ce96..0000000 --- a/advent24/src/advent24tape.hs +++ /dev/null @@ -1,89 +0,0 @@ - --- import Debug.Trace - - -import Data.Bool (bool) -import Data.Distributive (Distributive(..)) -import Data.Functor.Rep (Representable(..), distributeRep) -import Data.Functor.Identity (Identity(..)) -import Control.Comonad.Representable.Store (Store(..), StoreT(..), store, experiment, runStore) -import Control.Comonad (Comonad(..)) - -import Data.Maybe -import Data.List -import qualified Data.Set as S -import qualified Data.Map as M - -import Control.Concurrent (threadDelay) -import Control.Monad (forM_) - -import Control.Comonad -import Control.Comonad.Cofree -import Data.Distributive -import Data.Functor.Rep -import qualified Data.Sequence as Q -import qualified Data.List.NonEmpty as NE - - -data TPossible a = TPossible - { leftward :: a - , rightward :: a - , above :: a - , below :: a - } deriving (Show, Eq, Functor) - -data TChoice = L | R | U | D - deriving (Show, Eq) - -instance Distributive TPossible where - distribute :: Functor f => f (TPossible a) -> TPossible (f a) - distribute fga = TPossible (fmap leftward fga) (fmap rightward fga) - (fmap above fga) (fmap below fga) - -instance Representable TPossible where - type Rep TPossible = TChoice - - index :: TPossible a -> TChoice -> a - index here L = leftward here - index here R = rightward here - index here U = above here - index here D = below here - - tabulate :: (TChoice -> a) -> TPossible a - tabulate describe = TPossible (describe L) (describe R) - (describe U) (describe D) - -relativePosition :: Q.Seq TChoice -> Int -relativePosition = sum . fmap valOf - where - valOf L = (-1) - valOf R = 1 - valOf U = (-10) - valOf D = 10 - -numberLine :: Cofree TPossible Int -numberLine = tabulate relativePosition - -project :: NE.NonEmpty a -> Cofree TPossible a -project l = tabulate describe - where - describe = (l NE.!!) . foldl go 0 - maxIndex = length l - 1 - minIndex = 0 - go n L = max minIndex (n - 1) - go n R = min maxIndex (n + 1) - go n U = max minIndex (n - 1) - go n D = min maxIndex (n + 1) - -elems :: NE.NonEmpty String -elems = "one" NE.:| ["two", "three"] - -path :: Q.Seq TChoice -path = Q.fromList [R, R, R, R, L] - -moveTo :: Q.Seq TChoice -> Cofree TPossible a -> Cofree TPossible a -moveTo ind = extend (\cfr -> index cfr ind) - -main :: IO () -main = print $ index (project elems) path --- main = print elems diff --git a/advent24/src/advent24v.hs b/advent24/src/advent24v.hs deleted file mode 100644 index 7707dee..0000000 --- a/advent24/src/advent24v.hs +++ /dev/null @@ -1,78 +0,0 @@ - - -import Control.Concurrent (threadDelay) - - -import Data.Functor.Compose (Compose(..)) -import Data.Vector (Vector, (!), generate) -import Data.Bool (bool) -import Data.Distributive (Distributive(..)) -import Data.Functor.Rep (Representable(..), distributeRep) -import Data.Functor.Identity (Identity(..)) -import Control.Comonad.Representable.Store (Store(..), StoreT(..), store, experiment) -import Control.Comonad (Comonad(..)) -import Control.Monad (forM_) - -type Coord = (Int, Int) -type Grid = Store (Compose Vector Vector) Bool -type Rule = Grid -> Bool - -instance Distributive Vector where - distribute = distributeRep - -instance Representable Vector where - type Rep Vector = Int - index v i = v ! (i `mod` gridSize) - tabulate = generate gridSize - -gridSize :: Int -gridSize = 20 - -neighbourCoords :: [Coord] -neighbourCoords = [(x, y) | x <- [-1, 0, 1], y <- [-1, 0, 1], (x, y) /= (0, 0)] - -addCoords :: Coord -> Coord -> Coord -addCoords (x, y) (x', y') = (x + x', y + y') - -basicRule :: Rule -basicRule g = numNeighboursAlive == 3 || (alive && numNeighboursAlive == 2) - where - alive = extract g - neighbours = experiment (at neighbourCoords) g - numNeighboursAlive = length (filter id neighbours) - -step :: Rule -> Grid -> Grid -step = extend - -render :: Grid -> String -render (StoreT (Identity (Compose g)) _) = foldMap ((++ "\n") . foldMap (bool "." "#")) g - -mkGrid :: [Coord] -> Grid -mkGrid xs = store (`elem` xs) (0, 0) - -at :: [Coord] -> Coord -> [Coord] -coords `at` origin = map (addCoords origin) coords - -glider, blinker, beacon :: [Coord] -glider = [(1, 0), (2, 1), (0, 2), (1, 2), (2, 2)] -blinker = [(0, 0), (1, 0), (2, 0)] -beacon = [(0, 0), (1, 0), (0, 1), (3, 2), (2, 3), (3, 3)] - - - - - - -tickTime :: Int -tickTime = 200000 - -start :: Grid -start = mkGrid $ - glider `at` (0, 0) - ++ beacon `at` (15, 5) - -main :: IO () -main = forM_ (iterate (step basicRule) start) $ \grid -> do - putStr "\ESC[2J" -- Clear terminal screen - putStrLn (render grid) - threadDelay tickTime \ No newline at end of file diff --git a/problems/day24.html b/problems/day24.html new file mode 100644 index 0000000..011bfd2 --- /dev/null +++ b/problems/day24.html @@ -0,0 +1,328 @@ +<!DOCTYPE html> +<html lang="en-us"> +<head> +<meta charset="utf-8"/> +<title>Day 24 - Advent of Code 2019</title> +<!--[if lt IE 9]><script src="/static/html5.js"></script><![endif]--> +<link href='//fonts.googleapis.com/css?family=Source+Code+Pro:300&subset=latin,latin-ext' rel='stylesheet' type='text/css'/> +<link rel="stylesheet" type="text/css" href="/static/style.css?25"/> +<link rel="stylesheet alternate" type="text/css" href="/static/highcontrast.css?0" title="High Contrast"/> +<link rel="shortcut icon" href="/favicon.png"/> +</head><!-- + + + + +Oh, hello! Funny seeing you here. + +I appreciate your enthusiasm, but you aren't going to find much down here. +There certainly aren't clues to any of the puzzles. The best surprises don't +even appear in the source until you unlock them for real. + +Please be careful with automated requests; I'm not a massive company, and I can +only take so much traffic. Please be considerate so that everyone gets to play. + +If you're curious about how Advent of Code works, it's running on some custom +Perl code. Other than a few integrations (auth, analytics, social media), I +built the whole thing myself, including the design, animations, prose, and all +of the puzzles. + +The puzzles are most of the work; preparing a new calendar and a new set of +puzzles each year takes all of my free time for 4-5 months. A lot of effort +went into building this thing - I hope you're enjoying playing it as much as I +enjoyed making it for you! + +If you'd like to hang out, I'm @ericwastl on Twitter. + +- Eric Wastl + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +--> +<body> +<header><div><h1 class="title-global"><a href="/">Advent of Code</a></h1><nav><ul><li><a href="/2019/about">[About]</a></li><li><a href="/2019/events">[Events]</a></li><li><a href="https://teespring.com/stores/advent-of-code" target="_blank">[Shop]</a></li><li><a href="/2019/settings">[Settings]</a></li><li><a href="/2019/auth/logout">[Log Out]</a></li></ul></nav><div class="user">Neil Smith <a href="/2019/support" class="supporter-badge" title="Advent of Code Supporter">(AoC++)</a> <span class="star-count">48*</span></div></div><div><h1 class="title-event"> <span class="title-event-wrap">0x0000|</span><a href="/2019">2019</a><span class="title-event-wrap"></span></h1><nav><ul><li><a href="/2019">[Calendar]</a></li><li><a href="/2019/support">[AoC++]</a></li><li><a href="/2019/sponsors">[Sponsors]</a></li><li><a href="/2019/leaderboard">[Leaderboard]</a></li><li><a href="/2019/stats">[Stats]</a></li></ul></nav></div></header> + +<div id="sidebar"> +<div id="sponsor"><div class="quiet">Our <a href="/2019/sponsors">sponsors</a> help make Advent of Code possible:</div><div class="sponsor"><a href="https://www.twilio.com/quest" target="_blank" onclick="if(ga)ga('send','event','sponsor','sidebar',this.href);" rel="noopener">TwilioQuest</a> - Play Advent of Code and earn rad loot in TwilioQuest, a developer RPG for Mac, Windows, and Linux. Learn JavaScript, Python, git, APIs for SMS, VoIP, or WhatsApp, and much more.</div></div> +</div><!--/sidebar--> + +<main> +<script>window.addEventListener('click', function(e,s,r){if(e.target.nodeName==='CODE'&&e.detail===3){s=window.getSelection();s.removeAllRanges();r=document.createRange();r.selectNodeContents(e.target);s.addRange(r);}});</script> +<article class="day-desc"><h2>--- Day 24: Planet of Discord ---</h2><p>You land on <a href="https://en.wikipedia.org/wiki/Eris_(dwarf_planet)">Eris</a>, your last stop before reaching Santa. As soon as you do, your sensors start picking up strange life forms moving around: Eris is infested with <a href="https://www.nationalgeographic.org/thisday/sep9/worlds-first-computer-bug/">bugs</a>! With an <span title="For a sad version of this story, look up Voices of a Distant Star.">over 24-hour roundtrip</span> for messages between you and Earth, you'll have to deal with this problem on your own.</p> +<p>Eris isn't a very large place; a scan of the entire area fits into a 5x5 grid (your puzzle input). The scan shows <em>bugs</em> (<code>#</code>) and <em>empty spaces</em> (<code>.</code>).</p> +<p>Each <em>minute</em>, The bugs live and die based on the number of bugs in the <em>four adjacent tiles</em>:</p> +<ul> +<li>A bug <em>dies</em> (becoming an empty space) unless there is <em>exactly one</em> bug adjacent to it.</li> +<li>An empty space <em>becomes infested</em> with a bug if <em>exactly one or two</em> bugs are adjacent to it.</li> +</ul> +<p>Otherwise, a bug or empty space remains the same. (Tiles on the edges of the grid have fewer than four adjacent tiles; the missing tiles count as empty space.) This process happens in every location <em>simultaneously</em>; that is, within the same minute, the number of adjacent bugs is counted for every tile first, and then the tiles are updated.</p> +<p>Here are the first few minutes of an example scenario:</p> +<pre><code>Initial state: +....# +#..#. +#..## +..#.. +#.... + +After 1 minute: +#..#. +####. +###.# +##.## +.##.. + +After 2 minutes: +##### +....# +....# +...#. +#.### + +After 3 minutes: +#.... +####. +...## +#.##. +.##.# + +After 4 minutes: +####. +....# +##..# +..... +##... +</code></pre> +<p>To understand the nature of the bugs, watch for the first time a layout of bugs and empty spaces <em>matches any previous layout</em>. In the example above, the first layout to appear twice is:</p> +<pre><code>..... +..... +..... +#.... +.#... +</code></pre> +<p>To calculate the <em>biodiversity rating</em> for this layout, consider each tile left-to-right in the top row, then left-to-right in the second row, and so on. Each of these tiles is worth biodiversity points equal to <em>increasing powers of two</em>: 1, 2, 4, 8, 16, 32, and so on. Add up the biodiversity points for tiles with bugs; in this example, the 16th tile (<code>32768</code> points) and 22nd tile (<code>2097152</code> points) have bugs, a total biodiversity rating of <code><em>2129920</em></code>.</p> +<p><em>What is the biodiversity rating for the first layout that appears twice?</em></p> +</article> +<p>Your puzzle answer was <code>17863711</code>.</p><article class="day-desc"><h2 id="part2">--- Part Two ---</h2><p>After careful analysis, one thing is certain: <em>you have no idea where all these bugs are coming from</em>.</p> +<p>Then, you remember: Eris is an old <a href="20">Plutonian</a> settlement! Clearly, the bugs are coming from recursively-folded space.</p> +<p>This 5x5 grid is <em>only one</em> level in an <em>infinite</em> number of recursion levels. The tile in the middle of the grid is actually another 5x5 grid, the grid in your scan is contained as the middle tile of a larger 5x5 grid, and so on. Two levels of grids look like this:</p> +<pre><code> | | | | + | | | | + | | | | +-----+-----+---------+-----+----- + | | | | + | | | | + | | | | +-----+-----+---------+-----+----- + | | | | | | | | + | |-+-+-+-+-| | + | | | | | | | | + | |-+-+-+-+-| | + | | | |?| | | | + | |-+-+-+-+-| | + | | | | | | | | + | |-+-+-+-+-| | + | | | | | | | | +-----+-----+---------+-----+----- + | | | | + | | | | + | | | | +-----+-----+---------+-----+----- + | | | | + | | | | + | | | | +</code></pre> +<p>(To save space, some of the tiles are not drawn to scale.) Remember, this is only a small part of the infinitely recursive grid; there is a 5x5 grid that contains this diagram, and a 5x5 grid that contains that one, and so on. Also, the <code>?</code> in the diagram contains another 5x5 grid, which itself contains another 5x5 grid, and so on.</p> +<p>The scan you took (your puzzle input) shows where the bugs are <em>on a single level</em> of this structure. The middle tile of your scan is empty to accommodate the recursive grids within it. Initially, no other levels contain bugs.</p> +<p>Tiles still count as <em>adjacent</em> if they are directly <em>up, down, left, or right</em> of a given tile. Some tiles have adjacent tiles at a recursion level above or below its own level. For example:</p> +<pre><code> | | | | + 1 | 2 | 3 | 4 | 5 + | | | | +-----+-----+---------+-----+----- + | | | | + 6 | 7 | 8 | 9 | 10 + | | | | +-----+-----+---------+-----+----- + | |A|B|C|D|E| | + | |-+-+-+-+-| | + | |F|G|H|I|J| | + | |-+-+-+-+-| | + 11 | 12 |K|L|?|N|O| 14 | 15 + | |-+-+-+-+-| | + | |P|Q|R|S|T| | + | |-+-+-+-+-| | + | |U|V|W|X|Y| | +-----+-----+---------+-----+----- + | | | | + 16 | 17 | 18 | 19 | 20 + | | | | +-----+-----+---------+-----+----- + | | | | + 21 | 22 | 23 | 24 | 25 + | | | | +</code></pre> +<ul> +<li>Tile 19 has four adjacent tiles: 14, 18, 20, and 24.</li> +<li>Tile G has four adjacent tiles: B, F, H, and L.</li> +<li>Tile D has four adjacent tiles: 8, C, E, and I.</li> +<li>Tile E has four adjacent tiles: 8, D, 14, and J.</li> +<li>Tile 14 has <em>eight</em> adjacent tiles: 9, E, J, O, T, Y, 15, and 19.</li> +<li>Tile N has <em>eight</em> adjacent tiles: I, O, S, and five tiles within the sub-grid marked <code>?</code>.</li> +</ul> +<p>The rules about bugs living and dying are the same as before.</p> +<p>For example, consider the same initial state as above:</p> +<pre><code>....# +#..#. +#.?## +..#.. +#.... +</code></pre> +<p>The center tile is drawn as <code>?</code> to indicate the next recursive grid. Call this level 0; the grid within this one is level 1, and the grid that contains this one is level -1. Then, after <em>ten</em> minutes, the grid at each level would look like this:</p> +<pre><code>Depth -5: +..#.. +.#.#. +..?.# +.#.#. +..#.. + +Depth -4: +...#. +...## +..?.. +...## +...#. + +Depth -3: +#.#.. +.#... +..?.. +.#... +#.#.. + +Depth -2: +.#.## +....# +..?.# +...## +.###. + +Depth -1: +#..## +...## +..?.. +...#. +.#### + +Depth 0: +.#... +.#.## +.#?.. +..... +..... + +Depth 1: +.##.. +#..## +..?.# +##.## +##### + +Depth 2: +###.. +##.#. +#.?.. +.#.## +#.#.. + +Depth 3: +..### +..... +#.?.. +#.... +#...# + +Depth 4: +.###. +#..#. +#.?.. +##.#. +..... + +Depth 5: +####. +#..#. +#.?#. +####. +..... +</code></pre> +<p>In this example, after 10 minutes, a total of <code><em>99</em></code> bugs are present.</p> +<p>Starting with your scan, <em>how many bugs are present after 200 minutes?</em></p> +</article> +<p>Your puzzle answer was <code>1937</code>.</p><p class="day-success">Both parts of this puzzle are complete! They provide two gold stars: **</p> +<p>At this point, you should <a href="/2019">return to your Advent calendar</a> and try another puzzle.</p> +<p>If you still want to see it, you can <a href="24/input" target="_blank">get your puzzle input</a>.</p> +<p>You can also <span class="share">[Share<span class="share-content">on + <a href="https://twitter.com/intent/tweet?text=I%27ve+completed+%22Planet+of+Discord%22+%2D+Day+24+%2D+Advent+of+Code+2019&url=https%3A%2F%2Fadventofcode%2Ecom%2F2019%2Fday%2F24&related=ericwastl&hashtags=AdventOfCode" target="_blank">Twitter</a> + <a href="javascript:void(0);" onclick="var mastodon_instance=prompt('Mastodon Instance / Server Name?'); if(typeof mastodon_instance==='string' && mastodon_instance.length){this.href='https://'+mastodon_instance+'/share?text=I%27ve+completed+%22Planet+of+Discord%22+%2D+Day+24+%2D+Advent+of+Code+2019+%23AdventOfCode+https%3A%2F%2Fadventofcode%2Ecom%2F2019%2Fday%2F24'}else{return false;}" target="_blank">Mastodon</a +></span>]</span> this puzzle.</p> +</main> + +<!-- ga --> +<script> +(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ +(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), +m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) +})(window,document,'script','//www.google-analytics.com/analytics.js','ga'); +ga('create', 'UA-69522494-1', 'auto'); +ga('set', 'anonymizeIp', true); +ga('send', 'pageview'); +</script> +<!-- /ga --> +</body> +</html> \ No newline at end of file -- 2.43.0