d17 first tries
This commit is contained in:
parent
134332c66e
commit
60da954585
5 changed files with 428 additions and 5 deletions
97
Cargo.lock
generated
97
Cargo.lock
generated
|
@ -8,6 +8,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"automod",
|
||||
"num",
|
||||
"pathfinding",
|
||||
"rayon",
|
||||
"regex",
|
||||
"scan_fmt",
|
||||
|
@ -79,12 +80,61 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deprecate-until"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a3767f826efbbe5a5ae093920b58b43b01734202be697e1354914e862e8e704"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"semver",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "fixedbitset"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "integer-sqrt"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "276ec31bcb4a9ee45f58bec6f9ec700ae4cf4f4f8f2fa7e06cb406bd5ffdd770"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
|
@ -182,6 +232,21 @@ dependencies = [
|
|||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pathfinding"
|
||||
version = "4.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ea07a6e677e47d6a84724d4fdf88b1e37fcb49ac94e236d7caeefd8fee75c8a"
|
||||
dependencies = [
|
||||
"deprecate-until",
|
||||
"fixedbitset",
|
||||
"indexmap",
|
||||
"integer-sqrt",
|
||||
"num-traits",
|
||||
"rustc-hash",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.70"
|
||||
|
@ -249,6 +314,12 @@ version = "0.8.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
|
@ -270,6 +341,12 @@ version = "1.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.193"
|
||||
|
@ -312,6 +389,26 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.51"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.12"
|
||||
|
|
|
@ -8,6 +8,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
automod = "1.0.13"
|
||||
num = "0.4.1"
|
||||
pathfinding = "4.6.0"
|
||||
rayon = "1.8.0"
|
||||
regex = "1.10.2"
|
||||
scan_fmt = "0.2.6"
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
2413432311323
|
||||
3215453535623
|
||||
3255245654254
|
||||
3446585845452
|
||||
4546657867536
|
||||
1438598798454
|
||||
4457876987766
|
||||
3637877979653
|
||||
4654967986887
|
||||
4564679986453
|
||||
1224686865563
|
||||
2546548887735
|
||||
4322674655533
|
318
src/days/d17.rs
318
src/days/d17.rs
|
@ -1,16 +1,328 @@
|
|||
use std::fs;
|
||||
use std::{
|
||||
cmp::{Ordering, Reverse},
|
||||
collections::{BTreeMap, BinaryHeap, HashMap},
|
||||
fs,
|
||||
};
|
||||
|
||||
pub fn solve() {
|
||||
let path = "res/17/example";
|
||||
|
||||
let mut _contents = fs::read_to_string(path).expect("I/O error, wrong path?");
|
||||
let contents = fs::read_to_string(path).expect("I/O error, wrong path?");
|
||||
//let contents = BufReader::new(fs::File::open(path).expect("I/O error, wrong path?"));
|
||||
|
||||
let result: usize = 0;
|
||||
let grid: Vec<Vec<u32>> = contents
|
||||
.lines()
|
||||
.map(|line| {
|
||||
line.chars()
|
||||
.map(|c| c.to_digit(10).unwrap())
|
||||
.collect::<Vec<u32>>()
|
||||
})
|
||||
.collect();
|
||||
|
||||
let start = (0, 0);
|
||||
let target = (grid.len() - 1, grid[0].len() - 1);
|
||||
|
||||
let results = dijkstra2(&grid, start);
|
||||
|
||||
let mut pri = grid.clone();
|
||||
let mut curr = (grid.len() - 1, grid[0].len() - 1);
|
||||
while curr != (0, 0) {
|
||||
pri[curr.0][curr.1] = 0;
|
||||
curr = results.get(&curr).unwrap().unwrap().0;
|
||||
}
|
||||
for row in pri {
|
||||
for num in row {
|
||||
if num == 0 {
|
||||
print!("#")
|
||||
} else {
|
||||
print!("{}", num)
|
||||
}
|
||||
}
|
||||
println!()
|
||||
}
|
||||
println!();
|
||||
|
||||
let result = results.get(&target).unwrap().unwrap().1;
|
||||
println!("Result 1: {result}");
|
||||
|
||||
let result: usize = 0;
|
||||
|
||||
println!("Result 2: {result}");
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
struct State {
|
||||
cost: usize,
|
||||
position: (usize, usize),
|
||||
}
|
||||
|
||||
impl Ord for State {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
other
|
||||
.cost
|
||||
.cmp(&self.cost)
|
||||
.then_with(|| self.position.cmp(&other.position))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for State {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Edge {
|
||||
node: (usize, usize),
|
||||
cost: usize,
|
||||
}
|
||||
/*
|
||||
fn dijkstra(grid: &Vec<Vec<u32>>, start: (usize, usize), goal: (usize, usize)) -> Option<usize> {
|
||||
let mut dist: HashMap<(usize, usize), usize> = HashMap::new();
|
||||
let mut visited: HashMap<(usize, usize), bool> = HashMap::new();
|
||||
let mut prev: HashMap<(usize, usize), (usize, usize)> = HashMap::new();
|
||||
for x in 0..grid.len() {
|
||||
for y in 0..grid[0].len() {
|
||||
dist.insert((x, y), usize::MAX);
|
||||
visited.insert((x, y), false);
|
||||
}
|
||||
}
|
||||
|
||||
dist.insert(start, 0);
|
||||
prev.insert(start, start);
|
||||
|
||||
let mut heap = BinaryHeap::new();
|
||||
|
||||
heap.push(State {
|
||||
cost: 0,
|
||||
position: start,
|
||||
});
|
||||
|
||||
while let Some(State { cost, position }) = heap.pop() {
|
||||
if position == goal {
|
||||
let mut pri = grid.clone();
|
||||
let mut curr = (grid.len() - 1, grid[0].len() - 1);
|
||||
while curr != (0, 0) {
|
||||
pri[curr.0][curr.1] = 0;
|
||||
curr = *prev.get(&curr).unwrap();
|
||||
}
|
||||
for row in pri {
|
||||
for num in row {
|
||||
if num == 0 {
|
||||
print!("#")
|
||||
} else {
|
||||
print!("{}", num)
|
||||
}
|
||||
}
|
||||
println!()
|
||||
}
|
||||
println!();
|
||||
for x in 0..grid.len() {
|
||||
for y in 0..grid[0].len() {
|
||||
if dist.contains_key(&(x, y)) {
|
||||
print!("{}", format!(" {:04}", dist.get(&(x, y)).unwrap()))
|
||||
} else {
|
||||
print!(" ###")
|
||||
}
|
||||
}
|
||||
println!()
|
||||
}
|
||||
return Some(cost);
|
||||
}
|
||||
|
||||
if cost > *dist.get(&position)? {
|
||||
continue;
|
||||
}
|
||||
|
||||
let is_max_in_dir = max_in_dir(position, &prev);
|
||||
let adj_list: Vec<Edge> =
|
||||
get_adjacent_positions(position, is_max_in_dir, *prev.get(&position).unwrap())
|
||||
.iter()
|
||||
.filter(|(x, y)| *x < grid.len() && *y < grid[0].len())
|
||||
.map(|pos| Edge {
|
||||
node: *pos,
|
||||
cost: grid[pos.0][pos.1] as usize,
|
||||
})
|
||||
.collect();
|
||||
|
||||
//println!("pos: {position:?}, adj: {:?}", &adj_list);
|
||||
for edge in adj_list {
|
||||
let next = State {
|
||||
cost: cost + edge.cost,
|
||||
position: edge.node,
|
||||
};
|
||||
|
||||
if next.cost < *dist.get(&next.position)? {
|
||||
heap.push(next);
|
||||
|
||||
*dist.get_mut(&next.position)? = next.cost;
|
||||
prev.insert(next.position, position);
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
*/
|
||||
//
|
||||
// returns a map that for each reachable vertex associates the distance and the predecessor
|
||||
// since the start has no predecessor but is reachable, map[start] will be None
|
||||
pub fn dijkstra2(
|
||||
graph: &Vec<Vec<u32>>,
|
||||
start: (usize, usize),
|
||||
) -> BTreeMap<(usize, usize), Option<((usize, usize), u32)>> {
|
||||
let mut ans = BTreeMap::new();
|
||||
let mut prio = BinaryHeap::new();
|
||||
|
||||
// start is the special case that doesn't have a predecessor
|
||||
ans.insert(start, None);
|
||||
|
||||
for coord in vec![(0, 1), (1, 0)] {
|
||||
ans.insert(coord, Some((start, graph[coord.0][coord.1])));
|
||||
prio.push(Reverse((graph[coord.0][coord.1], coord, start, 0, 0)));
|
||||
prio.push(Reverse((graph[coord.0][coord.1], coord, start, 1, 0)));
|
||||
}
|
||||
|
||||
while let Some(Reverse((dist_new, new, prev, dir, steps))) = prio.pop() {
|
||||
match ans[&new] {
|
||||
// what we popped is what is in ans, we'll compute it
|
||||
Some((p, d)) if p == prev && d == dist_new => {}
|
||||
// otherwise it's not interesting
|
||||
_ => continue,
|
||||
}
|
||||
|
||||
let adj_list: Vec<((usize, usize), u32, i32, i32)> =
|
||||
get_adjacent_positions(new, dir, steps, ans.get(&new).unwrap().unwrap().0)
|
||||
.iter()
|
||||
.filter(|((x, y), _, _)| *x < graph.len() && *y < graph[0].len())
|
||||
.map(|(pos, dir, steps)| (*pos, graph[pos.0][pos.1], *dir, *steps))
|
||||
.collect();
|
||||
|
||||
for (next, weight, dir, steps) in adj_list {
|
||||
match ans.get(&next) {
|
||||
// if ans[next] is a lower dist than the alternative one, we do nothing
|
||||
Some(Some((_, dist_next))) if dist_new + weight > *dist_next => {}
|
||||
// if ans[next] is None then next is start and so the distance won't be changed, it won't be added again in prio
|
||||
Some(None) => {}
|
||||
// the new path is shorter, either new was not in ans or it was farther
|
||||
_ => {
|
||||
ans.insert(next, Some((new, weight + dist_new)));
|
||||
prio.push(Reverse((weight + dist_new, next, new, dir, steps)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ans
|
||||
}
|
||||
|
||||
fn get_adjacent_positions(
|
||||
pos: (usize, usize),
|
||||
dir: i32,
|
||||
steps: i32,
|
||||
last_pos: (usize, usize),
|
||||
) -> Vec<((usize, usize), i32, i32)> {
|
||||
let mut adj_positions = Vec::new();
|
||||
|
||||
let directions = vec![(0, 1), (1, 0), (0, -1), (-1, 0)]; // Right, Down, Left, Up
|
||||
|
||||
for &(dx, dy) in &directions {
|
||||
let new_pos = (pos.0 as isize + dx, pos.1 as isize + dy);
|
||||
|
||||
if new_pos.0 < 0 || new_pos.1 < 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let new_pos = (new_pos.0 as usize, new_pos.1 as usize);
|
||||
|
||||
if new_pos == last_pos {
|
||||
// wrong dir
|
||||
continue;
|
||||
}
|
||||
|
||||
if new_pos.0.abs_diff(last_pos.0) == 2 || new_pos.1.abs_diff(last_pos.1) == 2 {
|
||||
if steps < 3 {
|
||||
adj_positions.push((new_pos, dir, steps + 1))
|
||||
}
|
||||
} else {
|
||||
let dir = match (dx, dy) {
|
||||
(0, 1) => 0,
|
||||
(1, 0) => 1,
|
||||
(0, -1) => 2,
|
||||
_ => 3,
|
||||
};
|
||||
adj_positions.push((new_pos, dir, 1));
|
||||
}
|
||||
}
|
||||
|
||||
adj_positions
|
||||
}
|
||||
|
||||
fn max_in_dir(pos: (usize, usize), prev: &HashMap<(usize, usize), (usize, usize)>) -> bool {
|
||||
if !prev.contains_key(&pos)
|
||||
|| !prev.contains_key(prev.get(&pos).unwrap())
|
||||
|| !prev.contains_key(prev.get(prev.get(&pos).unwrap()).unwrap())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
let prev1 = *prev.get(&pos).unwrap();
|
||||
let prev2 = *prev.get(&prev1).unwrap();
|
||||
let prev3 = *prev.get(&prev2).unwrap();
|
||||
|
||||
let diff = (prev1.0.abs_diff(pos.0), prev1.1.abs_diff(pos.1));
|
||||
|
||||
if diff == (prev2.0.abs_diff(prev1.0), prev2.1.abs_diff(prev1.1))
|
||||
&& diff == (prev3.0.abs_diff(prev2.0), prev3.1.abs_diff(prev2.1))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
fn max_in_dir2(
|
||||
pos: (usize, usize),
|
||||
prev: &BTreeMap<(usize, usize), Option<((usize, usize), u32)>>,
|
||||
) -> bool {
|
||||
if !prev.contains_key(&pos)
|
||||
|| !prev.get(&pos).unwrap().is_some()
|
||||
|| !prev.contains_key(&prev.get(&pos).unwrap().unwrap().0)
|
||||
|| !prev
|
||||
.get(&prev.get(&pos).unwrap().unwrap().0)
|
||||
.unwrap()
|
||||
.is_some()
|
||||
|| !prev.contains_key(
|
||||
&prev
|
||||
.get(&prev.get(&pos).unwrap().unwrap().0)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.0,
|
||||
)
|
||||
|| !prev
|
||||
.get(
|
||||
&prev
|
||||
.get(&prev.get(&pos).unwrap().unwrap().0)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
.0,
|
||||
)
|
||||
.unwrap()
|
||||
.is_some()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
let prev1 = prev.get(&pos).unwrap().unwrap().0;
|
||||
let prev2 = prev.get(&prev1).unwrap().unwrap().0;
|
||||
let prev3 = prev.get(&prev2).unwrap().unwrap().0;
|
||||
|
||||
let diff = (prev1.0.abs_diff(pos.0), prev1.1.abs_diff(pos.1));
|
||||
|
||||
if diff == (prev2.0.abs_diff(prev1.0), prev2.1.abs_diff(prev1.1))
|
||||
&& diff == (prev3.0.abs_diff(prev2.0), prev3.1.abs_diff(prev2.1))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@ extern crate scan_fmt;
|
|||
use std::time::Instant;
|
||||
|
||||
fn main() {
|
||||
//days::d16::solve()
|
||||
_all_days()
|
||||
days::d17::solve()
|
||||
//_all_days()
|
||||
}
|
||||
|
||||
#[allow(unreachable_code, unused)]
|
||||
|
|
Loading…
Reference in a new issue