Now with use of monad loops
authorNeil Smith <neil.git@njae.me.uk>
Thu, 24 Dec 2020 10:55:25 +0000 (10:55 +0000)
committerNeil Smith <neil.git@njae.me.uk>
Thu, 24 Dec 2020 11:36:52 +0000 (11:36 +0000)
advent15/package.yaml
advent15/src/advent15.hs
advent15/src/advent15loop.hs [new file with mode: 0644]
advent15/src/advent15slow.hs
problems/day15.html [new file with mode: 0644]

index cd2c591d649464553e9b960c3fce1d0f84efb3f9..ddc9415b94df99b6360e021155b8dacf979d618b 100644 (file)
@@ -56,7 +56,6 @@ executables:
     source-dirs: src
     dependencies:
     - base >= 2 && < 6
-    - text
     - vector
 
   advent15slow:
@@ -64,6 +63,12 @@ executables:
     source-dirs: src
     dependencies:
     - base >= 2 && < 6
-    - text
     - containers
 
+  advent15loop:
+    main: advent15loop.hs
+    source-dirs: src
+    dependencies:
+    - base >= 2 && < 6
+    - vector
+    - monad-loops
index 87cbf3de8c38a443ed195335c403913e6af1edec..ac0f2b450129f73b1a45396dd13e3aa3fa70cfff 100644 (file)
@@ -7,6 +7,9 @@ import Data.STRef
 import qualified Data.Vector.Unboxed.Mutable as V
 
 
+type STInt s = STRef s Int
+type VInt s = V.MVector s Int
+
 main :: IO ()
 main = 
   do  let seed = [20, 0, 1, 11, 6, 3]
@@ -18,24 +21,25 @@ main =
 part1 seed = runGame seed 2020
 part2 seed = runGame seed 30000000
 
-zeroInt :: Int
-zeroInt = 0
+runGame :: [Int] -> Int -> Int
+runGame seed roundsNeeded =
+  runST $ 
+    do (round, word, history) <- seedGame seed roundsNeeded
+       gameSteps roundsNeeded round word history
+       readSTRef word
 
+seedGame :: [Int] -> Int -> ST s (STInt s, STInt s,  VInt s)
 seedGame seed historySize = 
   do round <- newSTRef $ length seed
      word <- newSTRef $ last seed
-     history <- V.replicate historySize zeroInt
+     history <- V.replicate historySize 0
      forM_ (zip (init seed) [1..]) $ \(t, s) -> V.write history t s
      return (round, word, history)
 
-runGame seed roundsNeeded =
-  runST $ 
-    do (round, word, history) <- seedGame seed roundsNeeded
-       gameStep roundsNeeded round word history
-       readSTRef word
 
-gameStep :: Int -> STRef s Int -> STRef s Int -> V.MVector s Int -> ST s ()
-gameStep targetRound round word history =
+-- gameSteps :: Int -> STRef s Int -> STRef s Int -> V.MVector s Int -> ST s ()
+gameSteps :: Int -> STInt s -> STInt s -> VInt s -> ST s ()
+gameSteps targetRound round word history =
   do roundVal <- readSTRef round
      if roundVal == targetRound
      then return ()
@@ -46,7 +50,7 @@ gameStep targetRound round word history =
            V.write history wordVal roundVal
            modifySTRef round (+1)
            writeSTRef word word'
-           gameStep targetRound round word history
+           gameSteps targetRound round word history
 
 
 speakWord :: Int -> Int -> Int
diff --git a/advent15/src/advent15loop.hs b/advent15/src/advent15loop.hs
new file mode 100644 (file)
index 0000000..7d2d258
--- /dev/null
@@ -0,0 +1,75 @@
+-- import Debug.Trace
+
+import Prelude hiding (round)
+import Control.Monad
+import Control.Monad.ST
+import Control.Monad.Loops
+import Data.STRef
+import qualified Data.Vector.Unboxed.Mutable as V
+
+
+main :: IO ()
+main = 
+  do  let seed = [20, 0, 1, 11, 6, 3]
+      -- print seed
+      print $ part1 seed
+      print $ part2 seed
+
+
+part1 seed = runGame seed 2020
+part2 seed = runGame seed 30000000
+
+runGame seed roundsNeeded =
+  runST $ 
+    do (round, word, history) <- seedGame seed roundsNeeded
+       gameLoop roundsNeeded round word history
+       readSTRef word
+
+-- gameLoop targetRound round word history =
+--     do ( gameStep round word history 
+--          `untilM_` (do r <- readSTRef round
+--                        return $ r == targetRound)
+--         )
+--        return ()
+
+-- gameLoop targetRound round word history =
+--     do untilM_ (gameStep round word history ) 
+--                (do r <- readSTRef round
+--                    return $ r == targetRound )
+--        return ()
+
+-- gameLoop targetRound round word history =
+--     do whileM_ (do r <- readSTRef round
+--                    return $ r /= targetRound )
+--                (gameStep round word history ) 
+--        return ()
+
+gameLoop targetRound round word history =
+    do whileM_ (do r <- readSTRef round
+                   return $ r /= targetRound )
+               $ gameStep round word history
+       return ()
+
+seedGame seed historySize = 
+  do round <- newSTRef $ length seed
+     word <- newSTRef $ last seed
+     history <- V.replicate historySize 0
+     forM_ (zip (init seed) [1..]) $ \(t, s) -> V.write history t s
+     return (round, word, history)
+
+gameStep :: STRef s Int -> STRef s Int -> V.MVector s Int -> ST s ()
+gameStep round word history =
+  do roundVal <- readSTRef round
+     wordVal <- readSTRef word
+     wordH <- V.read history wordVal
+     let word' = speakWord wordH roundVal
+     V.write history wordVal roundVal
+     modifySTRef round (+1)
+     writeSTRef word word'
+     return ()
+
+speakWord :: Int -> Int -> Int
+speakWord 0 _ = 0
+speakWord prev now = now - prev
+
+
index 508fedd077cc4472b1262bcdcf6a209d8f1e50c9..4c6ff073660e07dfd3e1949547edf85de9d5aa89 100644 (file)
@@ -3,7 +3,6 @@
 import Prelude hiding (round)
 import qualified Data.IntMap.Strict as M
 
-
 data Game = Game { round :: Int
                  , word :: Int
                  , history :: M.IntMap Int
diff --git a/problems/day15.html b/problems/day15.html
new file mode 100644 (file)
index 0000000..cc9a773
--- /dev/null
@@ -0,0 +1,165 @@
+<!DOCTYPE html>
+<html lang="en-us">
+<head>
+<meta charset="utf-8"/>
+<title>Day 15 - 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">30*</span></div></div><div><h1 class="title-event">&nbsp;&nbsp;&nbsp;<span class="title-event-wrap">int y=</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://careers.bolt.eu/positions?team=engineering&amp;utm_source=adventofcode&amp;utm_medium=banner&amp;utm_campaign=adventofcode_traffic" target="_blank" onclick="if(ga)ga('send','event','sponsor','sidebar',this.href);" rel="noopener">Bolt</a> - Fastest growing mobility startup in Europe: distributed systems, microservices, ML, complex algorithms for demand prediction, 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 15: Rambunctious Recitation ---</h2><p>You catch the airport shuttle and try to book a new flight to your vacation island. Due to the storm, all direct flights have been cancelled, but a route is available to get around the storm. You take it.</p>
+<p>While you wait for your flight, you decide to check in with the Elves back at the North Pole. They're playing a <em>memory game</em> and are <span title="Of course they are.">ever so excited</span> to explain the rules!</p>
+<p>In this game, the players take turns saying <em>numbers</em>. They begin by taking turns reading from a list of <em>starting numbers</em> (your puzzle input). Then, each turn consists of considering the <em>most recently spoken number</em>:</p>
+<ul>
+<li>If that was the <em>first</em> time the number has been spoken, the current player says <em><code>0</code></em>.</li>
+<li>Otherwise, the number had been spoken before; the current player announces <em>how many turns apart</em> the number is from when it was previously spoken.</li>
+</ul>
+<p>So, after the starting numbers, each turn results in that player speaking aloud either <em><code>0</code></em> (if the last number is new) or an <em>age</em> (if the last number is a repeat).</p>
+<p>For example, suppose the starting numbers are <code>0,3,6</code>:</p>
+<ul>
+<li><em>Turn 1</em>: The <code>1</code>st number spoken is a starting number, <em><code>0</code></em>.</li>
+<li><em>Turn 2</em>: The <code>2</code>nd number spoken is a starting number, <em><code>3</code></em>.</li>
+<li><em>Turn 3</em>: The <code>3</code>rd number spoken is a starting number, <em><code>6</code></em>.</li>
+<li><em>Turn 4</em>: Now, consider the last number spoken, <code>6</code>. Since that was the first time the number had been spoken, the <code>4</code>th number spoken is <em><code>0</code></em>.</li>
+<li><em>Turn 5</em>: Next, again consider the last number spoken, <code>0</code>. Since it <em>had</em> been spoken before, the next number to speak is the difference between the turn number when it was last spoken (the previous turn, <code>4</code>) and the turn number of the time it was most recently spoken before then (turn <code>1</code>). Thus, the <code>5</code>th number spoken is <code>4 - 1</code>, <em><code>3</code></em>.</li>
+<li><em>Turn 6</em>: The last number spoken, <code>3</code> had also been spoken before, most recently on turns <code>5</code> and <code>2</code>. So, the <code>6</code>th number spoken is <code>5 - 2</code>, <em><code>3</code></em>.</li>
+<li><em>Turn 7</em>: Since <code>3</code> was just spoken twice in a row, and the last two turns are <code>1</code> turn apart, the <code>7</code>th number spoken is <em><code>1</code></em>.</li>
+<li><em>Turn 8</em>: Since <code>1</code> is new, the <code>8</code>th number spoken is <em><code>0</code></em>.</li>
+<li><em>Turn 9</em>: <code>0</code> was last spoken on turns <code>8</code> and <code>4</code>, so the <code>9</code>th number spoken is the difference between them, <em><code>4</code></em>.</li>
+<li><em>Turn 10</em>: <code>4</code> is new, so the <code>10</code>th number spoken is <em><code>0</code></em>.</li>
+</ul>
+<p>(The game ends when the Elves get sick of playing or dinner is ready, whichever comes first.)</p>
+<p>Their question for you is: what will be the <em><code>2020</code>th</em> number spoken? In the example above, the <code>2020</code>th number spoken will be <code>436</code>.</p>
+<p>Here are a few more examples:</p>
+<ul>
+<li>Given the starting numbers <code>1,3,2</code>, the <code>2020</code>th number spoken is <code>1</code>.</li>
+<li>Given the starting numbers <code>2,1,3</code>, the <code>2020</code>th number spoken is <code>10</code>.</li>
+<li>Given the starting numbers <code>1,2,3</code>, the <code>2020</code>th number spoken is <code>27</code>.</li>
+<li>Given the starting numbers <code>2,3,1</code>, the <code>2020</code>th number spoken is <code>78</code>.</li>
+<li>Given the starting numbers <code>3,2,1</code>, the <code>2020</code>th number spoken is <code>438</code>.</li>
+<li>Given the starting numbers <code>3,1,2</code>, the <code>2020</code>th number spoken is <code>1836</code>.</li>
+</ul>
+<p>Given your starting numbers, <em>what will be the <code>2020</code>th number spoken?</em></p>
+</article>
+<p>Your puzzle answer was <code>421</code>.</p><article class="day-desc"><h2 id="part2">--- Part Two ---</h2><p>Impressed, the Elves issue you a challenge: determine the <code>30000000</code>th number spoken. For example, given the same starting numbers as above:</p>
+<ul>
+<li>Given <code>0,3,6</code>, the <code>30000000</code>th number spoken is <code>175594</code>.</li>
+<li>Given <code>1,3,2</code>, the <code>30000000</code>th number spoken is <code>2578</code>.</li>
+<li>Given <code>2,1,3</code>, the <code>30000000</code>th number spoken is <code>3544142</code>.</li>
+<li>Given <code>1,2,3</code>, the <code>30000000</code>th number spoken is <code>261214</code>.</li>
+<li>Given <code>2,3,1</code>, the <code>30000000</code>th number spoken is <code>6895259</code>.</li>
+<li>Given <code>3,2,1</code>, the <code>30000000</code>th number spoken is <code>18</code>.</li>
+<li>Given <code>3,1,2</code>, the <code>30000000</code>th number spoken is <code>362</code>.</li>
+</ul>
+<p>Given your starting numbers, <em>what will be the <code>30000000</code>th number spoken?</em></p>
+</article>
+<p>Your puzzle answer was <code>436</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">20,0,1,11,6,3</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+%22Rambunctious+Recitation%22+%2D+Day+15+%2D+Advent+of+Code+2020&amp;url=https%3A%2F%2Fadventofcode%2Ecom%2F2020%2Fday%2F15&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+%22Rambunctious+Recitation%22+%2D+Day+15+%2D+Advent+of+Code+2020+%23AdventOfCode+https%3A%2F%2Fadventofcode%2Ecom%2F2020%2Fday%2F15'}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