Day 10
authorNeil Smith <neil.git@njae.me.uk>
Sun, 10 Dec 2017 16:46:59 +0000 (16:46 +0000)
committerNeil Smith <neil.git@njae.me.uk>
Sun, 10 Dec 2017 16:46:59 +0000 (16:46 +0000)
advent-of-code.cabal
data/advent10.txt [new file with mode: 0644]
problems/day10.html [new file with mode: 0644]
src/advent10/advent10.hs [new file with mode: 0644]
src/advent10/advent10.ipynb [new file with mode: 0644]

index 347896b784f4ae008d65cf6686e60386362851fc..3ad97bd6a65e5574fe3e88962d7374560d02d86a 100644 (file)
@@ -94,4 +94,10 @@ executable advent09
   main-is:             advent09.hs
   default-language:    Haskell2010
   build-depends:       base >= 4.7 && < 5
-                                         
\ No newline at end of file
+
+executable advent10
+  hs-source-dirs:      src/advent10
+  main-is:             advent10.hs
+  default-language:    Haskell2010
+  build-depends:       base >= 4.7 && < 5
+                     , split
diff --git a/data/advent10.txt b/data/advent10.txt
new file mode 100644 (file)
index 0000000..64328f2
--- /dev/null
@@ -0,0 +1 @@
+189,1,111,246,254,2,0,120,215,93,255,50,84,15,94,62
\ No newline at end of file
diff --git a/problems/day10.html b/problems/day10.html
new file mode 100644 (file)
index 0000000..50c374b
--- /dev/null
@@ -0,0 +1,186 @@
+<!DOCTYPE html>
+<html lang="en-us">
+<head>
+<meta charset="utf-8"/>
+<title>Day 10 - Advent of Code 2017</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?11"/>
+<link rel="stylesheet alternate" type="text/css" href="/static/highcontrast.css?0" title="High Contrast"/>
+<link rel="shortcut icon" href="/favicon.ico?2"/>
+</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 probably took the longest; the easiest ones took an hour or two
+each, but the harder ones took 4-5 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="/2017/about">[About]</a></li><li><a href="/2017/support">[AoC++]</a></li><li><a href="/2017/events">[Events]</a></li><li><a href="/2017/settings">[Settings]</a></li><li><a href="/2017/auth/logout">[Log Out]</a></li></ul></nav><div class="user">Neil Smith <span class="supporter">(AoC++)</span> <span class="star-count">20*</span></div></div><div><h1 class="title-event">&nbsp;&nbsp;&nbsp;<span class="title-event-wrap">$year=</span><a href="/2017">2017</a><span class="title-event-wrap">;</span></h1><nav><ul><li><a href="/2017">[Calendar]</a></li><li><a href="/2017/leaderboard">[Leaderboard]</a></li><li><a href="/2017/stats">[Stats]</a></li><li><a href="/2017/sponsors">[Sponsors]</a></li></ul></nav></div></header>
+
+<div id="sidebar">
+<div id="sponsor"><div class="quiet">Our <a href="/2017/sponsors">sponsors</a> help make Advent of Code possible:</div><p><a href="https://cheppers.com/" target="_blank" onclick="if(ga)ga('send','event','sponsor','click',this.href);" rel="noopener">Cheppers</a> - xor(Pz0pQUI7Ch cmER8YDAEYAh4L GwEP, ↑↑↓↓←→←→BA)</p></div>
+<div id="ad">
+<script async src="//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
+<!-- Advent of Code Wide Skyscraper -->
+<ins class="adsbygoogle"
+     style="display:inline-block;width:160px;height:600px"
+     data-ad-client="ca-pub-9420604735624631"
+     data-ad-slot="8014013294"></ins>
+<script>
+(adsbygoogle = window.adsbygoogle || []).push({});
+</script>
+</div><!--/ad-->
+</div><!--/sidebar-->
+
+<main>
+<article class="day-desc"><h2>--- Day 10: Knot Hash ---</h2><p>You come across some programs that are trying to implement a software emulation of a hash based on knot-tying. The hash these programs are implementing isn't very strong, but you decide to help them anyway. You make a mental note to remind the Elves later not to <span title="NEW CRYPTOSYSTEM WHO DIS">invent their own cryptographic functions</span>.</p>
+<p>This hash function simulates tying a knot in a circle of string with 256 marks on it. Based on the input to be hashed, the function repeatedly selects a span of string, brings the ends together, and gives the span a half-twist to reverse the order of the marks within it. After doing this many times, the order of the marks is used to build the resulting hash.</p>
+<pre><code>  4--5   pinch   4  5           4   1
+ /    \  5,0,1  / \/ \  twist  / \ / \
+3      0  -->  3      0  -->  3   X   0
+ \    /         \ /\ /         \ / \ /
+  2--1           2  1           2   5
+</code></pre>
+<p>To achieve this, begin with a <em>list</em> of numbers from <code>0</code> to <code>255</code>, a <em>current position</em> which begins at <code>0</code> (the first element in the list), a <em>skip size</em> (which starts at <code>0</code>), and a sequence of <em>lengths</em> (your puzzle input).  Then, for each length:</p>
+<ul>
+<li><em>Reverse</em> the order of that <em>length</em> of elements in the <em>list</em>, starting with the element at the <em>current position</em>.</li>
+<li><em>Move</em> the <em>current position</em> forward by that <em>length</em> plus the <em>skip size</em>.</li>
+<li><em>Increase</em> the <em>skip size</em> by one.</li>
+</ul>
+<p>The <em>list</em> is circular; if the <em>current position</em> and the <em>length</em> try to reverse elements beyond the end of the list, the operation reverses using as many extra elements as it needs from the front of the list. If the <em>current position</em> moves past the end of the list, it wraps around to the front. <em>Lengths</em> larger than the size of the <em>list</em> are invalid.</p>
+<p>Here's an example using a smaller list:</p>
+<p>Suppose we instead only had a circular list containing five elements, <code>0, 1, 2, 3, 4</code>, and were given input lengths of <code>3, 4, 1, 5</code>.</p>
+<ul>
+<li>The list begins as <code>[0] 1 2 3 4</code> (where square brackets indicate the <em>current position</em>).</li>
+<li>The first length, <code>3</code>, selects <code>([0] 1 2) 3 4</code> (where parentheses indicate the sublist to be reversed).</li>
+<li>After reversing that section (<code>0 1 2</code> into <code>2 1 0</code>), we get <code>([2] 1 0) 3 4</code>.</li>
+<li>Then, the <em>current position</em> moves forward by the <em>length</em>, <code>3</code>, plus the <em>skip size</em>, 0: <code>2 1 0 [3] 4</code>. Finally, the <em>skip size</em> increases to <code>1</code>.</li>
+</ul>
+<ul>
+<li>The second length, <code>4</code>, selects a section which wraps: <code>2 1) 0 ([3] 4</code>.</li>
+<li>The sublist <code>3 4 2 1</code> is reversed to form <code>1 2 4 3</code>: <code>4 3) 0 ([1] 2</code>.</li>
+<li>The <em>current position</em> moves forward by the <em>length</em> plus the <em>skip size</em>, a total of <code>5</code>, causing it not to move because it wraps around: <code>4 3 0 [1] 2</code>. The <em>skip size</em> increases to <code>2</code>.</li>
+</ul>
+<ul>
+<li>The third length, <code>1</code>, selects a sublist of a single element, and so reversing it has no effect.</li>
+<li>The <em>current position</em> moves forward by the <em>length</em> (<code>1</code>) plus the <em>skip size</em> (<code>2</code>): <code>4 [3] 0 1 2</code>. The <em>skip size</em> increases to <code>3</code>.</li>
+</ul>
+<ul>
+<li>The fourth length, <code>5</code>, selects every element starting with the second: <code>4) ([3] 0 1 2</code>. Reversing this sublist (<code>3 0 1 2 4</code> into <code>4 2 1 0 3</code>) produces: <code>3) ([4] 2 1 0</code>.</li>
+<li>Finally, the <em>current position</em> moves forward by <code>8</code>: <code>3 4 2 1 [0]</code>. The <em>skip size</em> increases to <code>4</code>.</li>
+</ul>
+<p>In this example, the first two numbers in the list end up being <code>3</code> and <code>4</code>; to check the process, you can multiply them together to produce <code>12</code>.</p>
+<p>However, you should instead use the standard list size of <code>256</code> (with values <code>0</code> to <code>255</code>) and the sequence of <em>lengths</em> in your puzzle input. Once this process is complete, <em>what is the result of multiplying the first two numbers in the list</em>?</p>
+</article>
+<p>Your puzzle answer was <code>38415</code>.</p><article class="day-desc"><h2>--- Part Two ---</h2><p>The logic you've constructed forms a single <em>round</em> of the <em>Knot Hash</em> algorithm; running the full thing requires many of these rounds. Some input and output processing is also required.</p>
+<p>First, from now on, your input should be taken not as a list of numbers, but as a string of bytes instead. Unless otherwise specified, convert characters to bytes using their <a href="https://en.wikipedia.org/wiki/ASCII#Printable_characters">ASCII codes</a>. This will allow you to handle arbitrary ASCII strings, and it also ensures that your input lengths are never larger than <code>255</code>. For example, if you are given <code>1,2,3</code>, you should convert it to the ASCII codes for each character: <code>49,44,50,44,51</code>.</p>
+<p>Once you have determined the sequence of lengths to use, add the following lengths to the end of the sequence: <code>17, 31, 73, 47, 23</code>. For example, if you are given <code>1,2,3</code>, your final sequence of lengths should be <code>49,44,50,44,51,17,31,73,47,23</code> (the ASCII codes from the input string combined with the standard length suffix values).</p>
+<p>Second, instead of merely running one <em>round</em> like you did above, run a total of <code>64</code> rounds, using the same <em>length</em> sequence in each round. The <em>current position</em> and <em>skip size</em> should be preserved between rounds. For example, if the previous example was your first round, you would start your second round with the same <em>length</em> sequence (<code>3, 4, 1, 5, 17, 31, 73, 47, 23</code>, now assuming they came from ASCII codes and include the suffix), but start with the previous round's <em>current position</em> (<code>4</code>) and <em>skip size</em> (<code>4</code>).</p>
+<p>Once the rounds are complete, you will be left with the numbers from <code>0</code> to <code>255</code> in some order, called the <em>sparse hash</em>. Your next task is to reduce these to a list of only <code>16</code> numbers called the <em>dense hash</em>. To do this, use numeric bitwise <a href="https://en.wikipedia.org/wiki/Bitwise_operation#XOR">XOR</a> to combine each consecutive block of <code>16</code> numbers in the sparse hash (there are <code>16</code> such blocks in a list of <code>256</code> numbers). So, the first element in the dense hash is the first sixteen elements of the sparse hash XOR'd together, the second element in the dense hash is the second sixteen elements of the sparse hash XOR'd together, etc.</p>
+<p>For example, if the first sixteen elements of your sparse hash are as shown below, and the XOR operator is <code>^</code>, you would calculate the first output number like this:</p>
+<pre><code>65 ^ 27 ^ 9 ^ 1 ^ 4 ^ 3 ^ 40 ^ 50 ^ 91 ^ 7 ^ 6 ^ 0 ^ 2 ^ 5 ^ 68 ^ 22 = 64</code></pre>
+<p>Perform this operation on each of the sixteen blocks of sixteen numbers in your sparse hash to determine the sixteen numbers in your dense hash.</p>
+<p>Finally, the standard way to represent a Knot Hash is as a single <a href="https://en.wikipedia.org/wiki/Hexadecimal">hexadecimal</a> string; the final output is the dense hash in hexadecimal notation. Because each number in your dense hash will be between <code>0</code> and <code>255</code> (inclusive), always represent each number as two hexadecimal digits (including a leading zero as necessary). So, if your first three numbers are <code>64, 7, 255</code>, they correspond to the hexadecimal numbers <code>40, 07, ff</code>, and so the first six characters of the hash would be <code>4007ff</code>. Because every Knot Hash is sixteen such numbers, the hexadecimal representation is always <code>32</code> hexadecimal digits (<code>0</code>-<code>f</code>) long.
+<p>Here are some example hashes:</p>
+<ul>
+<li>The empty string becomes <code>a2582a3a0e66e6e86e3812dcb672a272</code>.</li>
+<li><code>AoC 2017</code> becomes <code>33efeb34ea91902bb2f59c9920caa6cd</code>.</li>
+<li><code>1,2,3</code> becomes <code>3efbe78a8d82f29979031a4aa0b16a9d</code>.</li>
+<li><code>1,2,4</code> becomes <code>63960835bcdc130f0b66d7ff4f6a5a8e</code>.</li>
+</ul>
+<p>Treating your puzzle input as a string of ASCII characters, <em>what is the Knot Hash of your puzzle input?</em> Ignore any leading or trailing whitespace you might encounter.</p>
+</article>
+<p>Your puzzle answer was <code>9de8846431eef262be78f590e39a4848</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="/2017">return to your advent calendar</a> and try another puzzle.</p>
+<p>If you still want to see it, you can <a href="10/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+%22Knot+Hash%22+%2D+Day+10+%2D+Advent+of+Code+2017&amp;url=http%3A%2F%2Fadventofcode%2Ecom%2F2017%2Fday%2F10&amp;related=ericwastl&amp;hashtags=AdventOfCode" target="_blank">Twitter</a>
+  <a href="https://plus.google.com/share?url=http%3A%2F%2Fadventofcode%2Ecom%2F2017%2Fday%2F10" target="_blank">Google+</a>
+  <a href="http://www.reddit.com/submit?url=http%3A%2F%2Fadventofcode%2Ecom%2F2017%2Fday%2F10&amp;title=I%27ve+completed+%22Knot+Hash%22+%2D+Day+10+%2D+Advent+of+Code+2017" 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/advent10/advent10.hs b/src/advent10/advent10.hs
new file mode 100644 (file)
index 0000000..cf1fff3
--- /dev/null
@@ -0,0 +1,52 @@
+import Data.List.Split (splitOn, chunksOf)
+import Data.Char (ord)
+import Data.Bits (xor)
+import Text.Printf (printf)
+
+main :: IO ()
+main = do 
+        text <- readFile "data/advent10.txt"
+        let ls = map read $ splitOn "," text
+        print $ part1 ls
+        putStrLn $ part2 text
+
+
+part1 :: [Int] -> Int
+part1 lengths = (tied!!0) * (tied!!1)
+    where (tied, _, _) = foldl step ([0..255], 0, 0) lengths
+
+
+part2 :: String -> String
+part2 text = densify tied
+    where lengths = p2lengths text
+          (tied, _, _) = foldl step ([0..255], 0, 0) lengths
+
+step :: ([Int], Int, Int) -> Int -> ([Int], Int, Int)
+step (original, start, skip) len = (replaced, start', skip + 1)
+    where replaced = tie original start len
+          start' = (start + len + skip) `mod` (length original)
+
+tie :: [a] -> Int -> Int -> [a]
+tie original start len = replace original replacement start
+    where replacement = reverse $ extract original start len
+
+extract :: [a] -> Int -> Int -> [a]
+extract items from len = take len $ drop from $ items ++ items
+
+replace :: [a] -> [a] -> Int -> [a]
+replace original replacement from = take (length original) (start ++ replacement ++ remainder)
+    where excess = drop (length original - from) replacement
+          stub = drop (length excess) original
+          start = take from (excess ++ stub)
+          remainder = drop (length $ start ++ replacement) original 
+
+
+p2lengths :: String -> [Int]
+p2lengths text = take (length chunk * 64) $ cycle chunk
+    where chunk = map ord text ++ [17, 31, 73, 47, 23]
+
+densify :: [Int] -> String
+densify ns = concatMap (printf "%02x") codes
+    where chunks = chunksOf 16 ns
+          compress = foldl1 xor
+          codes = map compress chunks
diff --git a/src/advent10/advent10.ipynb b/src/advent10/advent10.ipynb
new file mode 100644 (file)
index 0000000..2a39401
--- /dev/null
@@ -0,0 +1,680 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "{-# LANGUAGE NegativeLiterals #-}\n",
+    "{-# LANGUAGE FlexibleContexts #-}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 113,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import Data.List.Split (splitOn, chunksOf)\n",
+    "import Data.Char (ord, chr)\n",
+    "import Data.Bits\n",
+    "import Numeric (showHex)\n",
+    "import Text.Printf"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "extract items from len = take len $ drop from $ items ++ items"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 24,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "-- replace original replacement from \n",
+    "--     | from + length replacement <= length original = replacement ++ drop (length replacement) original\n",
+    "--     | otherwise = drop (length original) extended ++ \n",
+    "--             where extended = take from original ++ replacement ++ drop suflen original\n",
+    "--                   suflen = from + length replacement - length original "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 51,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "replace original replacement from = take (length original) (start ++ replacement ++ remainder)\n",
+    "    where excess = drop (length original - from) replacement\n",
+    "          stub = drop (length excess) original\n",
+    "          start = take from (excess ++ stub)\n",
+    "          remainder = drop (length $ start ++ replacement) original "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 52,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[0,1,2]"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "extract [0, 1, 2, 3, 4] 0 3"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 53,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[2,1,0]"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "reverse [0,1,2]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 54,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "l0 = [0,1,2,3,4]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 55,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[2,1,0,3,4]"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "replace l0 (reverse $ extract l0 0 3) 0"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 56,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[4,0,1]"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "extract l0 4 3"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 57,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[0,4,2,3,1]"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "replace l0 (reverse $ extract l0 4 3) 4"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "0 1 2 3 4\n",
+    "0 1 2 3 [4]\n",
+    "0 1) 2 3 ([4]\n",
+    "0 4) 2 3 (1\n",
+    "\n",
+    "0 1 2 3   4  | 0 1  2 3 4\n",
+    "0 1 2 3  [4] | 0 1  2 3 4\n",
+    "0 1 2 3 ([4] | 0 1) 2 3 4\n",
+    "0 1 2 3 ( 1  | 0 4) 2 3 4\n",
+    "\n",
+    "\n",
+    "  0  1 2  3 4 | 0 1 2 3 4\n",
+    " [0] 1 2  3 4 | 0 1 2 3 4\n",
+    "([0] 1 2) 3 4 | 0 1 2 3 4\n",
+    "( 2  1 0) 3 4 | 0 1 2 3 4"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 58,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "tie original start len = replace original replacement start\n",
+    "    where replacement = reverse $ extract original start len"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 59,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<style>/* Styles used for the Hoogle display in the pager */\n",
+       ".hoogle-doc {\n",
+       "display: block;\n",
+       "padding-bottom: 1.3em;\n",
+       "padding-left: 0.4em;\n",
+       "}\n",
+       ".hoogle-code {\n",
+       "display: block;\n",
+       "font-family: monospace;\n",
+       "white-space: pre;\n",
+       "}\n",
+       ".hoogle-text {\n",
+       "display: block;\n",
+       "}\n",
+       ".hoogle-name {\n",
+       "color: green;\n",
+       "font-weight: bold;\n",
+       "}\n",
+       ".hoogle-head {\n",
+       "font-weight: bold;\n",
+       "}\n",
+       ".hoogle-sub {\n",
+       "display: block;\n",
+       "margin-left: 0.4em;\n",
+       "}\n",
+       ".hoogle-package {\n",
+       "font-weight: bold;\n",
+       "font-style: italic;\n",
+       "}\n",
+       ".hoogle-module {\n",
+       "font-weight: bold;\n",
+       "}\n",
+       ".hoogle-class {\n",
+       "font-weight: bold;\n",
+       "}\n",
+       ".get-type {\n",
+       "color: green;\n",
+       "font-weight: bold;\n",
+       "font-family: monospace;\n",
+       "display: block;\n",
+       "white-space: pre-wrap;\n",
+       "}\n",
+       ".show-type {\n",
+       "color: green;\n",
+       "font-weight: bold;\n",
+       "font-family: monospace;\n",
+       "margin-left: 1em;\n",
+       "}\n",
+       ".mono {\n",
+       "font-family: monospace;\n",
+       "display: block;\n",
+       "}\n",
+       ".err-msg {\n",
+       "color: red;\n",
+       "font-style: italic;\n",
+       "font-family: monospace;\n",
+       "white-space: pre;\n",
+       "display: block;\n",
+       "}\n",
+       "#unshowable {\n",
+       "color: red;\n",
+       "font-weight: bold;\n",
+       "}\n",
+       ".err-msg.in.collapse {\n",
+       "padding-top: 0.7em;\n",
+       "}\n",
+       ".highlight-code {\n",
+       "white-space: pre;\n",
+       "font-family: monospace;\n",
+       "}\n",
+       ".suggestion-warning { \n",
+       "font-weight: bold;\n",
+       "color: rgb(200, 130, 0);\n",
+       "}\n",
+       ".suggestion-error { \n",
+       "font-weight: bold;\n",
+       "color: red;\n",
+       "}\n",
+       ".suggestion-name {\n",
+       "font-weight: bold;\n",
+       "}\n",
+       "</style><div class=\"suggestion-name\" style=\"clear:both;\">Redundant bracket</div><div class=\"suggestion-row\" style=\"float: left;\"><div class=\"suggestion-warning\">Found:</div><div class=\"highlight-code\" id=\"haskell\">(start + len + skip) `mod` (length original)</div></div><div class=\"suggestion-row\" style=\"float: left;\"><div class=\"suggestion-warning\">Why Not:</div><div class=\"highlight-code\" id=\"haskell\">(start + len + skip) `mod` length original</div></div>"
+      ],
+      "text/plain": [
+       "Line 3: Redundant bracket\n",
+       "Found:\n",
+       "(start + len + skip) `mod` (length original)\n",
+       "Why not:\n",
+       "(start + len + skip) `mod` length original"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "step (original, start, skip) len = (replaced, start', skip + 1)\n",
+    "    where replaced = tie original start len\n",
+    "          start' = (start + len + skip) `mod` (length original)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 60,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[0,1,2,3,4]"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "[0..4]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 61,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "([2,1,0,3,4],3,1)"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "step ([0..4], 0, 0) 3"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 66,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "([3,4,2,1,0],4,4)"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "foldl step ([0..4], 0, 0) [3, 4, 1, 5]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 79,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "part1 :: [Int] -> Int\n",
+    "part1 lengths = (tied!!0) * (tied!!1)\n",
+    "    where (tied, _, _) = foldl step ([0..255], 0, 0) lengths"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 101,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "part2 text = tied\n",
+    "    where lengths = p2lengths text\n",
+    "          (tied, _, _) = foldl step ([0..255], 0, 0) lengths"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 102,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "main :: IO ()\n",
+    "main = do \n",
+    "        text <- readFile \"../../data/advent10.txt\"\n",
+    "        let instrs = map read $ splitOn \",\" text\n",
+    "        print $ part1 instrs\n",
+    "        print $ part2 text"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 103,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "38415\n",
+       "[166,221,219,74,89,118,226,182,77,185,188,87,238,181,229,173,45,68,84,147,10,194,196,201,55,80,171,119,186,54,154,46,52,161,9,149,135,255,180,210,129,214,127,18,51,236,56,78,24,187,97,25,131,70,143,106,211,218,189,224,179,220,41,141,240,233,76,26,253,207,159,172,86,241,136,215,12,197,112,62,23,138,0,169,99,50,235,205,122,103,116,71,251,160,206,22,4,202,252,40,234,242,193,39,32,191,63,217,152,117,33,163,61,213,164,133,6,16,110,58,102,43,126,67,31,30,95,199,2,183,1,208,239,96,20,13,57,66,38,132,177,195,44,203,247,65,14,227,100,82,151,3,28,150,98,146,140,37,42,120,168,91,83,27,209,148,176,250,101,162,145,79,115,15,228,192,142,104,155,29,19,53,49,35,128,5,184,248,222,123,124,216,178,64,113,198,244,245,246,167,47,11,170,212,109,114,237,94,144,69,243,254,121,231,59,108,17,153,249,34,72,7,130,21,200,175,81,134,105,137,75,165,156,174,232,125,92,88,8,93,157,223,225,48,111,85,107,204,36,158,90,139,190,230,60,73]"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "main"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 85,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "97"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "ord 'a'"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 86,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'a'"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "chr 97"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 88,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "4"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "7 `xor` 3"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 112,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "\"ff\""
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "showHex 255 \"\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 116,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "ff"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "printf \"%02x\" 255"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 93,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "p2lengths text = take (length chunk * 64) $ cycle chunk\n",
+    "    where chunk = map ord text ++ [17, 31, 73, 47, 23]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 117,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "densify ns = concatMap (printf \"%02x\") codes\n",
+    "    where chunks = chunksOf 16 ns\n",
+    "          compress = foldl1 xor\n",
+    "          codes = map compress chunks"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 126,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "part2 :: String -> String\n",
+    "part2 text = densify tied\n",
+    "    where lengths = p2lengths text\n",
+    "          (tied, _, _) = foldl step ([0..255], 0, 0) lengths"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 121,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "a2582a3a0e66e6e86e3812dcb672a272"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "putStrLn $ part2 \"\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 122,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "33efeb34ea91902bb2f59c9920caa6cd"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "putStrLn $ part2 \"AoC 2017\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 123,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "3efbe78a8d82f29979031a4aa0b16a9d"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "putStrLn $ part2 \"1,2,3\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 124,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "63960835bcdc130f0b66d7ff4f6a5a8e"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "putStrLn $ part2 \"1,2,4\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 129,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "main :: IO ()\n",
+    "main = do \n",
+    "        text <- readFile \"../../data/advent10.txt\"\n",
+    "        let instrs = map read $ splitOn \",\" text\n",
+    "        print $ part1 instrs\n",
+    "        putStrLn $ part2 text"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 130,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "38415\n",
+       "9de8846431eef262be78f590e39a4848"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "main"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Haskell",
+   "language": "haskell",
+   "name": "haskell"
+  },
+  "language_info": {
+   "codemirror_mode": "ihaskell",
+   "file_extension": ".hs",
+   "name": "haskell",
+   "version": "8.0.2"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}