Add 2024 Quest 10

This commit is contained in:
Chris Alge 2024-11-16 17:58:42 +01:00
parent 403749e75d
commit f7f796ed93

View file

@ -2,14 +2,16 @@ use core::fmt::Display;
#[derive(Debug, PartialEq, Eq)] #[derive(Debug, PartialEq, Eq)]
pub enum ParseError { pub enum ParseError {
GridMalformed, GridMalformed(String),
GridOfGridsMalformed,
ParseCharError(char), ParseCharError(char),
} }
impl Display for ParseError { impl Display for ParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Self::GridMalformed => write!(f, "Grid must be 8*8 characters"), Self::GridMalformed(e) => write!(f, "Grid must be 8*8 characters: {e}"),
Self::GridOfGridsMalformed => write!(f, "All grid components must be of equal length"),
Self::ParseCharError(e) => write!(f, "Unable to parse character {e}"), Self::ParseCharError(e) => write!(f, "Unable to parse character {e}"),
} }
} }
@ -29,7 +31,7 @@ impl TryFrom<&str> for Grid {
fn try_from(value: &str) -> Result<Self, Self::Error> { fn try_from(value: &str) -> Result<Self, Self::Error> {
let lines: Vec<_> = value.lines().collect(); let lines: Vec<_> = value.lines().collect();
if !lines.len() == 8 || lines.iter().any(|line| line.len() != 8) { if !lines.len() == 8 || lines.iter().any(|line| line.len() != 8) {
return Err(Self::Error::GridMalformed); return Err(Self::Error::GridMalformed(value.to_string()));
} }
let rows = lines[2..6].iter().map(|line| line.chars().take(2).chain(line.chars().skip(6)).collect::<Vec<char>>()).collect(); let rows = lines[2..6].iter().map(|line| line.chars().take(2).chain(line.chars().skip(6)).collect::<Vec<char>>()).collect();
let columns = (2..6).map(|col| [0, 1, 6, 7].iter().map(|row| lines[*row].chars().nth(col).unwrap()).collect::<Vec<char>>()).collect(); let columns = (2..6).map(|col| [0, 1, 6, 7].iter().map(|row| lines[*row].chars().nth(col).unwrap()).collect::<Vec<char>>()).collect();
@ -65,7 +67,7 @@ impl Grid {
} }
} }
fn into_grids_split(input: &str) -> Vec<Vec<String>> { fn into_grids_split(input: &str) -> Result<Vec<Vec<String>>, ParseError> {
let rows: Vec<_> = input.split("\n\n").collect(); let rows: Vec<_> = input.split("\n\n").collect();
rows rows
.iter() .iter()
@ -79,21 +81,22 @@ fn into_grids_split(input: &str) -> Vec<Vec<String>> {
(0..cells[0].len()) (0..cells[0].len())
.map(|idx| cells .map(|idx| cells
.iter() .iter()
.map(|line| line[idx]) .map(|line| line.get(idx).copied().ok_or(ParseError::GridOfGridsMalformed))
.collect() .collect::<Result<Vec<&str>, _>>()
).collect::<Vec<Vec<&str>>>()
.iter()
.map(|s| s.join("\n")) .map(|s| s.join("\n"))
.collect::<Vec<String>>() ).collect::<Result<Vec<String>, _>>()
}).collect() }).collect::<Result<Vec<_>, ParseError>>()
} }
fn into_grids_shared(input: &str) -> Vec<Vec<String>> { fn into_grids_shared(input: &str) -> Result<Vec<Vec<String>>, ParseError> {
let lines: Vec<_> = input.lines().collect(); let lines: Vec<_> = input.lines().collect();
(0..lines.len()-7) (0..lines.len()-7)
.step_by(6) .step_by(6)
.map(|first_row| { .map(|first_row| {
(0..lines[first_row].len()-7) if lines[first_row].len() < 8 {
Err(ParseError::GridOfGridsMalformed)
} else {
Ok((0..lines[first_row].len()-7)
.step_by(6) .step_by(6)
.map(|first_col| { .map(|first_col| {
lines[first_row..first_row+8] lines[first_row..first_row+8]
@ -101,13 +104,14 @@ fn into_grids_shared(input: &str) -> Vec<Vec<String>> {
.map(|line| line.chars().skip(first_col).take(8).collect::<String>()) .map(|line| line.chars().skip(first_col).take(8).collect::<String>())
.collect::<Vec<String>>() .collect::<Vec<String>>()
.join("\n") .join("\n")
}).collect::<Vec<String>>() }).collect::<Vec<String>>())
}).collect() }
}).collect::<Result<Vec<_>, _>>()
} }
fn into_grids(input: &str) -> Vec<Vec<String>> { fn into_grids(input: &str) -> Result<Vec<Vec<String>>, ParseError> {
match input.lines().nth(8) { match input.lines().nth(8) {
None => vec![vec![input.to_string()]], None => Ok(vec![vec![input.to_string()]]),
Some("") => into_grids_split(input), Some("") => into_grids_split(input),
_ => into_grids_shared(input), _ => into_grids_shared(input),
} }
@ -186,7 +190,7 @@ fn solve_grids(grids: &mut [Vec<Grid>]) -> bool {
} }
pub fn run(input: &str, part: usize) -> Result<String, ParseError> { pub fn run(input: &str, part: usize) -> Result<String, ParseError> {
let mut grids = into_grids(input).iter().map(|row| row.iter().map(|g| Grid::try_from(&g[..])).collect::<Result<Vec<_>, _>>()).collect::<Result<Vec<Vec<_>>, _>>()?; let mut grids = into_grids(input)?.iter().map(|row| row.iter().map(|g| Grid::try_from(&g[..])).collect::<Result<Vec<_>, _>>()).collect::<Result<Vec<Vec<_>>, _>>()?;
match part { match part {
1 => Ok(grids[0][0].runic_word()), 1 => Ok(grids[0][0].runic_word()),
2 => Ok(format!("{}", grids.iter_mut().flatten().map(|g| g.effective_power()).sum::<usize>())), 2 => Ok(format!("{}", grids.iter_mut().flatten().map(|g| g.effective_power()).sum::<usize>())),