1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
//! # [Day 17: Spinlock](http://adventofcode.com/2017/day/17) //! //! Suddenly, whirling in the distance, you notice what looks like a //! massive, <span title="You know, as opposed to all those non-pixelated //! hurricanes you see on TV.">pixelated hurricane</span>: a deadly [spinlock]. //! This spinlock isn't just consuming computing power, but memory, too; vast, //! digital mountains are being ripped from the ground and consumed by the //! vortex. //! //! If you don't move quickly, fixing that printer will be the least of your //! problems. //! //! This spinlock's algorithm is simple but efficient, quickly consuming //! everything in its path. It starts with a circular buffer containing only //! the value `0`, which it marks as the *current position*. It then steps //! forward through the circular buffer some number of steps (your puzzle //! input) before inserting the first new value, `1`, after the value it //! stopped on. The inserted value becomes the *current position*. Then, it //! steps forward from there the same number of steps, and wherever it //! stops, inserts after it the second new value, `2`, and uses that as the //! new *current position* again. //! //! It repeats this process of *stepping forward*, *inserting a new value*, //! and *using the location of the inserted value as the new current //! position* a total of `2017` times, inserting `2017` as its final //! operation, and ending with a total of `2018` values (including `0`) in //! the circular buffer. //! //! [spinlock]: https://en.wikipedia.org/wiki/Spinlock /// For example, if the spinlock were to step `3` times per insert, the /// circular buffer would begin to evolve like this (using parentheses to /// mark the current position after each iteration of the algorithm): /// /// - `(0)`, the initial state before any insertions. /// - `0 (1)`: the spinlock steps forward three times (`0`, `0`, `0`), and /// then inserts the first value, `1`, after it. `1` becomes the current /// position. /// - `0 (2) 1`: the spinlock steps forward three times (`0`, `1`, `0`), /// and then inserts the second value, `2`, after it. `2` becomes the /// current position. /// - `0 2 (3) 1`: the spinlock steps forward three times (`1`, `0`, /// `2`), and then inserts the third value, `3`, after it. `3` becomes /// the current position. /// /// And so on: /// /// - `0 2 (4) 3 1` /// - `0 (5) 2 4 3 1` /// - `0 5 2 4 3 (6) 1` /// - `0 5 (7) 2 4 3 6 1` /// - `0 5 7 2 4 3 (8) 6 1` /// - `0 (9) 5 7 2 4 3 8 6 1` /// /// Eventually, after 2017 insertions, the section of the circular buffer /// near the last insertion looks like this: /// /// ```text /// 1512 1134 151 (2017) 638 1513 851 /// ``` /// /// Perhaps, if you can identify the value that will ultimately be *after* /// the last value written (`2017`), you can short-circuit the spinlock. In /// this example, that would be `638`. /// /// ``` /// # use advent_solutions::advent2017::day17::part1; /// assert_eq!(part1(&3), 638) /// ``` /// /// *What is the value after `2017`* in your completed circular buffer? pub fn part1(input: &usize) -> usize { let mut position = 0; let mut buffer = vec![0]; for i in 0..2017 { position = 1 + (position + input) % buffer.len(); buffer.insert(position, i + 1); } buffer[(position + 1) % buffer.len()] } /// The spinlock does not short-circuit. Instead, it gets *more* angry. At /// least, you assume that's what happened; it's spinning significantly /// faster than it was a moment ago. /// /// You have good news and bad news. /// /// The good news is that you have improved calculations for how to stop the /// spinlock. They indicate that you actually need to identify *the value /// after `0`* in the current state of the circular buffer. /// /// The bad news is that while you were determining this, the spinlock has /// just finished inserting its fifty millionth value (`50000000`). /// /// *What is the value after `0`* the moment `50000000` is inserted? pub fn part2(input: &usize) -> usize { let mut position = 0; let mut last_i = 0; for i in 1..50_000_000 { position = 1 + (position + input) % i; if position == 1 { last_i = i; } } last_i } pub fn parse_input(input: &str) -> usize { input[..input.len() - 1] .parse::<usize>() .expect("Unexpected non-integer") } test_day!("17", 1561, 33454823);