mirror of
https://gitlab.com/MisterBiggs/aoc-2023-rust.git
synced 2025-07-23 22:51:32 +00:00
day 1 leggoo
This commit is contained in:
126
src/day1.rs
126
src/day1.rs
@@ -1,4 +1,4 @@
|
||||
use itertools::Itertools;
|
||||
// use itertools::Itertools;
|
||||
use std::fs;
|
||||
|
||||
pub fn run() {
|
||||
@@ -9,32 +9,69 @@ pub fn run() {
|
||||
println!("\tPart 2: {}", part2(&input));
|
||||
}
|
||||
|
||||
fn part1(food_input: &str) -> usize {
|
||||
food_input
|
||||
.split("\n\n")
|
||||
.into_iter()
|
||||
.map(|elf| {
|
||||
elf.split_whitespace()
|
||||
.map(|food| food.parse::<usize>().unwrap())
|
||||
.sum()
|
||||
fn part1(calibration_input: &str) -> usize {
|
||||
calibration_input
|
||||
.split("\n")
|
||||
.map(|line| {
|
||||
let digits = line.chars().filter(|c| c.is_digit(10)).collect::<String>();
|
||||
|
||||
if digits.len() == 1 {
|
||||
digits.parse::<usize>().unwrap() * 11
|
||||
} else {
|
||||
let tens = digits.chars().nth(0).unwrap().to_digit(10).unwrap();
|
||||
let ones = digits.chars().last().unwrap().to_digit(10).unwrap();
|
||||
(tens * 10 + ones) as usize
|
||||
}
|
||||
})
|
||||
.into_iter()
|
||||
.max()
|
||||
.unwrap()
|
||||
.sum()
|
||||
}
|
||||
fn part2(food_input: &str) -> usize {
|
||||
food_input
|
||||
.split("\n\n")
|
||||
.collect::<Vec<&str>>()
|
||||
.into_iter()
|
||||
.map(|elf| {
|
||||
elf.split_whitespace()
|
||||
.map(|food| food.parse::<usize>().unwrap())
|
||||
.sum::<usize>()
|
||||
|
||||
fn part2(calibration_input: &str) -> usize {
|
||||
let word_to_digit_map: [(&str, usize); 9] = [
|
||||
("one", 1),
|
||||
("two", 2),
|
||||
("three", 3),
|
||||
("four", 4),
|
||||
("five", 5),
|
||||
("six", 6),
|
||||
("seven", 7),
|
||||
("eight", 8),
|
||||
("nine", 9),
|
||||
];
|
||||
|
||||
calibration_input
|
||||
.split("\n")
|
||||
.map(|line| {
|
||||
let mut index_and_digit: Vec<(usize, usize)> = vec![];
|
||||
|
||||
for (word, digit) in word_to_digit_map {
|
||||
for (index, _) in line.match_indices(word).collect::<Vec<_>>() {
|
||||
index_and_digit.push((index, digit));
|
||||
}
|
||||
}
|
||||
|
||||
for (index, c) in line.chars().enumerate() {
|
||||
match c.to_digit(10) {
|
||||
Some(digit) => index_and_digit.push((index, digit as usize)),
|
||||
None => continue,
|
||||
}
|
||||
}
|
||||
|
||||
if index_and_digit.len() == 1 {
|
||||
index_and_digit[0].1 * 11
|
||||
} else {
|
||||
index_and_digit.sort_by(|a, b| a.0.cmp(&b.0));
|
||||
println!(
|
||||
"{} {}",
|
||||
&line,
|
||||
index_and_digit[0].1 * 10 + index_and_digit.last().unwrap().1
|
||||
);
|
||||
|
||||
index_and_digit[0].1 * 10 + index_and_digit.last().unwrap().1
|
||||
}
|
||||
})
|
||||
.sorted()
|
||||
.rev()
|
||||
.take(3)
|
||||
.into_iter()
|
||||
.sum()
|
||||
}
|
||||
|
||||
@@ -44,41 +81,24 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_1() {
|
||||
let input = "1000
|
||||
2000
|
||||
3000
|
||||
let input = "1abc2
|
||||
pqr3stu8vwx
|
||||
a1b2c3d4e5f
|
||||
treb7uchet";
|
||||
|
||||
4000
|
||||
|
||||
5000
|
||||
6000
|
||||
|
||||
7000
|
||||
8000
|
||||
9000
|
||||
|
||||
10000";
|
||||
|
||||
assert_eq!(part1(input), 24000);
|
||||
assert_eq!(part1(input), 142);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_2() {
|
||||
let input = "1000
|
||||
2000
|
||||
3000
|
||||
let input = "two1nine
|
||||
eightwothree
|
||||
abcone2threexyz
|
||||
xtwone3four
|
||||
4nineeightseven2
|
||||
zoneight234
|
||||
7pqrstsixteen";
|
||||
|
||||
4000
|
||||
|
||||
5000
|
||||
6000
|
||||
|
||||
7000
|
||||
8000
|
||||
9000
|
||||
|
||||
10000";
|
||||
|
||||
assert_eq!(part2(input), 45000);
|
||||
assert_eq!(part2(input), 281);
|
||||
}
|
||||
}
|
||||
|
110
src/day2.rs
110
src/day2.rs
@@ -1,110 +0,0 @@
|
||||
use itertools::Itertools;
|
||||
use std::fs;
|
||||
|
||||
pub fn run() {
|
||||
println!("Day 2:");
|
||||
let input = fs::read_to_string("./inputs/day2.txt").expect("Could not read file");
|
||||
|
||||
println!("\tPart 1: {}", part1(&input));
|
||||
println!("\tPart 2: {}", part2(&input));
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Clone, Copy)]
|
||||
enum Hand {
|
||||
Rock = 1,
|
||||
Paper,
|
||||
Scissors,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum Outcome {
|
||||
Lost = 0,
|
||||
Draw = 3,
|
||||
Win = 6,
|
||||
}
|
||||
|
||||
fn part1(input: &str) -> usize {
|
||||
input
|
||||
.trim()
|
||||
.split('\n')
|
||||
.map(|round_str| {
|
||||
let round = round_str.split_once(' ').unwrap();
|
||||
let opponent = match round.0 {
|
||||
"A" => Hand::Rock,
|
||||
"B" => Hand::Paper,
|
||||
"C" => Hand::Scissors,
|
||||
_ => panic!(),
|
||||
};
|
||||
let me = match round.1 {
|
||||
"X" => Hand::Rock,
|
||||
"Y" => Hand::Paper,
|
||||
"Z" => Hand::Scissors,
|
||||
_ => panic!(),
|
||||
};
|
||||
|
||||
let outcome = match (opponent, me) {
|
||||
(l, r) if l == r => Outcome::Draw,
|
||||
(Hand::Rock, Hand::Paper) => Outcome::Win,
|
||||
(Hand::Paper, Hand::Scissors) => Outcome::Win,
|
||||
(Hand::Scissors, Hand::Rock) => Outcome::Win,
|
||||
_ => Outcome::Lost,
|
||||
};
|
||||
outcome as usize + me as usize
|
||||
})
|
||||
.sum()
|
||||
}
|
||||
fn part2(input: &str) -> usize {
|
||||
input
|
||||
.trim()
|
||||
.split('\n')
|
||||
.map(|round_str| {
|
||||
let round = round_str.split_once(' ').unwrap();
|
||||
let opponent = match round.0 {
|
||||
"A" => Hand::Rock,
|
||||
"B" => Hand::Paper,
|
||||
"C" => Hand::Scissors,
|
||||
_ => panic!(),
|
||||
};
|
||||
let outcome = match round.1 {
|
||||
"X" => Outcome::Lost,
|
||||
"Y" => Outcome::Draw,
|
||||
"Z" => Outcome::Win,
|
||||
_ => panic!(),
|
||||
};
|
||||
|
||||
let me = match (outcome, opponent) {
|
||||
(Outcome::Draw, _) => opponent,
|
||||
(Outcome::Win, Hand::Rock) => Hand::Paper,
|
||||
(Outcome::Win, Hand::Paper) => Hand::Scissors,
|
||||
(Outcome::Win, Hand::Scissors) => Hand::Rock,
|
||||
(Outcome::Lost, Hand::Rock) => Hand::Scissors,
|
||||
(Outcome::Lost, Hand::Paper) => Hand::Rock,
|
||||
(Outcome::Lost, Hand::Scissors) => Hand::Paper,
|
||||
};
|
||||
outcome as usize + me as usize
|
||||
})
|
||||
.sum()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_1() {
|
||||
let input = "A Y
|
||||
B X
|
||||
C Z";
|
||||
|
||||
assert_eq!(part1(input), 15);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_2() {
|
||||
let input = "A Y
|
||||
B X
|
||||
C Z";
|
||||
|
||||
assert_eq!(part2(input), 12);
|
||||
}
|
||||
}
|
112
src/day3.rs
112
src/day3.rs
@@ -1,112 +0,0 @@
|
||||
use itertools::Itertools;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use std::fs;
|
||||
|
||||
pub fn run() {
|
||||
println!("Day 3:");
|
||||
let input = fs::read_to_string("./inputs/day3.txt").expect("Could not read file");
|
||||
|
||||
println!("\tPart 1: {}", part1(&input));
|
||||
println!("\tPart 2: {}", part2(&input));
|
||||
}
|
||||
|
||||
fn part1(input: &str) -> usize {
|
||||
let mut alphabet_map = HashMap::new();
|
||||
let alph = "abcdefghijklmnopqrstuvwxyz";
|
||||
for (value, letter) in format!("{}{}", alph, alph.to_uppercase())
|
||||
.chars()
|
||||
.enumerate()
|
||||
{
|
||||
alphabet_map.insert(letter, value + 1);
|
||||
}
|
||||
|
||||
input
|
||||
.split_whitespace()
|
||||
.map(|line| {
|
||||
let (left, right) = line.split_at(line.len() / 2);
|
||||
assert!(left.len() == right.len());
|
||||
|
||||
let bag_intersection = left
|
||||
.chars()
|
||||
.collect::<HashSet<char>>()
|
||||
.intersection(&right.chars().collect::<HashSet<char>>())
|
||||
.collect::<HashSet<&char>>()
|
||||
.into_iter()
|
||||
.copied()
|
||||
.collect::<Vec<char>>();
|
||||
|
||||
assert!(bag_intersection.len() == 1);
|
||||
|
||||
alphabet_map.get(&bag_intersection[0]).unwrap()
|
||||
})
|
||||
.sum()
|
||||
}
|
||||
|
||||
fn part2(input: &str) -> usize {
|
||||
let mut alphabet_map = HashMap::new();
|
||||
let alph = "abcdefghijklmnopqrstuvwxyz";
|
||||
for (value, letter) in format!("{}{}", alph, alph.to_uppercase())
|
||||
.chars()
|
||||
.enumerate()
|
||||
{
|
||||
alphabet_map.insert(letter, value + 1);
|
||||
}
|
||||
|
||||
input
|
||||
.split_whitespace()
|
||||
.collect::<Vec<&str>>()
|
||||
.into_iter()
|
||||
.tuples()
|
||||
.map(|line| {
|
||||
let (left, mid, right) = line;
|
||||
|
||||
let bag_intersection = left
|
||||
.chars()
|
||||
.collect::<HashSet<char>>()
|
||||
.intersection(&right.chars().collect::<HashSet<char>>())
|
||||
.collect::<HashSet<&char>>()
|
||||
.into_iter()
|
||||
.copied()
|
||||
.collect::<HashSet<char>>()
|
||||
.intersection(&mid.chars().collect::<HashSet<char>>())
|
||||
.collect::<HashSet<&char>>()
|
||||
.into_iter()
|
||||
.copied()
|
||||
.collect::<Vec<char>>();
|
||||
|
||||
assert!(bag_intersection.len() == 1);
|
||||
|
||||
alphabet_map.get(&bag_intersection[0]).unwrap()
|
||||
})
|
||||
.sum()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_1() {
|
||||
let input = "vJrwpWtwJgWrhcsFMMfFFhFp
|
||||
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
|
||||
PmmdzqPrVvPwwTWBwg
|
||||
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
|
||||
ttgJtRGJQctTZtZT
|
||||
CrZsJsPPZsGzwwsLwLmpwMDw";
|
||||
|
||||
assert_eq!(part1(input), 157);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_2() {
|
||||
let input = "vJrwpWtwJgWrhcsFMMfFFhFp
|
||||
jqHRNqRjqzjGDLGLrsFMfFZSrLrFZsSL
|
||||
PmmdzqPrVvPwwTWBwg
|
||||
wMqvLMZHhHMvwLHjbvcjnnSBnvTQFn
|
||||
ttgJtRGJQctTZtZT
|
||||
CrZsJsPPZsGzwwsLwLmpwMDw";
|
||||
|
||||
assert_eq!(part2(input), 70);
|
||||
}
|
||||
}
|
84
src/day4.rs
84
src/day4.rs
@@ -1,84 +0,0 @@
|
||||
use std::collections::HashSet;
|
||||
use std::fs;
|
||||
|
||||
pub fn run() {
|
||||
println!("Day 4:");
|
||||
let input = fs::read_to_string("./inputs/day4.txt").expect("Could not read file");
|
||||
|
||||
println!("\tPart 1: {}", part1(&input));
|
||||
println!("\tPart 2: {}", part2(&input));
|
||||
}
|
||||
|
||||
struct SectionAssignment {
|
||||
left: HashSet<usize>,
|
||||
right: HashSet<usize>,
|
||||
}
|
||||
|
||||
fn deserialize(line: &str) -> SectionAssignment {
|
||||
let (left, right) = line.split_once(',').unwrap();
|
||||
let left = left
|
||||
.split_once('-')
|
||||
.map(|(l, r)| l.parse().unwrap()..=r.parse().unwrap())
|
||||
.unwrap()
|
||||
.collect();
|
||||
let right = right
|
||||
.split_once('-')
|
||||
.map(|(l, r)| l.parse().unwrap()..=r.parse().unwrap())
|
||||
.unwrap()
|
||||
.collect();
|
||||
|
||||
SectionAssignment { left, right }
|
||||
}
|
||||
|
||||
fn part1(input: &str) -> usize {
|
||||
let assignments = input.split_whitespace().map(deserialize);
|
||||
let mut sum = 0;
|
||||
for assignment in assignments {
|
||||
if assignment.left.is_subset(&assignment.right)
|
||||
|| assignment.right.is_subset(&assignment.left)
|
||||
{
|
||||
sum += 1;
|
||||
}
|
||||
}
|
||||
sum
|
||||
}
|
||||
|
||||
fn part2(input: &str) -> usize {
|
||||
let assignments = input.split_whitespace().map(deserialize);
|
||||
let mut sum = 0;
|
||||
for assignment in assignments {
|
||||
if assignment.left.intersection(&assignment.right).count() >= 1 {
|
||||
sum += 1;
|
||||
}
|
||||
}
|
||||
sum
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_1() {
|
||||
let input = "2-4,6-8
|
||||
2-3,4-5
|
||||
5-7,7-9
|
||||
2-8,3-7
|
||||
6-6,4-6
|
||||
2-6,4-8";
|
||||
|
||||
assert_eq!(part1(input), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_2() {
|
||||
let input = "2-4,6-8
|
||||
2-3,4-5
|
||||
5-7,7-9
|
||||
2-8,3-7
|
||||
6-6,4-6
|
||||
2-6,4-8";
|
||||
|
||||
assert_eq!(part2(input), 4);
|
||||
}
|
||||
}
|
163
src/day5.rs
163
src/day5.rs
@@ -1,163 +0,0 @@
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::fmt::format;
|
||||
use std::fs;
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
pub fn run() {
|
||||
println!("Day 5:");
|
||||
let input = fs::read_to_string("./inputs/day5.txt").expect("Could not read file");
|
||||
|
||||
println!("\tPart 1: {}", part1(&input));
|
||||
println!("\tPart 2: {}", part2(&input));
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Command {
|
||||
amount: usize,
|
||||
from: usize,
|
||||
to: usize,
|
||||
}
|
||||
|
||||
fn part1(input: &str) -> String {
|
||||
let (stack_input, moves_input) = input.split_once("\n\n").unwrap();
|
||||
|
||||
let mut containers: HashMap<usize, VecDeque<char>> = HashMap::new();
|
||||
for row in stack_input.lines() {
|
||||
for (column, (lbracket, container, _rbracket, _)) in
|
||||
format!("{} ", row).chars().tuples().enumerate()
|
||||
{
|
||||
if lbracket == '[' && !container.is_whitespace() {
|
||||
containers
|
||||
.entry(column + 1)
|
||||
.or_insert_with(VecDeque::new)
|
||||
.push_back(container);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let commands = moves_input.lines().map(|line| {
|
||||
let (amount, from, to) =
|
||||
scan_fmt!(line, "move {} from {} to {}", usize, usize, usize).unwrap();
|
||||
Command { amount, from, to }
|
||||
});
|
||||
|
||||
for command in commands {
|
||||
for _ in 0..command.amount {
|
||||
let container = containers
|
||||
.entry(command.from)
|
||||
.or_insert_with(VecDeque::new)
|
||||
.pop_front()
|
||||
.unwrap_or(' ');
|
||||
|
||||
if container != ' ' {
|
||||
containers
|
||||
.entry(command.to)
|
||||
.or_insert_with(VecDeque::new)
|
||||
.push_front(container)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut answer = "".to_string();
|
||||
for column in 1..=containers.len() {
|
||||
answer = format!(
|
||||
"{}{}",
|
||||
answer,
|
||||
containers.get(&column).unwrap().front().unwrap()
|
||||
);
|
||||
}
|
||||
answer
|
||||
}
|
||||
|
||||
fn part2(input: &str) -> String {
|
||||
let (stack_input, moves_input) = input.split_once("\n\n").unwrap();
|
||||
|
||||
let mut containers: HashMap<usize, VecDeque<char>> = HashMap::new();
|
||||
for row in stack_input.lines() {
|
||||
for (column, (lbracket, container, _rbracket, _)) in
|
||||
format!("{} ", row).chars().tuples().enumerate()
|
||||
{
|
||||
if lbracket == '[' && !container.is_whitespace() {
|
||||
containers
|
||||
.entry(column + 1)
|
||||
.or_insert_with(VecDeque::new)
|
||||
.push_back(container);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let commands = moves_input.lines().map(|line| {
|
||||
let (amount, from, to) =
|
||||
scan_fmt!(line, "move {} from {} to {}", usize, usize, usize).unwrap();
|
||||
Command { amount, from, to }
|
||||
});
|
||||
|
||||
let mut crane = VecDeque::new();
|
||||
|
||||
for command in commands {
|
||||
for _ in 0..command.amount {
|
||||
let container = containers
|
||||
.entry(command.from)
|
||||
.or_insert_with(VecDeque::new)
|
||||
.pop_front()
|
||||
.unwrap_or(' ');
|
||||
|
||||
crane.push_back(container);
|
||||
}
|
||||
for _ in 0..command.amount {
|
||||
let container = crane.pop_back().unwrap();
|
||||
if container != ' ' {
|
||||
containers
|
||||
.entry(command.to)
|
||||
.or_insert_with(VecDeque::new)
|
||||
.push_front(container)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut answer = "".to_string();
|
||||
for column in 1..=containers.len() {
|
||||
answer = format!(
|
||||
"{}{}",
|
||||
answer,
|
||||
containers.get(&column).unwrap().front().unwrap()
|
||||
);
|
||||
}
|
||||
answer
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_1() {
|
||||
let input = " [D]
|
||||
[N] [C]
|
||||
[Z] [M] [P]
|
||||
1 2 3
|
||||
|
||||
move 1 from 2 to 1
|
||||
move 3 from 1 to 3
|
||||
move 2 from 2 to 1
|
||||
move 1 from 1 to 2";
|
||||
|
||||
assert_eq!(part1(input), "CMZ");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_2() {
|
||||
let input = " [D]
|
||||
[N] [C]
|
||||
[Z] [M] [P]
|
||||
1 2 3
|
||||
|
||||
move 1 from 2 to 1
|
||||
move 3 from 1 to 3
|
||||
move 2 from 2 to 1
|
||||
move 1 from 1 to 2";
|
||||
|
||||
assert_eq!(part2(input), "MCD");
|
||||
}
|
||||
}
|
13
src/main.rs
13
src/main.rs
@@ -1,16 +1,9 @@
|
||||
#[macro_use]
|
||||
// #[macro_use]
|
||||
extern crate scan_fmt;
|
||||
|
||||
mod day1;
|
||||
mod day2;
|
||||
mod day3;
|
||||
mod day4;
|
||||
mod day5;
|
||||
|
||||
fn main() {
|
||||
println!("Running Advent of Code 2022");
|
||||
println!("Running Advent of Code 2023");
|
||||
day1::run();
|
||||
day2::run();
|
||||
day3::run();
|
||||
day4::run();
|
||||
day5::run();
|
||||
}
|
||||
|
Reference in New Issue
Block a user