aoc-2021-rust

git clone https://git.sinitax.com/sinitax/aoc-2021-rust
Log | Files | Refs | README | sfeed.txt

commit e27d180ed44afae12fb299507ea0ad0d4d098ad1
parent 8a3e03c5892f6dc3a9562f76a1cdf54404e65e17
Author: Louis Burda <quent.burda@gmail.com>
Date:   Sun,  9 Apr 2023 22:20:08 -0400

Fix existing days and amend day 12 solution

Diffstat:
Msrc/.gitignore | 3+++
Msrc/01/Cargo.toml | 2+-
Msrc/02/Cargo.toml | 2+-
Msrc/03/Cargo.toml | 2+-
Msrc/04/Cargo.toml | 2+-
Msrc/05/Cargo.toml | 2+-
Msrc/06/Cargo.toml | 2+-
Msrc/07/Cargo.toml | 2+-
Msrc/08/Cargo.toml | 2+-
Msrc/08/src/main.rs | 16++++++++--------
Msrc/09/Cargo.toml | 2+-
Msrc/09/src/main.rs | 10++++------
Msrc/10/Cargo.toml | 2+-
Msrc/11/Cargo.toml | 2+-
Msrc/11/src/main.rs | 12+-----------
Msrc/12/Cargo.toml | 2+-
Msrc/12/src/main.rs | 139++++++++++++++++++++++++++++++++++++-------------------------------------------
Asrc/12/test1 | 7+++++++
Asrc/Makefile | 37+++++++++++++++++++++++++++++++++++++
Asrc/common/Cargo.toml | 0
Msrc/common/aoc/src/lib.rs | 73++++++++++++++++++++++++++++++-------------------------------------------
21 files changed, 166 insertions(+), 155 deletions(-)

diff --git a/src/.gitignore b/src/.gitignore @@ -1,2 +1,5 @@ target Cargo.lock +template +compile_commands.json +main diff --git a/src/01/Cargo.toml b/src/01/Cargo.toml @@ -4,4 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies] -aoc = { path = "../../lib/aoc" } +aoc = { path = "../common/aoc" } diff --git a/src/02/Cargo.toml b/src/02/Cargo.toml @@ -4,4 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies] -aoc = { path = "../../lib/aoc" } +aoc = { path = "../common/aoc" } diff --git a/src/03/Cargo.toml b/src/03/Cargo.toml @@ -4,4 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies] -aoc = { path = "../../lib/aoc" } +aoc = { path = "../common/aoc" } diff --git a/src/04/Cargo.toml b/src/04/Cargo.toml @@ -4,4 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies] -aoc = { path = "../../lib/aoc" } +aoc = { path = "../common/aoc" } diff --git a/src/05/Cargo.toml b/src/05/Cargo.toml @@ -4,4 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies] -aoc = { path = "../../lib/aoc" } +aoc = { path = "../common/aoc" } diff --git a/src/06/Cargo.toml b/src/06/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] -aoc = { path = "../../lib/aoc" } +aoc = { path = "../common/aoc" } num-bigint = "0.4.3" num-traits = "*" diff --git a/src/07/Cargo.toml b/src/07/Cargo.toml @@ -4,5 +4,5 @@ version = "0.1.0" edition = "2021" [dependencies] -aoc = { path = "../../lib/aoc" } +aoc = { path = "../common/aoc" } diff --git a/src/08/Cargo.toml b/src/08/Cargo.toml @@ -4,5 +4,5 @@ version = "0.1.0" edition = "2021" [dependencies] -aoc = { path = "../../lib/aoc" } +aoc = { path = "../common/aoc" } diff --git a/src/08/src/main.rs b/src/08/src/main.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use aoc::debugln; fn code2bin(code: &str) -> u32 { let alph = "abcdefg"; @@ -26,8 +27,7 @@ fn bits_set(bin: u32) -> u32 { return cnt; } -fn decode_value(aoc: &mut aoc::Info, - codes: &Vec<&str>, out_codes: &Vec<&str>) -> u32 { +fn decode_value(codes: &Vec<&str>, out_codes: &Vec<&str>) -> u32 { let len2code: HashMap<u32,u32> = HashMap::from([ (2, 1), (3, 7), @@ -76,26 +76,26 @@ fn decode_value(aoc: &mut aoc::Info, for digit in 0..10 { fit = true; for cmp in 0..10 { - aoc::debug!(aoc, "-- {} {} --\n", digit, cmp); + debugln!("-- {} {} --", digit, cmp); let cmplen = overlaps[digit][cmp]; if digit == cmp && bits_set(code) != cmplen { - aoc::debug!(aoc, "wrong length\n"); + debugln!("wrong length"); fit = false; break; } if mapping[cmp] == 0 { continue; } if bits_set(code & mapping[cmp]) != cmplen { - aoc::debug!(aoc, "wrong # of same bits: {:08b} & {:08b} != {}\n", + debugln!("wrong # of same bits: {:08b} & {:08b} != {}", code, mapping[cmp], cmplen); fit = false; break; } - aoc::debug!(aoc, "{}: {:08b} {:08b}\n", cmplen, code, mapping[cmp]); + debugln!("{}: {:08b} {:08b}", cmplen, code, mapping[cmp]); } if fit == true { - aoc::debug!(aoc, "add {:08b} => {}\n", code, digit); + debugln!("add {:08b} => {}", code, digit); mapping[digit] = code; break; } @@ -145,7 +145,7 @@ fn part2(aoc: &mut aoc::Info) { .split(" ").collect(); let out_codes: Vec<&str> = line.split_once(" | ").unwrap().1 .split(" ").collect(); - sum += decode_value(aoc, &sig_codes, &out_codes); + sum += decode_value(&sig_codes, &out_codes); } aoc.answer = Some(format!("{}", sum)); diff --git a/src/09/Cargo.toml b/src/09/Cargo.toml @@ -4,5 +4,5 @@ version = "0.1.0" edition = "2021" [dependencies] -aoc = { path = "../../lib/aoc" } +aoc = { path = "../common/aoc" } diff --git a/src/09/src/main.rs b/src/09/src/main.rs @@ -1,3 +1,5 @@ +use aoc::debugln; + #[derive(PartialEq,Eq)] struct Pos { x: i32, @@ -78,9 +80,7 @@ fn part2(aoc: &mut aoc::Info) { let mut basin_sizes: Vec<usize> = Vec::new(); for start in lowest { - if aoc.debug { - println!("START {} {}", start.x, start.y); - } + debugln!("START {} {}", start.x, start.y); let mut visited: Vec<Pos> = Vec::new(); let mut outer: Vec<Pos> = Vec::new(); @@ -108,9 +108,7 @@ fn part2(aoc: &mut aoc::Info) { outer = new_outer; } - if aoc.debug { - println!("VISITED COUNT: {}", visited.len()); - } + debugln!("VISITED COUNT: {}", visited.len()); basin_sizes.push(visited.len()); } diff --git a/src/10/Cargo.toml b/src/10/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] -aoc = { path = "../../lib/aoc" } +aoc = { path = "../common/aoc" } lazy_static = "*" bimap = "*" diff --git a/src/11/Cargo.toml b/src/11/Cargo.toml @@ -4,5 +4,5 @@ version = "0.1.0" edition = "2021" [dependencies] -aoc = { path = "../../lib/aoc" } +aoc = { path = "../common/aoc" } diff --git a/src/11/src/main.rs b/src/11/src/main.rs @@ -15,16 +15,6 @@ const SURROUNDING: [Pos; 8] = [ Pos { x: 1, y: 1 } ]; -fn print_octos(octos: &Vec<Vec<u32>>) { - for row in octos { - for octo in row { - print!("{}", octo); - } - println!(); - } - println!(); -} - fn inc_check(flashed: &mut Vec<Pos>, octos: &mut Vec<Vec<u32>>, x: usize, y: usize) { let pos = Pos { x: x as i32, y: y as i32 }; if flashed.contains(&pos) { return; } @@ -72,7 +62,7 @@ fn part1(aoc: &mut aoc::Info) { flashes += sim_step(&mut octos); } - println!("{}", flashes); + aoc.answer = Some(format!("{}", flashes)); aoc.solution = Some("1681"); } diff --git a/src/12/Cargo.toml b/src/12/Cargo.toml @@ -4,4 +4,4 @@ version = "0.1.0" edition = "2021" [dependencies] -aoc = { path = "../../lib/aoc" } +aoc = { path = "../common/aoc" } diff --git a/src/12/src/main.rs b/src/12/src/main.rs @@ -1,7 +1,5 @@ use std::collections::HashMap; - -/* assume no two big caves are next to each other - * => otherwise infinite paths possible */ +use aoc::{debug, debugln}; #[derive(PartialEq,Clone)] struct Node { @@ -43,70 +41,48 @@ fn parse_input(input: &String) -> HashMap<String, Node> { fn part1(aoc: &mut aoc::Info) { let nodes = parse_input(&aoc.input); - let mut path: Vec<&Node> = Vec::new(); - let mut adj_index = 0; + let mut path: Vec<NodeState> = Vec::new(); - path.push(nodes.get("start").unwrap()); + let start_node = nodes.get("start").unwrap(); + let start_state = NodeState { + node: &start_node, + index: 0 + }; + path.push(start_state); - let mut paths: usize = 0; - while path.len() > 0 { - let current = path.last().unwrap().clone(); - if adj_index >= current.adj.len() { - /* backtrack */ - path.pop(); - if path.len() == 0 { break; } - let next = path.last().unwrap(); - adj_index = next.adj.iter().position(|x| *x == current.name).unwrap() + 1; - } else { - let adj = nodes.get(&current.adj[adj_index]).unwrap(); - if adj.name == "end" { - // for p in &path { - // print!("{} -> ", p.name); - // } - // println!("end"); - paths += 1; - adj_index += 1; - } else if !path.contains(&adj) || !adj.small { - path.push(adj); - adj_index = 0; - } else { - adj_index += 1; - } - } - } + /* depth first search of nodes with no recursing + * since two big caves can not be next to each other */ - println!("{}", paths); -} + let mut pathcnt: usize = 0; + while path.len() > 0 { + let mut tail = path.last().unwrap().clone(); -fn self_paths<'a>(nodes: &'a HashMap<String,Node>, - path: &'a Vec<NodeState<'a>>, cur: &'a Node) -> usize { - let prevlen = path.len(); - - let mut path: Vec<NodeState<'a>> = path.to_vec(); - path.push(NodeState { node: cur, index: 0 }); - - let mut paths: usize = 0; - while path.len() > prevlen { - let current = path.last_mut().unwrap(); - if current.index < current.node.adj.len() { - let adj: &Node = nodes.get(&current.node.adj[current.index]) - .unwrap(); - current.index += 1; - if adj == cur { - paths += 1; - } else if adj.name != "start" && adj.name != "end" { - let count = path.iter().filter(|x| x.node == adj).count(); - if count <= 1 || !adj.small { - path.push(NodeState { node: adj, index: 0 }); + let mut next: Option<&Node> = None; + if tail.index < tail.node.adj.len() { + let adj = nodes.get(&tail.node.adj[tail.index]).unwrap(); + if adj.name == "end" { + for p in &path { + debug!("{} -> ", p.node.name); } + debugln!("end"); + pathcnt += 1; + } else if !adj.small || path.iter().find(|x| x.node == adj).is_none() { + next = Some(&adj); } + tail.index += 1; + path.last_mut().unwrap().clone_from(&tail); } else { - /* backtrack */ path.pop(); } + + if next.is_some() { + let state = NodeState { node: next.unwrap(), index: 0 }; + path.push(state); + } } - return paths; + aoc.answer = Some(format!("{}", pathcnt)); + aoc.solution = Some("5457"); } fn part2(aoc: &mut aoc::Info) { @@ -114,37 +90,50 @@ fn part2(aoc: &mut aoc::Info) { let mut path: Vec<NodeState> = Vec::new(); - path.push(NodeState { node: nodes.get("start").unwrap(), index: 0 }); + let start_node = nodes.get("start").unwrap(); + let start_state = NodeState { node: start_node, index: 0 }; + path.push(start_state); - let mut paths: usize = 0; + let mut double: Option<&Node> = None; + let mut pathcnt: usize = 0; while path.len() > 0 { - let current = path.last_mut().unwrap(); - if current.index < current.node.adj.len() { - let adj: &Node = nodes.get(&current.node.adj[current.index]) - .unwrap(); - current.index += 1; + let mut tail = path.last().unwrap().clone(); + + let mut next: Option<&Node> = None; + if tail.index < tail.node.adj.len() { + let adj = nodes.get(&tail.node.adj[tail.index]).unwrap(); if adj.name == "end" { - let mut prod: usize = 1; - for (i, p) in path.iter().enumerate() { - aoc::debug!(aoc, "{} -> ", p.node.name); - if i == 0 { continue; } - prod += 1 + self_paths(&nodes, &path, p.node); + debug!("{} : ", double.is_some()); + for p in &path { + debug!("{} -> ", p.node.name); } - paths += prod; - aoc::debug!(aoc, "end\n"); + debugln!("end"); + pathcnt += 1; } else if adj.name != "start" { - let count = path.iter().filter(|x| x.node == adj).count(); - if count < 1 || !adj.small { - path.push(NodeState { node: adj, index: 0 } ); + let inpath = path.iter().find(|x| x.node == adj).is_some(); + if !adj.small || !inpath || (inpath && double.is_none()) { + if adj.small && inpath { + double = Some(&adj); + } + next = Some(&adj); } } + tail.index += 1; + path.last_mut().unwrap().clone_from(&tail); } else { - /* backtrack */ + if double.is_some() && tail.node == double.unwrap() { + double = None; + } path.pop(); } + + if next.is_some() { + let state = NodeState { node: next.unwrap(), index: 0 }; + path.push(state); + } } - println!("{}", paths); + aoc.answer = Some(format!("{}", pathcnt)); } fn main() { diff --git a/src/12/test1 b/src/12/test1 @@ -0,0 +1,7 @@ +start-A +start-b +A-c +A-b +b-d +A-end +b-end diff --git a/src/Makefile b/src/Makefile @@ -0,0 +1,37 @@ +DAYS = $(shell seq 1 25 | xargs printf "%02i\n") + +all:: build run + +define make-day + +run:: $1/run + +build:: $1/main + +clean:: $1/clean + +.PHONY: $1/run $1/clean + +$1/main: $1/src/main.rs + cd $1 && cargo build && cp ./target/debug/day$1 main + +$1/run1: $1/main + @cd $1 && time ./main 1 + +$1/run2: $1/main + @cd $1 && time ./main 2 + +$1/run: + @echo "== day $1 ==" + @echo -en "\npart 1: " && cd $1 && time ./main 1 + @echo -en "\npart 2: " && cd $1 && time ./main 2 + @echo "" + +$1/clean: + rm $1/main + +endef + +$(foreach day,$(DAYS),$(eval $(call make-day,$(day)))) + +.PHONY: all build run clean diff --git a/src/common/Cargo.toml b/src/common/Cargo.toml diff --git a/src/common/aoc/src/lib.rs b/src/common/aoc/src/lib.rs @@ -1,19 +1,9 @@ use std::env; use std::fs; use std::process::exit; - -#[derive(PartialEq, PartialOrd)] -pub enum Loglvl { - LogNone = 0, - LogVerb, - LogDebug, - LogAll -} +use std::sync::atomic::{AtomicU8, Ordering}; pub struct Info { - pub verbose: bool, - pub debug: bool, - pub filename: String, pub input: String, pub part: u32, @@ -22,45 +12,44 @@ pub struct Info { pub answer: Option<String>, } -#[macro_export] -macro_rules! die { - ($( $arg:expr ),*) => { - eprintln!($( $arg ), *); - exit(1); - } +static DEBUG: AtomicU8 = AtomicU8::new(0); + +pub fn get_debug() -> u8 { + DEBUG.load(Ordering::Relaxed) +} + +pub fn set_debug(lvl: u8) { + DEBUG.store(lvl, Ordering::Relaxed); } #[macro_export] macro_rules! debug { - ($aoc:expr, $( $arg:expr ),*) => { - if $aoc.debug { + ($( $arg:expr ),*) => { + if aoc::get_debug() > 0 { eprint!($( $arg ), *); } } } #[macro_export] -macro_rules! verbose { - ($aoc:expr, $( $arg:expr ),*) => { - if $aoc.verbose { - eprint!($( $arg ), *); +macro_rules! debugln { + ($( $arg:expr ),*) => { + if aoc::get_debug() > 0 { + eprintln!($( $arg ), *); } } } -pub fn to_loglvl(val: u32) -> Loglvl { - match val { - 0 => return Loglvl::LogNone, - 1 => return Loglvl::LogVerb, - 2 => return Loglvl::LogAll, - _ => panic!("Invalid log level {}", val) +#[macro_export] +macro_rules! err { + ($( $arg:expr ),*) => { + eprintln!($( $arg ), *); + exit(1); } } pub fn run(part1: fn(info: &mut Info), part2: fn(info: &mut Info)) { let mut info = Info { - verbose: false, - debug: false, filename: "input".to_string(), input: "".to_string(), part: 0, @@ -68,35 +57,33 @@ pub fn run(part1: fn(info: &mut Info), part2: fn(info: &mut Info)) { answer: None, }; - let input_file = env::var("AOCINPUT"); + let input_file = env::var("AOC_INPUT"); if input_file.is_ok() { info.filename = input_file.unwrap(); } let content = fs::read_to_string(info.filename.clone()); if content.is_err() { - die!("Failed to read from file: {}", info.filename); + err!("Failed to read from file: {}", info.filename); } info.input = content.unwrap(); - let debug = env::var("AOCDEBUG"); - if debug.is_ok() { - let num = debug.unwrap().parse::<u32>().unwrap(); - let lvl = to_loglvl(num); - info.verbose = lvl >= Loglvl::LogVerb; - info.debug = lvl >= Loglvl::LogDebug; + let envvar = env::var("AOC_DEBUG"); + if envvar.is_ok() { + let lvl = envvar.unwrap().parse::<u32>().unwrap(); + set_debug(lvl as u8); } let args: Vec<String> = env::args().collect(); if args.len() > 1 { let num = args[1].parse(); if num.is_err() { - die!("Invalid part number: {}", args[1]); + err!("Invalid part number: {}", args[1]); } info.part = num.unwrap(); } else { - die!("Usage: aoc run PART"); + err!("Usage: aoc run PART"); } if info.part == 1 { @@ -104,7 +91,7 @@ pub fn run(part1: fn(info: &mut Info), part2: fn(info: &mut Info)) { } else if info.part == 2 { part2(&mut info); } else { - die!("No such part: {}", info.part); + err!("No such part: {}", info.part); } if info.answer.is_some() { @@ -113,7 +100,7 @@ pub fn run(part1: fn(info: &mut Info), part2: fn(info: &mut Info)) { if info.solution.is_some() { let solution = info.solution.unwrap(); if answer != solution { - die!("Incorrect solution!"); + err!("Incorrect solution!"); } } }