Files
adventofcode-2019/day03/Day03.rs

366 lines
9.8 KiB
Rust
Raw Normal View History

use std::{
error::Error,
fmt::{self, Formatter, Display},
io::{self, Read},
mem,
str::FromStr,
};
type Result<T> = std::result::Result<T, Box<dyn Error>>;
#[derive(Debug, Clone)]
struct ErrorMessage(String);
impl From<String> for ErrorMessage {
fn from(other: String) -> Self {
ErrorMessage(other)
}
}
impl ErrorMessage {
fn message(&self) -> &String {
&self.0
}
}
impl Display for ErrorMessage {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
write!(fmt, "{}", self.message())
}
}
impl Error for ErrorMessage {
fn description(&self) -> &str {
self.message()
}
}
#[derive(Debug, Clone, Copy)]
enum Wire {
Up(usize),
Down(usize),
Left(usize),
Right(usize),
}
impl Wire {
fn magnitude(&self) -> usize {
match self {
Wire::Up(m)
| Wire::Down(m)
| Wire::Left(m)
| Wire::Right(m) => *m
}
}
fn add_pos(&self, (x, y): (isize, isize)) -> (isize, isize) {
let (x0, y0) = match self {
Wire::Up(y0) => (0, -(*y0 as isize)),
Wire::Down(y0) => (0, *y0 as isize),
Wire::Left(x0) => (-(*x0 as isize), 0),
Wire::Right(x0) => (*x0 as isize, 0),
};
(x + x0, y + y0)
}
}
impl FromStr for Wire {
type Err = ErrorMessage;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
let num = s[1..].parse::<usize>()
.map_err(|e| ErrorMessage(e.description().to_string()))?;
let c = s.chars().nth(0)
.ok_or_else(|| ErrorMessage("expected U, D, L, or R followed by a number".to_string()))?;
match c {
'U' => Ok(Wire::Up(num)),
'D' => Ok(Wire::Down(num)),
'L' => Ok(Wire::Left(num)),
'R' => Ok(Wire::Right(num)),
_ => Err(ErrorMessage("expected U, D, L, or R followed by a number".to_string())),
}
}
}
#[derive(Debug, Clone, Copy, Default)]
struct Cell {
pass: usize,
steps: [usize; 2],
}
const FIRST_PASS: usize = 1;
const SECOND_PASS: usize = 2;
const BOTH_PASS: usize = FIRST_PASS | SECOND_PASS;
#[derive(Debug)]
struct Board {
board: Vec<Vec<Cell>>,
pos: (isize, isize),
origin: (isize, isize),
steps: usize,
}
impl Default for Board {
fn default() -> Self {
Board {
board: vec![vec![Default::default()]],
pos: Default::default(),
origin: Default::default(),
steps: Default::default(),
}
}
}
impl Display for Board {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
for (y, row) in self.board.iter().enumerate() {
let y = y as isize;
for (x, col) in row.iter().enumerate() {
let x = x as isize;
let c = if (x, y) == self.origin {
'o'
} else if (x, y) == self.pos {
'*'
} else if col.pass > 0 {
'+'
} else {
'.'
};
write!(fmt, "{}", c)?;
}
writeln!(fmt)?;
}
Ok(())
}
}
impl Board {
fn x(&self) -> isize {
self.pos.0
}
fn y(&self) -> isize {
self.pos.1
}
fn origin_x(&self) -> isize {
self.origin.0
}
fn origin_y(&self) -> isize {
self.origin.1
}
fn min_x(&self) -> isize {
-self.origin_x()
}
fn min_y(&self) -> isize {
-self.origin_y()
}
fn max_x(&self) -> isize {
self.board_w() - self.origin_x()
}
fn max_y(&self) -> isize {
self.board_h() - self.origin_y()
}
fn board_w(&self) -> isize {
if self.board.is_empty() {
0
} else {
self.board[0].len() as isize
}
}
fn board_h(&self) -> isize {
self.board.len() as isize
}
fn ensure_pos(&mut self, (pos_x, pos_y): (isize, isize)) {
self.ensure_y_pos(pos_y);
self.ensure_x_pos(pos_x);
}
fn ensure_x_pos(&mut self, pos_x: isize) {
if pos_x >= self.max_x() {
let amount = pos_x - self.max_x() + 1;
self.grow_right(amount as usize);
} else if pos_x <= self.min_x() {
let amount = (self.min_x() - pos_x).abs() + 1;
self.grow_left(amount as usize);
}
}
fn ensure_y_pos(&mut self, pos_y: isize) {
if pos_y >= self.max_y() {
let amount = pos_y - self.max_y() + 1;
self.grow_down(amount as usize);
} else if pos_y <= self.min_y() {
let amount = (self.min_y() - pos_y).abs() + 1;
self.grow_up(amount as usize);
}
}
fn grow_down(&mut self, amount: usize) {
let rows = vec!(vec!(Default::default(); self.board_w() as usize); amount);
self.board.extend(rows);
}
fn grow_up(&mut self, amount: usize) {
let w = self.board_w();
let rows = mem::replace(&mut self.board, vec!(vec!(Default::default(); w as usize); amount));
self.board.extend(rows);
self.origin.1 += amount as isize;
}
fn grow_left(&mut self, amount: usize) {
for row in self.board.iter_mut() {
let row_remainder = mem::replace(row, vec!(Default::default(); amount));
row.extend(row_remainder);
}
self.origin.0 += amount as isize;
}
fn grow_right(&mut self, amount: usize) {
for row in self.board.iter_mut() {
row.extend(vec!(Cell::default(); amount));
}
}
fn apply_wire(&mut self, wire: Wire, which_pass: usize) -> Vec<(Cell, isize, isize)> {
let end_pos = wire.add_pos(self.pos);
self.ensure_pos(end_pos);
let x = (self.x() + self.origin_x()) as usize;
let y = (self.y() + self.origin_y()) as usize;
/*
println!("applying wire {:?}", wire);
println!("pos: {:?}", self.pos);
println!("end pos: {:?}", end_pos);
println!("origin: {:?}", self.origin);
println!("start pos: {:?}", (x, y));
println!("size: {:?}", self.board_size());
*/
let mut crossings = Vec::new();
let step_index = which_pass - 1;
match wire {
Wire::Up(amount) => for offset in 0..amount {
let y0 = y - offset;
self.board[y0][x].pass |= which_pass;
if self.board[y0][x].steps[step_index] == 0 {
self.board[y0][x].steps[step_index] = self.steps + offset;
}
if self.board[y0][x].pass == BOTH_PASS {
let cell = self.board[y0][x];
crossings.push((cell, self.x(), self.y() - (offset as isize)));
}
}
Wire::Down(amount) => for offset in 0..amount {
let y0 = y + offset;
self.board[y0][x].pass |= which_pass;
if self.board[y0][x].steps[step_index] == 0 {
self.board[y0][x].steps[step_index] = self.steps + offset;
}
if self.board[y0][x].pass == BOTH_PASS {
let cell = self.board[y0][x];
crossings.push((cell, self.x(), self.y() + (offset as isize)));
}
}
Wire::Left(amount) => for offset in 0..amount {
let x0 = x - offset;
self.board[y][x0].pass |= which_pass;
if self.board[y][x0].steps[step_index] == 0 {
self.board[y][x0].steps[step_index] = self.steps + offset;
}
if self.board[y][x0].pass == BOTH_PASS {
let cell = self.board[y][x0];
crossings.push((cell, self.x() - (offset as isize), self.y()));
}
}
Wire::Right(amount) => for offset in 0..amount {
let x0 = x + offset;
self.board[y][x0].pass |= which_pass;
if self.board[y][x0].steps[step_index] == 0 {
self.board[y][x0].steps[step_index] = self.steps + offset;
}
if self.board[y][x0].pass == BOTH_PASS {
let cell = self.board[y][x0];
crossings.push((cell, self.x() + (offset as isize), self.y()));
}
}
}
self.steps += wire.magnitude();
self.pos = end_pos;
crossings.retain(|(_, x, y)| (*x, *y) != (0, 0));
crossings
}
fn reset_pos(&mut self) {
self.steps = 0;
self.pos = (0, 0);
}
}
fn get_input_string() -> io::Result<String> {
let mut buffer = String::new();
io::stdin().read_to_string(&mut buffer)?;
Ok(buffer)
}
fn main() -> Result<()> {
let input = get_input_string()?;
let mut lines = input
.trim()
.lines()
.map(|line| line.trim()
.split(",")
.map(|wire| wire.parse::<Wire>().map_err(From::from))
.collect::<Result<Vec<_>>>());
let wires1 = lines.next()
.expect("two lines of input")?;
let wires2 = lines.next()
.expect("two lines of input")?;
day3(&wires1, &wires2);
Ok(())
}
fn day3(wires1: &Vec<Wire>, wires2: &Vec<Wire>) {
let mut board = Board::default();
for wire in wires1.iter() {
board.apply_wire(*wire, FIRST_PASS);
}
board.reset_pos();
let mut crossings = Vec::new();
for wire in wires2.iter() {
crossings.extend(board.apply_wire(*wire, SECOND_PASS));
}
//println!("{}", board);
//println!("{:#?}", crossings);
let shortest: isize = crossings.iter()
.map(|(_, x, y)| x.abs() + y.abs())
.min()
.unwrap();
println!("Part 1: {}", shortest);
let fewest: usize = crossings.iter()
.map(|(cell, _, _)| cell.steps[0] + cell.steps[1])
.min()
.unwrap();
println!("Part 2: {}", fewest);
}