1
0

fix: change rust fmt defaults

This commit is contained in:
Rokas Puzonas 2022-06-14 00:27:04 +03:00
parent 87cfe7a587
commit 2e495f674c
23 changed files with 2924 additions and 2386 deletions

4
rustfmt.toml Normal file
View File

@ -0,0 +1,4 @@
tab_spaces = 2
hard_tabs = true
reorder_imports = true
newline_style = "Unix"

View File

@ -1,9 +1,7 @@
use std::num::ParseIntError; use std::num::ParseIntError;
pub fn parse_input(input: &str) -> Result<Vec<u32>, ParseIntError> { pub fn parse_input(input: &str) -> Result<Vec<u32>, ParseIntError> {
input.split_whitespace() input.split_whitespace().map(|s| s.parse()).collect()
.map(|s| s.parse())
.collect()
} }
pub fn part1(depths: &[u32]) -> u32 { pub fn part1(depths: &[u32]) -> u32 {
@ -44,4 +42,3 @@ mod tests {
assert_eq!(result, 5); assert_eq!(result, 5);
} }
} }

View File

@ -1,10 +1,9 @@
#[derive(PartialEq)] #[derive(PartialEq)]
enum ChunkVariant { enum ChunkVariant {
Parenthesis, Parenthesis,
Bracket, Bracket,
Curly, Curly,
Pointy Pointy,
} }
pub fn parse_input(input: &str) -> Vec<String> { pub fn parse_input(input: &str) -> Vec<String> {
@ -23,7 +22,7 @@ fn get_chunk_variant(c: char) -> ChunkVariant {
'[' | ']' => ChunkVariant::Bracket, '[' | ']' => ChunkVariant::Bracket,
'{' | '}' => ChunkVariant::Curly, '{' | '}' => ChunkVariant::Curly,
'<' | '>' => ChunkVariant::Pointy, '<' | '>' => ChunkVariant::Pointy,
_ => panic!("Invalid chunk character") _ => panic!("Invalid chunk character"),
} }
} }
@ -52,7 +51,7 @@ pub fn part1(lines: &Vec<String>) -> u32 {
Some(ChunkVariant::Bracket) => 57, Some(ChunkVariant::Bracket) => 57,
Some(ChunkVariant::Curly) => 1197, Some(ChunkVariant::Curly) => 1197,
Some(ChunkVariant::Pointy) => 25137, Some(ChunkVariant::Pointy) => 25137,
None => 0 None => 0,
} }
} }
return score; return score;
@ -84,7 +83,7 @@ pub fn part2(lines: &Vec<String>) -> u64 {
ChunkVariant::Parenthesis => 1, ChunkVariant::Parenthesis => 1,
ChunkVariant::Bracket => 2, ChunkVariant::Bracket => 2,
ChunkVariant::Curly => 3, ChunkVariant::Curly => 3,
ChunkVariant::Pointy => 4 ChunkVariant::Pointy => 4,
} }
} }
scores.push(score); scores.push(score);
@ -134,4 +133,3 @@ mod tests {
assert_eq!(result, 288957); assert_eq!(result, 288957);
} }
} }

View File

@ -1,12 +1,15 @@
use arrayvec::ArrayVec; use arrayvec::ArrayVec;
pub fn parse_input(input: &str) -> [[u32; 10]; 10] { pub fn parse_input(input: &str) -> [[u32; 10]; 10] {
input.lines() input
.map(|s| s.chars() .lines()
.map(|s| {
s.chars()
.map(|s| s.to_digit(10).unwrap()) .map(|s| s.to_digit(10).unwrap())
.collect::<ArrayVec<u32, 10>>() .collect::<ArrayVec<u32, 10>>()
.into_inner() .into_inner()
.unwrap()) .unwrap()
})
.collect::<ArrayVec<[u32; 10], 10>>() .collect::<ArrayVec<[u32; 10], 10>>()
.into_inner() .into_inner()
.unwrap() .unwrap()
@ -144,7 +147,7 @@ mod tests {
[2, 1, 7, 6, 8, 4, 1, 7, 2, 1], [2, 1, 7, 6, 8, 4, 1, 7, 2, 1],
[6, 8, 8, 2, 8, 8, 1, 1, 3, 4], [6, 8, 8, 2, 8, 8, 1, 1, 3, 4],
[4, 8, 4, 6, 8, 4, 8, 5, 5, 4], [4, 8, 4, 6, 8, 4, 8, 5, 5, 4],
[5, 2, 8, 3, 7, 5, 1, 5, 2, 6] [5, 2, 8, 3, 7, 5, 1, 5, 2, 6],
]; ];
let result = part1(&input); let result = part1(&input);
assert_eq!(result, 1656); assert_eq!(result, 1656);
@ -162,10 +165,9 @@ mod tests {
[2, 1, 7, 6, 8, 4, 1, 7, 2, 1], [2, 1, 7, 6, 8, 4, 1, 7, 2, 1],
[6, 8, 8, 2, 8, 8, 1, 1, 3, 4], [6, 8, 8, 2, 8, 8, 1, 1, 3, 4],
[4, 8, 4, 6, 8, 4, 8, 5, 5, 4], [4, 8, 4, 6, 8, 4, 8, 5, 5, 4],
[5, 2, 8, 3, 7, 5, 1, 5, 2, 6] [5, 2, 8, 3, 7, 5, 1, 5, 2, 6],
]; ];
let result = part2(&input); let result = part2(&input);
assert_eq!(result, 195); assert_eq!(result, 195);
} }
} }

View File

@ -15,11 +15,13 @@ fn edges_to_map(edges: &Vec<(String, String)>) -> HashMap<String, Vec<String>> {
let mut map = HashMap::new(); let mut map = HashMap::new();
for line in edges { for line in edges {
map.entry(line.1.clone()) map
.entry(line.1.clone())
.or_insert(Vec::new()) .or_insert(Vec::new())
.push(line.0.clone()); .push(line.0.clone());
map.entry(line.0.clone()) map
.entry(line.0.clone())
.or_insert(Vec::new()) .or_insert(Vec::new())
.push(line.1.clone()); .push(line.1.clone());
} }
@ -28,7 +30,7 @@ fn edges_to_map(edges: &Vec<(String, String)>) -> HashMap<String, Vec<String>> {
} }
fn is_path_finished(path: &Vec<&str>) -> bool { fn is_path_finished(path: &Vec<&str>) -> bool {
return path.contains(&"end") return path.contains(&"end");
} }
fn can_be_appended_part1(path: &Vec<&str>, node: &str) -> bool { fn can_be_appended_part1(path: &Vec<&str>, node: &str) -> bool {
@ -67,14 +69,23 @@ pub fn part1(edges: &Vec<(String, String)>) -> usize {
} }
fn can_be_appended_part2(path: &Vec<&str>, node: &str) -> bool { fn can_be_appended_part2(path: &Vec<&str>, node: &str) -> bool {
if node == "start" { return false; } if node == "start" {
if node == "end" { return true; } return false;
if node.to_uppercase() == node { return true; } }
if node == "end" {
return true;
}
if node.to_uppercase() == node {
return true;
}
// If all lowercase nodes only apear once we can be assure that any lowercase // If all lowercase nodes only apear once we can be assure that any lowercase
// node that will be added will be correct. // node that will be added will be correct.
let mut uniq = HashSet::new(); let mut uniq = HashSet::new();
if path.into_iter().all(move |x| x.to_lowercase() != *x || uniq.insert(x)) { if path
.into_iter()
.all(move |x| x.to_lowercase() != *x || uniq.insert(x))
{
return true; return true;
} }
@ -125,7 +136,9 @@ mod tests {
#[test] #[test]
fn part1_larger_example() { fn part1_larger_example() {
let cave_system = parse_input("dc-end\nHN-start\nstart-kj\ndc-start\ndc-HN\nLN-dc\nHN-end\nkj-sa\nkj-HN\nkj-dc"); let cave_system = parse_input(
"dc-end\nHN-start\nstart-kj\ndc-start\ndc-HN\nLN-dc\nHN-end\nkj-sa\nkj-HN\nkj-dc",
);
let result = part1(&cave_system); let result = part1(&cave_system);
assert_eq!(result, 19); assert_eq!(result, 19);
} }
@ -146,7 +159,9 @@ mod tests {
#[test] #[test]
fn part2_larger_example() { fn part2_larger_example() {
let cave_system = parse_input("dc-end\nHN-start\nstart-kj\ndc-start\ndc-HN\nLN-dc\nHN-end\nkj-sa\nkj-HN\nkj-dc"); let cave_system = parse_input(
"dc-end\nHN-start\nstart-kj\ndc-start\ndc-HN\nLN-dc\nHN-end\nkj-sa\nkj-HN\nkj-dc",
);
let result = part2(&cave_system); let result = part2(&cave_system);
assert_eq!(result, 103); assert_eq!(result, 103);
} }

View File

@ -11,15 +11,12 @@ pub enum Fold {
pub struct InputData { pub struct InputData {
dots: Vec<Dot>, dots: Vec<Dot>,
folds: Vec<Fold> folds: Vec<Fold>,
} }
fn parse_dot(line: &str) -> Dot { fn parse_dot(line: &str) -> Dot {
let (x, y) = line.split_once(',').unwrap(); let (x, y) = line.split_once(',').unwrap();
return Dot( return Dot(x.parse().unwrap(), y.parse().unwrap());
x.parse().unwrap(),
y.parse().unwrap()
);
} }
fn parse_fold(line: &str) -> Fold { fn parse_fold(line: &str) -> Fold {
@ -28,24 +25,17 @@ fn parse_fold(line: &str) -> Fold {
match axis { match axis {
"fold along x" => Fold::X(coordinate), "fold along x" => Fold::X(coordinate),
"fold along y" => Fold::Y(coordinate), "fold along y" => Fold::Y(coordinate),
_ => unreachable!("Unable to parse fold direction") _ => unreachable!("Unable to parse fold direction"),
} }
} }
pub fn parse_input(input: &str) -> InputData { pub fn parse_input(input: &str) -> InputData {
let (dots_section, folds_section) = input.split_once("\n\n").unwrap(); let (dots_section, folds_section) = input.split_once("\n\n").unwrap();
let dots = dots_section.lines() let dots = dots_section.lines().map(parse_dot).collect();
.map(parse_dot) let folds = folds_section.lines().map(parse_fold).collect();
.collect();
let folds = folds_section.lines()
.map(parse_fold)
.collect();
return InputData { return InputData { dots, folds };
dots,
folds
};
} }
fn perform_fold(dots: &HashSet<Dot>, fold: &Fold) -> HashSet<Dot> { fn perform_fold(dots: &HashSet<Dot>, fold: &Fold) -> HashSet<Dot> {
@ -59,14 +49,14 @@ fn perform_fold(dots: &HashSet<Dot>, fold: &Fold) -> HashSet<Dot> {
} else { } else {
dot.clone() dot.clone()
} }
}, }
Fold::Y(y) => { Fold::Y(y) => {
if dot.1 > *y { if dot.1 > *y {
Dot(dot.0, 2 * y - dot.1) Dot(dot.0, 2 * y - dot.1)
} else { } else {
dot.clone() dot.clone()
} }
}, }
}; };
folded_dots.insert(folded_dot); folded_dots.insert(folded_dot);
} }
@ -148,12 +138,9 @@ mod tests {
Dot(1, 10), Dot(1, 10),
Dot(2, 14), Dot(2, 14),
Dot(8, 10), Dot(8, 10),
Dot(9, 0) Dot(9, 0),
];
let folds = vec![
Fold::Y(7),
Fold::X(5),
]; ];
let folds = vec![Fold::Y(7), Fold::X(5)];
let result = part1(&InputData { dots, folds }); let result = part1(&InputData { dots, folds });
assert_eq!(result, 17); assert_eq!(result, 17);
} }

View File

@ -2,7 +2,7 @@ use std::collections::HashMap;
pub struct InputData { pub struct InputData {
polymer_template: String, polymer_template: String,
rules: HashMap<[char; 2], char> rules: HashMap<[char; 2], char>,
} }
pub fn parse_input(input: &str) -> InputData { pub fn parse_input(input: &str) -> InputData {
@ -11,13 +11,16 @@ pub fn parse_input(input: &str) -> InputData {
for line in rules_section.lines() { for line in rules_section.lines() {
let (pattern, expansion) = line.split_once(" -> ").unwrap(); let (pattern, expansion) = line.split_once(" -> ").unwrap();
rules.insert( rules.insert(
[pattern.chars().nth(0).unwrap(), pattern.chars().nth(1).unwrap()], [
expansion.chars().nth(0).unwrap() pattern.chars().nth(0).unwrap(),
pattern.chars().nth(1).unwrap(),
],
expansion.chars().nth(0).unwrap(),
); );
} }
return InputData { return InputData {
polymer_template: polymer_template.into(), polymer_template: polymer_template.into(),
rules rules,
}; };
} }
@ -47,12 +50,23 @@ pub fn part1(input: &InputData) -> u32 {
*amount += 1; *amount += 1;
} }
let least_common_element = element_amounts.iter().min_by(|a, b| a.1.cmp(b.1)).unwrap().1; let least_common_element = element_amounts
let most_common_element = element_amounts.iter().max_by(|a, b| a.1.cmp(b.1)).unwrap().1; .iter()
.min_by(|a, b| a.1.cmp(b.1))
.unwrap()
.1;
let most_common_element = element_amounts
.iter()
.max_by(|a, b| a.1.cmp(b.1))
.unwrap()
.1;
return most_common_element - least_common_element; return most_common_element - least_common_element;
} }
fn expand_polymer(polymer_pairs: &HashMap<[char; 2], u64>, rules: &HashMap<[char; 2], char>) -> HashMap<[char; 2], u64> { fn expand_polymer(
polymer_pairs: &HashMap<[char; 2], u64>,
rules: &HashMap<[char; 2], char>,
) -> HashMap<[char; 2], u64> {
let mut new_pairs = HashMap::new(); let mut new_pairs = HashMap::new();
for entry in polymer_pairs { for entry in polymer_pairs {
let pair = entry.0; let pair = entry.0;
@ -72,7 +86,6 @@ fn expand_polymer(polymer_pairs: &HashMap<[char; 2], u64>, rules: &HashMap<[char
} }
} }
return new_pairs; return new_pairs;
} }
pub fn part2(input: &InputData) -> u64 { pub fn part2(input: &InputData) -> u64 {
@ -81,7 +94,7 @@ pub fn part2(input: &InputData) -> u64 {
for i in 0..polymer_template.len() - 1 { for i in 0..polymer_template.len() - 1 {
let pair = [ let pair = [
polymer_template.chars().nth(i).unwrap(), polymer_template.chars().nth(i).unwrap(),
polymer_template.chars().nth(i+1).unwrap() polymer_template.chars().nth(i + 1).unwrap(),
]; ];
let entry = polymer_pairs.entry(pair).or_insert(0); let entry = polymer_pairs.entry(pair).or_insert(0);
*entry += 1; *entry += 1;
@ -99,8 +112,16 @@ pub fn part2(input: &InputData) -> u64 {
} }
} }
let least_common_element = element_amounts.iter().min_by(|a, b| a.1.cmp(b.1)).unwrap().1; let least_common_element = element_amounts
let most_common_element = element_amounts.iter().max_by(|a, b| a.1.cmp(b.1)).unwrap().1; .iter()
.min_by(|a, b| a.1.cmp(b.1))
.unwrap()
.1;
let most_common_element = element_amounts
.iter()
.max_by(|a, b| a.1.cmp(b.1))
.unwrap()
.1;
return (most_common_element - least_common_element) / 2 + 1; return (most_common_element - least_common_element) / 2 + 1;
} }
@ -127,9 +148,12 @@ mod tests {
(['B', 'B'], 'N'), (['B', 'B'], 'N'),
(['B', 'C'], 'B'), (['B', 'C'], 'B'),
(['C', 'C'], 'N'), (['C', 'C'], 'N'),
(['C', 'N'], 'C') (['C', 'N'], 'C'),
]); ]);
let result = part1(&InputData { polymer_template, rules }); let result = part1(&InputData {
polymer_template,
rules,
});
assert_eq!(result, 1588); assert_eq!(result, 1588);
} }
@ -152,9 +176,12 @@ mod tests {
(['B', 'B'], 'N'), (['B', 'B'], 'N'),
(['B', 'C'], 'B'), (['B', 'C'], 'B'),
(['C', 'C'], 'N'), (['C', 'C'], 'N'),
(['C', 'N'], 'C') (['C', 'N'], 'C'),
]); ]);
let result = part2(&InputData { polymer_template, rules }); let result = part2(&InputData {
polymer_template,
rules,
});
assert_eq!(result, 2188189693529); assert_eq!(result, 2188189693529);
} }
} }

View File

@ -1,21 +1,22 @@
use std::collections::{HashMap, HashSet};
use priority_queue::PriorityQueue; use priority_queue::PriorityQueue;
use std::collections::{HashMap, HashSet};
#[derive(Debug)] #[derive(Debug)]
pub struct Grid { pub struct Grid {
rows: u32, rows: u32,
cols: u32, cols: u32,
data: Vec<u32>, data: Vec<u32>,
scale: u32 scale: u32,
} }
impl Grid { impl Grid {
fn new(rows: u32, cols: u32, data: Vec<u32>) -> Grid { fn new(rows: u32, cols: u32, data: Vec<u32>) -> Grid {
return Grid { return Grid {
rows, cols, data, rows,
scale: 1 cols,
} data,
scale: 1,
};
} }
fn get(&self, point: &(u32, u32)) -> u32 { fn get(&self, point: &(u32, u32)) -> u32 {
@ -45,7 +46,9 @@ pub fn parse_input(input: &str) -> Grid {
for line in input.lines() { for line in input.lines() {
rows += 1; rows += 1;
for c in line.chars() { for c in line.chars() {
if rows == 1 { cols += 1 } if rows == 1 {
cols += 1
}
data.push(c.to_digit(10).unwrap()); data.push(c.to_digit(10).unwrap());
} }
} }
@ -90,7 +93,9 @@ fn find_shortest_path_cost(grid: &Grid) -> u32 {
} }
} }
return *total_costs.get(&(grid.height()-1, grid.width()-1)).unwrap(); return *total_costs
.get(&(grid.height() - 1, grid.width() - 1))
.unwrap();
} }
pub fn part1(grid: &Grid) -> u32 { pub fn part1(grid: &Grid) -> u32 {
@ -108,7 +113,8 @@ mod tests {
#[test] #[test]
fn part1_example() { fn part1_example() {
let grid = parse_input("1163751742 let grid = parse_input(
"1163751742
1381373672 1381373672
2136511328 2136511328
3694931569 3694931569
@ -117,14 +123,16 @@ mod tests {
1359912421 1359912421
3125421639 3125421639
1293138521 1293138521
2311944581"); 2311944581",
);
let result = part1(&grid); let result = part1(&grid);
assert_eq!(result, 40); assert_eq!(result, 40);
} }
#[test] #[test]
fn part2_example() { fn part2_example() {
let mut grid = parse_input("1163751742 let mut grid = parse_input(
"1163751742
1381373672 1381373672
2136511328 2136511328
3694931569 3694931569
@ -133,9 +141,9 @@ mod tests {
1359912421 1359912421
3125421639 3125421639
1293138521 1293138521
2311944581"); 2311944581",
);
let result = part2(&mut grid); let result = part2(&mut grid);
assert_eq!(result, 315); assert_eq!(result, 315);
} }
} }

View File

@ -1,13 +1,12 @@
pub enum PacketBody { pub enum PacketBody {
Literal(u64), Literal(u64),
Operator(Vec<Packet>) Operator(Vec<Packet>),
} }
pub struct Packet { pub struct Packet {
version: u8, version: u8,
r#type: u8, r#type: u8,
body: PacketBody body: PacketBody,
} }
fn to_bits(hex: &str) -> String { fn to_bits(hex: &str) -> String {
@ -16,7 +15,7 @@ fn to_bits(hex: &str) -> String {
match c { match c {
b'0'..=b'9' => bits.push_str(format!("{:0>4b}", c - b'0').as_str()), b'0'..=b'9' => bits.push_str(format!("{:0>4b}", c - b'0').as_str()),
b'A'..=b'F' => bits.push_str(format!("{:0>4b}", c - b'A' + 10).as_str()), b'A'..=b'F' => bits.push_str(format!("{:0>4b}", c - b'A' + 10).as_str()),
_ => () _ => (),
} }
} }
return bits; return bits;
@ -28,7 +27,9 @@ fn parse_literal_body(bits_str: &str) -> (PacketBody, u32) {
let bytes = bits_str.as_bytes(); let bytes = bits_str.as_bytes();
loop { loop {
value_bits.push_str(&bits_str[cursor + 1..cursor + 5]); value_bits.push_str(&bits_str[cursor + 1..cursor + 5]);
if bytes[cursor] == b'0' { break; } if bytes[cursor] == b'0' {
break;
}
cursor += 5; cursor += 5;
} }
let value = u64::from_str_radix(&value_bits, 2).unwrap(); let value = u64::from_str_radix(&value_bits, 2).unwrap();
@ -65,15 +66,16 @@ fn parse_packet(bits: &str) -> (Packet, u32) {
let r#type = u8::from_str_radix(&bits[3..6], 2).unwrap(); let r#type = u8::from_str_radix(&bits[3..6], 2).unwrap();
let (body, body_size) = match r#type { let (body, body_size) = match r#type {
4 => parse_literal_body(&bits[6..]), 4 => parse_literal_body(&bits[6..]),
_ => parse_operator_body(&bits[6..]) _ => parse_operator_body(&bits[6..]),
}; };
return (Packet { return (
Packet {
version: u8::from_str_radix(&bits[0..3], 2).unwrap(), version: u8::from_str_radix(&bits[0..3], 2).unwrap(),
r#type, r#type,
body body,
}, },
body_size + 6 body_size + 6,
); );
} }
@ -89,8 +91,8 @@ fn sum_packet_versions(packet: &Packet) -> u32 {
for sub_packet in packets { for sub_packet in packets {
sum += sum_packet_versions(sub_packet); sum += sum_packet_versions(sub_packet);
} }
}, }
_ => () _ => (),
}; };
return sum; return sum;
} }
@ -130,24 +132,35 @@ fn eval_maximum_packets(packets: &[Packet]) -> u64 {
fn eval_greater_packets(packets: &[Packet]) -> u64 { fn eval_greater_packets(packets: &[Packet]) -> u64 {
let first_packet = packets.get(0).unwrap(); let first_packet = packets.get(0).unwrap();
let second_packet = packets.get(1).unwrap(); let second_packet = packets.get(1).unwrap();
if eval_packet(first_packet) > eval_packet(second_packet) { 1 } else { 0 } if eval_packet(first_packet) > eval_packet(second_packet) {
1
} else {
0
}
} }
fn eval_less_packets(packets: &[Packet]) -> u64 { fn eval_less_packets(packets: &[Packet]) -> u64 {
let first_packet = packets.get(0).unwrap(); let first_packet = packets.get(0).unwrap();
let second_packet = packets.get(1).unwrap(); let second_packet = packets.get(1).unwrap();
if eval_packet(first_packet) < eval_packet(second_packet) { 1 } else { 0 } if eval_packet(first_packet) < eval_packet(second_packet) {
1
} else {
0
}
} }
fn eval_equal_packets(packets: &[Packet]) -> u64 { fn eval_equal_packets(packets: &[Packet]) -> u64 {
let first_packet = packets.get(0).unwrap(); let first_packet = packets.get(0).unwrap();
let second_packet = packets.get(1).unwrap(); let second_packet = packets.get(1).unwrap();
if eval_packet(first_packet) == eval_packet(second_packet) { 1 } else { 0 } if eval_packet(first_packet) == eval_packet(second_packet) {
1
} else {
0
}
} }
fn eval_packet(packet: &Packet) -> u64 { fn eval_packet(packet: &Packet) -> u64 {
match &packet.body { match &packet.body {
PacketBody::Literal(value) => *value, PacketBody::Literal(value) => *value,
PacketBody::Operator(packets) => { PacketBody::Operator(packets) => match packet.r#type {
match packet.r#type {
0 => eval_sum_packets(packets), 0 => eval_sum_packets(packets),
1 => eval_product_packets(packets), 1 => eval_product_packets(packets),
2 => eval_minimum_packets(packets), 2 => eval_minimum_packets(packets),
@ -155,9 +168,8 @@ fn eval_packet(packet: &Packet) -> u64 {
5 => eval_greater_packets(packets), 5 => eval_greater_packets(packets),
6 => eval_less_packets(packets), 6 => eval_less_packets(packets),
7 => eval_equal_packets(packets), 7 => eval_equal_packets(packets),
_ => unreachable!() _ => unreachable!(),
} },
}
} }
} }
@ -253,4 +265,3 @@ mod tests {
assert_eq!(result, 1); assert_eq!(result, 1);
} }
} }

View File

@ -1,11 +1,13 @@
pub struct Rect { pub struct Rect {
x0: i32, x1: i32, x0: i32,
y0: i32, y1: i32, x1: i32,
y0: i32,
y1: i32,
} }
pub fn parse_input(input: &str) -> Rect { pub fn parse_input(input: &str) -> Rect {
let (x_part, y_part) = input.strip_suffix("\n") let (x_part, y_part) = input
.strip_suffix("\n")
.or(Some(input)) .or(Some(input))
.unwrap() .unwrap()
.strip_prefix("target area: ") .strip_prefix("target area: ")
@ -18,12 +20,18 @@ pub fn parse_input(input: &str) -> Rect {
x0: x0.parse().unwrap(), x0: x0.parse().unwrap(),
x1: x1.parse().unwrap(), x1: x1.parse().unwrap(),
y0: y0.parse().unwrap(), y0: y0.parse().unwrap(),
y1: y1.parse().unwrap() y1: y1.parse().unwrap(),
} };
} }
fn sign(x: i32) -> i32 { fn sign(x: i32) -> i32 {
if x > 0 { 1 } else if x < 0 { -1 } else { 0 } if x > 0 {
1
} else if x < 0 {
-1
} else {
0
}
} }
fn is_overshot(px: i32, py: i32, target: &Rect) -> bool { fn is_overshot(px: i32, py: i32, target: &Rect) -> bool {
@ -31,8 +39,7 @@ fn is_overshot(px: i32, py: i32, target: &Rect) -> bool {
} }
fn is_in_rect(px: i32, py: i32, target: &Rect) -> bool { fn is_in_rect(px: i32, py: i32, target: &Rect) -> bool {
target.x0 <= px && px <= target.x1 && target.x0 <= px && px <= target.x1 && target.y0 <= py && py <= target.y1
target.y0 <= py && py <= target.y1
} }
fn simulate(target: &Rect, initial_vx: i32, initial_vy: i32) -> i32 { fn simulate(target: &Rect, initial_vx: i32, initial_vy: i32) -> i32 {
@ -99,4 +106,3 @@ mod tests {
assert_eq!(result, 112); assert_eq!(result, 112);
} }
} }

View File

@ -7,8 +7,8 @@ fn parse_snailfish(line: &str) -> Vec<(i32, u8)> {
match c { match c {
'[' => depth += 1, '[' => depth += 1,
']' => depth -= 1, ']' => depth -= 1,
',' => {}, ',' => {}
_ => nums.push(((c as u8 - b'0') as i32, depth)) _ => nums.push(((c as u8 - b'0') as i32, depth)),
} }
} }
return nums; return nums;
@ -48,7 +48,9 @@ fn add_snailfish(a: &Vec<(i32, u8)>, b: &Vec<(i32, u8)>) -> Vec<(i32, u8)> {
fn try_exploding(num: &mut Vec<(i32, u8)>) -> bool { fn try_exploding(num: &mut Vec<(i32, u8)>) -> bool {
let i = find_deepest_index(num); let i = find_deepest_index(num);
if num[i].1 < 5 { return false; } if num[i].1 < 5 {
return false;
}
let (left_num, depth) = num[i]; let (left_num, depth) = num[i];
let right_num = num.remove(i + 1).0; let right_num = num.remove(i + 1).0;
if i > 0 { if i > 0 {
@ -74,8 +76,12 @@ fn try_splitting(num: &mut Vec<(i32, u8)>) -> bool {
fn reduce_snailfish(num: &mut Vec<(i32, u8)>) { fn reduce_snailfish(num: &mut Vec<(i32, u8)>) {
loop { loop {
if try_exploding(num) { continue; } if try_exploding(num) {
if try_splitting(num) { continue; } continue;
}
if try_splitting(num) {
continue;
}
break; break;
} }
} }
@ -130,7 +136,8 @@ mod tests {
#[test] #[test]
fn part1_example() { fn part1_example() {
let nums = parse_input("[[[0,[5,8]],[[1,7],[9,6]]],[[4,[1,2]],[[1,4],2]]] let nums = parse_input(
"[[[0,[5,8]],[[1,7],[9,6]]],[[4,[1,2]],[[1,4],2]]]
[[[5,[2,8]],4],[5,[[9,9],0]]] [[[5,[2,8]],4],[5,[[9,9],0]]]
[6,[[[6,2],[5,6]],[[7,6],[4,7]]]] [6,[[[6,2],[5,6]],[[7,6],[4,7]]]]
[[[6,[0,7]],[0,9]],[4,[9,[9,0]]]] [[[6,[0,7]],[0,9]],[4,[9,[9,0]]]]
@ -139,14 +146,16 @@ mod tests {
[[[[5,4],[7,7]],8],[[8,3],8]] [[[[5,4],[7,7]],8],[[8,3],8]]
[[9,3],[[9,9],[6,[4,9]]]] [[9,3],[[9,9],[6,[4,9]]]]
[[2,[[7,7],7]],[[5,8],[[9,3],[0,2]]]] [[2,[[7,7],7]],[[5,8],[[9,3],[0,2]]]]
[[[[5,2],5],[8,[3,7]]],[[5,[7,5]],[4,4]]]"); [[[[5,2],5],[8,[3,7]]],[[5,[7,5]],[4,4]]]",
);
let result = part1(&nums); let result = part1(&nums);
assert_eq!(result, 4140); assert_eq!(result, 4140);
} }
#[test] #[test]
fn part2_example() { fn part2_example() {
let nums = parse_input("[[[0,[5,8]],[[1,7],[9,6]]],[[4,[1,2]],[[1,4],2]]] let nums = parse_input(
"[[[0,[5,8]],[[1,7],[9,6]]],[[4,[1,2]],[[1,4],2]]]
[[[5,[2,8]],4],[5,[[9,9],0]]] [[[5,[2,8]],4],[5,[[9,9],0]]]
[6,[[[6,2],[5,6]],[[7,6],[4,7]]]] [6,[[[6,2],[5,6]],[[7,6],[4,7]]]]
[[[6,[0,7]],[0,9]],[4,[9,[9,0]]]] [[[6,[0,7]],[0,9]],[4,[9,[9,0]]]]
@ -155,7 +164,8 @@ mod tests {
[[[[5,4],[7,7]],8],[[8,3],8]] [[[[5,4],[7,7]],8],[[8,3],8]]
[[9,3],[[9,9],[6,[4,9]]]] [[9,3],[[9,9],[6,[4,9]]]]
[[2,[[7,7],7]],[[5,8],[[9,3],[0,2]]]] [[2,[[7,7],7]],[[5,8],[[9,3],[0,2]]]]
[[[[5,2],5],[8,[3,7]]],[[5,[7,5]],[4,4]]]"); [[[[5,2],5],[8,[3,7]]],[[5,[7,5]],[4,4]]]",
);
let result = part2(&nums); let result = part2(&nums);
assert_eq!(result, 3993); assert_eq!(result, 3993);
} }
@ -180,11 +190,17 @@ mod tests {
} }
#[test] #[test]
fn exploding_4() { fn exploding_4() {
test_explosion("[[3,[2,[1,[7,3]]]],[6,[5,[4,[3,2]]]]]", "[[3,[2,[8,0]]],[9,[5,[4,[3,2]]]]]"); test_explosion(
"[[3,[2,[1,[7,3]]]],[6,[5,[4,[3,2]]]]]",
"[[3,[2,[8,0]]],[9,[5,[4,[3,2]]]]]",
);
} }
#[test] #[test]
fn exploding_5() { fn exploding_5() {
test_explosion("[[3,[2,[8,0]]],[9,[5,[4,[3,2]]]]]", "[[3,[2,[8,0]]],[9,[5,[7,0]]]]"); test_explosion(
"[[3,[2,[8,0]]],[9,[5,[4,[3,2]]]]]",
"[[3,[2,[8,0]]],[9,[5,[7,0]]]]",
);
} }
fn test_sum(nums: Vec<&str>, expected: &str) { fn test_sum(nums: Vec<&str>, expected: &str) {
@ -197,35 +213,17 @@ mod tests {
#[test] #[test]
fn sum_1() { fn sum_1() {
let nums = vec![ let nums = vec!["[1,1]", "[2,2]", "[3,3]", "[4,4]"];
"[1,1]",
"[2,2]",
"[3,3]",
"[4,4]"
];
test_sum(nums, "[[[[1,1],[2,2]],[3,3]],[4,4]]"); test_sum(nums, "[[[[1,1],[2,2]],[3,3]],[4,4]]");
} }
#[test] #[test]
fn sum_2() { fn sum_2() {
let nums = vec![ let nums = vec!["[1,1]", "[2,2]", "[3,3]", "[4,4]", "[5,5]"];
"[1,1]",
"[2,2]",
"[3,3]",
"[4,4]",
"[5,5]"
];
test_sum(nums, "[[[[3,0],[5,3]],[4,4]],[5,5]]"); test_sum(nums, "[[[[3,0],[5,3]],[4,4]],[5,5]]");
} }
#[test] #[test]
fn sum_3() { fn sum_3() {
let nums = vec![ let nums = vec!["[1,1]", "[2,2]", "[3,3]", "[4,4]", "[5,5]", "[6,6]"];
"[1,1]",
"[2,2]",
"[3,3]",
"[4,4]",
"[5,5]",
"[6,6]",
];
test_sum(nums, "[[[[5,0],[7,4]],[5,5]],[6,6]]"); test_sum(nums, "[[[[5,0],[7,4]],[5,5]],[6,6]]");
} }
#[test] #[test]
@ -240,9 +238,12 @@ mod tests {
"[2,9]", "[2,9]",
"[1,[[[9,3],9],[[9,0],[0,7]]]]", "[1,[[[9,3],9],[[9,0],[0,7]]]]",
"[[[5,[7,4]],7],1]", "[[[5,[7,4]],7],1]",
"[[[[4,2],2],6],[8,7]]" "[[[[4,2],2],6],[8,7]]",
]; ];
test_sum(nums, "[[[[8,7],[7,7]],[[8,6],[7,7]]],[[[0,7],[6,6]],[8,7]]]"); test_sum(
nums,
"[[[[8,7],[7,7]],[[8,6],[7,7]]],[[[0,7],[6,6]],[8,7]]]",
);
} }
fn test_magnitude(initial: &str, expected: i32) { fn test_magnitude(initial: &str, expected: i32) {
@ -272,7 +273,9 @@ mod tests {
} }
#[test] #[test]
fn magnitude_6() { fn magnitude_6() {
test_magnitude("[[[[8,7],[7,7]],[[8,6],[7,7]]],[[[0,7],[6,6]],[8,7]]]", 3488); test_magnitude(
"[[[[8,7],[7,7]],[[8,6],[7,7]]],[[[0,7],[6,6]],[8,7]]]",
3488,
);
} }
} }

View File

@ -9,7 +9,7 @@ pub enum ParseCommandError {
pub enum CommandType { pub enum CommandType {
Forward, Forward,
Down, Down,
Up Up,
} }
pub struct Command(CommandType, u32); pub struct Command(CommandType, u32);
@ -20,16 +20,14 @@ fn parse_line(line: &str) -> Result<Command, ParseCommandError> {
"up" => Ok(CommandType::Up), "up" => Ok(CommandType::Up),
"down" => Ok(CommandType::Down), "down" => Ok(CommandType::Down),
"forward" => Ok(CommandType::Forward), "forward" => Ok(CommandType::Forward),
_ => Err(ParseCommandError::ParseEnumError) _ => Err(ParseCommandError::ParseEnumError),
}?; }?;
let amount = parts[1].parse().map_err(ParseCommandError::ParseIntError)?; let amount = parts[1].parse().map_err(ParseCommandError::ParseIntError)?;
Ok(Command(command, amount)) Ok(Command(command, amount))
} }
pub fn parse_input(input: &str) -> Result<Vec<Command>, ParseCommandError> { pub fn parse_input(input: &str) -> Result<Vec<Command>, ParseCommandError> {
input.split_terminator('\n') input.split_terminator('\n').map(parse_line).collect()
.map(parse_line)
.collect()
} }
pub fn part1(commands: &[Command]) -> u32 { pub fn part1(commands: &[Command]) -> u32 {
@ -74,7 +72,7 @@ mod tests {
Command(CommandType::Forward, 8), Command(CommandType::Forward, 8),
Command(CommandType::Up, 3), Command(CommandType::Up, 3),
Command(CommandType::Down, 8), Command(CommandType::Down, 8),
Command(CommandType::Forward, 2) Command(CommandType::Forward, 2),
]; ];
let result = part1(&commands); let result = part1(&commands);
assert_eq!(result, 150); assert_eq!(result, 150);
@ -88,10 +86,9 @@ mod tests {
Command(CommandType::Forward, 8), Command(CommandType::Forward, 8),
Command(CommandType::Up, 3), Command(CommandType::Up, 3),
Command(CommandType::Down, 8), Command(CommandType::Down, 8),
Command(CommandType::Forward, 2) Command(CommandType::Forward, 2),
]; ];
let result = part2(&commands); let result = part2(&commands);
assert_eq!(result, 900) assert_eq!(result, 900)
} }
} }

View File

@ -1,5 +1,4 @@
use std::{ops::Range, fmt::Display}; use std::{fmt::Display, ops::Range};
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Image { pub struct Image {
@ -8,7 +7,7 @@ pub struct Image {
data: Vec<bool>, data: Vec<bool>,
default_value: bool, default_value: bool,
offset_x: i32, offset_x: i32,
offset_y: i32 offset_y: i32,
} }
impl Image { impl Image {
@ -20,7 +19,7 @@ impl Image {
data, data,
default_value: false, default_value: false,
offset_x: 0, offset_x: 0,
offset_y: 0 offset_y: 0,
} }
} }
@ -81,7 +80,7 @@ impl Image {
let padding = padding as i32; let padding = padding as i32;
Range { Range {
start: -self.offset_x - padding, start: -self.offset_x - padding,
end: self.width as i32 - self.offset_x + padding end: self.width as i32 - self.offset_x + padding,
} }
} }
@ -89,7 +88,7 @@ impl Image {
let padding = padding as i32; let padding = padding as i32;
Range { Range {
start: -self.offset_y - padding, start: -self.offset_y - padding,
end: self.height as i32 - self.offset_y + padding end: self.height as i32 - self.offset_y + padding,
} }
} }
@ -99,7 +98,7 @@ impl Image {
-self.offset_x, -self.offset_x,
-self.offset_y, -self.offset_y,
self.width as i32 - self.offset_x, self.width as i32 - self.offset_x,
self.height as i32 - self.offset_y self.height as i32 - self.offset_y,
); );
} }
} }
@ -139,22 +138,25 @@ fn parse_enchancer(input: &str) -> [bool; 512] {
enhancer[i] = c == '#'; enhancer[i] = c == '#';
i += 1; i += 1;
} }
return enhancer return enhancer;
} }
pub fn parse_input(input: &str) -> ([bool; 512], Image) { pub fn parse_input(input: &str) -> ([bool; 512], Image) {
let (section1, section2) = input.split_once("\n\n").unwrap(); let (section1, section2) = input.split_once("\n\n").unwrap();
return ( return (parse_enchancer(section1), parse_image(section2));
parse_enchancer(section1),
parse_image(section2)
);
} }
fn lookup_enhancer(x: i32, y: i32, image: &Image, enhancer: &[bool; 512]) -> bool { fn lookup_enhancer(x: i32, y: i32, image: &Image, enhancer: &[bool; 512]) -> bool {
let pixel_offsets = [ let pixel_offsets = [
(-1, -1), ( 0, -1), ( 1, -1), (-1, -1),
(-1, 0), ( 0, 0), ( 1, 0), (0, -1),
(-1, 1), ( 0, 1), ( 1, 1) (1, -1),
(-1, 0),
(0, 0),
(1, 0),
(-1, 1),
(0, 1),
(1, 1),
]; ];
let mut lookup_index = 0; let mut lookup_index = 0;
@ -202,7 +204,6 @@ pub fn part2(data: &([bool; 512], Image)) -> usize {
enhanced_image.count(true) enhanced_image.count(true)
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View File

@ -1,8 +1,8 @@
use std::collections::HashMap; use std::collections::HashMap;
pub fn parse_input(input: &str) -> (u8, u8) { pub fn parse_input(input: &str) -> (u8, u8) {
let players: Vec<u8> = input.lines() let players: Vec<u8> = input
.lines()
.map(|l| l.split_once(": ").unwrap().1.parse().unwrap()) .map(|l| l.split_once(": ").unwrap().1.parse().unwrap())
.collect(); .collect();
return (players[0], players[1]); return (players[0], players[1]);
@ -42,10 +42,21 @@ pub fn part1(starting_positions: &(u8, u8)) -> u32 {
player1_score.min(player2_score) * rolled_count as u32 player1_score.min(player2_score) * rolled_count as u32
} }
fn get_wins_amount(starting_pos1: u32, starting_pos2: u32, starting_score1: u32, starting_score2: u32, memo: &mut HashMap<(u32, u32, u32, u32), (u64, u64)>) -> (u64, u64) { fn get_wins_amount(
let memo_key = (starting_pos1, starting_pos2, starting_score1, starting_score2); starting_pos1: u32,
starting_pos2: u32,
starting_score1: u32,
starting_score2: u32,
memo: &mut HashMap<(u32, u32, u32, u32), (u64, u64)>,
) -> (u64, u64) {
let memo_key = (
starting_pos1,
starting_pos2,
starting_score1,
starting_score2,
);
if memo.contains_key(&memo_key) { if memo.contains_key(&memo_key) {
return *memo.get(&memo_key).unwrap() return *memo.get(&memo_key).unwrap();
} }
let mut total_wins1 = 0; let mut total_wins1 = 0;
let mut total_wins2 = 0; let mut total_wins2 = 0;

View File

@ -1,17 +1,20 @@
use std::{convert::{TryFrom, TryInto}, num::ParseIntError, collections::HashSet}; use std::{
collections::HashSet,
convert::{TryFrom, TryInto},
num::ParseIntError,
};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Cuboid { pub struct Cuboid {
x: (i32, i32), x: (i32, i32),
y: (i32, i32), y: (i32, i32),
z: (i32, i32) z: (i32, i32),
} }
#[derive(Debug)] #[derive(Debug)]
pub enum StepAction { pub enum StepAction {
On, On,
Off Off,
} }
#[derive(Debug)] #[derive(Debug)]
@ -21,14 +24,14 @@ pub struct RebootStep(StepAction, Cuboid);
pub enum ParseRangeError { pub enum ParseRangeError {
Empty, Empty,
BadLen, BadLen,
ParseInt(ParseIntError) ParseInt(ParseIntError),
} }
#[derive(Debug)] #[derive(Debug)]
pub enum ParseCuboidError { pub enum ParseCuboidError {
Empty, Empty,
BadLen, BadLen,
ParseRange(ParseRangeError) ParseRange(ParseRangeError),
} }
#[derive(Debug)] #[derive(Debug)]
@ -36,14 +39,17 @@ pub enum ParseRebootStepError {
Empty, Empty,
BadLen, BadLen,
BadAction, BadAction,
ParseCuboid(ParseCuboidError) ParseCuboid(ParseCuboidError),
} }
impl Cuboid { impl Cuboid {
fn contains(&self, point: &(i32, i32, i32)) -> bool { fn contains(&self, point: &(i32, i32, i32)) -> bool {
self.x.0 <= point.0 && point.0 <= self.x.1 && self.x.0 <= point.0
self.y.0 <= point.1 && point.1 <= self.y.1 && && point.0 <= self.x.1
self.z.0 <= point.2 && point.2 <= self.z.1 && self.y.0 <= point.1
&& point.1 <= self.y.1
&& self.z.0 <= point.2
&& point.2 <= self.z.1
} }
fn clamp(&self, other: &Cuboid) -> Cuboid { fn clamp(&self, other: &Cuboid) -> Cuboid {
@ -55,16 +61,22 @@ impl Cuboid {
} }
fn intersection(&self, other: &Cuboid) -> Option<Cuboid> { fn intersection(&self, other: &Cuboid) -> Option<Cuboid> {
if self.z.0 > other.z.1 || other.z.0 > self.z.1 { return None; } if self.z.0 > other.z.1 || other.z.0 > self.z.1 {
if self.y.0 > other.y.1 || other.y.0 > self.y.1 { return None; } return None;
if self.x.0 > other.x.1 || other.x.0 > self.x.1 { return None; } }
if self.y.0 > other.y.1 || other.y.0 > self.y.1 {
return None;
}
if self.x.0 > other.x.1 || other.x.0 > self.x.1 {
return None;
}
Some(self.clamp(other)) Some(self.clamp(other))
} }
fn volume(&self) -> u64 { fn volume(&self) -> u64 {
(self.x.1 - self.x.0 + 1) as u64 * (self.x.1 - self.x.0 + 1) as u64
(self.y.1 - self.y.0 + 1) as u64 * * (self.y.1 - self.y.0 + 1) as u64
(self.z.1 - self.z.0 + 1) as u64 * (self.z.1 - self.z.0 + 1) as u64
} }
} }
@ -84,9 +96,7 @@ fn parse_range(value: &str) -> Result<(i32, i32), ParseRangeError> {
if value.is_empty() { if value.is_empty() {
return Err(ParseRangeError::Empty); return Err(ParseRangeError::Empty);
} }
let (start, end) = value[2..] let (start, end) = value[2..].split_once("..").ok_or(ParseRangeError::BadLen)?;
.split_once("..")
.ok_or(ParseRangeError::BadLen)?;
Ok((start.parse()?, end.parse()?)) Ok((start.parse()?, end.parse()?))
} }
@ -97,7 +107,8 @@ impl TryFrom<&str> for Cuboid {
if value.is_empty() { if value.is_empty() {
return Err(Self::Error::Empty); return Err(Self::Error::Empty);
} }
let ranges: Vec<_> = value.split(',') let ranges: Vec<_> = value
.split(',')
.map(parse_range) .map(parse_range)
.collect::<Result<_, _>>()?; .collect::<Result<_, _>>()?;
if ranges.len() != 3 { if ranges.len() != 3 {
@ -106,7 +117,7 @@ impl TryFrom<&str> for Cuboid {
Ok(Cuboid { Ok(Cuboid {
x: ranges[0], x: ranges[0],
y: ranges[1], y: ranges[1],
z: ranges[2] z: ranges[2],
}) })
} }
} }
@ -129,7 +140,7 @@ impl TryFrom<&str> for RebootStep {
let action = match action_str { let action = match action_str {
"on" => StepAction::On, "on" => StepAction::On,
"off" => StepAction::Off, "off" => StepAction::Off,
_ => return Err(Self::Error::BadAction) _ => return Err(Self::Error::BadAction),
}; };
Ok(RebootStep(action, cuboid.try_into()?)) Ok(RebootStep(action, cuboid.try_into()?))
@ -137,9 +148,7 @@ impl TryFrom<&str> for RebootStep {
} }
pub fn parse_input(input: &str) -> Vec<RebootStep> { pub fn parse_input(input: &str) -> Vec<RebootStep> {
input.lines() input.lines().map(|l| l.try_into().unwrap()).collect()
.map(|l| l.try_into().unwrap())
.collect()
} }
fn count_cubes_in_cuboid(steps: &[RebootStep], region: &Cuboid) -> u32 { fn count_cubes_in_cuboid(steps: &[RebootStep], region: &Cuboid) -> u32 {
@ -153,7 +162,7 @@ fn count_cubes_in_cuboid(steps: &[RebootStep], region: &Cuboid) -> u32 {
let cube = (x, y, z); let cube = (x, y, z);
match step.0 { match step.0 {
StepAction::On => cubes.insert(cube), StepAction::On => cubes.insert(cube),
StepAction::Off => cubes.remove(&cube) StepAction::Off => cubes.remove(&cube),
}; };
} }
} }
@ -259,7 +268,7 @@ pub fn part1(steps: &[RebootStep]) -> u32 {
let region = Cuboid { let region = Cuboid {
x: (-50, 50), x: (-50, 50),
y: (-50, 50), y: (-50, 50),
z: (-50, 50) z: (-50, 50),
}; };
count_cubes_in_cuboid(steps, &region) count_cubes_in_cuboid(steps, &region)
} }
@ -274,7 +283,8 @@ mod tests {
#[test] #[test]
fn part1_example() { fn part1_example() {
let steps = parse_input("on x=-20..26,y=-36..17,z=-47..7 let steps = parse_input(
"on x=-20..26,y=-36..17,z=-47..7
on x=-20..33,y=-21..23,z=-26..28 on x=-20..33,y=-21..23,z=-26..28
on x=-22..28,y=-29..23,z=-38..16 on x=-22..28,y=-29..23,z=-38..16
on x=-46..7,y=-6..46,z=-50..-1 on x=-46..7,y=-6..46,z=-50..-1
@ -295,14 +305,16 @@ on x=-49..-5,y=-3..45,z=-29..18
off x=18..30,y=-20..-8,z=-3..13 off x=18..30,y=-20..-8,z=-3..13
on x=-41..9,y=-7..43,z=-33..15 on x=-41..9,y=-7..43,z=-33..15
on x=-54112..-39298,y=-85059..-49293,z=-27449..7877 on x=-54112..-39298,y=-85059..-49293,z=-27449..7877
on x=967..23432,y=45373..81175,z=27513..53682"); on x=967..23432,y=45373..81175,z=27513..53682",
);
let result = part1(&steps); let result = part1(&steps);
assert_eq!(result, 590784); assert_eq!(result, 590784);
} }
#[test] #[test]
fn part2_example() { fn part2_example() {
let steps = parse_input("on x=-5..47,y=-31..22,z=-19..33 let steps = parse_input(
"on x=-5..47,y=-31..22,z=-19..33
on x=-44..5,y=-27..21,z=-14..35 on x=-44..5,y=-27..21,z=-14..35
on x=-49..-1,y=-11..42,z=-10..38 on x=-49..-1,y=-11..42,z=-10..38
on x=-20..34,y=-40..6,z=-44..1 on x=-20..34,y=-40..6,z=-44..1
@ -361,7 +373,8 @@ off x=-37810..49457,y=-71013..-7894,z=-105357..-13188
off x=-27365..46395,y=31009..98017,z=15428..76570 off x=-27365..46395,y=31009..98017,z=15428..76570
off x=-70369..-16548,y=22648..78696,z=-1892..86821 off x=-70369..-16548,y=22648..78696,z=-1892..86821
on x=-53470..21291,y=-120233..-33476,z=-44150..38147 on x=-53470..21291,y=-120233..-33476,z=-44150..38147
off x=-93533..-4276,y=-16170..68771,z=-104985..-24507"); off x=-93533..-4276,y=-16170..68771,z=-104985..-24507",
);
let result = part2(steps); let result = part2(steps);
assert_eq!(result, 2758514936282235); assert_eq!(result, 2758514936282235);
} }

View File

@ -1,7 +1,8 @@
use std::{num::ParseIntError, slice::Iter}; use std::{num::ParseIntError, slice::Iter};
pub fn parse_input(input: &str) -> Result<Vec<i32>, ParseIntError> { pub fn parse_input(input: &str) -> Result<Vec<i32>, ParseIntError> {
input.split_whitespace() input
.split_whitespace()
.map(|s| i32::from_str_radix(s, 2)) .map(|s| i32::from_str_radix(s, 2))
.collect() .collect()
} }
@ -58,9 +59,15 @@ pub fn part2(diagnostics: &[i32]) -> i32 {
if oxygen_len > 1 { if oxygen_len > 1 {
let bit_count = count_bits(oxygen_diagnostics.iter(), &power); let bit_count = count_bits(oxygen_diagnostics.iter(), &power);
if 2 * bit_count >= oxygen_len { if 2 * bit_count >= oxygen_len {
oxygen_diagnostics = oxygen_diagnostics.into_iter().filter(|n| n & power > 0).collect(); oxygen_diagnostics = oxygen_diagnostics
.into_iter()
.filter(|n| n & power > 0)
.collect();
} else { } else {
oxygen_diagnostics = oxygen_diagnostics.into_iter().filter(|n| n & power == 0).collect(); oxygen_diagnostics = oxygen_diagnostics
.into_iter()
.filter(|n| n & power == 0)
.collect();
} }
} }
@ -68,13 +75,21 @@ pub fn part2(diagnostics: &[i32]) -> i32 {
if carbon_len > 1 { if carbon_len > 1 {
let bit_count = count_bits(carbon_diagnostics.iter(), &power); let bit_count = count_bits(carbon_diagnostics.iter(), &power);
if 2 * bit_count < carbon_len { if 2 * bit_count < carbon_len {
carbon_diagnostics = carbon_diagnostics.into_iter().filter(|n| n & power > 0).collect(); carbon_diagnostics = carbon_diagnostics
.into_iter()
.filter(|n| n & power > 0)
.collect();
} else { } else {
carbon_diagnostics = carbon_diagnostics.into_iter().filter(|n| n & power == 0).collect(); carbon_diagnostics = carbon_diagnostics
.into_iter()
.filter(|n| n & power == 0)
.collect();
} }
} }
if oxygen_len == 1 && carbon_len == 1 { break; } if oxygen_len == 1 && carbon_len == 1 {
break;
}
power /= 2; power /= 2;
} }
@ -88,16 +103,21 @@ mod tests {
#[test] #[test]
fn part1_example() { fn part1_example() {
let diagnostics = [0b00100, 0b11110, 0b10110, 0b10111, 0b10101, 0b01111, 0b00111, 0b11100, 0b10000, 0b11001, 0b00010, 0b01010]; let diagnostics = [
0b00100, 0b11110, 0b10110, 0b10111, 0b10101, 0b01111, 0b00111, 0b11100, 0b10000, 0b11001,
0b00010, 0b01010,
];
let result = part1(&diagnostics); let result = part1(&diagnostics);
assert_eq!(result, 198); assert_eq!(result, 198);
} }
#[test] #[test]
fn part2_example() { fn part2_example() {
let diagnostics = [0b00100, 0b11110, 0b10110, 0b10111, 0b10101, 0b01111, 0b00111, 0b11100, 0b10000, 0b11001, 0b00010, 0b01010]; let diagnostics = [
0b00100, 0b11110, 0b10110, 0b10111, 0b10101, 0b01111, 0b00111, 0b11100, 0b10000, 0b11001,
0b00010, 0b01010,
];
let result = part2(&diagnostics); let result = part2(&diagnostics);
assert_eq!(result, 230); assert_eq!(result, 230);
} }
} }

View File

@ -1,10 +1,9 @@
use std::num::ParseIntError; use std::num::ParseIntError;
#[derive(Debug)] #[derive(Debug)]
pub struct BingoGame { pub struct BingoGame {
numbers: Vec<i32>, numbers: Vec<i32>,
boards: Vec<[i32; 25]> boards: Vec<[i32; 25]>,
} }
#[derive(Debug)] #[derive(Debug)]
@ -16,9 +15,7 @@ pub enum ParseBingoGameError {
pub fn parse_input(input: &str) -> Result<BingoGame, ParseBingoGameError> { pub fn parse_input(input: &str) -> Result<BingoGame, ParseBingoGameError> {
let mut sections = input.split_terminator("\n\n"); let mut sections = input.split_terminator("\n\n");
let numbers_section = sections let numbers_section = sections.next().ok_or(ParseBingoGameError::NoNumbersError)?;
.next()
.ok_or(ParseBingoGameError::NoNumbersError)?;
let numbers = numbers_section let numbers = numbers_section
.split_terminator(",") .split_terminator(",")
@ -33,7 +30,10 @@ pub fn parse_input(input: &str) -> Result<BingoGame, ParseBingoGameError> {
for row in section.split_terminator("\n") { for row in section.split_terminator("\n") {
let mut x = 0; let mut x = 0;
for s in row.split_whitespace() { for s in row.split_whitespace() {
let n = s.trim().parse::<i32>().map_err(ParseBingoGameError::ParseNumberError)?; let n = s
.trim()
.parse::<i32>()
.map_err(ParseBingoGameError::ParseNumberError)?;
board[5 * y + x] = n; board[5 * y + x] = n;
x += 1; x += 1;
} }
@ -58,7 +58,7 @@ fn mark_number(board: &[i32], markings: &mut i32, value: i32) -> bool {
let pos: usize; let pos: usize;
match find_number(board, value) { match find_number(board, value) {
None => return false, None => return false,
Some(n) => pos = n Some(n) => pos = n,
}; };
*markings |= 1 << pos; *markings |= 1 << pos;
return true; return true;
@ -116,14 +116,21 @@ pub fn part2(game: &BingoGame) -> i32 {
for num in game.numbers.iter() { for num in game.numbers.iter() {
for i in 0..game.boards.len() { for i in 0..game.boards.len() {
if winning_numbers[i] == 0 && mark_number(&game.boards[i], &mut markings[i], *num) && contains_win(markings[i]) { if winning_numbers[i] == 0
&& mark_number(&game.boards[i], &mut markings[i], *num)
&& contains_win(markings[i])
{
winning_numbers[i] = *num; winning_numbers[i] = *num;
last_winning_board = i; last_winning_board = i;
} }
} }
} }
return winning_numbers[last_winning_board] * sum_unmarked_numbers(&game.boards[last_winning_board], markings[last_winning_board]); return winning_numbers[last_winning_board]
* sum_unmarked_numbers(
&game.boards[last_winning_board],
markings[last_winning_board],
);
} }
#[cfg(test)] #[cfg(test)]
@ -141,30 +148,21 @@ mod tests {
#[test] #[test]
fn part1_example() { fn part1_example() {
let input = BingoGame { let input = BingoGame {
numbers: vec![7,4,9,5,11,17,23,2,0,14,21,24,10,16,13,6,15,25,12,22,18,20,8,19,3,26,1], numbers: vec![
7, 4, 9, 5, 11, 17, 23, 2, 0, 14, 21, 24, 10, 16, 13, 6, 15, 25, 12, 22, 18, 20, 8, 19, 3,
26, 1,
],
boards: vec![ boards: vec![
[ [
22, 13, 17, 11, 0, 22, 13, 17, 11, 0, 8, 2, 23, 4, 24, 21, 9, 14, 16, 7, 6, 10, 3, 18, 5, 1, 12, 20, 15, 19,
8, 2, 23, 4, 24,
21, 9, 14, 16, 7,
6, 10, 3, 18, 5,
1, 12, 20, 15, 19
], ],
[ [
3, 15, 0, 2, 22, 3, 15, 0, 2, 22, 9, 18, 13, 17, 5, 19, 8, 7, 25, 23, 20, 11, 10, 24, 4, 14, 21, 16, 12, 6,
9, 18, 13, 17, 5,
19, 8, 7, 25, 23,
20, 11, 10, 24, 4,
14, 21, 16, 12, 6
], ],
[ [
14, 21, 17, 24, 4, 14, 21, 17, 24, 4, 10, 16, 15, 9, 19, 18, 8, 23, 26, 20, 22, 11, 13, 6, 5, 2, 0, 12, 3, 7,
10, 16, 15, 9, 19, ],
18, 8, 23, 26, 20, ],
22, 11, 13, 6, 5,
2, 0, 12, 3, 7
]
]
}; };
let result = part1(&input); let result = part1(&input);
assert_eq!(result, 4512); assert_eq!(result, 4512);
@ -173,30 +171,21 @@ mod tests {
#[test] #[test]
fn part2_example() { fn part2_example() {
let input = BingoGame { let input = BingoGame {
numbers: vec![7,4,9,5,11,17,23,2,0,14,21,24,10,16,13,6,15,25,12,22,18,20,8,19,3,26,1], numbers: vec![
7, 4, 9, 5, 11, 17, 23, 2, 0, 14, 21, 24, 10, 16, 13, 6, 15, 25, 12, 22, 18, 20, 8, 19, 3,
26, 1,
],
boards: vec![ boards: vec![
[ [
22, 13, 17, 11, 0, 22, 13, 17, 11, 0, 8, 2, 23, 4, 24, 21, 9, 14, 16, 7, 6, 10, 3, 18, 5, 1, 12, 20, 15, 19,
8, 2, 23, 4, 24,
21, 9, 14, 16, 7,
6, 10, 3, 18, 5,
1, 12, 20, 15, 19
], ],
[ [
3, 15, 0, 2, 22, 3, 15, 0, 2, 22, 9, 18, 13, 17, 5, 19, 8, 7, 25, 23, 20, 11, 10, 24, 4, 14, 21, 16, 12, 6,
9, 18, 13, 17, 5,
19, 8, 7, 25, 23,
20, 11, 10, 24, 4,
14, 21, 16, 12, 6
], ],
[ [
14, 21, 17, 24, 4, 14, 21, 17, 24, 4, 10, 16, 15, 9, 19, 18, 8, 23, 26, 20, 22, 11, 13, 6, 5, 2, 0, 12, 3, 7,
10, 16, 15, 9, 19, ],
18, 8, 23, 26, 20, ],
22, 11, 13, 6, 5,
2, 0, 12, 3, 7
]
]
}; };
let result = part2(&input); let result = part2(&input);
assert_eq!(result, 1924); assert_eq!(result, 1924);
@ -226,4 +215,3 @@ mod tests {
assert!(contains_win(markings)); assert!(contains_win(markings));
} }
} }

View File

@ -1,4 +1,7 @@
use std::{num::ParseIntError, cmp::{min, max}}; use std::{
cmp::{max, min},
num::ParseIntError,
};
type Grid = Vec<Vec<i32>>; type Grid = Vec<Vec<i32>>;
@ -7,23 +10,25 @@ pub struct Line {
x1: i32, x1: i32,
y1: i32, y1: i32,
x2: i32, x2: i32,
y2: i32 y2: i32,
} }
#[derive(Debug)] #[derive(Debug)]
pub enum ParseLineError { pub enum ParseLineError {
ParseNumberError(ParseIntError), ParseNumberError(ParseIntError),
ParsePointsError, ParsePointsError,
ParsePointError ParsePointError,
} }
pub fn parse_point(input: &str) -> Result<(i32, i32), ParseLineError> { pub fn parse_point(input: &str) -> Result<(i32, i32), ParseLineError> {
let mut parts = input.split(','); let mut parts = input.split(',');
let x = parts.next() let x = parts
.next()
.ok_or(ParseLineError::ParsePointError)? .ok_or(ParseLineError::ParsePointError)?
.parse() .parse()
.map_err(ParseLineError::ParseNumberError)?; .map_err(ParseLineError::ParseNumberError)?;
let y = parts.next() let y = parts
.next()
.ok_or(ParseLineError::ParsePointError)? .ok_or(ParseLineError::ParsePointError)?
.parse() .parse()
.map_err(ParseLineError::ParseNumberError)?; .map_err(ParseLineError::ParseNumberError)?;
@ -142,16 +147,66 @@ mod tests {
#[test] #[test]
fn part1_example() { fn part1_example() {
let input = [ let input = [
Line { x1: 0, y1: 9, x2: 5, y2: 9 }, Line {
Line { x1: 8, y1: 0, x2: 0, y2: 8 }, x1: 0,
Line { x1: 9, y1: 4, x2: 3, y2: 4 }, y1: 9,
Line { x1: 2, y1: 2, x2: 2, y2: 1 }, x2: 5,
Line { x1: 7, y1: 0, x2: 7, y2: 4 }, y2: 9,
Line { x1: 6, y1: 4, x2: 2, y2: 0 }, },
Line { x1: 0, y1: 9, x2: 2, y2: 9 }, Line {
Line { x1: 3, y1: 4, x2: 1, y2: 4 }, x1: 8,
Line { x1: 0, y1: 0, x2: 8, y2: 8 }, y1: 0,
Line { x1: 5, y1: 5, x2: 8, y2: 2 } x2: 0,
y2: 8,
},
Line {
x1: 9,
y1: 4,
x2: 3,
y2: 4,
},
Line {
x1: 2,
y1: 2,
x2: 2,
y2: 1,
},
Line {
x1: 7,
y1: 0,
x2: 7,
y2: 4,
},
Line {
x1: 6,
y1: 4,
x2: 2,
y2: 0,
},
Line {
x1: 0,
y1: 9,
x2: 2,
y2: 9,
},
Line {
x1: 3,
y1: 4,
x2: 1,
y2: 4,
},
Line {
x1: 0,
y1: 0,
x2: 8,
y2: 8,
},
Line {
x1: 5,
y1: 5,
x2: 8,
y2: 2,
},
]; ];
let result = part1(&input); let result = part1(&input);
assert_eq!(result, 5); assert_eq!(result, 5);
@ -160,16 +215,66 @@ mod tests {
#[test] #[test]
fn part2_example() { fn part2_example() {
let input = [ let input = [
Line { x1: 0, y1: 9, x2: 5, y2: 9 }, Line {
Line { x1: 8, y1: 0, x2: 0, y2: 8 }, x1: 0,
Line { x1: 9, y1: 4, x2: 3, y2: 4 }, y1: 9,
Line { x1: 2, y1: 2, x2: 2, y2: 1 }, x2: 5,
Line { x1: 7, y1: 0, x2: 7, y2: 4 }, y2: 9,
Line { x1: 6, y1: 4, x2: 2, y2: 0 }, },
Line { x1: 0, y1: 9, x2: 2, y2: 9 }, Line {
Line { x1: 3, y1: 4, x2: 1, y2: 4 }, x1: 8,
Line { x1: 0, y1: 0, x2: 8, y2: 8 }, y1: 0,
Line { x1: 5, y1: 5, x2: 8, y2: 2 } x2: 0,
y2: 8,
},
Line {
x1: 9,
y1: 4,
x2: 3,
y2: 4,
},
Line {
x1: 2,
y1: 2,
x2: 2,
y2: 1,
},
Line {
x1: 7,
y1: 0,
x2: 7,
y2: 4,
},
Line {
x1: 6,
y1: 4,
x2: 2,
y2: 0,
},
Line {
x1: 0,
y1: 9,
x2: 2,
y2: 9,
},
Line {
x1: 3,
y1: 4,
x2: 1,
y2: 4,
},
Line {
x1: 0,
y1: 0,
x2: 8,
y2: 8,
},
Line {
x1: 5,
y1: 5,
x2: 8,
y2: 2,
},
]; ];
let result = part2(&input); let result = part2(&input);
assert_eq!(result, 12); assert_eq!(result, 12);

View File

@ -1,7 +1,9 @@
use std::num::ParseIntError; use std::num::ParseIntError;
pub fn parse_input(input: &str) -> Result<Vec<i32>, ParseIntError> { pub fn parse_input(input: &str) -> Result<Vec<i32>, ParseIntError> {
input.trim_end().split_terminator(',') input
.trim_end()
.split_terminator(',')
.map(|s| s.parse()) .map(|s| s.parse())
.collect() .collect()
} }
@ -78,4 +80,3 @@ mod tests {
assert_eq!(result, 26984457539 as u64); assert_eq!(result, 26984457539 as u64);
} }
} }

View File

@ -1,13 +1,19 @@
use std::num::ParseIntError; use std::num::ParseIntError;
pub fn parse_input(input: &str) -> Result<Vec<i32>, ParseIntError> { pub fn parse_input(input: &str) -> Result<Vec<i32>, ParseIntError> {
input.trim_end().split_terminator(',') input
.trim_end()
.split_terminator(',')
.map(|s| s.parse()) .map(|s| s.parse())
.collect() .collect()
} }
fn abs(x: i32) -> u32 { fn abs(x: i32) -> u32 {
if x < 0 { -x as u32 } else { x as u32 } if x < 0 {
-x as u32
} else {
x as u32
}
} }
fn calculate_total_cost_to1(crabs: &[i32], target: i32) -> u32 { fn calculate_total_cost_to1(crabs: &[i32], target: i32) -> u32 {
@ -82,4 +88,3 @@ mod tests {
assert_eq!(result, 168); assert_eq!(result, 168);
} }
} }

View File

@ -1,4 +1,4 @@
use std::{convert::TryInto, collections::HashMap}; use std::{collections::HashMap, convert::TryInto};
pub struct Entry([String; 10], [String; 4]); pub struct Entry([String; 10], [String; 4]);
@ -20,9 +20,7 @@ fn parse_line(line: &str) -> Entry {
} }
pub fn parse_input(input: &str) -> Vec<Entry> { pub fn parse_input(input: &str) -> Vec<Entry> {
input.lines() input.lines().map(parse_line).collect()
.map(parse_line)
.collect()
} }
pub fn part1(entries: &[Entry]) -> u32 { pub fn part1(entries: &[Entry]) -> u32 {
@ -51,7 +49,7 @@ fn signal_to_bitmask(signal: &str) -> u32 {
'e' => bitmask += 0b0010000, 'e' => bitmask += 0b0010000,
'f' => bitmask += 0b0100000, 'f' => bitmask += 0b0100000,
'g' => bitmask += 0b1000000, 'g' => bitmask += 0b1000000,
_ => bitmask += 0 _ => bitmask += 0,
} }
} }
return bitmask; return bitmask;
@ -144,16 +142,181 @@ mod tests {
#[test] #[test]
fn part1_example() { fn part1_example() {
let input = vec![ let input = vec![
Entry(["be" .into(), "cfbegad" .into(), "cbdgef" .into(), "fgaecd" .into(), "cgeb" .into(), "fdcge" .into(), "agebfd" .into(), "fecdb" .into(), "fabcd" .into(), "edb".into()], ["fdgacbe" .into(), "cefdb" .into(), "cefbgd" .into(), "gcbe".into()]), Entry(
Entry(["edbfga" .into(), "begcd" .into(), "cbg" .into(), "gc" .into(), "gcadebf" .into(), "fbgde" .into(), "acbgfd" .into(), "abcde" .into(), "gfcbed" .into(), "gfec".into()], ["fcgedb" .into(), "cgb" .into(), "dgebacf" .into(), "gc".into()]), [
Entry(["fgaebd" .into(), "cg" .into(), "bdaec" .into(), "gdafb" .into(), "agbcfd" .into(), "gdcbef" .into(), "bgcad" .into(), "gfac" .into(), "gcb" .into(), "cdgabef".into()], ["cg" .into(), "cg" .into(), "fdcagb" .into(), "cbg".into()]), "be".into(),
Entry(["fbegcd" .into(), "cbd" .into(), "adcefb" .into(), "dageb" .into(), "afcb" .into(), "bc" .into(), "aefdc" .into(), "ecdab" .into(), "fgdeca" .into(), "fcdbega".into()], ["efabcd" .into(), "cedba" .into(), "gadfec" .into(), "cb".into()]), "cfbegad".into(),
Entry(["aecbfdg" .into(), "fbg" .into(), "gf" .into(), "bafeg" .into(), "dbefa" .into(), "fcge" .into(), "gcbea" .into(), "fcaegb" .into(), "dgceab" .into(), "fcbdga".into()], ["gecf" .into(), "egdcabf" .into(), "bgf" .into(), "bfgea".into()]), "cbdgef".into(),
Entry(["fgeab" .into(), "ca" .into(), "afcebg" .into(), "bdacfeg" .into(), "cfaedg" .into(), "gcfdb" .into(), "baec" .into(), "bfadeg" .into(), "bafgc" .into(), "acf".into()], ["gebdcfa" .into(), "ecba" .into(), "ca" .into(), "fadegcb".into()]), "fgaecd".into(),
Entry(["dbcfg" .into(), "fgd" .into(), "bdegcaf" .into(), "fgec" .into(), "aegbdf" .into(), "ecdfab" .into(), "fbedc" .into(), "dacgb" .into(), "gdcebf" .into(), "gf".into()], ["cefg" .into(), "dcbef" .into(), "fcge" .into(), "gbcadfe".into()]), "cgeb".into(),
Entry(["bdfegc" .into(), "cbegaf" .into(), "gecbf" .into(), "dfcage" .into(), "bdacg" .into(), "ed" .into(), "bedf" .into(), "ced" .into(), "adcbefg" .into(), "gebcd".into()], ["ed" .into(), "bcgafe" .into(), "cdgba" .into(), "cbgef".into()]), "fdcge".into(),
Entry(["egadfb" .into(), "cdbfeg" .into(), "cegd" .into(), "fecab" .into(), "cgb" .into(), "gbdefca" .into(), "cg" .into(), "fgcdab" .into(), "egfdb" .into(), "bfceg".into()], ["gbdfcae" .into(), "bgc" .into(), "cg" .into(), "cgb".into()]), "agebfd".into(),
Entry(["gcafb" .into(), "gcf" .into(), "dcaebfg" .into(), "ecagb" .into(), "gf" .into(), "abcdeg" .into(), "gaef" .into(), "cafbge" .into(), "fdbac" .into(), "fegbdc".into()], ["fgae" .into(), "cfgab" .into(), "fg" .into(), "bagce".into()]), "fecdb".into(),
"fabcd".into(),
"edb".into(),
],
[
"fdgacbe".into(),
"cefdb".into(),
"cefbgd".into(),
"gcbe".into(),
],
),
Entry(
[
"edbfga".into(),
"begcd".into(),
"cbg".into(),
"gc".into(),
"gcadebf".into(),
"fbgde".into(),
"acbgfd".into(),
"abcde".into(),
"gfcbed".into(),
"gfec".into(),
],
["fcgedb".into(), "cgb".into(), "dgebacf".into(), "gc".into()],
),
Entry(
[
"fgaebd".into(),
"cg".into(),
"bdaec".into(),
"gdafb".into(),
"agbcfd".into(),
"gdcbef".into(),
"bgcad".into(),
"gfac".into(),
"gcb".into(),
"cdgabef".into(),
],
["cg".into(), "cg".into(), "fdcagb".into(), "cbg".into()],
),
Entry(
[
"fbegcd".into(),
"cbd".into(),
"adcefb".into(),
"dageb".into(),
"afcb".into(),
"bc".into(),
"aefdc".into(),
"ecdab".into(),
"fgdeca".into(),
"fcdbega".into(),
],
[
"efabcd".into(),
"cedba".into(),
"gadfec".into(),
"cb".into(),
],
),
Entry(
[
"aecbfdg".into(),
"fbg".into(),
"gf".into(),
"bafeg".into(),
"dbefa".into(),
"fcge".into(),
"gcbea".into(),
"fcaegb".into(),
"dgceab".into(),
"fcbdga".into(),
],
[
"gecf".into(),
"egdcabf".into(),
"bgf".into(),
"bfgea".into(),
],
),
Entry(
[
"fgeab".into(),
"ca".into(),
"afcebg".into(),
"bdacfeg".into(),
"cfaedg".into(),
"gcfdb".into(),
"baec".into(),
"bfadeg".into(),
"bafgc".into(),
"acf".into(),
],
[
"gebdcfa".into(),
"ecba".into(),
"ca".into(),
"fadegcb".into(),
],
),
Entry(
[
"dbcfg".into(),
"fgd".into(),
"bdegcaf".into(),
"fgec".into(),
"aegbdf".into(),
"ecdfab".into(),
"fbedc".into(),
"dacgb".into(),
"gdcebf".into(),
"gf".into(),
],
[
"cefg".into(),
"dcbef".into(),
"fcge".into(),
"gbcadfe".into(),
],
),
Entry(
[
"bdfegc".into(),
"cbegaf".into(),
"gecbf".into(),
"dfcage".into(),
"bdacg".into(),
"ed".into(),
"bedf".into(),
"ced".into(),
"adcbefg".into(),
"gebcd".into(),
],
["ed".into(), "bcgafe".into(), "cdgba".into(), "cbgef".into()],
),
Entry(
[
"egadfb".into(),
"cdbfeg".into(),
"cegd".into(),
"fecab".into(),
"cgb".into(),
"gbdefca".into(),
"cg".into(),
"fgcdab".into(),
"egfdb".into(),
"bfceg".into(),
],
["gbdfcae".into(), "bgc".into(), "cg".into(), "cgb".into()],
),
Entry(
[
"gcafb".into(),
"gcf".into(),
"dcaebfg".into(),
"ecagb".into(),
"gf".into(),
"abcdeg".into(),
"gaef".into(),
"cafbge".into(),
"fdbac".into(),
"fegbdc".into(),
],
["fgae".into(), "cfgab".into(), "fg".into(), "bagce".into()],
),
]; ];
let result = part1(&input); let result = part1(&input);
assert_eq!(result, 26); assert_eq!(result, 26);
@ -162,16 +325,181 @@ mod tests {
#[test] #[test]
fn part2_example() { fn part2_example() {
let input = vec![ let input = vec![
Entry(["be" .into(), "cfbegad" .into(), "cbdgef" .into(), "fgaecd" .into(), "cgeb" .into(), "fdcge" .into(), "agebfd" .into(), "fecdb" .into(), "fabcd" .into(), "edb".into()], ["fdgacbe" .into(), "cefdb" .into(), "cefbgd" .into(), "gcbe".into()]), Entry(
Entry(["edbfga" .into(), "begcd" .into(), "cbg" .into(), "gc" .into(), "gcadebf" .into(), "fbgde" .into(), "acbgfd" .into(), "abcde" .into(), "gfcbed" .into(), "gfec".into()], ["fcgedb" .into(), "cgb" .into(), "dgebacf" .into(), "gc".into()]), [
Entry(["fgaebd" .into(), "cg" .into(), "bdaec" .into(), "gdafb" .into(), "agbcfd" .into(), "gdcbef" .into(), "bgcad" .into(), "gfac" .into(), "gcb" .into(), "cdgabef".into()], ["cg" .into(), "cg" .into(), "fdcagb" .into(), "cbg".into()]), "be".into(),
Entry(["fbegcd" .into(), "cbd" .into(), "adcefb" .into(), "dageb" .into(), "afcb" .into(), "bc" .into(), "aefdc" .into(), "ecdab" .into(), "fgdeca" .into(), "fcdbega".into()], ["efabcd" .into(), "cedba" .into(), "gadfec" .into(), "cb".into()]), "cfbegad".into(),
Entry(["aecbfdg" .into(), "fbg" .into(), "gf" .into(), "bafeg" .into(), "dbefa" .into(), "fcge" .into(), "gcbea" .into(), "fcaegb" .into(), "dgceab" .into(), "fcbdga".into()], ["gecf" .into(), "egdcabf" .into(), "bgf" .into(), "bfgea".into()]), "cbdgef".into(),
Entry(["fgeab" .into(), "ca" .into(), "afcebg" .into(), "bdacfeg" .into(), "cfaedg" .into(), "gcfdb" .into(), "baec" .into(), "bfadeg" .into(), "bafgc" .into(), "acf".into()], ["gebdcfa" .into(), "ecba" .into(), "ca" .into(), "fadegcb".into()]), "fgaecd".into(),
Entry(["dbcfg" .into(), "fgd" .into(), "bdegcaf" .into(), "fgec" .into(), "aegbdf" .into(), "ecdfab" .into(), "fbedc" .into(), "dacgb" .into(), "gdcebf" .into(), "gf".into()], ["cefg" .into(), "dcbef" .into(), "fcge" .into(), "gbcadfe".into()]), "cgeb".into(),
Entry(["bdfegc" .into(), "cbegaf" .into(), "gecbf" .into(), "dfcage" .into(), "bdacg" .into(), "ed" .into(), "bedf" .into(), "ced" .into(), "adcbefg" .into(), "gebcd".into()], ["ed" .into(), "bcgafe" .into(), "cdgba" .into(), "cbgef".into()]), "fdcge".into(),
Entry(["egadfb" .into(), "cdbfeg" .into(), "cegd" .into(), "fecab" .into(), "cgb" .into(), "gbdefca" .into(), "cg" .into(), "fgcdab" .into(), "egfdb" .into(), "bfceg".into()], ["gbdfcae" .into(), "bgc" .into(), "cg" .into(), "cgb".into()]), "agebfd".into(),
Entry(["gcafb" .into(), "gcf" .into(), "dcaebfg" .into(), "ecagb" .into(), "gf" .into(), "abcdeg" .into(), "gaef" .into(), "cafbge" .into(), "fdbac" .into(), "fegbdc".into()], ["fgae" .into(), "cfgab" .into(), "fg" .into(), "bagce".into()]), "fecdb".into(),
"fabcd".into(),
"edb".into(),
],
[
"fdgacbe".into(),
"cefdb".into(),
"cefbgd".into(),
"gcbe".into(),
],
),
Entry(
[
"edbfga".into(),
"begcd".into(),
"cbg".into(),
"gc".into(),
"gcadebf".into(),
"fbgde".into(),
"acbgfd".into(),
"abcde".into(),
"gfcbed".into(),
"gfec".into(),
],
["fcgedb".into(), "cgb".into(), "dgebacf".into(), "gc".into()],
),
Entry(
[
"fgaebd".into(),
"cg".into(),
"bdaec".into(),
"gdafb".into(),
"agbcfd".into(),
"gdcbef".into(),
"bgcad".into(),
"gfac".into(),
"gcb".into(),
"cdgabef".into(),
],
["cg".into(), "cg".into(), "fdcagb".into(), "cbg".into()],
),
Entry(
[
"fbegcd".into(),
"cbd".into(),
"adcefb".into(),
"dageb".into(),
"afcb".into(),
"bc".into(),
"aefdc".into(),
"ecdab".into(),
"fgdeca".into(),
"fcdbega".into(),
],
[
"efabcd".into(),
"cedba".into(),
"gadfec".into(),
"cb".into(),
],
),
Entry(
[
"aecbfdg".into(),
"fbg".into(),
"gf".into(),
"bafeg".into(),
"dbefa".into(),
"fcge".into(),
"gcbea".into(),
"fcaegb".into(),
"dgceab".into(),
"fcbdga".into(),
],
[
"gecf".into(),
"egdcabf".into(),
"bgf".into(),
"bfgea".into(),
],
),
Entry(
[
"fgeab".into(),
"ca".into(),
"afcebg".into(),
"bdacfeg".into(),
"cfaedg".into(),
"gcfdb".into(),
"baec".into(),
"bfadeg".into(),
"bafgc".into(),
"acf".into(),
],
[
"gebdcfa".into(),
"ecba".into(),
"ca".into(),
"fadegcb".into(),
],
),
Entry(
[
"dbcfg".into(),
"fgd".into(),
"bdegcaf".into(),
"fgec".into(),
"aegbdf".into(),
"ecdfab".into(),
"fbedc".into(),
"dacgb".into(),
"gdcebf".into(),
"gf".into(),
],
[
"cefg".into(),
"dcbef".into(),
"fcge".into(),
"gbcadfe".into(),
],
),
Entry(
[
"bdfegc".into(),
"cbegaf".into(),
"gecbf".into(),
"dfcage".into(),
"bdacg".into(),
"ed".into(),
"bedf".into(),
"ced".into(),
"adcbefg".into(),
"gebcd".into(),
],
["ed".into(), "bcgafe".into(), "cdgba".into(), "cbgef".into()],
),
Entry(
[
"egadfb".into(),
"cdbfeg".into(),
"cegd".into(),
"fecab".into(),
"cgb".into(),
"gbdefca".into(),
"cg".into(),
"fgcdab".into(),
"egfdb".into(),
"bfceg".into(),
],
["gbdfcae".into(), "bgc".into(), "cg".into(), "cgb".into()],
),
Entry(
[
"gcafb".into(),
"gcf".into(),
"dcaebfg".into(),
"ecagb".into(),
"gf".into(),
"abcdeg".into(),
"gaef".into(),
"cafbge".into(),
"fdbac".into(),
"fegbdc".into(),
],
["fgae".into(), "cfgab".into(), "fg".into(), "bagce".into()],
),
]; ];
let result = part2(&input); let result = part2(&input);
assert_eq!(result, 61229); assert_eq!(result, 61229);

View File

@ -1,8 +1,8 @@
use std::collections::HashSet; use std::collections::HashSet;
pub fn parse_input(input: &str) -> Vec<Vec<u32>> { pub fn parse_input(input: &str) -> Vec<Vec<u32>> {
input.lines() input
.lines()
.map(|s| s.chars().map(|c| c.to_digit(10).unwrap()).collect()) .map(|s| s.chars().map(|c| c.to_digit(10).unwrap()).collect())
.collect() .collect()
} }
@ -16,7 +16,8 @@ fn find_low_points(grid: &Vec<Vec<u32>>) -> Vec<(usize, usize)> {
if (i == 0 || grid[i - 1][j] > grid[i][j]) if (i == 0 || grid[i - 1][j] > grid[i][j])
&& (i == height - 1 || grid[i + 1][j] > grid[i][j]) && (i == height - 1 || grid[i + 1][j] > grid[i][j])
&& (j == 0 || grid[i][j - 1] > grid[i][j]) && (j == 0 || grid[i][j - 1] > grid[i][j])
&& (j == width-1 || grid[i][j+1] > grid[i][j]) { && (j == width - 1 || grid[i][j + 1] > grid[i][j])
{
low_points.push((i, j)); low_points.push((i, j));
} }
} }
@ -44,10 +45,18 @@ fn find_basin_size(grid: &Vec<Vec<u32>>, location: (usize, usize)) -> u32 {
explored_spots.insert(leaf_node); explored_spots.insert(leaf_node);
let (i, j) = leaf_node; let (i, j) = leaf_node;
if i > 0 && !explored_spots.contains(&(i-1, j)) && grid[i-1][j] != 9 { leaf_nodes.push((i-1, j)); } if i > 0 && !explored_spots.contains(&(i - 1, j)) && grid[i - 1][j] != 9 {
if i < height-1 && !explored_spots.contains(&(i+1, j)) && grid[i+1][j] != 9 { leaf_nodes.push((i+1, j)); } leaf_nodes.push((i - 1, j));
if j > 0 && !explored_spots.contains(&(i, j-1)) && grid[i][j-1] != 9 { leaf_nodes.push((i, j-1)); } }
if j < width-1 && !explored_spots.contains(&(i, j+1)) && grid[i][j+1] != 9 { leaf_nodes.push((i, j+1)); } if i < height - 1 && !explored_spots.contains(&(i + 1, j)) && grid[i + 1][j] != 9 {
leaf_nodes.push((i + 1, j));
}
if j > 0 && !explored_spots.contains(&(i, j - 1)) && grid[i][j - 1] != 9 {
leaf_nodes.push((i, j - 1));
}
if j < width - 1 && !explored_spots.contains(&(i, j + 1)) && grid[i][j + 1] != 9 {
leaf_nodes.push((i, j + 1));
}
} }
return explored_spots.len() as u32; return explored_spots.len() as u32;
@ -67,7 +76,6 @@ pub fn part2(grid: Vec<Vec<u32>>) -> u32 {
return basin_sizes[0] * basin_sizes[1] * basin_sizes[2]; return basin_sizes[0] * basin_sizes[1] * basin_sizes[2];
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@ -79,7 +87,7 @@ mod tests {
vec![3, 9, 8, 7, 8, 9, 4, 9, 2, 1], vec![3, 9, 8, 7, 8, 9, 4, 9, 2, 1],
vec![9, 8, 5, 6, 7, 8, 9, 8, 9, 2], vec![9, 8, 5, 6, 7, 8, 9, 8, 9, 2],
vec![8, 7, 6, 7, 8, 9, 6, 7, 8, 9], vec![8, 7, 6, 7, 8, 9, 6, 7, 8, 9],
vec![9, 8, 9, 9, 9, 6, 5, 6, 7, 8] vec![9, 8, 9, 9, 9, 6, 5, 6, 7, 8],
]; ];
let result = part1(input); let result = part1(input);
assert_eq!(result, 15); assert_eq!(result, 15);
@ -92,7 +100,7 @@ mod tests {
vec![3, 9, 8, 7, 8, 9, 4, 9, 2, 1], vec![3, 9, 8, 7, 8, 9, 4, 9, 2, 1],
vec![9, 8, 5, 6, 7, 8, 9, 8, 9, 2], vec![9, 8, 5, 6, 7, 8, 9, 8, 9, 2],
vec![8, 7, 6, 7, 8, 9, 6, 7, 8, 9], vec![8, 7, 6, 7, 8, 9, 6, 7, 8, 9],
vec![9, 8, 9, 9, 9, 6, 5, 6, 7, 8] vec![9, 8, 9, 9, 9, 6, 5, 6, 7, 8],
]; ];
let result = part2(input); let result = part2(input);
assert_eq!(result, 1134); assert_eq!(result, 1134);

View File

@ -20,6 +20,7 @@ mod day19;
mod day20; mod day20;
mod day21; mod day21;
mod day22; mod day22;
mod day23;
use std::{env, process}; use std::{env, process};
use std::fs::File; use std::fs::File;
@ -80,6 +81,8 @@ fn run(day: i32, part: i32, input_filename: &str) {
"21.2" => println!("{}", day21::part2(&day21::parse_input(&contents))), "21.2" => println!("{}", day21::part2(&day21::parse_input(&contents))),
"22.1" => println!("{}", day22::part1(&day22::parse_input(&contents))), "22.1" => println!("{}", day22::part1(&day22::parse_input(&contents))),
"22.2" => println!("{}", day22::part2(day22::parse_input(&contents))), "22.2" => println!("{}", day22::part2(day22::parse_input(&contents))),
"23.1" => println!("{}", day23::part1(&day23::parse_input(&contents))),
"23.2" => println!("{}", day23::part2(&day23::parse_input(&contents))),
_ => println!("Day {} part {} not found", day, part) _ => println!("Day {} part {} not found", day, part)
} }
} }