|
|
@@ -0,0 +1,226 @@
|
|
|
+use std::fs;
|
|
|
+use std::env;
|
|
|
+
|
|
|
+use std::collections::HashSet;
|
|
|
+use std::collections::HashMap;
|
|
|
+
|
|
|
+#[derive(Copy, Clone, Hash, PartialEq, Eq)]
|
|
|
+struct Coord {
|
|
|
+ row: i64,
|
|
|
+ col: i64,
|
|
|
+ grid_row: i64,
|
|
|
+ grid_col: i64,
|
|
|
+}
|
|
|
+
|
|
|
+fn get_adj_coords(c: Coord, n_rows: i64, n_cols: i64) -> Vec<Coord> {
|
|
|
+ let mut n1 = c;
|
|
|
+ n1.row = c.row + 1;
|
|
|
+ if n1.row >= n_rows {
|
|
|
+ n1.row -= n_rows;
|
|
|
+ n1.grid_row += 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ let mut n2 = c;
|
|
|
+ n2.row = c.row - 1;
|
|
|
+ if n2.row < 0 {
|
|
|
+ n2.row += n_rows;
|
|
|
+ n2.grid_row -= 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ let mut n3 = c;
|
|
|
+ n3.col = c.col + 1;
|
|
|
+ if n3.col >= n_cols {
|
|
|
+ n3.col -= n_cols;
|
|
|
+ n3.grid_col += 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ let mut n4 = c;
|
|
|
+ n4.col = c.col - 1;
|
|
|
+ if n4.col < 0 {
|
|
|
+ n4.col += n_cols;
|
|
|
+ n4.grid_col -= 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ vec![n1, n2, n3, n4]
|
|
|
+}
|
|
|
+
|
|
|
+fn get_adj_plot_coords(c: Coord, grid: &Vec<Vec<char>>) -> Vec<Coord> {
|
|
|
+ let n_rows: i64 = grid.len().try_into().unwrap();
|
|
|
+ let n_cols: i64 = grid[0].len().try_into().unwrap();
|
|
|
+
|
|
|
+ let mut plots = Vec::new();
|
|
|
+ for n in get_adj_coords(c, n_rows, n_cols).into_iter() {
|
|
|
+ if grid[n.row as usize][n.col as usize] == '#' {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ plots.push(n);
|
|
|
+ }
|
|
|
+ plots
|
|
|
+}
|
|
|
+
|
|
|
+fn get_grid(text: String) -> Vec<Vec<char>> {
|
|
|
+ let mut grid = Vec::new();
|
|
|
+ let mut row = Vec::new();
|
|
|
+ for c in text.chars() {
|
|
|
+ if c == '\n' {
|
|
|
+ grid.push(row.clone());
|
|
|
+ row.clear();
|
|
|
+ } else {
|
|
|
+ row.push(c);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if !row.is_empty() {
|
|
|
+ grid.push(row)
|
|
|
+ }
|
|
|
+ grid
|
|
|
+}
|
|
|
+
|
|
|
+fn get_start_coord(grid: &Vec<Vec<char>>) -> Coord {
|
|
|
+ for r in 0..grid.len() {
|
|
|
+ for c in 0..grid[0].len() {
|
|
|
+ if grid[r][c] == 'S' {
|
|
|
+ return Coord {
|
|
|
+ row: r.try_into().unwrap(),
|
|
|
+ col: c.try_into().unwrap(),
|
|
|
+ grid_row: 0,
|
|
|
+ grid_col: 0,
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ panic!("Can't get coord!");
|
|
|
+}
|
|
|
+
|
|
|
+fn make_step(positions: HashSet<Coord>, grid: &Vec<Vec<char>>) -> HashSet<Coord> {
|
|
|
+ let mut next_positions = HashSet::new();
|
|
|
+ for position in positions.into_iter() {
|
|
|
+ for next_position in get_adj_plot_coords(position, grid).into_iter() {
|
|
|
+ next_positions.insert(next_position);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ next_positions
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+fn populate_cache(cache: &mut HashMap<Coord, Vec<HashSet<Coord>>>, steps: usize, pos: Coord, grid: &Vec<Vec<char>>) {
|
|
|
+ let mut initial_pos = HashSet::new();
|
|
|
+ initial_pos.insert(pos);
|
|
|
+ cache.insert(pos, vec![initial_pos]);
|
|
|
+
|
|
|
+ let step_options = cache.get_mut(&pos).unwrap();
|
|
|
+ for _i in 0..steps {
|
|
|
+ let last_pos = step_options.last().unwrap().clone();
|
|
|
+ step_options.push(make_step(last_pos, grid));
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+fn get_cache_steps(cache: &HashMap<Coord, Vec<HashSet<Coord>>>, grid: &Vec<Vec<char>>) -> usize {
|
|
|
+ for r in 0..grid.len() {
|
|
|
+ for c in 0..grid[0].len() {
|
|
|
+ if grid[r][c] != '#' {
|
|
|
+ let coord = Coord {
|
|
|
+ row: r.try_into().unwrap(),
|
|
|
+ col: c.try_into().unwrap(),
|
|
|
+ grid_row: 0,
|
|
|
+ grid_col: 0,
|
|
|
+ };
|
|
|
+
|
|
|
+ return cache.get(&coord).unwrap().len() - 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ panic!("can't find cache len");
|
|
|
+}
|
|
|
+
|
|
|
+fn make_steps_with_cache(cache: &HashMap<Coord, Vec<HashSet<Coord>>>, steps: &mut usize,
|
|
|
+ positions: HashSet<Coord>, grid: &Vec<Vec<char>>) -> HashSet<Coord> {
|
|
|
+ let cache_steps = get_cache_steps(cache, grid);
|
|
|
+ if cache_steps >= *steps {
|
|
|
+ let mut next_positions = HashSet::new();
|
|
|
+
|
|
|
+ for position in positions.into_iter() {
|
|
|
+ let normalized_position = Coord {
|
|
|
+ row: position.row,
|
|
|
+ col: position.col,
|
|
|
+ grid_row: 0,
|
|
|
+ grid_col: 0,
|
|
|
+ };
|
|
|
+
|
|
|
+ let step_options = cache.get(&normalized_position).unwrap();
|
|
|
+ for next_position in step_options[*steps].iter() {
|
|
|
+ next_positions.insert(Coord {
|
|
|
+ row: next_position.row,
|
|
|
+ col: next_position.col,
|
|
|
+ grid_row: next_position.grid_row + position.grid_row,
|
|
|
+ grid_col: next_position.grid_col + position.grid_col,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ *steps = 0;
|
|
|
+ return next_positions;
|
|
|
+ } else {
|
|
|
+ let mut next_positions = HashSet::new();
|
|
|
+
|
|
|
+ for position in positions.into_iter() {
|
|
|
+ let normalized_position = Coord {
|
|
|
+ row: position.row,
|
|
|
+ col: position.col,
|
|
|
+ grid_row: 0,
|
|
|
+ grid_col: 0,
|
|
|
+ };
|
|
|
+
|
|
|
+ let step_options = cache.get(&normalized_position).unwrap();
|
|
|
+ for next_position in step_options[cache_steps].iter() {
|
|
|
+ next_positions.insert(Coord {
|
|
|
+ row: next_position.row,
|
|
|
+ col: next_position.col,
|
|
|
+ grid_row: next_position.grid_row + position.grid_row,
|
|
|
+ grid_col: next_position.grid_col + position.grid_col,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ *steps -= cache_steps;
|
|
|
+ return next_positions;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+fn main() {
|
|
|
+ let steps: usize = 500;
|
|
|
+
|
|
|
+ let args: Vec<String> = env::args().collect();
|
|
|
+ let file_path = &args[1];
|
|
|
+ let input_data = fs::read_to_string(file_path).unwrap_or_else(
|
|
|
+ |_|{panic!("Can't read file {}", file_path)});
|
|
|
+ let grid = get_grid(input_data);
|
|
|
+
|
|
|
+ let mut cache = HashMap::new();
|
|
|
+ for r in 0..grid.len() {
|
|
|
+ for c in 0..grid[0].len() {
|
|
|
+ if grid[r][c] != '#' {
|
|
|
+ let coord = Coord {
|
|
|
+ row: r.try_into().unwrap(),
|
|
|
+ col: c.try_into().unwrap(),
|
|
|
+ grid_row: 0,
|
|
|
+ grid_col: 0,
|
|
|
+ };
|
|
|
+
|
|
|
+ populate_cache(&mut cache, 50, coord, &grid);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let start_coord = get_start_coord(&grid);
|
|
|
+ let mut positions = HashSet::new();
|
|
|
+ positions.insert(start_coord);
|
|
|
+
|
|
|
+ let mut steps_left = steps;
|
|
|
+ while steps_left > 0 {
|
|
|
+ positions = make_steps_with_cache(&mut cache, &mut steps_left, positions, &grid);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ println!("{}", positions.len());
|
|
|
+}
|