91 lines
2.0 KiB
Rust
91 lines
2.0 KiB
Rust
use std::io::{self, Read};
|
|
use std::collections::HashSet;
|
|
|
|
|
|
fn main() {
|
|
let mut buffer = String::new();
|
|
|
|
io::stdin().read_to_string(&mut buffer).unwrap();
|
|
|
|
let (end, real) = follow_instructions(&buffer);
|
|
|
|
if let Some((x, y)) = end {
|
|
println!("end position: x={}, y={}", x, y);
|
|
}
|
|
if let Some((x, y)) = real {
|
|
println!("real position: x={}, y={}", x, y);
|
|
}
|
|
}
|
|
|
|
fn follow_instructions(input: &str) -> (Option<(i32, i32)>, Option<(i32, i32)>) {
|
|
let instructions = input
|
|
.split(',')
|
|
.map(|x| x.trim())
|
|
.map(|x| x.split_at(1))
|
|
.map(|(x, y)| (x, y.parse::<i32>().unwrap()));
|
|
|
|
let mut x = 0;
|
|
let mut y = 0;
|
|
|
|
let mut delta = (0, 1);
|
|
|
|
let mut visited = HashSet::new();
|
|
let mut position: Option<(i32, i32)> = None;
|
|
|
|
for (direction, steps) in instructions {
|
|
delta = match direction {
|
|
"R" => (delta.1, delta.0 * -1),
|
|
"L" => (delta.1 * -1, delta.0),
|
|
_ => unreachable!(),
|
|
};
|
|
|
|
for _ in 0..steps {
|
|
x += delta.0;
|
|
y += delta.1;
|
|
|
|
if position.is_none() {
|
|
if visited.contains(&(x, y)) {
|
|
position = Some((x, y));
|
|
} else {
|
|
visited.insert((x, y));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
(Some((x, y)), position)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::follow_instructions;
|
|
|
|
#[test]
|
|
fn example_01() {
|
|
let input = "R2, L3";
|
|
|
|
assert_eq!((Some((2, 3)), None), follow_instructions(input));
|
|
}
|
|
|
|
#[test]
|
|
fn example_02() {
|
|
let input = "R2, R2, R2";
|
|
|
|
assert_eq!((Some((0, -2)), None), follow_instructions(input));
|
|
}
|
|
|
|
#[test]
|
|
fn example_03() {
|
|
let input = "R5, L5, R5, R3";
|
|
|
|
assert_eq!((Some((10, 2)), None), follow_instructions(input));
|
|
}
|
|
|
|
#[test]
|
|
fn example_04() {
|
|
let input = "R8, R4, R4, R8";
|
|
|
|
assert_eq!((Some((4, 4)), Some((4, 0))), follow_instructions(input));
|
|
}
|
|
}
|