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