day14: rust
This commit is contained in:
parent
5dfbe7c237
commit
3d5270034b
22
14/README.md
Normal file
22
14/README.md
Normal file
@ -0,0 +1,22 @@
|
||||
# [Day 14](https://adventofcode.com/2023/day/14)
|
||||
:gift::gift::gift::gift::gift::gift::gift::gift::gift::gift::gift::gift::gift::gift:
|
||||
|
||||
Today's language: **Rust**
|
||||
|
||||
Lines of code: **84**
|
||||
|
||||
Execution time: **0,171 s**
|
||||
|
||||
This solution uses a single function for the tilting procedure.
|
||||
Different tilting directions are achieved by "remapping" `x` and `y` through captures.
|
||||
|
||||
For task 2, a cycle is searched by comparing the rocks after each nwse-tilt with all previous results.
|
||||
After finding two equal states, only `(1.000.000.000 - cycle_start) % cycle_length` cycles have to be performed to get the correct result.
|
||||
This approach requires making copies of the 2D array in a loop, which involves expensive heap allocations.
|
||||
It is still pretty fast.
|
||||
|
||||
```shell
|
||||
rustc day14.rs
|
||||
./day14
|
||||
```
|
||||
<!-- no bruteforce in < 90 lines -->
|
107
14/day14.rs
Normal file
107
14/day14.rs
Normal file
@ -0,0 +1,107 @@
|
||||
use std::io::{self, BufRead};
|
||||
|
||||
type Rocks = Vec<Vec<u8>>;
|
||||
|
||||
// tilt so that all 'O' characters want to DECREMENT their Y index
|
||||
// using custom `at` function that "remaps" x and y, this function can be used for all directions
|
||||
fn tilt<F>(rocks: &mut Rocks, at: F, x_len: usize, y_len: usize)
|
||||
where F: Fn(&mut Rocks, usize, usize) -> &mut u8 {
|
||||
for x in 0..x_len {
|
||||
let mut next_y: usize = 0; // lowest reachable position
|
||||
for y in 0..y_len {
|
||||
match *at(rocks, x, y) as char {
|
||||
'#' => next_y = y + 1,
|
||||
'O' => {
|
||||
if next_y != y {
|
||||
*at(rocks, x, next_y) = 'O' as u8;
|
||||
*at(rocks, x, y) = '.' as u8;
|
||||
}
|
||||
while next_y < y_len - 1 {
|
||||
next_y += 1;
|
||||
if *at(rocks, x, next_y) != '#' as u8 { break }
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --> y
|
||||
// |
|
||||
// V
|
||||
// x
|
||||
// West is the orientation that looks like the input
|
||||
// When printing with one of these, the rocks want to roll to the left side
|
||||
fn west_at(rocks: &mut Rocks, x: usize, y: usize) -> &mut u8 { &mut rocks[x][y] }
|
||||
fn east_at(rocks: &mut Rocks, x: usize, y: usize) -> &mut u8 { let ylen = rocks[0].len(); &mut rocks[x][ylen - y - 1] }
|
||||
fn south_at (rocks: &mut Rocks, x: usize, y: usize) -> &mut u8 { let xlen = rocks.len(); let ylen = rocks[0].len(); &mut rocks[xlen - y - 1][ylen - x - 1] }
|
||||
fn north_at (rocks: &mut Rocks, x: usize, y: usize) -> &mut u8 { let ylen = rocks[0].len(); &mut rocks[y][ylen - x - 1] }
|
||||
|
||||
fn print<F>(rocks: &mut Rocks, at: F, x_len: usize, y_len: usize)
|
||||
where F: Fn(&mut Rocks, usize, usize) -> &mut u8 {
|
||||
(0..x_len).for_each(|x| { (0..y_len).for_each(|y| print!("{}", *at(rocks, x, y) as char)); println!() });
|
||||
}
|
||||
fn weigh<F>(rocks: &mut Rocks, at: F, x_len: usize, y_len: usize) -> usize
|
||||
where F: Fn(&mut Rocks, usize, usize) -> &mut u8 {
|
||||
let mut weight: usize = 0;
|
||||
(0..x_len).for_each(|x| (0..y_len).for_each(|y| if *at(rocks, x, y) == 'O' as u8 { weight += y_len - y }) );
|
||||
return weight;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// let input = "example.txt";
|
||||
let input = "input.txt";
|
||||
let lines = read_lines(&input);
|
||||
let mut original: Rocks = Vec::new();
|
||||
for line in lines.map(|r| r.ok().unwrap()) {
|
||||
original.push(line.chars().map(|c| c as u8).collect());
|
||||
}
|
||||
let ew_xlen = original.len();
|
||||
let ew_ylen = original[0].len();
|
||||
let ns_xlen = ew_ylen;
|
||||
let ns_ylen = ew_xlen;
|
||||
|
||||
// TASK 1
|
||||
let mut rocks = original.clone();
|
||||
tilt(&mut rocks, north_at, ns_xlen, ns_ylen);
|
||||
println!("Load on north support beams (1): {}", weigh(&mut rocks, north_at, ns_xlen, ns_ylen));
|
||||
// print(&mut rocks, west_at, ew_xlen, ew_ylen);
|
||||
|
||||
// TASK 2
|
||||
rocks = original.clone();
|
||||
// find a cycle
|
||||
let mut rocks_store: Vec<Rocks> = Vec::new();
|
||||
let mut cycle_start: usize = 0;
|
||||
let mut cycle_length: usize = 0;
|
||||
for i in 0..1_000_000_000 as usize {
|
||||
tilt(&mut rocks, north_at, ns_xlen, ns_ylen);
|
||||
tilt(&mut rocks, west_at, ew_xlen, ew_ylen);
|
||||
tilt(&mut rocks, south_at, ns_xlen, ns_ylen);
|
||||
tilt(&mut rocks, east_at, ew_xlen, ew_ylen);
|
||||
if let Some(j) = rocks_store.iter().position(|r| r.eq(&rocks)) {
|
||||
cycle_start = j;
|
||||
cycle_length = i - j;
|
||||
println!("Cycle found! rocks at {} == rocks at {}", i, j);
|
||||
break;
|
||||
}
|
||||
rocks_store.push(rocks.clone());
|
||||
}
|
||||
// do the cycles that remain after the ... Cycle
|
||||
for _ in 0..(1_000_000_000 as usize - cycle_start) % cycle_length - 1 {
|
||||
tilt(&mut rocks, north_at, ns_xlen, ns_ylen);
|
||||
tilt(&mut rocks, west_at, ew_xlen, ew_ylen);
|
||||
tilt(&mut rocks, south_at, ns_xlen, ns_ylen);
|
||||
tilt(&mut rocks, east_at, ew_xlen, ew_ylen);
|
||||
}
|
||||
// tilt(&mut rocks, north_at, ns_xlen, ns_ylen);
|
||||
println!("Load on north support beams (2): {}", weigh(&mut rocks, north_at, ns_xlen, ns_ylen));
|
||||
}
|
||||
|
||||
fn read_lines<P>(filename: P) -> io::Lines<io::BufReader<std::fs::File>>
|
||||
where P: AsRef<std::path::Path>, {
|
||||
return match std::fs::File::open(filename) {
|
||||
Err(why) => panic!("Could not open file. {}", why),
|
||||
Ok(file) => std::io::BufReader::new(file).lines()
|
||||
};
|
||||
}
|
@ -16,5 +16,6 @@ This is a repository for my solutions for the [advent of code 2023](https://adve
|
||||
| [10](10) | Rust | 136 | 0,003 s | lots of bitwise operations |
|
||||
| [11](11) | Rust | 66 | 0,005 s | |
|
||||
| [13](13) | Rust | 84 | 0,002 s | binary encoding ftw |
|
||||
| [14](14) | Rust | 84 | 0,171 s | no bruteforce in < 90 lines |
|
||||
|
||||
Lines of code are without blank lines and comments
|
||||
|
Loading…
Reference in New Issue
Block a user