Add Rust solutions for days 1-3
Signed-off-by: Alek Ratzloff <alekr@jsausa.com>
This commit is contained in:
56
day01/Day01.rs
Normal file
56
day01/Day01.rs
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
use std::io::{self, Read};
|
||||||
|
|
||||||
|
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
||||||
|
|
||||||
|
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 mass_list: Vec<_> = get_input_string()?
|
||||||
|
.split("\n")
|
||||||
|
.filter(|n| !n.is_empty())
|
||||||
|
.map(|n| n.parse::<u64>().unwrap())
|
||||||
|
.collect();
|
||||||
|
part1(&mass_list);
|
||||||
|
part2(&mass_list);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1(mass_list: &Vec<u64>) {
|
||||||
|
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<u64>) {
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
68
day02/Day02.rs
Normal file
68
day02/Day02.rs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
use std::io::{self, Read};
|
||||||
|
|
||||||
|
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
||||||
|
|
||||||
|
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 program: Vec<_> = get_input_string()?
|
||||||
|
.trim()
|
||||||
|
.split(",")
|
||||||
|
.filter(|s| !s.is_empty())
|
||||||
|
.map(|n| n.parse::<usize>().unwrap())
|
||||||
|
.collect();
|
||||||
|
part1(&program);
|
||||||
|
part2(&program);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1(program: &Vec<usize>) {
|
||||||
|
let data = run_program(12, 2, program.clone());
|
||||||
|
println!("Part 1: {}", data[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part2(program: &Vec<usize>) {
|
||||||
|
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<usize>) -> Vec<usize> {
|
||||||
|
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
|
||||||
|
}
|
||||||
365
day03/Day03.rs
Normal file
365
day03/Day03.rs
Normal file
@@ -0,0 +1,365 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
11
day04/Day04.rs
Normal file
11
day04/Day04.rs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
//use std::io::{self, Read};
|
||||||
|
|
||||||
|
//type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
part1(246515, 739105);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part1(lower: usize, upper: usize) {
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user