aboutsummaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs197
1 files changed, 195 insertions, 2 deletions
diff --git a/src/main.rs b/src/main.rs
index 7dd441b..4929590 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -117,7 +117,7 @@ fn day2() {
println!("2b: {}", count);
}
-#[derive(Eq, PartialEq, Hash, Clone, Copy)]
+#[derive(Eq, PartialEq, Hash, Clone, Copy, Debug)]
struct Point {
x: usize,
y: usize,
@@ -712,8 +712,178 @@ fn day10() {
println!("10b: {}", paths);
}
+#[derive(PartialEq, Eq, Copy, Clone, Debug)]
+enum SeatingObject {
+ FLOOR,
+ EMPTY,
+ OCCUPIED,
+}
+
+struct SeatingMap {
+ map: HashMap<Point, SeatingObject>,
+ dimensions: Point,
+}
+
+impl SeatingMap {
+ fn new(input: &[String]) -> SeatingMap {
+ let mut map = HashMap::new();
+ let mut dimensions = Point { x: 0, y: 0 };
+ for (y, line) in input.iter().enumerate() {
+ for (x, symbol) in line.chars().enumerate() {
+ let obj = match symbol {
+ '.' => SeatingObject::FLOOR,
+ 'L' => SeatingObject::EMPTY,
+ '#' => SeatingObject::OCCUPIED,
+ _ => panic!("unsupported object"),
+ };
+ map.insert(Point{x, y}, obj);
+ dimensions.x = cmp::max(dimensions.x, x + 1);
+ }
+ dimensions.y = cmp::max(dimensions.y, y + 1);
+ }
+ SeatingMap { map, dimensions }
+ }
+
+ fn count_adjacent_occupied(&self, pos: &Point, part2: bool) -> u32 {
+ match part2 {
+ false => self.count_adjacent_occupied1(pos),
+ true => self.count_adjacent_occupied2(pos),
+ }
+ }
+
+ fn count_adjacent_occupied1(&self, pos: &Point) -> u32 {
+ let mut count = 0;
+ for x in 0..=2 {
+ if pos.x + x == 0 {
+ continue;
+ }
+ for y in 0..=2 {
+ if (x, y) == (1, 1) {
+ /* skip center point */
+ continue
+ }
+ if pos.y + y == 0 {
+ continue;
+ }
+ let pos_check = Point {
+ x: pos.x + x - 1,
+ y: pos.y + y - 1
+ };
+ if let Some(SeatingObject::OCCUPIED) = self.map.get(&pos_check) {
+ count += 1;
+ }
+ }
+ }
+ count
+ }
+
+ fn seat_at_direction(&self, pos: &Point, dx: i32, dy: i32) -> SeatingObject {
+ let mut pos = *pos;
+ loop {
+ if pos.x == 0 && dx < 0 { break; }
+ if pos.y == 0 && dy < 0 { break; }
+ if pos.x == self.dimensions.x - 1 && dx > 0 { break; }
+ if pos.y == self.dimensions.y - 1 && dy > 0 { break; }
+ pos = Point {
+ x: ((pos.x as i32) + dx) as usize,
+ y: ((pos.y as i32) + dy) as usize,
+ };
+ match &self.map[&pos] {
+ SeatingObject::FLOOR => {},
+ state => return *state,
+ }
+ }
+ SeatingObject::FLOOR
+ }
+
+ fn count_adjacent_occupied2(&self, pos: &Point) -> u32 {
+ let mut count = 0;
+
+ if self.seat_at_direction(pos, -1, -1) == SeatingObject::OCCUPIED { count += 1 };
+ if self.seat_at_direction(pos, 0, -1) == SeatingObject::OCCUPIED { count += 1 };
+ if self.seat_at_direction(pos, 1, -1) == SeatingObject::OCCUPIED { count += 1 };
+ if self.seat_at_direction(pos, -1, 0) == SeatingObject::OCCUPIED { count += 1 };
+ if self.seat_at_direction(pos, 1, 0) == SeatingObject::OCCUPIED { count += 1 };
+ if self.seat_at_direction(pos, -1, 1) == SeatingObject::OCCUPIED { count += 1 };
+ if self.seat_at_direction(pos, 0, 1) == SeatingObject::OCCUPIED { count += 1 };
+ if self.seat_at_direction(pos, 1, 1) == SeatingObject::OCCUPIED { count += 1 };
+
+ count
+ }
+
+ fn dump_map(&self) {
+ for y in 0..self.dimensions.y {
+ for x in 0..self.dimensions.x {
+ let pos = Point {x, y};
+ let char = match self.map[&pos] {
+ SeatingObject::FLOOR => '.',
+ SeatingObject::EMPTY => 'L',
+ SeatingObject::OCCUPIED => '#',
+ };
+ print!("{}", char);
+ }
+ println!();
+ }
+ println!();
+ }
+
+ fn step(&mut self, part2: bool) -> HashMap<Point, SeatingObject> {
+ let mut new_map = HashMap::new();
+ let occupied_required = if part2 { 5 } else { 4 };
+ for (pos, obj) in &self.map {
+ let new_state = match *obj {
+ SeatingObject::FLOOR => SeatingObject::FLOOR,
+ SeatingObject::EMPTY => {
+ if self.count_adjacent_occupied(pos, part2) == 0 {
+ SeatingObject::OCCUPIED
+ } else {
+ SeatingObject::EMPTY
+ }
+ },
+ SeatingObject::OCCUPIED => {
+ if self.count_adjacent_occupied(pos, part2) >= occupied_required {
+ SeatingObject::EMPTY
+ } else {
+ SeatingObject::OCCUPIED
+ }
+ }
+ };
+ new_map.insert(*pos, new_state);
+ }
+ new_map
+ }
+
+ fn stabilize(&mut self, part2: bool) {
+ loop {
+ let new_map = self.step(part2);
+ if new_map == self.map {
+ break;
+ }
+ self.map = new_map;
+ }
+ }
+
+ fn count_occupied(&self) -> usize {
+ self.map.iter()
+ .filter(|(_, state)| *state == &SeatingObject::OCCUPIED)
+ .count()
+ }
+}
+
+fn day11() {
+ let input = read_lines("input11");
+
+ let mut map = SeatingMap::new(&input);
+ map.stabilize(false);
+ println!("11a: {}", map.count_occupied());
+
+ let mut map = SeatingMap::new(&input);
+ map.stabilize(true);
+ println!("11b: {}", map.count_occupied());
+}
+
fn main() {
- day10();
+ day11();
}
#[cfg(test)]
@@ -922,4 +1092,27 @@ mod tests {
let mut path_cache = HashMap::new();
assert_eq!(count_jolt_paths(&map, &mut path_cache, 0, max_jolts), 19208);
}
+
+ #[test]
+ fn test_day11() {
+ let input = "L.LL.LL.LL\n\
+ LLLLLLL.LL\n\
+ L.L.L..L..\n\
+ LLLL.LL.LL\n\
+ L.LL.LL.LL\n\
+ L.LLLLL.LL\n\
+ ..L.L.....\n\
+ LLLLLLLLLL\n\
+ L.LLLLLL.L\n\
+ L.LLLLL.LL\n";
+ let input = read_lines_str(input);
+
+ let mut map = SeatingMap::new(&input);
+ map.stabilize(false);
+ assert_eq!(map.count_occupied(), 37);
+
+ let mut map = SeatingMap::new(&input);
+ map.stabilize(true);
+ assert_eq!(map.count_occupied(), 26);
+ }
}