y2024d10
This commit is contained in:
parent
ada97e5ad6
commit
9b2497f31e
41
y2024/resources/10_input.txt
Normal file
41
y2024/resources/10_input.txt
Normal file
@ -0,0 +1,41 @@
|
||||
21056789894321015012980123498787601045687
|
||||
32346543765601156703474544567896012138796
|
||||
10107632659892349821563678989345643029655
|
||||
23218101256781015430412101071234754910544
|
||||
14569870345432016321003012560109867801033
|
||||
05678963256789127879854303456078105932122
|
||||
18723450109898038910765210010563254541001
|
||||
69011201298788945125898998323454569679852
|
||||
78760345345654876034787677401235378089760
|
||||
89456896012503876965014586512765432123601
|
||||
32387987003412965872123298703890101984512
|
||||
01291876121101234989456107654965278854603
|
||||
00180145030980325678327890217874369763254
|
||||
14343232145671013454310691307893454610169
|
||||
23432165430110302169234582456732108905678
|
||||
96547078923231231078105673454321097214523
|
||||
87678432214348940987017894765870986341014
|
||||
96589541009857654320123765891963475498765
|
||||
01434630111766789010432143210452560167876
|
||||
32345721210951999016549054789301001456965
|
||||
21076890129810878321678945643219812332109
|
||||
78789001234723765430321238756106734323458
|
||||
09654160345654210389210109987005125010767
|
||||
12323271657601345678780125678014056541893
|
||||
25414987798542343456690034329123987932012
|
||||
56905677810439652987501145016510345801101
|
||||
67856298923128721987432156987421256789210
|
||||
22347107654098910876543087870330107654301
|
||||
11298231012347654305678898981278798987652
|
||||
00109545691056763211219767874569678690343
|
||||
12065456783345894320105656913450569541289
|
||||
43874321092132101899234541002321256632176
|
||||
54930010561001234788765432211056746789045
|
||||
67821123472390545654123101347849839874330
|
||||
78934010589487698763034567456931028765221
|
||||
67785697696590101672105698741022210540100
|
||||
58696788787781234589789789012013307632101
|
||||
49545459810170301075674654323454458989032
|
||||
30432365923965432165463210498569567976543
|
||||
21021876854876523678354112347678678875301
|
||||
30010966763987014589210001456565589765432
|
20
y2024/src/bin/d10.rs
Normal file
20
y2024/src/bin/d10.rs
Normal file
@ -0,0 +1,20 @@
|
||||
use std::fs;
|
||||
|
||||
use y2024::days::d10;
|
||||
|
||||
fn main() {
|
||||
part1();
|
||||
part2();
|
||||
}
|
||||
|
||||
fn part1() {
|
||||
let root = env!("CARGO_MANIFEST_DIR");
|
||||
let content = fs::read_to_string(format!("{root}/resources/10_input.txt")).unwrap();
|
||||
println!("{}", d10::process_part1(&content));
|
||||
}
|
||||
|
||||
fn part2() {
|
||||
let root = env!("CARGO_MANIFEST_DIR");
|
||||
let content = fs::read_to_string(format!("{root}/resources/10_input.txt")).unwrap();
|
||||
println!("{}", d10::process_part2(&content));
|
||||
}
|
332
y2024/src/days/d10.rs
Normal file
332
y2024/src/days/d10.rs
Normal file
@ -0,0 +1,332 @@
|
||||
use itertools::Itertools;
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default, Hash, PartialEq, Eq)]
|
||||
struct TrailTile {
|
||||
coords: (i32, i32),
|
||||
height: u8,
|
||||
up: Option<bool>,
|
||||
down: Option<bool>,
|
||||
left: Option<bool>,
|
||||
right: Option<bool>,
|
||||
}
|
||||
|
||||
impl TrailTile {
|
||||
fn get_neighbors(&self, map: &[Vec<TrailTile>]) -> Vec<TrailTile> {
|
||||
let mut neighbors = Vec::new();
|
||||
if let Some(up) = self.up {
|
||||
if up {
|
||||
let neighbor = map[self.coords.1 as usize - 1][self.coords.0 as usize];
|
||||
if neighbor.height == self.height + 1 {
|
||||
neighbors.push(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(down) = self.down {
|
||||
if down {
|
||||
let neighbor = map[self.coords.1 as usize + 1][self.coords.0 as usize];
|
||||
if neighbor.height == self.height + 1 {
|
||||
neighbors.push(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(left) = self.left {
|
||||
if left {
|
||||
let neighbor = map[self.coords.1 as usize][self.coords.0 as usize - 1];
|
||||
if neighbor.height == self.height + 1 {
|
||||
neighbors.push(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(right) = self.right {
|
||||
if right {
|
||||
let neighbor = map[self.coords.1 as usize][self.coords.0 as usize + 1];
|
||||
if neighbor.height == self.height + 1 {
|
||||
neighbors.push(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
neighbors
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_part1(input: &str) -> i32 {
|
||||
let map = input
|
||||
.lines()
|
||||
.enumerate()
|
||||
.map(|(yidx, line)| {
|
||||
line.as_bytes()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(xidx, &height)| TrailTile {
|
||||
coords: (xidx as i32, yidx as i32),
|
||||
height,
|
||||
..Default::default()
|
||||
})
|
||||
.collect_vec()
|
||||
})
|
||||
.collect_vec();
|
||||
let mut updated_map = Vec::new();
|
||||
let mut trailheads = Vec::new();
|
||||
for row in map.iter() {
|
||||
let mut new_row = Vec::new();
|
||||
for tile in row {
|
||||
let up = match map.get((tile.coords.1 - 1) as usize) {
|
||||
Some(row) => {
|
||||
let up = row[tile.coords.0 as usize];
|
||||
Some(up.height == tile.height + 1)
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
let down = match map.get((tile.coords.1 + 1) as usize) {
|
||||
Some(row) => {
|
||||
let down = row[tile.coords.0 as usize];
|
||||
Some(down.height == tile.height + 1)
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
let left = map[tile.coords.1 as usize]
|
||||
.get((tile.coords.0 - 1) as usize)
|
||||
.map(|left| left.height == tile.height + 1);
|
||||
let right = map[tile.coords.1 as usize]
|
||||
.get((tile.coords.0 + 1) as usize)
|
||||
.map(|right| right.height == tile.height + 1);
|
||||
let tile = TrailTile {
|
||||
up,
|
||||
down,
|
||||
left,
|
||||
right,
|
||||
..*tile
|
||||
};
|
||||
if tile.height == b'0' {
|
||||
trailheads.push(tile);
|
||||
}
|
||||
//print!(
|
||||
// "{}: {}, {} ",
|
||||
// tile.height as char, tile.coords.0, tile.coords.1
|
||||
//);
|
||||
new_row.push(tile);
|
||||
}
|
||||
//println!();
|
||||
updated_map.push(new_row);
|
||||
}
|
||||
let mut res = 0;
|
||||
//println!("0 {trailheads:?}");
|
||||
for trailhead in trailheads {
|
||||
let mut neighbors = trailhead.get_neighbors(&updated_map);
|
||||
//println!("1 {neighbors:?}");
|
||||
for _idx in 2..=9 {
|
||||
//println!("{idx}");
|
||||
if neighbors.is_empty() {
|
||||
//println!("empty");
|
||||
break;
|
||||
}
|
||||
let inner_neighbors = neighbors.clone();
|
||||
neighbors.clear();
|
||||
for neighbor in inner_neighbors {
|
||||
neighbors.extend_from_slice(&neighbor.get_neighbors(&updated_map));
|
||||
}
|
||||
//println!("{idx} {neighbors:?}");
|
||||
}
|
||||
res += neighbors.iter().unique().count();
|
||||
}
|
||||
res as i32
|
||||
}
|
||||
|
||||
pub fn process_part2(input: &str) -> i32 {
|
||||
let map = input
|
||||
.lines()
|
||||
.enumerate()
|
||||
.map(|(yidx, line)| {
|
||||
line.as_bytes()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(xidx, &height)| TrailTile {
|
||||
coords: (xidx as i32, yidx as i32),
|
||||
height,
|
||||
..Default::default()
|
||||
})
|
||||
.collect_vec()
|
||||
})
|
||||
.collect_vec();
|
||||
let mut updated_map = Vec::new();
|
||||
let mut trailheads = Vec::new();
|
||||
for row in map.iter() {
|
||||
let mut new_row = Vec::new();
|
||||
for tile in row {
|
||||
let up = match map.get((tile.coords.1 - 1) as usize) {
|
||||
Some(row) => {
|
||||
let up = row[tile.coords.0 as usize];
|
||||
Some(up.height == tile.height + 1)
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
let down = match map.get((tile.coords.1 + 1) as usize) {
|
||||
Some(row) => {
|
||||
let down = row[tile.coords.0 as usize];
|
||||
Some(down.height == tile.height + 1)
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
let left = map[tile.coords.1 as usize]
|
||||
.get((tile.coords.0 - 1) as usize)
|
||||
.map(|left| left.height == tile.height + 1);
|
||||
let right = map[tile.coords.1 as usize]
|
||||
.get((tile.coords.0 + 1) as usize)
|
||||
.map(|right| right.height == tile.height + 1);
|
||||
let tile = TrailTile {
|
||||
up,
|
||||
down,
|
||||
left,
|
||||
right,
|
||||
..*tile
|
||||
};
|
||||
if tile.height == b'0' {
|
||||
trailheads.push(tile);
|
||||
}
|
||||
//print!(
|
||||
// "{}: {}, {} ",
|
||||
// tile.height as char, tile.coords.0, tile.coords.1
|
||||
//);
|
||||
new_row.push(tile);
|
||||
}
|
||||
//println!();
|
||||
updated_map.push(new_row);
|
||||
}
|
||||
let mut res = 0;
|
||||
//println!("0 {trailheads:?}");
|
||||
for trailhead in trailheads {
|
||||
let mut neighbors = trailhead.get_neighbors(&updated_map);
|
||||
//println!("1 {neighbors:?}");
|
||||
for _idx in 2..=9 {
|
||||
//println!("{idx}");
|
||||
if neighbors.is_empty() {
|
||||
//println!("empty");
|
||||
break;
|
||||
}
|
||||
let inner_neighbors = neighbors.clone();
|
||||
neighbors.clear();
|
||||
for neighbor in inner_neighbors {
|
||||
neighbors.extend_from_slice(&neighbor.get_neighbors(&updated_map));
|
||||
}
|
||||
//println!("{idx} {neighbors:?}");
|
||||
}
|
||||
res += neighbors.len();
|
||||
}
|
||||
res as i32
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
const INPUT_SMALL: &str = "0123
|
||||
1234
|
||||
8765
|
||||
9876";
|
||||
|
||||
const INPUT_LARGE: &str = "89010123
|
||||
78121874
|
||||
87430965
|
||||
96549874
|
||||
45678903
|
||||
32019012
|
||||
01329801
|
||||
10456732";
|
||||
|
||||
const INPUT_SIMPLIFIED_1: &str = "...0...
|
||||
...1...
|
||||
...2...
|
||||
6543456
|
||||
7.....7
|
||||
8.....8
|
||||
9.....9";
|
||||
const INPUT_SIMPLIFIED_2: &str = "..90..9
|
||||
...1.98
|
||||
...2..7
|
||||
6543456
|
||||
765.987
|
||||
876....
|
||||
987....";
|
||||
const INPUT_SIMPLIFIED_3: &str = "10..9..
|
||||
2...8..
|
||||
3...7..
|
||||
4567654
|
||||
...8..3
|
||||
...9..2
|
||||
.....01";
|
||||
|
||||
const INPUT_SIMPLIFIED_4: &str = ".....0.
|
||||
..4321.
|
||||
..5..2.
|
||||
..6543.
|
||||
..7..4.
|
||||
..8765.
|
||||
..9....";
|
||||
|
||||
const INPUT_SIMPLIFIED_5: &str = "012345
|
||||
123456
|
||||
234567
|
||||
345678
|
||||
4.6789
|
||||
56789.";
|
||||
|
||||
#[test]
|
||||
fn part1_small() {
|
||||
let result = process_part1(INPUT_SMALL);
|
||||
assert_eq!(result, 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part1_large() {
|
||||
let result = process_part1(INPUT_LARGE);
|
||||
assert_eq!(result, 36);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part1_simplified_1() {
|
||||
let result = process_part1(INPUT_SIMPLIFIED_1);
|
||||
assert_eq!(result, 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part1_simplified_2() {
|
||||
let result = process_part1(INPUT_SIMPLIFIED_2);
|
||||
assert_eq!(result, 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part1_simplified_3() {
|
||||
let result = process_part1(INPUT_SIMPLIFIED_3);
|
||||
assert_eq!(result, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_small() {
|
||||
let result = process_part2(INPUT_SMALL);
|
||||
assert_eq!(result, 16);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_large() {
|
||||
let result = process_part2(INPUT_LARGE);
|
||||
assert_eq!(result, 81);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_simplified_2() {
|
||||
let result = process_part2(INPUT_SIMPLIFIED_2);
|
||||
assert_eq!(result, 13);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_simplified_4() {
|
||||
let result = process_part2(INPUT_SIMPLIFIED_4);
|
||||
assert_eq!(result, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_simplified_5() {
|
||||
let result = process_part2(INPUT_SIMPLIFIED_5);
|
||||
assert_eq!(result, 227);
|
||||
}
|
||||
}
|
@ -7,3 +7,5 @@ pub mod d6;
|
||||
pub mod d7;
|
||||
pub mod d8;
|
||||
pub mod d9;
|
||||
|
||||
pub mod d10;
|
||||
|
Loading…
Reference in New Issue
Block a user