Solution for 2022/day13-part1

This commit is contained in:
Tobias Marschner 2024-02-23 21:33:18 +01:00
parent 6110626937
commit 8c5887132b
2 changed files with 148 additions and 0 deletions

View File

@ -0,0 +1,8 @@
[package]
name = "day13-part1"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

View File

@ -0,0 +1,140 @@
use std::{cmp::Ordering, iter::zip, str::Chars};
#[derive(Debug)]
enum Packet {
Number(i32),
List(Vec<Packet>),
}
impl Packet {
// Parse a single packet line into the Packet data structure.
fn from_string(s: &mut Chars) -> Vec<Packet> {
// println!("Entering with {}", s.clone().collect::<String>());
// We're going to iterate through this character by character.
// It is assumed that the opening '[' is already stripped.
// Create an empty vector packet to fill in a loop.
let mut packet_list: Vec<Packet> = Vec::new();
// Now iterate through all the remaining characters.
loop {
// Collect a single element, i.e. all characters until the first occurence of '[', ']' or ','.
// The delimiter itself will be collected into `c`.
let mut elem = String::new();
let mut c: char;
loop {
c = s.next().unwrap();
if c == '[' || c == ']' || c == ',' {
break;
} else {
elem.push(c);
}
}
// Parse the element if it isn't empty and add it to the list.
if !elem.is_empty() {
let num = Packet::Number(elem.parse().unwrap());
packet_list.push(num);
}
// Encountering a new list?
// Call recursively and collect everything there.
if c == '[' {
let sublist = Packet::from_string(s);
packet_list.push(Packet::List(sublist));
}
// Encountered the end of the list?
// Then we're done here.
if c == ']' {
break;
}
}
packet_list
}
}
fn main() {
// Use command line arguments to specify the input filename.
let args: Vec<String> = std::env::args().collect();
if args.len() < 2 {
panic!("Usage: ./main <input-file>\nNo input file provided. Exiting.");
}
// Next, read the contents of the input file into a string for easier processing.
let input = std::fs::read_to_string(&args[1]).expect("Error opening file");
// --- TASK BEGIN ---
// Keep track of the results.
let mut results: Vec<Ordering> = Vec::new();
// Iterate through all packet-pairs and compare them.
for packets in input.split("\n\n") {
// Parse both of the packets.
let packets: Vec<_> = packets
.lines()
.map(|x| Packet::from_string(&mut x[1..].chars()))
.collect();
// Actually compare both packets and record the result.
results.push(packet_compare(&packets[0], &packets[1]));
}
// Finally, collect the sum of indices where packet_compare yielded Less.
let magic_number = results.iter().enumerate().fold(0, |acc, (idx, e)| {
if *e == Ordering::Less {
acc + idx + 1
} else {
acc
}
});
println!(
"Sum of indices of correctly ordered packets: {}",
magic_number
);
}
fn packet_compare(left: &Vec<Packet>, right: &Vec<Packet>) -> Ordering {
let mut result: Ordering;
let mut zipper = zip(left, right);
loop {
match zipper.next() {
Some(d) => {
// Determine the Ordering result for the next two "elements", whatever they may be.
result = match d {
(Packet::Number(lv), Packet::Number(rv)) => {
// Compare the integers directly.
lv.cmp(rv)
}
(Packet::Number(lv), Packet::List(rl)) => {
// Left is a number, right is a list.
// Convert the number to a list and then compare those.
let ll: Vec<Packet> = vec![Packet::Number(*lv)];
packet_compare(&ll, rl)
}
(Packet::List(ll), Packet::Number(rv)) => {
// Left is a list, right is a number.
// Convert the number to a list and then compare those.
let rl: Vec<Packet> = vec![Packet::Number(*rv)];
packet_compare(ll, &rl)
}
(Packet::List(ll), Packet::List(rl)) => {
// Recursively step into the lists.
packet_compare(ll, rl)
}
};
}
None => {
// Zipper empty?
// We need to remember which of the lists ran out first.
result = left.len().cmp(&right.len());
// And definitely break, ofc, since the zipper is done.
break;
}
}
// Have we reached a conclusion already? If so, return.
if result != Ordering::Equal {
break;
}
}
result
}