2023-12-14 17:34:40 +01:00
|
|
|
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();
|
2023-12-14 17:37:54 +01:00
|
|
|
rocks_store.reserve(200);
|
2023-12-14 17:34:40 +01:00
|
|
|
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());
|
|
|
|
}
|
2023-12-14 21:41:20 +01:00
|
|
|
// do the cycles that remain after the ... Cycle - 1
|
|
|
|
let mut cycle_remainder = (1_000_000_000 as usize - cycle_start) % cycle_length;
|
|
|
|
if cycle_remainder == 0 { cycle_remainder = cycle_length - 1 }
|
|
|
|
else { cycle_remainder -= 1 }
|
|
|
|
for _ in 0..cycle_remainder {
|
2023-12-14 17:34:40 +01:00
|
|
|
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()
|
|
|
|
};
|
|
|
|
}
|