mirror of
https://github.com/wezm/advent-of-code.git
synced 2024-12-18 18:29:55 +00:00
Another go at day 3 solution that works this time
This commit is contained in:
parent
54b3860012
commit
67dcde80c5
2 changed files with 30 additions and 72 deletions
1
2017/day/3/input
Normal file
1
2017/day/3/input
Normal file
|
@ -0,0 +1 @@
|
||||||
|
289326
|
|
@ -1,83 +1,41 @@
|
||||||
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() {
|
fn main() {
|
||||||
println!("{}", manhattan_distance(289326));
|
println!("{}", manhattan_distance(289326));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the dimensions of the rectangle in the spiral that the given number must be on. Will
|
fn spiral_to(index: usize) -> (isize, isize) {
|
||||||
// always be an odd number as 1 is in the middle.
|
let mut x = 0isize;
|
||||||
fn spiral_diameter(index: i32) -> i32 {
|
let mut y = 0isize;
|
||||||
let sqrt = (index as f64).sqrt().ceil() as i32;
|
let mut edge = 1;
|
||||||
if sqrt % 2 == 0 { sqrt + 1 } else { sqrt }
|
let mut delta = 1isize;
|
||||||
|
let mut i = 1usize;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
// Horizontal
|
||||||
|
for _i in 0..edge {
|
||||||
|
x += delta;
|
||||||
|
i += 1;
|
||||||
|
if i == index { return (x, y) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns angle in radians of number on spiral
|
// Vertical
|
||||||
fn angle(index: i32) -> f64 {
|
for _i in 0..edge {
|
||||||
if index == 1 { return 0. }
|
y += delta;
|
||||||
|
i += 1;
|
||||||
let diameter = spiral_diameter(index);
|
if i == index { return (x, y) }
|
||||||
|
|
||||||
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 {
|
edge += 1;
|
||||||
|
delta *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn manhattan_distance(index: usize) -> usize {
|
||||||
if index == 1 { return 0 }
|
if index == 1 { return 0 }
|
||||||
|
|
||||||
let angle = angle(index);
|
let (x, y) = spiral_to(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
|
(x.abs() + y.abs()) as usize
|
||||||
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.
|
// Data from square 1 is carried 0 steps, since it's at the access port.
|
||||||
|
@ -145,4 +103,3 @@ fn test_example11() {
|
||||||
fn test_example12() {
|
fn test_example12() {
|
||||||
assert_eq!(manhattan_distance(37), 6);
|
assert_eq!(manhattan_distance(37), 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue