blob: 8f5bdd8e2ccc98fe3a5dbef57e1dacae0b22600f [file] [log] [blame]
use std::collections::HashMap;
fn is_symbol(character: &char) -> bool {
return !character.is_digit(10) && *character != '.';
}
#[derive(Debug, Clone)]
struct SchematicNumber {
number: u16,
surroundings: Vec<char>
}
impl SchematicNumber {
fn is_part_number(&self) -> bool {
self.surroundings.iter().any(is_symbol)
}
}
#[derive(Debug)]
struct Gear {
surroundings: Vec<SchematicNumber>
}
impl Gear {
fn sum(&self) -> u64 {
let mut part_number_count = 0;
let mut part_number_mul: u64 = 1;
for schematic_number in self.surroundings.iter() {
if schematic_number.is_part_number() {
part_number_count += 1;
part_number_mul *= Into::<u64>::into(schematic_number.number);
}
}
if part_number_count != 2 {
return 0;
}
return part_number_mul;
}
fn add_number(&mut self, number: SchematicNumber) {
self.surroundings.push(number);
}
}
fn process_gear(number: &SchematicNumber, gears: &mut HashMap<(usize, usize), Gear>, row: usize, col: usize) {
let position = gears.get_mut(&(row, col));
if let Some(gear) = position {
gear.add_number(number.clone())
} else {
gears.insert((row, col), Gear { surroundings: vec![ number.clone() ] });
}
}
fn process_number(gears: &mut HashMap<(usize, usize), Gear>, input: &str, digits: String, row: usize, start_col: usize, end_col: usize) -> SchematicNumber {
let mut surroundings: Vec<char> = vec![];
let input_lines: Vec<&str> = input.split('\n').collect();
let prev_line: Vec<char> = (if row > 0 { input_lines[row - 1] } else { "" }).chars().collect();
let current_line: Vec<char> = input_lines[row].chars().collect();
let next_line: Vec<char> = (if row < input_lines.len() - 1 { input_lines[row + 1] } else { "" }).chars().collect();
let mut gear_positions: Vec<(usize, usize)> = vec![];
if start_col > 0 {
surroundings.push(current_line[start_col - 1]);
if current_line[start_col - 1] == '*' {
gear_positions.push((row, start_col - 1));
}
}
if end_col < current_line.len() - 1 {
surroundings.push(current_line[end_col + 1]);
if current_line[end_col + 1] == '*' {
gear_positions.push((row, end_col + 1));
}
}
if !prev_line.is_empty() {
for col in start_col..end_col+1 {
surroundings.push(prev_line[col]);
if prev_line[col] == '*' {
gear_positions.push((row - 1, col));
}
}
if start_col > 0 {
surroundings.push(prev_line[start_col - 1]);
if prev_line[start_col - 1] == '*' {
gear_positions.push((row - 1, start_col - 1));
}
}
if end_col < prev_line.len() - 1 {
surroundings.push(prev_line[end_col + 1]);
if prev_line[end_col + 1] == '*' {
gear_positions.push((row - 1, end_col + 1));
}
}
}
if !next_line.is_empty() {
for col in start_col..end_col+1{
surroundings.push(next_line[col]);
if next_line[col] == '*' {
gear_positions.push((row + 1, col));
}
}
if start_col > 0 {
surroundings.push(next_line[start_col - 1]);
if next_line[start_col - 1] == '*' {
gear_positions.push((row + 1, start_col - 1));
}
}
if end_col < next_line.len() - 1 {
surroundings.push(next_line[end_col + 1]);
if next_line[end_col + 1] == '*' {
gear_positions.push((row + 1, end_col + 1));
}
}
}
println!("Surroundings: {:?}, digits: {}", surroundings, digits);
let schematic_number = SchematicNumber {
number: digits.parse().unwrap(),
surroundings
};
println!("{:#?}: is_part_number: {}", schematic_number, schematic_number.is_part_number());
for pos in gear_positions {
process_gear(&schematic_number, gears, pos.0, pos.1);
}
schematic_number
}
fn main() {
let input = include_str!("../input.txt");
let mut numbers: Vec<SchematicNumber> = vec![];
let mut gears: HashMap<(usize, usize), Gear> = HashMap::new();
let mut number_start: Option<usize> = None;
let mut number_digits = "".to_owned();
// Find numbers and their surroundings
for (row, line) in input.split('\n').enumerate() {
for (col, character) in line.chars().enumerate() {
match (number_start, character.is_digit(10)) {
(Some(_), true) => {
number_digits.push(character);
println!("{} is still a digit. number_digits is now {}", character, number_digits);
},
(Some(start_col), false) => {
numbers.push(process_number(&mut gears, input, number_digits, row, start_col, col - 1));
number_digits = "".to_owned();
number_start = None;
},
(None, true) => {
number_digits.push(character);
number_start = Some(col);
println!("{} is a digit. Starting a new number at postition {} with number_digits {}", character, number_start.unwrap(), number_digits);
},
(None, false) => {}
}
}
if let Some(start_col) = number_start {
numbers.push(process_number(&mut gears, input, number_digits, row, start_col, line.len() - 1));
number_digits = "".to_owned();
number_start = None;
}
}
let mut numbers_total: u64 = 0;
let mut gears_total: u64 = 0;
for number in numbers {
println!("{:?}, part_no: {}", number, number.is_part_number());
if number.is_part_number() {
numbers_total += Into::<u64>::into(number.number);
}
}
for gear in gears.values() {
println!("{:?}, sum: {}", gear, gear.sum());
gears_total += gear.sum();
}
println!("{}", numbers_total);
println!("{}", gears_total);
}