Skip to content

Commit d035570

Browse files
committed
day 17 reflections
1 parent caa6dc7 commit d035570

File tree

3 files changed

+65
-2
lines changed

3 files changed

+65
-2
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ processes and how my solutions all work. Benchmarks also included.
2727
* **[Day 14 Reflections][d14r]** *([code][d14c])* *([benchmarks][d14b])*
2828
* **[Day 15 Reflections][d15r]** *([code][d15c])* *([benchmarks][d15b])*
2929
* **[Day 16 Reflections][d16r]** *([code][d16c])* *([benchmarks][d16b])*
30-
* **Day 17 Reflections** *([code][d17c])* *([benchmarks][d17b])*
30+
* **[Day 17 Reflections][d17r]** *([code][d17c])* *([benchmarks][d17b])*
3131
* **Day 18 Reflections** *([code][d18c])* *([benchmarks][d18b])*
3232
* **Day 19 Reflections** *([code][d19c])* *([benchmarks][d19b])*
3333
* **Day 20 Reflections** *([code][d20c])* *([benchmarks][d20b])*

reflections.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1699,6 +1699,69 @@ Day 17
16991699

17001700
[d17c]: https://github.com/mstksg/advent-of-code-2017/blob/master/src/AOC2017/Day17.hs
17011701

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+
17021765
### Day 17 Benchmarks
17031766

17041767
```

src/AOC2017/Day17.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import Data.List (elemIndices, foldl')
77
unshift :: a -> Tape a -> Tape a
88
unshift y (Tape ls x rs) = Tape (x:ls) y rs
99

10-
step :: Int -> Tape Int -> Int -> Tape Int
10+
step :: Int -> Tape a -> a -> Tape a
1111
step n t0 x = unshift x . moveC n $ t0
1212

1313
day17a :: Challenge

0 commit comments

Comments
 (0)