From f3c80f2fd2eee54bc9c964073338b88cbfb0113d Mon Sep 17 00:00:00 2001 From: Alek Ratzloff Date: Wed, 4 Dec 2019 16:22:10 -0500 Subject: [PATCH] Add Rust solutions for days 1-3 Signed-off-by: Alek Ratzloff --- day01/Day01.rs | 56 ++++++++ day02/Day02.rs | 68 +++++++++ day03/Day03.rs | 365 +++++++++++++++++++++++++++++++++++++++++++++++++ day04/Day04.rs | 11 ++ 4 files changed, 500 insertions(+) create mode 100644 day01/Day01.rs create mode 100644 day02/Day02.rs create mode 100644 day03/Day03.rs create mode 100644 day04/Day04.rs diff --git a/day01/Day01.rs b/day01/Day01.rs new file mode 100644 index 0000000..d7fc42a --- /dev/null +++ b/day01/Day01.rs @@ -0,0 +1,56 @@ +use std::io::{self, Read}; + +type Result = std::result::Result>; + +fn get_input_string() -> io::Result { + let mut buffer = String::new(); + io::stdin().read_to_string(&mut buffer)?; + Ok(buffer) +} + +fn main() -> Result<()> { + let mass_list: Vec<_> = get_input_string()? + .split("\n") + .filter(|n| !n.is_empty()) + .map(|n| n.parse::().unwrap()) + .collect(); + part1(&mass_list); + part2(&mass_list); + Ok(()) +} + +fn part1(mass_list: &Vec) { + let total: u64 = mass_list.iter() + .copied() + .map(fuel_req) + .sum(); + + println!("Part 1: {}", total); +} + +fn fuel_req(mass: u64) -> u64 { + let frac = mass / 3; + if frac <= 2 { + 0 + } else { + frac - 2 + } +} + +fn part2(mass_list: &Vec) { + let total: u64 = mass_list.iter() + .copied() + .map(full_fuel_req) + .sum(); + + println!("Part 2: {}", total); +} + +fn full_fuel_req(mass: u64) -> u64 { + let req = fuel_req(mass); + if req == 0 { + 0 + } else { + req + full_fuel_req(req) + } +} diff --git a/day02/Day02.rs b/day02/Day02.rs new file mode 100644 index 0000000..7d33e41 --- /dev/null +++ b/day02/Day02.rs @@ -0,0 +1,68 @@ +use std::io::{self, Read}; + +type Result = std::result::Result>; + +fn get_input_string() -> io::Result { + let mut buffer = String::new(); + io::stdin().read_to_string(&mut buffer)?; + Ok(buffer) +} + +fn main() -> Result<()> { + let program: Vec<_> = get_input_string()? + .trim() + .split(",") + .filter(|s| !s.is_empty()) + .map(|n| n.parse::().unwrap()) + .collect(); + part1(&program); + part2(&program); + Ok(()) +} + +fn part1(program: &Vec) { + let data = run_program(12, 2, program.clone()); + println!("Part 1: {}", data[0]); +} + +fn part2(program: &Vec) { + const GOAL: usize = 19690720; + for noun in 0..=99 { + for verb in 0..=99 { + let data = run_program(noun, verb, program.clone()); + if data[0] == GOAL { + println!("Part 2: noun: {} verb: {} answer: {}", noun, verb, (noun * 100) + verb); + return; + } + } + } + println!("could not find a solution"); +} + +fn run_program(noun: usize, verb: usize, mut program: Vec) -> Vec { + let mut pc = 0; + program[1] = noun; + program[2] = verb; + + loop { + match program[pc] { + op @ 1 | op @ 2 => { + let in1 = program[program[pc + 1]]; + let in2 = program[program[pc + 2]]; + let out = program[pc + 3]; + + let value = if op == 1 { + in1 + in2 + } else { + in1 * in2 + }; + program[out] = value; + } + 99 => break, + _ => panic!("bad opcode: {}", program[pc]), + } + pc += 4; + } + + program +} diff --git a/day03/Day03.rs b/day03/Day03.rs new file mode 100644 index 0000000..708e1c8 --- /dev/null +++ b/day03/Day03.rs @@ -0,0 +1,365 @@ +use std::{ + error::Error, + fmt::{self, Formatter, Display}, + io::{self, Read}, + mem, + str::FromStr, +}; + +type Result = std::result::Result>; + +#[derive(Debug, Clone)] +struct ErrorMessage(String); + +impl From 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 { + let num = s[1..].parse::() + .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>, + 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 { + 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::().map_err(From::from)) + .collect::>>()); + 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, wires2: &Vec) { + 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); +} diff --git a/day04/Day04.rs b/day04/Day04.rs new file mode 100644 index 0000000..76df095 --- /dev/null +++ b/day04/Day04.rs @@ -0,0 +1,11 @@ +//use std::io::{self, Read}; + +//type Result = std::result::Result>; + +fn main() { + part1(246515, 739105); +} + +fn part1(lower: usize, upper: usize) { + +}