Day 11
authorNeil Smith <neil.git@njae.me.uk>
Tue, 11 Dec 2018 18:14:21 +0000 (18:14 +0000)
committerNeil Smith <neil.git@njae.me.uk>
Tue, 11 Dec 2018 18:14:21 +0000 (18:14 +0000)
advent-of-code.cabal
problems/day11.html [new file with mode: 0644]
src/advent11/advent11-map.hs [new file with mode: 0644]
src/advent11/advent11-naive.hs [new file with mode: 0644]
src/advent11/advent11.hs [new file with mode: 0644]

index 83c71a96f6917237de5b7b7601e9f4ef28b342e9..2910874a83c421013172410f20f9ea1430379f2b 100644 (file)
@@ -120,3 +120,42 @@ executable advent09pl
                      , megaparsec
                      , containers
                      , pointedlist
+
+executable advent10
+  hs-source-dirs:      src/advent10
+  main-is:             advent10.hs
+  default-language:    Haskell2010
+  build-depends:       base >= 4.7 && < 5
+                     , text
+                     , megaparsec
+                     , containers
+
+executable advent10iz
+  hs-source-dirs:      src/advent10
+  main-is:             advent10-iterate-zip.hs
+  default-language:    Haskell2010
+  build-depends:       base >= 4.7 && < 5
+                     , text
+                     , megaparsec
+                     , containers   
+
+executable advent11
+  hs-source-dirs:      src/advent11
+  main-is:             advent11.hs
+  default-language:    Haskell2010
+  build-depends:       base >= 4.7 && < 5
+                     , containers
+
+executable advent11m
+  hs-source-dirs:      src/advent11
+  main-is:             advent11-map.hs
+  default-language:    Haskell2010
+  build-depends:       base >= 4.7 && < 5
+                     , containers
+
+executable advent11naive
+  hs-source-dirs:      src/advent11
+  main-is:             advent11-naive.hs
+  default-language:    Haskell2010
+  build-depends:       base >= 4.7 && < 5
+                     , containers
diff --git a/problems/day11.html b/problems/day11.html
new file mode 100644 (file)
index 0000000..89e94a0
--- /dev/null
@@ -0,0 +1,173 @@
+<!DOCTYPE html>
+<html lang="en-us">
+<head>
+<meta charset="utf-8"/>
+<title>Day 11 - Advent of Code 2018</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?18"/>
+<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 Google, 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, ads, 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; the easiest ones take 3-4 hours each, but the
+harder ones take 6-8 hours, and a few even longer than that. 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="/2018/about">[About]</a></li><li><a href="/2018/events">[Events]</a></li><li><a href="https://teespring.com/adventofcode" target="_blank">[Shop]</a></li><li><a href="/2018/settings">[Settings]</a></li><li><a href="/2018/auth/logout">[Log Out]</a></li></ul></nav><div class="user">Neil Smith <a href="/2018/support" class="supporter-badge" title="Advent of Code Supporter">(AoC++)</a> <span class="star-count">22*</span></div></div><div><h1 class="title-event">&nbsp;&nbsp;<span class="title-event-wrap">{year=&gt;</span><a href="/2018">2018</a><span class="title-event-wrap">}</span></h1><nav><ul><li><a href="/2018">[Calendar]</a></li><li><a href="/2018/support">[AoC++]</a></li><li><a href="/2018/sponsors">[Sponsors]</a></li><li><a href="/2018/leaderboard">[Leaderboard]</a></li><li><a href="/2018/stats">[Stats]</a></li></ul></nav></div></header>
+
+<div id="sidebar">
+<div id="sponsor"><div class="quiet">Our <a href="/2018/sponsors">sponsors</a> help make Advent of Code possible:</div><div class="sponsor"><a href="https://clubhouse.io/?utm_source=spon&amp;utm_medium=ch&amp;utm_campaign=aoc2018" target="_blank" onclick="if(ga)ga('send','event','sponsor','click',this.href);" rel="noopener">Clubhouse</a> - The first project management platform for software development that brings everyone on every team together to build better products. AoC participants get two free months by signing up at r.clbh.se/mze9q9P Also, we're hiring!</div></div>
+</div><!--/sidebar-->
+
+<main>
+<article class="day-desc"><h2>--- Day 11: Chronal Charge ---</h2><p>You watch the Elves and their sleigh fade into the distance as they head toward the North Pole.</p>
+<p>Actually, you're the one fading. The <span title="wheeeeeeeeeeeeeeeeee">falling sensation</span> returns.</p>
+<p>The low fuel warning light is illuminated on your wrist-mounted device. Tapping it once causes it to project a hologram of the situation: a <em>300x300</em> grid of fuel cells and their current power levels, some negative. You're not sure what negative power means in the context of time travel, but it can't be good.</p>
+<p>Each fuel cell has a coordinate ranging <em>from 1 to 300</em> in both the X (horizontal) and Y (vertical) direction.  In <code>X,Y</code> notation, the top-left cell is <code>1,1</code>, and the top-right cell is <code>300,1</code>.</p>
+<p>The interface lets you select <em>any 3x3 square</em> of fuel cells. To increase your chances of getting to your destination, you decide to choose the 3x3 square with the <em>largest total power</em>.</p>
+<p>The power level in a given fuel cell can be found through the following process:</p>
+<ul>
+<li>Find the fuel cell's <em>rack ID</em>, which is its <em>X coordinate plus 10</em>.</li>
+<li>Begin with a power level of the <em>rack ID</em> times the <em>Y coordinate</em>.</li>
+<li>Increase the power level by the value of the <em>grid serial number</em> (your puzzle input).</li>
+<li>Set the power level to itself multiplied by the <em>rack ID</em>.</li>
+<li>Keep only the <em>hundreds digit</em> of the power level (so <code>12<em>3</em>45</code> becomes <code>3</code>; numbers with no hundreds digit become <code>0</code>).</li>
+<li><em>Subtract 5</em> from the power level.</li>
+</ul>
+<p>For example, to find the power level of the fuel cell at <code>3,5</code> in a grid with serial number <code>8</code>:</p>
+<ul>
+<li>The rack ID is <code>3 + 10 = <em>13</em></code>.</li>
+<li>The power level starts at <code>13 * 5 = <em>65</em></code>.</li>
+<li>Adding the serial number produces <code>65 + 8 = <em>73</em></code>.</li>
+<li>Multiplying by the rack ID produces <code>73 * 13 = <em>949</em></code>.</li>
+<li>The hundreds digit of <code><em>9</em>49</code> is <code><em>9</em></code>.</li>
+<li>Subtracting 5 produces <code>9 - 5 = <em>4</em></code>.</li>
+</ul>
+<p>So, the power level of this fuel cell is <code><em>4</em></code>.</p>
+<p>Here are some more example power levels:</p>
+<ul>
+<li>Fuel cell at &nbsp;<code>122,79</code>, grid serial number <code>57</code>: power level <code>-5</code>.</li>
+<li>Fuel cell at <code>217,196</code>, grid serial number <code>39</code>: power level &nbsp;<code>0</code>.</li>
+<li>Fuel cell at <code>101,153</code>, grid serial number <code>71</code>: power level &nbsp;<code>4</code>.</li>
+</ul>
+<p>Your goal is to find the 3x3 square which has the largest total power. The square must be entirely within the 300x300 grid. Identify this square using the <code>X,Y</code> coordinate of its <em>top-left fuel cell</em>. For example:</p>
+<p>For grid serial number <code>18</code>, the largest total 3x3 square has a top-left corner of <code><em>33,45</em></code> (with a total power of <code>29</code>); these fuel cells appear in the middle of this 5x5 region:</p>
+<pre><code>-2  -4   4   4   4
+-4  <em> 4   4   4  </em>-5
+ 4  <em> 3   3   4  </em>-4
+ 1  <em> 1   2   4  </em>-3
+-1   0   2  -5  -2
+</code></pre>
+<p>For grid serial number <code>42</code>, the largest 3x3 square's top-left is <code><em>21,61</em></code> (with a total power of <code>30</code>); they are in the middle of this region:</p>
+<pre><code>-3   4   2   2   2
+-4  <em> 4   3   3  </em> 4
+-5  <em> 3   3   4  </em>-4
+ 4  <em> 3   3   4  </em>-3
+ 3   3   3  -5  -1
+</code></pre>
+<p><em>What is the <code>X,Y</code> coordinate of the top-left fuel cell of the 3x3 square with the largest total power?</em></p>
+</article>
+<p>Your puzzle answer was <code>21,34</code>.</p><article class="day-desc"><h2 id="part2">--- Part Two ---</h2><p>You discover a dial on the side of the device; it seems to let you select a square of <em>any size</em>, not just 3x3. Sizes from 1x1 to 300x300 are supported.</p>
+<p>Realizing this, you now must find the <em>square of any size with the largest total power</em>. Identify this square by including its size as a third parameter after the top-left coordinate: a 9x9 square with a top-left corner of <code>3,5</code> is identified as <code>3,5,9</code>.</p>
+<p>For example:</p>
+<ul>
+<li>For grid serial number <code>18</code>, the largest total square (with a total power of <code>113</code>) is 16x16 and has a top-left corner of <code>90,269</code>, so its identifier is <code><em>90,269,16</em></code>.</li>
+<li>For grid serial number <code>42</code>, the largest total square (with a total power of <code>119</code>) is 12x12 and has a top-left corner of <code>232,251</code>, so its identifier is <code><em>232,251,12</em></code>.</li>
+</ul>
+<p><em>What is the <code>X,Y,size</code> identifier of the square with the largest total power?</em></p>
+</article>
+<p>Your puzzle answer was <code>90,244,16</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="/2018">return to your advent calendar</a> and try another puzzle.</p>
+<p>Your puzzle input was <code class="puzzle-input">5719</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+%22Chronal+Charge%22+%2D+Day+11+%2D+Advent+of+Code+2018&amp;url=https%3A%2F%2Fadventofcode%2Ecom%2F2018%2Fday%2F11&amp;related=ericwastl&amp;hashtags=AdventOfCode" target="_blank">Twitter</a>
+  <a href="http://www.reddit.com/submit?url=https%3A%2F%2Fadventofcode%2Ecom%2F2018%2Fday%2F11&amp;title=I%27ve+completed+%22Chronal+Charge%22+%2D+Day+11+%2D+Advent+of+Code+2018" target="_blank">Reddit</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('send', 'pageview');
+</script>
+<!-- /ga -->
+</body>
+</html>
\ No newline at end of file
diff --git a/src/advent11/advent11-map.hs b/src/advent11/advent11-map.hs
new file mode 100644 (file)
index 0000000..9549660
--- /dev/null
@@ -0,0 +1,58 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+import Data.List
+import qualified Data.Map.Strict as M
+-- import Data.Map.Strict ((!))
+-- import qualified Data.Set as S
+-- import Data.Function (on)
+import Data.Ord (comparing)
+
+type Coord = (Integer, Integer) -- x, y
+type Grid = M.Map Coord Integer
+
+key = 5719
+-- key = 42
+
+main :: IO ()
+main = do 
+        let g = makeGrid key
+        print $ part1 g
+        print $ part2 g
+
+
+part1 grid = keyOfMaxValue sg
+    where sg = allSubCellPower 3 grid
+
+
+part2 grid = maximumBy (comparing snd) $ [bestInGrid size grid | size <- [3..300]]
+
+-- bestSubCell size grid = 
+
+makeGrid :: Integer -> Grid
+makeGrid key = M.fromList [((x, y), powerLevel x y key) | x <- [1..300], y <- [1..300] ]
+
+powerLevel :: Integer -> Integer -> Integer -> Integer
+powerLevel x y key = ((interim `div` 100) `mod` 10) - 5
+    where rackID = x + 10
+          interim = ((rackID) * y + key) * rackID
+
+subCellPower :: Integer -> Integer -> Integer -> Grid -> Integer
+subCellPower size x y grid = M.foldr (+) 0 subGrid
+    where subGrid = M.filterWithKey inBounds grid
+          inBounds (kx, ky) _ = (kx >= x) && (kx < x+size) && (ky >= y) && (ky < y+size)
+
+allSubCellPower :: Integer -> Grid -> Grid
+allSubCellPower size grid = M.fromList [((x, y), subCellPower size x y grid)| x <- [1..(301-size)], y <- [1..(301-size)]]
+
+
+keyAndMaxValue :: Ord b => M.Map a b -> (a, b)
+keyAndMaxValue m = M.foldrWithKey mergeKV (M.findMin m) m
+    where mergeKV k v (bestK, bestV) = 
+            if v > bestV then (k, v) else (bestK, bestV)
+
+keyOfMaxValue :: Ord b => M.Map a b -> a
+keyOfMaxValue m = fst $ keyAndMaxValue m
+
+bestInGrid :: Integer -> Grid -> ((Integer, Integer, Integer), Integer)
+bestInGrid size grid = ((x, y, size), p)
+    where ((x, y), p) = keyAndMaxValue $ allSubCellPower size grid
diff --git a/src/advent11/advent11-naive.hs b/src/advent11/advent11-naive.hs
new file mode 100644 (file)
index 0000000..d79ebb4
--- /dev/null
@@ -0,0 +1,56 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+import Data.List
+import qualified Data.Map.Strict as M
+import Data.Map.Strict ((!))
+-- import qualified Data.Set as S
+-- import Data.Function (on)
+import Data.Ord (comparing)
+
+type Coord = (Integer, Integer) -- x, y
+type Grid = M.Map Coord Integer
+
+key = 5719
+-- key = 42
+
+main :: IO ()
+main = do 
+        let g = makeGrid key
+        print $ part1 g
+        print $ part2 g
+
+
+part1 grid = keyOfMaxValue sg
+    where sg = allSubCellPower 3 grid
+
+
+part2 grid = maximumBy (comparing snd) $ [bestInGrid size grid | size <- [3..300]]
+
+-- bestSubCell size grid = 
+
+makeGrid :: Integer -> Grid
+makeGrid key = M.fromList [((x, y), powerLevel x y key) | x <- [1..300], y <- [1..300] ]
+
+powerLevel :: Integer -> Integer -> Integer -> Integer
+powerLevel x y key = ((interim `div` 100) `mod` 10) - 5
+    where rackID = x + 10
+          interim = ((rackID) * y + key) * rackID
+
+subCellPower :: Integer -> Integer -> Integer -> Grid -> Integer
+subCellPower size x y grid = sum [grid!(sx, sy) | sx <- [x..(x+size-1)], sy <- [y..(y+size-1)]]
+
+allSubCellPower :: Integer -> Grid -> Grid
+allSubCellPower size grid = M.fromList [((x, y), subCellPower size x y grid)| x <- [1..(301-size)], y <- [1..(301-size)]]
+
+
+keyAndMaxValue :: Ord b => M.Map a b -> (a, b)
+keyAndMaxValue m = M.foldrWithKey mergeKV (M.findMin m) m
+    where mergeKV k v (bestK, bestV) = 
+            if v > bestV then (k, v) else (bestK, bestV)
+
+keyOfMaxValue :: Ord b => M.Map a b -> a
+keyOfMaxValue m = fst $ keyAndMaxValue m
+
+bestInGrid :: Integer -> Grid -> ((Integer, Integer, Integer), Integer)
+bestInGrid size grid = ((x, y, size), p)
+    where ((x, y), p) = keyAndMaxValue $ allSubCellPower size grid
diff --git a/src/advent11/advent11.hs b/src/advent11/advent11.hs
new file mode 100644 (file)
index 0000000..1472f31
--- /dev/null
@@ -0,0 +1,73 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+-- Using a summed-area table, e.g. see https://en.wikipedia.org/wiki/Summed-area_table
+
+import Data.List
+import qualified Data.Map.Strict as M
+import Data.Map.Strict ((!))
+-- import qualified Data.Set as S
+-- import Data.Function (on)
+import Data.Ord (comparing)
+
+type Coord = (Integer, Integer) -- x, y
+type Grid = M.Map Coord Integer
+
+key = 5719
+-- key = 42
+
+main :: IO ()
+main = do 
+        let g = makeGrid key
+        print $ part1 g
+        print $ part2 g
+
+
+part1 grid = keyOfMaxValue sg
+    where sg = allSubCellPower 3 grid
+
+
+part2 grid = maximumBy (comparing snd) $ [bestInGrid size grid | size <- [3..300]]
+
+-- bestSubCell size grid = 
+
+makeGrid :: Integer -> Grid
+-- makeGrid key = M.fromList [((x, y), powerLevel x y key) | x <- [1..300], y <- [1..300] ]
+makeGrid key = foldl' addSummedArea M.empty [((x, y), powerLevel x y key) | x <- [0..300], y <- [0..300] ]
+
+addSummedArea :: Grid -> ((Integer, Integer), Integer) -> Grid
+addSummedArea grid ((x, y), power) = M.insert (x, y) (power + upper + left - upperLeft) grid
+    where upper = M.findWithDefault 0 (x-1, y) grid
+          left  = M.findWithDefault 0 (x, y-1) grid
+          upperLeft = M.findWithDefault 0 (x-1, y-1) grid
+
+
+powerLevel :: Integer -> Integer -> Integer -> Integer
+powerLevel 0 y _ = 0
+powerLevel x 0 _ = 0
+powerLevel x y key = ((interim `div` 100) `mod` 10) - 5
+    where rackID = x + 10
+          interim = ((rackID) * y + key) * rackID
+
+subCellPower :: Integer -> Integer -> Integer -> Grid -> Integer
+-- subCellPower size x y grid = sum [grid!(sx, sy) | sx <- [x..(x+size-1)], sy <- [y..(y+size-1)]]
+subCellPower size x0 y0 grid = grid!(x,y) + grid!(x',y') - grid!(x,y') - grid!(x',y)
+    where x  = x0 - 1
+          x' = x + size
+          y  = y0 - 1
+          y' = y + size 
+
+allSubCellPower :: Integer -> Grid -> Grid
+allSubCellPower size grid = M.fromList [((x, y), subCellPower size x y grid)| x <- [1..(301-size)], y <- [1..(301-size)]]
+
+
+keyAndMaxValue :: Ord b => M.Map a b -> (a, b)
+keyAndMaxValue m = M.foldrWithKey mergeKV (M.findMin m) m
+    where mergeKV k v (bestK, bestV) = 
+            if v > bestV then (k, v) else (bestK, bestV)
+
+keyOfMaxValue :: Ord b => M.Map a b -> a
+keyOfMaxValue m = fst $ keyAndMaxValue m
+
+bestInGrid :: Integer -> Grid -> ((Integer, Integer, Integer), Integer)
+bestInGrid size grid = ((x, y, size), p)
+    where ((x, y), p) = keyAndMaxValue $ allSubCellPower size grid