mirror of
https://github.com/wezm/advent-of-code.git
synced 2024-12-18 10:19:55 +00:00
Add day 3 solution
This commit is contained in:
parent
23d9945b51
commit
2090b52c42
4 changed files with 193 additions and 0 deletions
4
2017/day/3/Cargo.lock
generated
Normal file
4
2017/day/3/Cargo.lock
generated
Normal file
|
@ -0,0 +1,4 @@
|
|||
[[package]]
|
||||
name = "day3"
|
||||
version = "0.1.0"
|
||||
|
6
2017/day/3/Cargo.toml
Normal file
6
2017/day/3/Cargo.toml
Normal file
|
@ -0,0 +1,6 @@
|
|||
[package]
|
||||
name = "day3"
|
||||
version = "0.1.0"
|
||||
authors = ["Wesley Moore <wes@wezm.net>"]
|
||||
|
||||
[dependencies]
|
35
2017/day/3/problem.txt
Normal file
35
2017/day/3/problem.txt
Normal file
|
@ -0,0 +1,35 @@
|
|||
--- Day 3: Spiral Memory ---
|
||||
|
||||
You come across an experimental new kind of memory stored on an infinite two-dimensional grid.
|
||||
|
||||
Each square on the grid is allocated in a spiral pattern starting at a location marked 1 and then counting up while spiraling outward. For example, the first few squares are allocated like this:
|
||||
|
||||
17 16 15 14 13
|
||||
18 5 4 3 12
|
||||
19 6 1 2 11
|
||||
20 7 8 9 10
|
||||
21 22 23---> ...
|
||||
|
||||
While this is very space-efficient (no squares are skipped), requested data must be carried back to square 1 (the location of the only access port for this memory system) by programs that can only move up, down, left, or right. They always take the shortest path: the Manhattan Distance between the location of the data and square 1.
|
||||
|
||||
For example:
|
||||
|
||||
Data from square 1 is carried 0 steps, since it's at the access port.
|
||||
Data from square 12 is carried 3 steps, such as: down, left, left.
|
||||
Data from square 23 is carried only 2 steps: up twice.
|
||||
Data from square 1024 must be carried 31 steps.
|
||||
|
||||
How many steps are required to carry the data from the square identified in your puzzle input all the way to the access port?
|
||||
|
||||
Your puzzle input is 289326.
|
||||
|
||||
---
|
||||
|
||||
37 36 35 34 33 32 31
|
||||
38 17 16 15 14 13 30
|
||||
39 18 5 4 3 12 29
|
||||
40 19 6 1 2 11 28
|
||||
41 20 7 8 9 10 27
|
||||
42 21 22 23 24 25 26
|
||||
43 44 45 46 47 48 49
|
||||
|
148
2017/day/3/src/main.rs
Normal file
148
2017/day/3/src/main.rs
Normal file
|
@ -0,0 +1,148 @@
|
|||
use std::f64::consts::PI;
|
||||
|
||||
// There might me a more elegant solution to this problem that I've missed (it was completed
|
||||
// without any Internet access). At least it runs in constant time and space.
|
||||
fn main() {
|
||||
println!("{}", manhattan_distance(289326));
|
||||
}
|
||||
|
||||
// Determine the dimensions of the rectangle in the spiral that the given number must be on. Will
|
||||
// always be an odd number as 1 is in the middle.
|
||||
fn spiral_diameter(index: i32) -> i32 {
|
||||
let sqrt = (index as f64).sqrt().ceil() as i32;
|
||||
if sqrt % 2 == 0 { sqrt + 1 } else { sqrt }
|
||||
}
|
||||
|
||||
// Returns angle in radians of number on spiral
|
||||
fn angle(index: i32) -> f64 {
|
||||
if index == 1 { return 0. }
|
||||
|
||||
let diameter = spiral_diameter(index);
|
||||
|
||||
let area_of_inner_rectangle = (diameter - 2).pow(2);
|
||||
let squares_around_rectangle = diameter.pow(2) - area_of_inner_rectangle;
|
||||
let squares_per_side = squares_around_rectangle / 4;
|
||||
|
||||
// Divide the space around the rectangle into squares_around_rectangle segments
|
||||
let angle_per_segment = 2. * PI / squares_around_rectangle as f64;
|
||||
|
||||
// Determine how far around the rectangle this index is.
|
||||
// Offset adjusts for the last number being at the bottom right corner of any
|
||||
// given rectangle.
|
||||
let offset = squares_per_side / 2;
|
||||
let angle = (index - area_of_inner_rectangle - offset) as f64 * angle_per_segment;
|
||||
|
||||
angle
|
||||
}
|
||||
|
||||
fn manhattan_distance(index: i32) -> i32 {
|
||||
if index == 1 { return 0 }
|
||||
|
||||
let angle = angle(index);
|
||||
let radius = (spiral_diameter(index) / 2) as f64;
|
||||
|
||||
// Calculate the x and y coordinates, scale by √2 so that sin/cos at corners is 1
|
||||
let horizontal_distance = 1f64.min((2f64.sqrt() * angle.cos()).abs());
|
||||
let vertical_distance = 1f64.min((2f64.sqrt() * angle.sin()).abs());
|
||||
|
||||
let distance = radius * (horizontal_distance + vertical_distance);
|
||||
|
||||
distance.round() as i32
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_angle_should_be_zero() {
|
||||
assert_eq!(angle(1), 0.);
|
||||
assert_eq!(angle(2), 0.);
|
||||
assert_eq!(angle(11), 0.);
|
||||
assert_eq!(angle(28), 0.);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_angle_should_be_half_pi() {
|
||||
use std::f64::consts::FRAC_PI_2;
|
||||
|
||||
assert_eq!(angle(4), FRAC_PI_2);
|
||||
assert_eq!(angle(15), FRAC_PI_2);
|
||||
assert_eq!(angle(34), FRAC_PI_2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_angle_should_be_1_point_75_pi() {
|
||||
assert_eq!(angle(9), 1.75 * PI);
|
||||
assert_eq!(angle(25), 1.75 * PI);
|
||||
assert_eq!(angle(49), 1.75 * PI);
|
||||
assert_eq!(angle(1089), 1.75 * PI);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_angle_37() {
|
||||
assert_eq!(angle(37), 0.75 * PI);
|
||||
}
|
||||
|
||||
// Data from square 1 is carried 0 steps, since it's at the access port.
|
||||
#[test]
|
||||
fn test_example1() {
|
||||
assert_eq!(manhattan_distance(1), 0);
|
||||
}
|
||||
|
||||
// Data from square 12 is carried 3 steps, such as: down, left, left.
|
||||
#[test]
|
||||
fn test_example2() {
|
||||
assert_eq!(manhattan_distance(12), 3);
|
||||
}
|
||||
|
||||
// Data from square 23 is carried only 2 steps: up twice.
|
||||
#[test]
|
||||
fn test_example3() {
|
||||
assert_eq!(manhattan_distance(23), 2);
|
||||
}
|
||||
|
||||
// Data from square 1024 must be carried 31 steps.
|
||||
#[test]
|
||||
fn test_example4() {
|
||||
assert_eq!(manhattan_distance(1024), 31);
|
||||
}
|
||||
|
||||
/*---*/
|
||||
|
||||
#[test]
|
||||
fn test_example5() {
|
||||
assert_eq!(manhattan_distance(46), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_example6() {
|
||||
assert_eq!(manhattan_distance(11), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_example7() {
|
||||
assert_eq!(manhattan_distance(10), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_example8() {
|
||||
assert_eq!(manhattan_distance(9), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_example9() {
|
||||
assert_eq!(manhattan_distance(49), 6);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_example10() {
|
||||
assert_eq!(manhattan_distance(28), 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_example11() {
|
||||
assert_eq!(manhattan_distance(1089), 32);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_example12() {
|
||||
assert_eq!(manhattan_distance(37), 6);
|
||||
}
|
||||
|
Loading…
Reference in a new issue