Couple of small tweaks and added missing test

This commit is contained in:
Dreaded_X 2022-12-23 20:35:26 +01:00
parent b1e04efaf9
commit 21fff6a4e7
Signed by: Dreaded_X
GPG Key ID: 76BDEC4E165D8AD9

View File

@ -33,6 +33,10 @@ mod tests {
fn part2_test2() -> Result<()> { fn part2_test2() -> Result<()> {
Day::test(Day::part2, "test-2", 20) Day::test(Day::part2, "test-2", 20)
} }
#[test]
fn part2_solution() -> Result<()> {
Day::test(Day::part2, "input", 995)
}
// Benchmarks // Benchmarks
extern crate test; extern crate test;
@ -67,12 +71,11 @@ impl Vec2 {
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
struct Elf { struct Elf {
considering: Vec2, considering: Vec2,
offset: usize,
} }
impl Elf { impl Elf {
fn new() -> Self { fn new() -> Self {
Self { considering: Vec2::new(0, 0), offset: 0 } Self { considering: Vec2::new(0, 0) }
} }
} }
@ -80,6 +83,7 @@ impl Elf {
struct Map { struct Map {
elves: HashMap<Vec2, Elf>, elves: HashMap<Vec2, Elf>,
considered: HashMap<Vec2, usize>, considered: HashMap<Vec2, usize>,
offset: usize,
} }
impl FromStr for Map { impl FromStr for Map {
@ -99,7 +103,7 @@ impl FromStr for Map {
}) })
}).collect(); }).collect();
Ok(Self { elves, considered: HashMap::new()}) Ok(Self { elves, considered: HashMap::new(), offset: 0})
} }
} }
@ -112,22 +116,19 @@ impl Map {
let moves = [north, south, west, east]; let moves = [north, south, west, east];
for (pos, elf) in self.elves.clone() { for pos in self.elves.clone().keys() {
// Default action is to stay in place // Default action is to stay in place
let mut next = pos; let mut next = *pos;
if self.need_to_move(&pos) { if self.need_to_move(&pos) {
for m in moves.iter().cycle().skip(elf.offset).take(4) { for m in moves.iter().cycle().skip(self.offset).take(4) {
if !self.occupied(pos.offset(&m.0[0])) && !self.occupied(pos.offset(&m.0[1])) && !self.occupied(pos.offset(&m.0[2])) { if !self.elves.contains_key(&pos.offset(&m.0[0])) && !self.elves.contains_key(&pos.offset(&m.0[1])) && !self.elves.contains_key(&pos.offset(&m.0[2])) {
next = pos.offset(&m.1); next = pos.offset(&m.1);
break; break;
} }
} }
} }
// The offset is updated every round for all elves
self.elves.get_mut(&pos).unwrap().offset += 1;
// Set the position that the elf is considering // Set the position that the elf is considering
self.elves.get_mut(&pos).unwrap().considering = next; self.elves.get_mut(&pos).unwrap().considering = next;
@ -136,11 +137,8 @@ impl Map {
} }
} }
fn occupied(&self, pos: Vec2) -> bool {
self.elves.contains_key(&pos)
}
fn need_to_move(&self, pos: &Vec2) -> bool { fn need_to_move(&self, pos: &Vec2) -> bool {
// Check all the spaces around the elf to determine if we need to move
for y in -1..2 { for y in -1..2 {
for x in -1..2 { for x in -1..2 {
if x == 0 && y == 0 { if x == 0 && y == 0 {
@ -157,18 +155,18 @@ impl Map {
} }
fn make_moves(&mut self) -> bool { fn make_moves(&mut self) -> bool {
// New hashmap that is going to contain the updated values
let mut elves = HashMap::new(); let mut elves = HashMap::new();
let mut moved = false; let mut moved = false;
for (pos, elf) in &self.elves { for (pos, elf) in &self.elves {
// Check if the move is a valid move
if *self.considered.get(&elf.considering).unwrap() == 1 { if *self.considered.get(&elf.considering).unwrap() == 1 {
// Check if the position of the elf has actually changed
if elf.considering.x != pos.x || elf.considering.y != pos.y { if elf.considering.x != pos.x || elf.considering.y != pos.y {
moved = true; moved = true;
} }
// If only one elf is considering the new location, insert the elf into the new
// HashMap at the new location // Insert the elf with the updated position
elves.insert(elf.considering, *elf); elves.insert(elf.considering, *elf);
} else { } else {
// Otherwise the elf will not move and stay at its old position // Otherwise the elf will not move and stay at its old position
@ -176,14 +174,14 @@ impl Map {
} }
} }
// Update the hashmap
self.elves = elves; self.elves = elves;
// Clear the map tracking considered moves
self.considered.clear(); self.considered.clear();
self.offset += 1;
return moved; return moved;
} }
// Gives the min and max of the smallest rectangle containing all the elves
fn get_size(&self) -> (Vec2, Vec2) { fn get_size(&self) -> (Vec2, Vec2) {
let mut min = Vec2::new(isize::MAX, isize::MAX); let mut min = Vec2::new(isize::MAX, isize::MAX);
let mut max = Vec2::new(0, 0); let mut max = Vec2::new(0, 0);
@ -199,25 +197,26 @@ impl Map {
(min, max) (min, max)
} }
// Calculate the amount of empty tiles in the smallest rectangle containing all the elves
fn empty_tiles(&self) -> isize { fn empty_tiles(&self) -> isize {
let (min, max) = self.get_size(); let (min, max) = self.get_size();
(max.x - min.x) * (max.y - min.y) - self.elves.len() as isize (max.x - min.x) * (max.y - min.y) - self.elves.len() as isize
} }
fn print(&self) { // fn print(&self) {
let (min, max) = self.get_size(); // let (min, max) = self.get_size();
for y in min.y..max.y { // for y in min.y..max.y {
for x in min.x..max.x { // for x in min.x..max.x {
if self.elves.contains_key(&Vec2::new(x, y)) { // if self.elves.contains_key(&Vec2::new(x, y)) {
print!("#"); // print!("#");
} else { // } else {
print!("."); // print!(".");
} // }
} // }
println!(""); // println!("");
} // }
println!(""); // println!("");
} // }
} }
// -- Solution -- // -- Solution --