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