aoc-2021-rust

git clone https://git.sinitax.com/sinitax/aoc-2021-rust
Log | Files | Refs | README | sfeed.txt

commit 06eb0a03a1382b10fa495dd388804713ef9e931a
parent af7aee76aea2b6a7bfd2f2d49d9c1f2487672c92
Author: Louis Burda <quent.burda@gmail.com>
Date:   Wed, 19 Apr 2023 18:25:06 +0200

[Day 23] Try bruteforce search with caching

Diffstat:
Msrc/23/src/main.rs | 122+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
1 file changed, 69 insertions(+), 53 deletions(-)

diff --git a/src/23/src/main.rs b/src/23/src/main.rs @@ -1,5 +1,5 @@ +use std::{collections::HashMap, hash::Hash}; use std::cmp::Reverse; -use std::{collections::HashMap, collections::BinaryHeap, hash::Hash}; macro_rules! idx2slot { ( $cfg:expr, $t:expr ) => { @@ -38,6 +38,8 @@ struct MapConfig { fixed: [[bool; 4]; 4] } +struct Min(Option<usize>); + // struct FastHasher(u64); static AGENT_SYMBS: [char; 4] = ['A', 'B', 'C', 'D']; @@ -68,6 +70,20 @@ static MOVE_COST: [usize; 4] = [1, 10, 100, 1000]; // } // } +impl Min { + fn update_min(&mut self, other: &Self) { + if other.0.is_some() { + self.update(&other.0.unwrap()); + } + } + + fn update(&mut self, other: &usize) { + if self.0.is_none() || &self.0.unwrap() > other { + self.0 = Some(*other); + } + } +} + impl Pos { fn dist_to(&self, other: &Self) -> usize { return (isize::abs(self.x - other.x) @@ -181,10 +197,9 @@ fn heuristic(cfg: &MapConfig, state: &DJKState) -> usize { return cost; } -fn try_move_out(map: &HashMap<Pos,char>, cfg: &MapConfig, +fn lowest_cost_move_out(map: &HashMap<Pos,char>, cfg: &MapConfig, costmap: &mut HashMap<[[Pos; 4]; 4],usize>, - active: &mut BinaryHeap<DJKState>, - state: &DJKState, at: usize, ai: usize) { + state: &DJKState, at: usize, ai: usize) -> Min { let cur = &state.agents[at][ai]; let mut minx: isize = cfg.hallway.min; @@ -194,7 +209,7 @@ fn try_move_out(map: &HashMap<Pos,char>, cfg: &MapConfig, if t == at && i == ai { continue; } let agent = state.agents[t][i]; - if agent.x == cur.x && agent.y < cur.y { return; } + if agent.x == cur.x && agent.y < cur.y { return Min(None); } if agent.y == cfg.hallway_y { if agent.x > cur.x { @@ -206,6 +221,7 @@ fn try_move_out(map: &HashMap<Pos,char>, cfg: &MapConfig, } } + let mut min_cost = Min(None); for x in minx..maxx { /* skip spots over slots */ if x >= cfg.slot_x.min && x < cfg.slot_x.max @@ -233,15 +249,17 @@ fn try_move_out(map: &HashMap<Pos,char>, cfg: &MapConfig, *res.unwrap() = nstate.cost; } - active.push(nstate); + let cost = lowest_cost(map, cfg, costmap, &nstate); + min_cost.update_min(&cost); } } + + return min_cost; } -fn try_move_in(map: &HashMap<Pos,char>, cfg: &MapConfig, +fn lowest_cost_move_in(map: &HashMap<Pos,char>, cfg: &MapConfig, costmap: &mut HashMap<[[Pos; 4]; 4],usize>, - active: &mut BinaryHeap<DJKState>, - state: &DJKState, at: usize, ai: usize) { + state: &DJKState, at: usize, ai: usize) -> Min { let mut slot_free_y = cfg.slot_y.max-1; for t in 0..cfg.type_cnt { @@ -252,13 +270,13 @@ fn try_move_in(map: &HashMap<Pos,char>, cfg: &MapConfig, if agent.y == cfg.hallway_y { /* another agent is in the way */ if agent.x > state.agents[at][ai].x { - if idx2slot!(cfg, at) > agent.x { return; } + if idx2slot!(cfg, at) > agent.x { return Min(None); } } else { - if idx2slot!(cfg, at) < agent.x { return; } + if idx2slot!(cfg, at) < agent.x { return Min(None); } } } else if agent.x == idx2slot!(cfg, at) { slot_free_y = isize::min(slot_free_y, agent.y - 1); - if slot_free_y == cfg.hallway_y { return; } + if slot_free_y == cfg.hallway_y { return Min(None); } } } } @@ -285,20 +303,23 @@ fn try_move_in(map: &HashMap<Pos,char>, cfg: &MapConfig, *res.unwrap() = nstate.cost; } - active.push(nstate); + return lowest_cost(map, cfg, costmap, &nstate); + } else { + return Min(None); } } -fn try_move(map: &HashMap<Pos,char>, cfg: &MapConfig, +fn lowest_cost_move(map: &HashMap<Pos,char>, cfg: &MapConfig, costmap: &mut HashMap<[[Pos; 4]; 4],usize>, - active: &mut BinaryHeap<DJKState>, - state: &DJKState, at: usize, ai: usize) { - if !state.moved_in(at, ai, cfg) { + state: &DJKState, at: usize, ai: usize) -> Min { + if !state.moved_in(at, ai, cfg) { if !state.moved_out(at, ai, cfg) { - try_move_out(map, cfg, costmap, active, state, at, ai); + return lowest_cost_move_out(map, cfg, costmap, state, at, ai); } else { - try_move_in(map, cfg, costmap, active, state, at, ai); + return lowest_cost_move_in(map, cfg, costmap, state, at, ai); } + } else { + return Min(None); } } @@ -311,8 +332,31 @@ fn all_moved_in(state: &DJKState, cfg: &MapConfig) -> bool { return true; } -fn organize(map: &HashMap<Pos,char>, cfg: &mut MapConfig) -> Option<usize> { - let mut active = BinaryHeap::with_capacity(10000000); +fn lowest_cost(map: &HashMap<Pos,char>, cfg: &MapConfig, + costmap: &mut HashMap<[[Pos; 4]; 4],usize>, prev: &DJKState) -> Min { + + if aoc::get_debug() > 1 { + aoc::debugln!("----"); + prev.print(&cfg, &map); + aoc::debugln!(""); + } + + if all_moved_in(&prev, cfg) { + return Min(Some(prev.cost as usize)); + } + + let mut min_cost = Min(None); + for t in 0..cfg.type_cnt { + for i in 0..cfg.agent_cnt { + let cost = lowest_cost_move(&map, &cfg, costmap, &prev, t, i); + min_cost.update_min(&cost); + } + } + + return min_cost; +} + +fn organize(map: &HashMap<Pos,char>, cfg: &mut MapConfig) -> Min { let mut costmap: HashMap<[[Pos; 4]; 4],usize> = HashMap::with_capacity(10000000); let mut counts: [usize; 4] = [0; 4]; @@ -332,38 +376,9 @@ fn organize(map: &HashMap<Pos,char>, cfg: &mut MapConfig) -> Option<usize> { } cfg.initial.cost = 0; cfg.initial.total = heuristic(&cfg, &cfg.initial); - active.push(cfg.initial.clone()); costmap.insert(cfg.initial.agents.clone(), 0); - let mut advanced: usize = 0; - while !active.is_empty() { - let state = active.pop().unwrap(); - - advanced += 1; - - if aoc::get_debug() > 1 { - aoc::debugln!("-----------------"); - aoc::debugln!("LEN {}", active.len()); - state.print(&cfg, &map); - aoc::debugln!(""); - } - aoc::debugln!("{}", state.cost); - - if all_moved_in(&state, cfg) { - return Some(state.cost as usize); - } - - for t in 0..cfg.type_cnt { - for i in 0..cfg.agent_cnt { - try_move(&map, &cfg, &mut costmap, - &mut active, &state, t, i); - } - } - } - - aoc::debugln!("Advanced {} states", advanced); - - return None; + return lowest_cost(map, cfg, &mut costmap, &cfg.initial); } fn extend_map(s_map: &HashMap<Pos,char>, s_cfg: &MapConfig) @@ -396,7 +411,7 @@ fn extend_map(s_map: &HashMap<Pos,char>, s_cfg: &MapConfig) fn part1(aoc: &mut aoc::Info) { let (map, mut cfg) = parse_input(&aoc.input); let answer = organize(&map, &mut cfg); - aoc.answer = Some(format!("{}", answer.unwrap())); + aoc.answer = Some(format!("{}", answer.0.unwrap())); aoc.solution = Some("15385"); } @@ -404,7 +419,8 @@ fn part2(aoc: &mut aoc::Info) { let (s_map, s_cfg) = parse_input(&aoc.input); let (map, mut cfg) = extend_map(&s_map, &s_cfg); let answer = organize(&map, &mut cfg); - aoc.answer = Some(format!("{}", answer.unwrap())); + aoc.answer = Some(format!("{}", answer.0.unwrap())); + aoc.solution = Some("49803") } fn main() {