Created
December 5, 2023 19:59
-
-
Save oisin/153bcfdfc408997cc69b744846731547 to your computer and use it in GitHub Desktop.
AOC 23 Day3 Part 2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![allow(dead_code, unused_variables, unused_mut)] | |
use std::env; | |
use std::fs::File; | |
use std::io::{self, BufRead}; | |
// PartNumber contains the i32 parsed value of the string slice that | |
// represents this part number, and records the start and end positions | |
// of the slice in the row. | |
#[derive(Clone, Copy)] | |
struct PartNumber { | |
value: i32, | |
start_pos: i32, | |
end_pos: i32 | |
} | |
// Row can contain a collection of part numbers and/or symbols. | |
// A row is a single line read from the file and parsed | |
struct Row { | |
part_numbers: Vec<PartNumber>, | |
symbols: Vec<i32> | |
} | |
use std::fmt; | |
impl fmt::Display for PartNumber { | |
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |
write!(f, "{} @ {}..{}", self.value, self.start_pos, self.end_pos) | |
} | |
} | |
fn main() { | |
let args: Vec<String> = env::args().collect(); | |
if args.len() != 2 { | |
eprintln!("Usage: {} <filename>", args[0]); | |
std::process::exit(1); | |
} | |
let filename = &args[1]; | |
let file = match File::open(filename) { | |
Ok(file) => file, | |
Err(error) => { | |
eprintln!("Error opening file {}: {}", filename, error); | |
std::process::exit(1); | |
} | |
}; | |
let reader = io::BufReader::new(file); | |
let mut field: Vec<Row> = Vec::new(); | |
for (line_number, line) in reader.lines().enumerate() { | |
match line { | |
Ok(line_content) => { | |
field.push(parse(line_number + 1, line_content)); | |
} | |
Err(error) => { | |
eprintln!("Error reading line {}: {}", line_number + 1, error); | |
} | |
} | |
} | |
// Process the field to get valid part numbers | |
// | |
// BUG a number can be counted as valid more than once | |
// eg | |
// | |
// ...33*44... | |
// ........*.. | |
// | |
// Valid part number found on row 0, 33 | |
// Valid part number found on row 0, 44 | |
// Valid part number found on row 0, 44 | |
// Total = 121 | |
// | |
let mut accum: i32 = 0; | |
for (row_index, row) in field.iter().enumerate() { | |
// For each row in the field... | |
for sym_pos in row.symbols.iter() { | |
let mut nums: Vec<i32> = Vec::new(); | |
// Iterate through all of the part numbers on the current row and | |
// if they align with this symbol. | |
for pn in row.part_numbers.iter() { | |
//println!("Symbol @ {} proximity check to part number {}", sym_pos, pn); | |
if *sym_pos == pn.end_pos + 1 { | |
// This symbol immediately follows a number. | |
// println!("{}: '{}' @ {}", row_index+1, pn.value, *sym_pos); | |
nums.push(pn.value); | |
} | |
if pn.start_pos > 0 && *sym_pos == pn.start_pos - 1 { | |
// This symbol immediately precedes a number. | |
//println!("{}: '{}' @ {}", row_index+1, pn.value, *sym_pos); | |
nums.push(pn.value); | |
} | |
} | |
// Iterate through all of the part numbers on the PREVIOUS row, if there is one, and | |
// if they align with this symbol. | |
if row_index > 0 { | |
for pn in field[row_index - 1].part_numbers.iter() { | |
//println!("Symbol @ {} above line proximity check to part number {}", sym_pos, pn); | |
// eg if symbol is at [1][3] then digit at [0][2/3/4] | |
let neg_off: i32 = if pn.start_pos == 0 { 0 } else { -1 }; | |
if *sym_pos >= pn.start_pos + neg_off && *sym_pos <= pn.end_pos + 1 { | |
// println!("{}: '{}' @ {}", row_index, pn.value, *sym_pos); | |
nums.push(pn.value); | |
} | |
} | |
} | |
// Iterate through all of the part numbers on the NEXT row, if there is one, and | |
// if they align with this symbol. | |
if row_index < field.len()-1 { | |
for pn in field[row_index + 1].part_numbers.iter() { | |
//println!("Symbol @ {} below line proximity check to part number {}", sym_pos, pn); | |
// eg if symbol is at [1][3] then digit at [0][2/3/4] | |
let neg_off: i32 = if pn.start_pos == 0 { 0 } else { -1 }; | |
if *sym_pos >= pn.start_pos + neg_off && *sym_pos <= pn.end_pos + 1 { | |
//println!("{}: '{}' @ {}", row_index+2, pn.value, *sym_pos); | |
nums.push(pn.value); | |
} | |
} | |
} | |
if nums.len() == 2 { | |
println!("Row {} nums are {:?}", row_index + 1, nums); | |
accum += nums[0] * nums[1]; | |
} | |
} | |
//println!("row {} : syms = {}, part numbers = {}", row_index + 1, row.symbols.len(), row.part_numbers.len()); | |
} | |
println!("Total = {}", accum); | |
} | |
#[derive(PartialEq)] | |
enum ParseState { | |
Start, | |
PartNumber | |
} | |
fn parse(line_number: usize, line_content: String) -> Row { | |
let mut row = Row { | |
part_numbers: Vec::new(), | |
symbols: vec![], | |
}; | |
let mut state = ParseState::Start; | |
let mut context = PartNumber { | |
value: 0, | |
start_pos: 0, | |
end_pos: 0 | |
}; | |
for (pos, c) in line_content.chars().enumerate() { | |
match c { | |
('0'..='9') => { | |
match state { | |
ParseState::Start => { | |
context = PartNumber { | |
value: c.to_digit(10).expect("Bum not a digit") as i32, | |
start_pos: pos as i32, | |
end_pos: 0 | |
}; | |
state = ParseState::PartNumber; | |
} | |
ParseState::PartNumber => { | |
context.value = context.value * 10 + c.to_digit(10).expect("Bum not a digit") as i32 | |
} | |
} | |
}, | |
'*' => { // Gears only for part 2 | |
if state == ParseState::PartNumber { | |
context.end_pos = pos as i32 - 1; | |
row.part_numbers.push(context); | |
} | |
row.symbols.push(pos as i32); | |
state = ParseState::Start; | |
}, | |
_ => { | |
if state == ParseState::PartNumber { | |
context.end_pos = pos as i32 - 1; | |
row.part_numbers.push(context); | |
} | |
// row.symbols.push(pos as i32); ignore a non | |
state = ParseState::Start; | |
} | |
} | |
} | |
if state == ParseState::PartNumber { // We have come to the end of the line while we are parsing a number! | |
context.end_pos = (line_content.len() - 1) as i32; | |
row.part_numbers.push(context); | |
} | |
row | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment