@@ -1699,6 +1699,69 @@ Day 17
1699
1699
1700
1700
[ d17c ] : https://github.com/mstksg/advent-of-code-2017/blob/master/src/AOC2017/Day17.hs
1701
1701
1702
+ For Day 17 I used ` Tape ` again -- for the O(1) insertions. (Even though moving
1703
+ around is amortized O(n)).
1704
+
1705
+ ``` haskell
1706
+ data Tape a = Tape { _tLefts :: [a ]
1707
+ , _tFocus :: a
1708
+ , _tRights :: [a ]
1709
+ }
1710
+ deriving Show
1711
+
1712
+ unshift :: a -> Tape a -> Tape a
1713
+ unshift y (Tape ls x rs) = Tape (x: ls) y rs
1714
+
1715
+ moveRight :: Tape a -> Tape a
1716
+ moveRight (Tape ls x rs) = case rs of
1717
+ [] -> let l :| ls' = NE. reverse (x :| ls)
1718
+ in Tape [] l ls'
1719
+ r: rs' -> Tape (x: ls) r rs'
1720
+ ```
1721
+
1722
+ The only difference between this motion and the previous motion is the periodic
1723
+ boundary conditions of tape motion. Before, if we went past the edge of the
1724
+ tape, we'd return ` Nothing ` . Here, however, we want to "cycle" around, so we
1725
+ reverse the left-hand list and move our focus to the last item in the list.
1726
+
1727
+ With that in mind, we can write our stepping function:
1728
+
1729
+ ``` haskell
1730
+ step :: Int -> Tape a -> a -> Tape a
1731
+ step n t0 x = unshift x . moveC n $ t0
1732
+ ```
1733
+
1734
+ We expect the number of steps to take, the initial tape, and the item to add.
1735
+ This will cycle the tape the given number of steps and then insert the desired
1736
+ item.
1737
+
1738
+ Part 1 is then just applying this as a ` foldl ` :
1739
+
1740
+ ``` haskell
1741
+ day17a :: Int -> Int
1742
+ day17a n = head . _tRights
1743
+ $ foldl' (step n) (Tape [] 0 [] ) [1 .. 2017 ]
1744
+ ````
1745
+
1746
+ Part 2 can't really be done by iterating this process 50 million times. One
1747
+ thing we can leverage is the fact that since 0 is there from the beginning (at
1748
+ position 0 ), we only need to keep track of all the items that are ever inserted
1749
+ at position 1 :
1750
+
1751
+ ```haskell
1752
+ day17b :: Int -> Int
1753
+ day17b n = last
1754
+ . elemIndices @ Int 1
1755
+ $ scanl jump 0 [1 .. 5e7 ]
1756
+ where
1757
+ jump i x = ((i + n) `mod` x) + 1
1758
+ ```
1759
+
1760
+ At each step, we "jump" the ` n ` steps from the current position, being sure to
1761
+ ` mod ` by the current size of the tape. ` scanl ` then gives us the position of
1762
+ the cursor for all points in our process. We then find all of the positions
1763
+ where the function jumps to ` 1 ` using ` elemIndices ` , and find the last one.
1764
+
1702
1765
### Day 17 Benchmarks
1703
1766
1704
1767
```
0 commit comments