day22 with hashmaps

slower, but more flexible
This commit is contained in:
Johannes
2018-12-25 14:04:03 +01:00
parent 12f32ed232
commit 719db128cf

View File

@@ -2,11 +2,18 @@ use crate::tasks::day22::Equipment::*;
use core::cmp::Ordering;
use std::collections::BinaryHeap;
use std::collections::HashMap;
use std::time::Instant;
pub fn both() {
let cave = Cave::create(3879, Node(8, 713, Torch));
let start = Instant::now();
let mut cave = Cave::create(3879, Node(8, 713, Torch));
println!("{:?}", Instant::now() - start);
let start = Instant::now();
println!("Sum of erosion indexes: {}", cave.erosion_sum());
println!("{:?}", Instant::now() - start);
let start = Instant::now();
println!("Shortest path length: {}", cave.shortest_path_length());
println!("{:?}", Instant::now() - start);
}
#[derive(PartialEq, Clone, Copy, Debug, Eq, Hash)]
@@ -20,8 +27,9 @@ enum Equipment {
struct Node(usize, usize, Equipment);
struct Cave {
map: Vec<Vec<usize>>,
map: HashMap<(usize, usize), usize>,
target: Node,
depth: usize,
}
impl Cave {
@@ -29,31 +37,12 @@ impl Cave {
if target.2 != Torch {
panic!("A valid target point needs the torch equipped");
}
let width = 5000;
let height = 5000;
let mut map: Vec<Vec<usize>> = Vec::with_capacity(width);
let mut inner_vec = Vec::with_capacity(height);
inner_vec.resize(height, 0);
map.resize(width, inner_vec);
let map = HashMap::with_capacity(target.0 * target.1);
for x in 0..width {
for y in 0..height {
let geo_index = match (x, y) {
(0, 0) => 0,
_ if target.0 == x && target.1 == y => 0,
(x, 0) => x * 16807,
(0, y) => y * 48271,
(x, y) => map[x - 1][y] * map[x][y - 1],
};
let erosion_index = (geo_index + depth) % 20183;
map[x][y] = erosion_index;
}
}
Cave { map, target }
Cave { map, target, depth }
}
fn erosion_sum(&self) -> usize {
fn erosion_sum(&mut self) -> usize {
(0..=self.target.0)
.map(|x| {
(0..=self.target.1)
@@ -63,11 +52,28 @@ impl Cave {
.sum()
}
fn field_type(&self, x: usize, y: usize) -> usize {
self.map[x][y] % 3
fn field_type(&mut self, x: usize, y: usize) -> usize {
self.erosion_index(x, y) % 3
}
fn shortest_path_length(&self) -> usize {
fn erosion_index(&mut self, x: usize, y: usize) -> usize {
if let Some(value) = self.map.get(&(x, y)) {
return *value;
} else {
let geo_index = match (x, y) {
(0, 0) => 0,
_ if self.target.0 == x && self.target.1 == y => 0,
(x, 0) => x * 16807,
(0, y) => y * 48271,
(x, y) => self.erosion_index(x - 1, y) * self.erosion_index(x, y - 1),
};
let erosion_index = (geo_index + self.depth) % 20183;
self.map.insert((x, y), erosion_index);
return erosion_index;
}
}
fn shortest_path_length(&mut self) -> usize {
let start = Node(0, 0, Torch);
let mut open: BinaryHeap<State> = BinaryHeap::new();
let mut distances: HashMap<Node, usize> = HashMap::new();
@@ -111,7 +117,7 @@ impl Cave {
unreachable!("There is always a path");
}
fn neighbors(&self, position: Node) -> Vec<Edge> {
fn neighbors(&mut self, position: Node) -> Vec<Edge> {
let mut result = Vec::new();
// add all variants of the current position
result.push(Edge {
@@ -146,7 +152,7 @@ impl Cave {
result
}
fn equipment_allowed_for_region(&self, x: usize, y: usize, equipment: Equipment) -> bool {
fn equipment_allowed_for_region(&mut self, x: usize, y: usize, equipment: Equipment) -> bool {
let field_type = self.field_type(x, y);
match field_type {
// rocky
@@ -159,7 +165,7 @@ impl Cave {
}
}
fn other_node_for_region(&self, position: Node) -> Node {
fn other_node_for_region(&mut self, position: Node) -> Node {
let field_type = self.field_type(position.0, position.1);
Node(
position.0,