day10: problem 1 solution
This commit is contained in:
196
10/src/main.rs
Normal file
196
10/src/main.rs
Normal file
@ -0,0 +1,196 @@
|
||||
use std::fs::File;
|
||||
use std::io::{BufRead, BufReader, Lines};
|
||||
|
||||
// BOILERPLATE
|
||||
type InputIter = Lines<BufReader<File>>;
|
||||
|
||||
fn get_input() -> InputIter {
|
||||
let f = File::open("input").unwrap();
|
||||
let br = BufReader::new(f);
|
||||
br.lines()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("Problem 1 solution: {}", problem1(get_input()));
|
||||
println!("Problem 2 solution: {}", problem2(get_input()));
|
||||
}
|
||||
|
||||
// PARSE
|
||||
|
||||
#[derive(Debug)]
|
||||
struct PipeSection {
|
||||
dist: u64,
|
||||
kind: char,
|
||||
}
|
||||
|
||||
impl From<char> for PipeSection {
|
||||
fn from(c: char) -> Self {
|
||||
PipeSection { dist: 0, kind: c }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct PipeMap {
|
||||
map: Vec<Vec<PipeSection>>,
|
||||
start: (usize, usize),
|
||||
}
|
||||
|
||||
const ALL_ADJ: [(isize, isize); 8] = [
|
||||
(-1, -1),
|
||||
(0, -1),
|
||||
(1, -1),
|
||||
(-1, 0),
|
||||
(1, 0),
|
||||
(-1, 1),
|
||||
(0, 1),
|
||||
(1, 1),
|
||||
];
|
||||
|
||||
impl PipeMap {
|
||||
fn adjacencies(c: char) -> Option<[(isize, isize); 2]> {
|
||||
match c {
|
||||
'|' => Some([(0, -1), (0, 1)]),
|
||||
'-' => Some([(-1, 0), (1, 0)]),
|
||||
'L' => Some([(0, -1), (1, 0)]),
|
||||
'J' => Some([(0, -1), (-1, 0)]),
|
||||
'7' => Some([(0, 1), (-1, 0)]),
|
||||
'F' => Some([(0, 1), (1, 0)]),
|
||||
'.' => None,
|
||||
'S' => None,
|
||||
_ => panic!("unhandled type"),
|
||||
}
|
||||
}
|
||||
fn valid_pos(&self, pos: (isize, isize)) -> bool {
|
||||
pos.0 >= 0
|
||||
&& pos.0 < self.map[0].len() as isize
|
||||
&& pos.1 >= 0
|
||||
&& pos.1 < self.map.len() as isize
|
||||
}
|
||||
|
||||
fn apply_adj(&self, pos: (usize, usize), adj: (isize, isize)) -> Option<(usize, usize)> {
|
||||
if self.valid_pos((pos.0 as isize + adj.0, pos.1 as isize + adj.1)) {
|
||||
Some((
|
||||
(pos.0 as isize + adj.0) as usize,
|
||||
(pos.1 as isize + adj.1) as usize,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn adjacent_positions(&self, pos: (usize, usize)) -> Option<[(usize, usize); 2]> {
|
||||
let adj = Self::adjacencies(self.map[pos.1][pos.0].kind);
|
||||
if let Some(adj) = adj {
|
||||
let mut positions = adj.iter().filter_map(|adj| self.apply_adj(pos, *adj));
|
||||
Some([positions.next().unwrap(), positions.next().unwrap()])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn start_adjacencies(&self) -> [(usize, usize); 2] {
|
||||
let mut adj_positions = Vec::new();
|
||||
for neighbour in ALL_ADJ
|
||||
.iter()
|
||||
.filter_map(|adj| self.apply_adj(self.start, *adj))
|
||||
{
|
||||
if let Some(neigh_adjs) = self.adjacent_positions(neighbour) {
|
||||
if neigh_adjs.contains(&self.start) {
|
||||
adj_positions.push(neighbour)
|
||||
}
|
||||
}
|
||||
}
|
||||
[adj_positions[0], adj_positions[1]]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: BufRead> From<Lines<T>> for PipeMap {
|
||||
fn from(lines: Lines<T>) -> Self {
|
||||
let mut map: Vec<Vec<PipeSection>> = Vec::new();
|
||||
for line in lines {
|
||||
map.push(line.unwrap().chars().map(PipeSection::from).collect());
|
||||
}
|
||||
|
||||
let start = map
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, row)| (row.iter().position(|p| p.kind == 'S'), idx))
|
||||
.find(|(x, _)| x.is_some())
|
||||
.unwrap();
|
||||
let start = (start.0.unwrap(), start.1);
|
||||
|
||||
let mut pipemap = PipeMap { map, start };
|
||||
|
||||
let mut cur_positions = pipemap.start_adjacencies();
|
||||
let mut cur_distance = 1;
|
||||
loop {
|
||||
for pos in cur_positions {
|
||||
pipemap.map[pos.1][pos.0].dist = cur_distance;
|
||||
}
|
||||
cur_distance += 1;
|
||||
|
||||
if let Some(new_pos1) = pipemap.adjacent_positions(cur_positions[0]) {
|
||||
if let Some(new_pos1) = new_pos1.iter().find(|pos| {
|
||||
pipemap.map[pos.1][pos.0].dist == 0 && pipemap.map[pos.1][pos.0].kind != 'S'
|
||||
}) {
|
||||
cur_positions[0] = *new_pos1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Some(new_pos2) = pipemap.adjacent_positions(cur_positions[1]) {
|
||||
if let Some(new_pos2) = new_pos2.iter().find(|pos| {
|
||||
pipemap.map[pos.1][pos.0].dist == 0 && pipemap.map[pos.1][pos.0].kind != 'S'
|
||||
}) {
|
||||
cur_positions[1] = *new_pos2;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if cur_positions[0] == cur_positions[1] {
|
||||
pipemap.map[cur_positions[0].1][cur_positions[0].0].dist = cur_distance;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pipemap
|
||||
}
|
||||
}
|
||||
|
||||
// PROBLEM 1 solution
|
||||
|
||||
fn problem1<T: BufRead>(input: Lines<T>) -> u64 {
|
||||
let map = PipeMap::from(input);
|
||||
|
||||
map.map.iter().map(|row| row.iter().map(|cell| cell.dist).max().unwrap()).max().unwrap()
|
||||
}
|
||||
|
||||
// PROBLEM 2 solution
|
||||
fn problem2<T: BufRead>(input: Lines<T>) -> u64 {
|
||||
0
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::*;
|
||||
use std::io::Cursor;
|
||||
|
||||
const EXAMPLE: &str = &"..F7.
|
||||
.FJ|.
|
||||
SJ.L7
|
||||
|F--J
|
||||
LJ...";
|
||||
|
||||
#[test]
|
||||
fn problem1_example() {
|
||||
let c = Cursor::new(EXAMPLE);
|
||||
assert_eq!(problem1(c.lines()), 8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn problem2_example() {
|
||||
let c = Cursor::new(EXAMPLE);
|
||||
assert_eq!(problem2(c.lines()), 0);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user