You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
140 lines
3.1 KiB
140 lines
3.1 KiB
use std::collections::HashMap;
|
|
use std::fmt;
|
|
use std::ops::Add;
|
|
use std::str::Chars;
|
|
|
|
pub fn solve(input: &str) -> i32 {
|
|
let mut santa = String::new();
|
|
let mut robo_santa = String::new();
|
|
let mut iter = input.chars();
|
|
|
|
loop {
|
|
match iter.next() {
|
|
Some(c) => santa.push(c),
|
|
None => break,
|
|
}
|
|
match iter.next() {
|
|
Some(c) => robo_santa.push(c),
|
|
None => break,
|
|
}
|
|
}
|
|
|
|
let mut houses: HashMap<Point, u32> = HashMap::new();
|
|
Santa::houses_visited(&santa, &mut houses);
|
|
Santa::houses_visited(&robo_santa, &mut houses);
|
|
houses.len() as i32
|
|
}
|
|
|
|
struct Santa<'a> {
|
|
location: Point,
|
|
directions: Chars<'a>,
|
|
}
|
|
|
|
impl<'a> Santa<'a> {
|
|
fn new(directions: &str) -> Santa {
|
|
Santa {
|
|
location: Point::origin(),
|
|
directions: directions.chars(),
|
|
}
|
|
}
|
|
|
|
fn houses_visited(directions: &str, houses: &mut HashMap<Point, u32>) {
|
|
let santa = Santa::new(directions);
|
|
houses.insert(santa.location, 1);
|
|
|
|
for point in santa {
|
|
*houses.entry(point).or_insert(0) += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> Iterator for Santa<'a> {
|
|
type Item = Point;
|
|
|
|
fn next(&mut self) -> Option<Point> {
|
|
let offset = match self.directions.next() {
|
|
Some('^') => Point { x: 0, y: 1 },
|
|
Some('v') => Point { x: 0, y: -1 },
|
|
Some('>') => Point { x: 1, y: 0 },
|
|
Some('<') => Point { x: -1, y: 0 },
|
|
_ => return None,
|
|
};
|
|
self.location = self.location + offset;
|
|
Some(self.location)
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_one() {
|
|
let directions = ">";
|
|
let santa = Santa::new(directions);
|
|
|
|
let points = santa.collect::<Vec<Point>>();
|
|
let expected = vec![Point { x: 1, y: 0 }];
|
|
assert_eq!(expected, points);
|
|
|
|
let mut houses: HashMap<Point, u32> = HashMap::new();
|
|
Santa::houses_visited(directions, &mut houses);
|
|
assert_eq!(2, houses.len());
|
|
assert_eq!(&1, houses.get(&Point::origin()).unwrap());
|
|
assert_eq!(&1, houses.get(&Point { x: 1, y: 0 }).unwrap());
|
|
}
|
|
|
|
#[test]
|
|
fn test_two() {
|
|
let directions = "^>v<";
|
|
|
|
let mut houses: HashMap<Point, u32> = HashMap::new();
|
|
Santa::houses_visited(directions, &mut houses);
|
|
assert_eq!(4, houses.len());
|
|
assert_eq!(&2, houses.get(&Point::origin()).unwrap());
|
|
assert_eq!(&1, houses.get(&Point { x: 1, y: 0 }).unwrap());
|
|
}
|
|
|
|
#[test]
|
|
fn test_three() {
|
|
let directions = "^v^v^v^v^v";
|
|
|
|
let mut houses: HashMap<Point, u32> = HashMap::new();
|
|
Santa::houses_visited(directions, &mut houses);
|
|
assert_eq!(2, houses.len());
|
|
assert_eq!(&6, houses.get(&Point::origin()).unwrap());
|
|
assert_eq!(&5, houses.get(&Point { x: 0, y: 1 }).unwrap());
|
|
}
|
|
|
|
#[derive(Clone,Copy,Debug,Eq,Hash,PartialEq)]
|
|
struct Point {
|
|
x: i32,
|
|
y: i32,
|
|
}
|
|
|
|
impl Point {
|
|
fn origin() -> Point {
|
|
Point { x: 0, y: 0 }
|
|
}
|
|
}
|
|
|
|
impl Add for Point {
|
|
type Output = Point;
|
|
|
|
fn add(self, other: Point) -> Point {
|
|
Point {
|
|
x: self.x + other.x,
|
|
y: self.y + other.y,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for Point {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
write!(f, "({}, {})", self.x, self.y)
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_point() {
|
|
let point = Point { x: 10, y: -10 };
|
|
let offset = Point { x: -10, y: 10 };
|
|
assert_eq!(Point::origin(), point + offset);
|
|
}
|