Created
December 17, 2024 19:44
-
-
Save weirddan455/f871942a8ce50c21a7be832125a1c749 to your computer and use it in GitHub Desktop.
Advent of Code Day 15 Part 2 (not working)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use std::ops::{Add, AddAssign}; | |
#[derive(Clone, Copy)] | |
enum Direction { | |
Up, | |
Down, | |
Left, | |
Right | |
} | |
#[derive(Clone, Copy, PartialEq, Eq)] | |
struct Vector2 { | |
x: i32, | |
y: i32 | |
} | |
impl Add<Direction> for Vector2 { | |
type Output = Self; | |
fn add(self, rhs: Direction) -> Self::Output { | |
match rhs { | |
Direction::Up => Self{x: self.x, y: self.y - 1}, | |
Direction::Down => Self{x: self.x, y: self.y + 1}, | |
Direction::Left => Self{x: self.x - 1, y: self.y}, | |
Direction::Right => Self{x: self.x + 1, y: self.y} | |
} | |
} | |
} | |
impl AddAssign<Direction> for Vector2 { | |
fn add_assign(&mut self, rhs: Direction) { | |
match rhs { | |
Direction::Up => self.y -= 1, | |
Direction::Down => self.y += 1, | |
Direction::Left => self.x -= 1, | |
Direction::Right => self.x += 1, | |
} | |
} | |
} | |
#[derive(Clone, Copy, PartialEq, Eq)] | |
struct Rect { | |
pos: Vector2, | |
width: i32, | |
height: i32 | |
} | |
impl Add<Direction> for Rect { | |
type Output = Self; | |
fn add(self, rhs: Direction) -> Self::Output { | |
Self { | |
pos: self.pos + rhs, | |
width: self.width, | |
height: self.height | |
} | |
} | |
} | |
impl AddAssign<Direction> for Rect { | |
fn add_assign(&mut self, rhs: Direction) { | |
self.pos += rhs; | |
} | |
} | |
impl Rect { | |
fn collides(&self, other: &Rect) -> bool { | |
self.pos.x < other.pos.x + other.width && | |
self.pos.x + self.width > other.pos.x && | |
self.pos.y < other.pos.y + other.height && | |
self.pos.y + self.height > other.pos.y | |
} | |
fn can_move(&self, dir: Direction, walls: &Vec<Rect>, boxes: &Vec<Rect>) -> Option<Vec<usize>> { | |
let new_rect = *self + dir; | |
for w in walls { | |
if new_rect.collides(w) { | |
return None; | |
} | |
} | |
let mut ret = Vec::new(); | |
for (i, b) in boxes.iter().enumerate() { | |
if b == self { | |
continue; | |
} | |
if new_rect.collides(b) { | |
match b.can_move(dir, walls, boxes) { | |
Some(mut v) => { | |
ret.push(i); | |
ret.append(&mut v); | |
}, | |
None => return None | |
} | |
} | |
} | |
Some(ret) | |
} | |
fn move_dir(&mut self, dir: Direction, walls: &Vec<Rect>, boxes: &mut Vec<Rect>) { | |
if let Some(v) = self.can_move(dir, walls, boxes) { | |
*self += dir; | |
for i in v { | |
boxes[i] += dir; | |
} | |
} | |
} | |
} | |
struct Input { | |
robot: Rect, | |
walls: Vec<Rect>, | |
boxes: Vec<Rect>, | |
directions: Vec<Direction> | |
} | |
fn parse_input() -> Input { | |
let data = std::fs::read("input").unwrap(); | |
let mut iter = data.split(|&c| c == b'\n'); | |
let mut width: i32 = 0; | |
let mut y: i32 = 0; | |
let mut robot = None; | |
let mut walls = Vec::new(); | |
let mut boxes = Vec::new(); | |
while let Some(line) = iter.next() { | |
if line.is_empty() { | |
break; | |
} | |
if width == 0 { | |
width = line.len().try_into().unwrap(); | |
} else { | |
let w: i32 = line.len().try_into().unwrap(); | |
assert_eq!(w, width, "Unequal grid widths"); | |
} | |
let mut x: i32 = 0; | |
for c in line { | |
match *c { | |
b'#' => walls.push(Rect{ | |
pos: Vector2{x, y}, | |
width: 2, | |
height: 1 | |
}), | |
b'O' => boxes.push(Rect{ | |
pos: Vector2{x, y}, | |
width: 2, | |
height: 1 | |
}), | |
b'.' => {}, | |
b'@' => { | |
assert!(robot.is_none(), "Found more than one robot"); | |
robot = Some(Rect{ | |
pos: Vector2{x, y}, | |
width: 1, | |
height: 1 | |
}); | |
} | |
_ => panic!("Invalid char in grid: {}", *c as char) | |
} | |
x += 2; | |
} | |
y += 1; | |
} | |
let mut directions = Vec::new(); | |
while let Some(line) = iter.next() { | |
for c in line { | |
match *c { | |
b'^' => directions.push(Direction::Up), | |
b'<' => directions.push(Direction::Left), | |
b'>' => directions.push(Direction::Right), | |
b'v' => directions.push(Direction::Down), | |
_ => panic!("Invalid char in input: {}", *c as char) | |
} | |
} | |
} | |
assert!(!directions.is_empty(), "Failed to parse directions"); | |
assert!(!walls.is_empty(), "Failed to parse walls"); | |
assert!(!boxes.is_empty(), "Failed to parse boxes"); | |
Input { | |
robot: robot.expect("Failed to find robot"), | |
walls, | |
boxes, | |
directions | |
} | |
} | |
fn main() { | |
let mut input = parse_input(); | |
for dir in input.directions { | |
input.robot.move_dir(dir, &input.walls, &mut input.boxes); | |
} | |
let mut answer = 0; | |
for b in input.boxes { | |
answer += b.pos.y * 100 + b.pos.x; | |
} | |
println!("Answer: {answer}"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment