Commit 5072f953 authored by Neil Smith's avatar Neil Smith
Browse files

Done day 23

parent ef99d985
# This YAML file describes your package. Stack will automatically generate a
# Cabal file when you run `stack build`. See the hpack website for help with
# this file: <https://github.com/sol/hpack>.
name: advent23
synopsis: Advent of Code
version: '0.0.1'
default-extensions:
- AllowAmbiguousTypes
- ApplicativeDo
- BangPatterns
- BlockArguments
- DataKinds
- DeriveFoldable
- DeriveFunctor
- DeriveGeneric
- DeriveTraversable
- EmptyCase
- FlexibleContexts
- FlexibleInstances
- FunctionalDependencies
- GADTs
- GeneralizedNewtypeDeriving
- ImplicitParams
- KindSignatures
- LambdaCase
- MonadComprehensions
- MonoLocalBinds
- MultiParamTypeClasses
- MultiWayIf
- NamedFieldPuns
- NegativeLiterals
- NumDecimals
# - OverloadedLists
- OverloadedStrings
- PartialTypeSignatures
- PatternGuards
- PatternSynonyms
- PolyKinds
- RankNTypes
- RecordWildCards
- ScopedTypeVariables
- TemplateHaskell
- TransformListComp
- TupleSections
- TypeApplications
- TypeFamilies
- TypeInType
- TypeOperators
- ViewPatterns
executables:
advent23:
main: advent23.hs
source-dirs: src
dependencies:
- base >= 2 && < 6
- pointedlist
- lens
- vector
-- import Debug.Trace
import qualified Data.List.PointedList.Circular as P
import Control.Lens
import Data.Maybe
import Data.Char (digitToInt)
import Control.Monad
import Control.Monad.ST
import Data.STRef
import qualified Data.Vector.Unboxed.Mutable as V
puzzleInput :: [Int]
puzzleInput = map digitToInt "538914762"
-- puzzleInput = map digitToInt "389125467" -- example
main :: IO ()
main =
do putStrLn $ part1 puzzleInput
print $ part2 puzzleInput
part1 nums = label $ playN cups 100
where cups = fromJust $ P.fromList nums
part2 nums = a * b
where finalCups = runGame nums 1000000 10000000
(a, b) = clockwiseOf1 finalCups
label cups = concatMap show $ tail $ takeRight (P.length cups) atOne
where atOne = fromJust $ P.find 1 cups
playN cups n = (iterate playOne cups) !! n
playOne cups = P.next replacedAtCurrent
where current = cups ^. P.focus
held = takeRight 3 $ P.next cups
shorter = fromJust $ dropRight 3 $ P.next cups
destination = validDestination (current - 1) 9 held
shorterAtDestination = fromJust $ P.find destination shorter
replaced = foldr P.insertRight shorterAtDestination $ reverse held
replacedAtCurrent = fromJust $ P.find current replaced
validDestination 0 max missing = validDestination max max missing
validDestination n max missing
| n `elem` missing = validDestination (n - 1) max missing
| otherwise = n
takeRight :: Int -> P.PointedList a -> [a]
takeRight 0 _ = []
takeRight n xs = (xs ^. P.focus):(takeRight (n - 1) $ P.next xs)
dropRight :: Int -> P.PointedList a -> Maybe (P.PointedList a)
dropRight 0 xs = Just xs
dropRight n xxs = case (P.deleteRight xxs) of
Just xs -> dropRight (n - 1) xs
Nothing -> Nothing
clockwiseOf1 cups = (a, b)
where a = cups!!1
b = cups!!a
runGame :: [Int] -> Int -> Int -> [Int]
runGame seed cupsNeeded roundsNeeded =
runST $
do cups <- seedGame seed cupsNeeded
gameLoop roundsNeeded cupsNeeded cups
mapM (V.read cups) [0..cupsNeeded]
seedGame :: [Int] -> Int -> ST s (V.MVector s Int)
seedGame seed cupsNeeded =
do cups <- V.new (cupsNeeded + 1)
let extended = seed ++ [10, 11..]
forM_ [0..cupsNeeded] $ \i -> V.write cups i (i + 1)
forM_ (zip seed $ tail extended) $ \(i, j) -> V.write cups i j
V.write cups 0 (head seed)
let end = if cupsNeeded > (length seed)
then cupsNeeded
else last seed
V.write cups end (head seed)
return cups
gameLoop targetRound maxCups cups =
do forM_ [1..targetRound]
(\_ -> gameStep maxCups cups)
return ()
gameStep :: Int -> V.MVector s Int -> ST s ()
gameStep maxCups cups =
do current <- V.read cups 0
held1 <- V.read cups current
held2 <- V.read cups held1
held3 <- V.read cups held2
afterHeld <- V.read cups held3
-- close the loop, removing the held cups
V.write cups current afterHeld
let destination =
validDestination (current - 1) maxCups [held1, held2, held3]
afterDestination <- V.read cups destination
-- make the held come after the destination
V.write cups destination held1
-- make the end of the held point into the rest of the loop
V.write cups held3 afterDestination
-- advance current
nextCup <- V.read cups current
-- and store it
V.write cups 0 nextCup
return ()
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8"/>
<title>Day 23 - Advent of Code 2020</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="/2020/about">[About]</a></li><li><a href="/2020/events">[Events]</a></li><li><a href="https://teespring.com/stores/advent-of-code" target="_blank">[Shop]</a></li><li><a href="/2020/settings">[Settings]</a></li><li><a href="/2020/auth/logout">[Log Out]</a></li></ul></nav><div class="user">Neil Smith <a href="/2020/support" class="supporter-badge" title="Advent of Code Supporter">(AoC++)</a> <span class="star-count">46*</span></div></div><div><h1 class="title-event">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="title-event-wrap"></span><a href="/2020">2020</a><span class="title-event-wrap"></span></h1><nav><ul><li><a href="/2020">[Calendar]</a></li><li><a href="/2020/support">[AoC++]</a></li><li><a href="/2020/sponsors">[Sponsors]</a></li><li><a href="/2020/leaderboard">[Leaderboard]</a></li><li><a href="/2020/stats">[Stats]</a></li></ul></nav></div></header>
<div id="sidebar">
<div id="sponsor"><div class="quiet">Our <a href="/2020/sponsors">sponsors</a> help make Advent of Code possible:</div><div class="sponsor"><a href="https://github.com/" target="_blank" onclick="if(ga)ga('send','event','sponsor','sidebar',this.href);" rel="noopener">GitHub</a> - We&apos;re hiring engineers to make GitHub fast. Interested? Email fast@github.com with details of exceptional performance work you&apos;ve done in the past.</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 23: Crab Cups ---</h2><p>The small crab challenges <em>you</em> to a game! The crab is going to mix up some cups, and you have to predict where they'll end up.</p>
<p>The cups will be arranged in a circle and labeled <em>clockwise</em> (your puzzle input). For example, if your labeling were <code>32415</code>, there would be five cups in the circle; going clockwise around the circle from the first cup, the cups would be labeled <code>3</code>, <code>2</code>, <code>4</code>, <code>1</code>, <code>5</code>, and then back to <code>3</code> again.</p>
<p>Before the crab starts, it will designate the first cup in your list as the <em>current cup</em>. The crab is then going to do <em>100 moves</em>.</p>
<p>Each <em>move</em>, the crab does the following actions:</p>
<ul>
<li>The crab picks up the <em>three cups</em> that are immediately <em>clockwise</em> of the <em>current cup</em>. They are removed from the circle; cup spacing is adjusted as necessary to maintain the circle.</li>
<li>The crab selects a <em>destination cup</em>: the cup with a <em>label</em> equal to the <em>current cup's</em> label minus one. If this would select one of the cups that was just picked up, the crab will keep subtracting one until it finds a cup that wasn't just picked up. If at any point in this process the value goes below the lowest value on any cup's label, it <em>wraps around</em> to the highest value on any cup's label instead.</li>
<li>The crab places the cups it just picked up so that they are <em>immediately clockwise</em> of the destination cup. They keep the same order as when they were picked up.</li>
<li>The crab selects a new <em>current cup</em>: the cup which is immediately clockwise of the current cup.</li>
</ul>
<p>For example, suppose your cup labeling were <code>389125467</code>. If the crab were to do merely 10 moves, the following changes would occur:</p>
<pre><code>-- move 1 --
cups: (3) 8 9 1 2 5 4 6 7
pick up: 8, 9, 1
destination: 2
-- move 2 --
cups: 3 (2) 8 9 1 5 4 6 7
pick up: 8, 9, 1
destination: 7
-- move 3 --
cups: 3 2 (5) 4 6 7 8 9 1
pick up: 4, 6, 7
destination: 3
-- move 4 --
cups: 7 2 5 (8) 9 1 3 4 6
pick up: 9, 1, 3
destination: 7
-- move 5 --
cups: 3 2 5 8 (4) 6 7 9 1
pick up: 6, 7, 9
destination: 3
-- move 6 --
cups: 9 2 5 8 4 (1) 3 6 7
pick up: 3, 6, 7
destination: 9
-- move 7 --
cups: 7 2 5 8 4 1 (9) 3 6
pick up: 3, 6, 7
destination: 8
-- move 8 --
cups: 8 3 6 7 4 1 9 (2) 5
pick up: 5, 8, 3
destination: 1
-- move 9 --
cups: 7 4 1 5 8 3 9 2 (6)
pick up: 7, 4, 1
destination: 5
-- move 10 --
cups: (5) 7 4 1 8 3 9 2 6
pick up: 7, 4, 1
destination: 3
-- final --
cups: 5 (8) 3 7 4 1 9 2 6
</code></pre>
<p>In the above example, the cups' values are the labels as they appear moving clockwise around the circle; the <em>current cup</em> is marked with <code>( )</code>.</p>
<p>After the crab is done, what order will the cups be in? Starting <em>after the cup labeled <code>1</code></em>, collect the other cups' labels clockwise into a single string with no extra characters; each number except <code>1</code> should appear exactly once. In the above example, after 10 moves, the cups clockwise from <code>1</code> are labeled <code>9</code>, <code>2</code>, <code>6</code>, <code>5</code>, and so on, producing <em><code>92658374</code></em>. If the crab were to complete all 100 moves, the order after cup <code>1</code> would be <em><code>67384529</code></em>.</p>
<p>Using your labeling, simulate 100 moves. <em>What are the labels on the cups after cup <code>1</code>?</em></p>
</article>
<p>Your puzzle answer was <code>54327968</code>.</p><article class="day-desc"><h2 id="part2">--- Part Two ---</h2><p>Due to what you can only assume is a mistranslation (you're <span title="If I were going for a programming language pun here, I'd say you were a little... RUSTy.">not exactly fluent in Crab</span>), you are quite surprised when the crab starts arranging <em>many</em> cups in a circle on your raft - <em>one million</em> (<code>1000000</code>) in total.</p>
<p>Your labeling is still correct for the first few cups; after that, the remaining cups are just numbered in an increasing fashion starting from the number after the highest number in your list and proceeding one by one until one million is reached. (For example, if your labeling were <code>54321</code>, the cups would be numbered <code>5</code>, <code>4</code>, <code>3</code>, <code>2</code>, <code>1</code>, and then start counting up from <code>6</code> until one million is reached.) In this way, every number from one through one million is used exactly once.</p>
<p>After discovering where you made the mistake in translating Crab Numbers, you realize the small crab isn't going to do merely 100 moves; the crab is going to do <em>ten million</em> (<code>10000000</code>) moves!</p>
<p>The crab is going to hide your <em class="star">stars</em> - one each - under the <em>two cups that will end up immediately clockwise of cup <code>1</code></em>. You can have them if you predict what the labels on those cups will be when the crab is finished.</p>
<p>In the above example (<code>389125467</code>), this would be <code>934001</code> and then <code>159792</code>; multiplying these together produces <em><code>149245887792</code></em>.</p>
<p>Determine which two cups will end up immediately clockwise of cup <code>1</code>. <em>What do you get if you multiply their labels together?</em></p>
</article>
<p>Your puzzle answer was <code>157410423276</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="/2020">return to your Advent calendar</a> and try another puzzle.</p>
<p>Your puzzle input was <code class="puzzle-input">538914762</code>.</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+%22Crab+Cups%22+%2D+Day+23+%2D+Advent+of+Code+2020&amp;url=https%3A%2F%2Fadventofcode%2Ecom%2F2020%2Fday%2F23&amp;related=ericwastl&amp;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+%22Crab+Cups%22+%2D+Day+23+%2D+Advent+of+Code+2020+%23AdventOfCode+https%3A%2F%2Fadventofcode%2Ecom%2F2020%2Fday%2F23'}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
......@@ -57,6 +57,7 @@ packages:
- advent20
- advent21
- advent22
- advent23
# Dependency packages to be pulled from upstream that are not in the resolver.
# These entries can reference officially published versions as well as
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment