diff --git a/03/.gitignore b/03/.gitignore new file mode 100644 index 0000000..b617c56 --- /dev/null +++ b/03/.gitignore @@ -0,0 +1 @@ +day03 diff --git a/03/README.md b/03/README.md new file mode 100644 index 0000000..94e368c --- /dev/null +++ b/03/README.md @@ -0,0 +1,9 @@ +# [Day 3](https://adventofcode.com/2023/day/3) +:gift::gift::gift: + +Today's language: **Rust** + +```shell +rustc day03.rs +./day03 +``` diff --git a/03/day03.rs b/03/day03.rs new file mode 100644 index 0000000..9712dc3 --- /dev/null +++ b/03/day03.rs @@ -0,0 +1,102 @@ +use std::io::BufRead; +use std::collections::HashMap; + +#[derive(Hash, Eq, PartialEq)] +struct Symbol(char, usize, usize); + + +fn main() { + let schematic = read_lines("input.txt"); + let mut part_sum = 0; + let mut gear_ratio_sum: u32 = 0; + let mut first_gears = HashMap::new(); // Symbol: first_gear + for (n_line, line) in schematic.iter().enumerate() { + // println!("{} {}", n_line, line); + let mut num_begin: usize = usize::MAX; + let mut num_end: usize = usize::MAX; + for (n_char, c) in line.char_indices() { + if num_begin == usize::MAX { + if is_digit(c) { num_begin = n_char; } + } + else { // in number + if !is_digit(c) { + num_end = n_char - 1; + } + else if n_char == line.chars().count() - 1 { // last char + num_end = n_char; + } + if num_end != usize::MAX { + let symbol = find_symbol(&schematic, n_line, num_begin, n_char-1); + if symbol != NO_SYMBOL { + let num = line[num_begin..=num_end].parse::().expect("Could not parse number"); + part_sum += num; + if symbol.0 == '*' { + if first_gears.contains_key(&symbol) { + gear_ratio_sum += first_gears[&symbol] * num; + } + else { first_gears.insert(symbol, num); } + } + } + num_begin = usize::MAX; + num_end = usize::MAX; + } + } + } + } + println!("Total sum of part numbers: {}", part_sum); + println!("Total sum of gear ratios: {}", gear_ratio_sum); + +} + + +fn is_digit(c: char) -> bool { + return '0' <= c && c <= '9' +} +fn is_symbol(c: char) -> bool { + return c != '.' && (!is_digit(c)); +} + +const NO_SYMBOL:Symbol = Symbol('\0', usize::MAX, usize::MAX); +// return symbol and its position +fn find_symbol(schematic: &Vec, num_line: usize, num_begin: usize, num_end: usize) -> Symbol { + // search char left and right + if num_begin > 0 { + let c = schematic[num_line].chars().nth(num_begin-1).unwrap(); + if is_symbol(c) { return Symbol(c, num_line, num_begin - 1); } + } + if num_end + 1 < schematic[num_line].chars().count() { + let c = schematic[num_line].chars().nth(num_end+1).unwrap(); + if is_symbol(c) { return Symbol(c, num_line, num_end + 1); } + } + + let skip: usize = num_begin.saturating_sub(1); + let take: usize; + if num_begin == 0 { + take = num_end.saturating_sub(num_begin) + 2; + } else { + take = num_end.saturating_sub(num_begin) + 3; + } + + // search top line + if num_line > 0 { + for (i, c) in schematic[num_line-1].char_indices().skip(skip).take(take) { + if is_symbol(c) { return Symbol(c, num_line-1, i); } + } + } + // search bottom line + if num_line + 1 < schematic.len() { + for (i, c) in schematic[num_line+1].char_indices().skip(skip).take(take) { + if is_symbol(c) { return Symbol(c, num_line+1, i); } + } + } + return NO_SYMBOL; +} + + +fn read_lines

(filename: P) -> Vec +where P: AsRef, { + return match std::fs::File::open(filename) { + Err(why) => panic!("Could not open file. {}", why), + Ok(file) => std::io::BufReader::new(file).lines().map(|l| {l.expect("Could not parse line")}).collect(), + }; +}