Day 23 (abandoned)
This commit is contained in:
parent
96e7d52445
commit
a36181d01b
@ -4,6 +4,7 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
debug = 1
|
||||
|
||||
[[bin]]
|
||||
@ -93,3 +94,7 @@ path = "src/day21.rs"
|
||||
[[bin]]
|
||||
name = "day22"
|
||||
path = "src/day22.rs"
|
||||
|
||||
[[bin]]
|
||||
name = "day23"
|
||||
path = "src/day23.rs"
|
||||
|
5
inputs/day23.txt
Normal file
5
inputs/day23.txt
Normal file
@ -0,0 +1,5 @@
|
||||
#############
|
||||
#...........#
|
||||
###D#D#C#B###
|
||||
#B#A#A#C#
|
||||
#########
|
245
src/day23.rs
Normal file
245
src/day23.rs
Normal file
@ -0,0 +1,245 @@
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::{BinaryHeap, HashMap};
|
||||
use std::fmt;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
#[derive(Copy, Clone, Eq)]
|
||||
enum Space {
|
||||
Empty = 1,
|
||||
Amber,
|
||||
Bronze,
|
||||
Copper,
|
||||
Desert,
|
||||
}
|
||||
|
||||
impl Space {
|
||||
fn cost(&self) -> usize {
|
||||
match self {
|
||||
Self::Amber => 1,
|
||||
Self::Bronze => 10,
|
||||
Self::Copper => 100,
|
||||
Self::Desert => 1000,
|
||||
_ => panic!("empty spaces don't move"),
|
||||
}
|
||||
}
|
||||
|
||||
fn glyph(&self) -> char {
|
||||
match self {
|
||||
Self::Empty => '.',
|
||||
Self::Amber => 'A',
|
||||
Self::Bronze => 'B',
|
||||
Self::Copper => 'C',
|
||||
Self::Desert => 'D',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Hash for Space {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
(*self as u32).hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Space {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
*self as u32 == *other as u32
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Space {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
(*other as u32).cmp(&(*self as u32))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Space {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Space {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}", self.glyph())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
struct Step {
|
||||
cost: usize,
|
||||
position: [Space; 19],
|
||||
}
|
||||
|
||||
impl Ord for Step {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
other
|
||||
.cost
|
||||
.cmp(&self.cost)
|
||||
.then_with(|| self.position.cmp(&other.position))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Step {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Step {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
writeln!(f, "#############")?;
|
||||
writeln!(
|
||||
f,
|
||||
"#{}#",
|
||||
self.position[0..11]
|
||||
.iter()
|
||||
.map(|space| space.glyph())
|
||||
.collect::<String>()
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
"###{}#{}#{}#{}###",
|
||||
self.position[11].glyph(),
|
||||
self.position[13].glyph(),
|
||||
self.position[15].glyph(),
|
||||
self.position[17].glyph()
|
||||
)?;
|
||||
writeln!(
|
||||
f,
|
||||
" #{}#{}#{}#{}#",
|
||||
self.position[12].glyph(),
|
||||
self.position[14].glyph(),
|
||||
self.position[16].glyph(),
|
||||
self.position[18].glyph()
|
||||
)?;
|
||||
writeln!(f, " #########")
|
||||
}
|
||||
}
|
||||
|
||||
fn swap(position: [Space; 19], a: usize, b: usize) -> [Space; 19] {
|
||||
let mut new_position = position;
|
||||
new_position[a] = position[b];
|
||||
new_position[b] = position[a];
|
||||
new_position
|
||||
}
|
||||
|
||||
struct Burrow {
|
||||
goal: [Space; 19],
|
||||
}
|
||||
|
||||
impl Burrow {
|
||||
fn valid_moves(&self, position: [Space; 19]) -> Vec<([Space; 19], usize)> {
|
||||
let mut moves = Vec::new();
|
||||
|
||||
for door in [2, 4, 6, 8] {
|
||||
if position[door] != Space::Empty {
|
||||
if position[door - 1] == Space::Empty {
|
||||
moves.push((swap(position, door - 1, door), position[door].cost()));
|
||||
}
|
||||
if position[door + 1] == Space::Empty {
|
||||
moves.push((swap(position, door, door + 1), position[door].cost()));
|
||||
}
|
||||
if !moves.is_empty() {
|
||||
return moves;
|
||||
}
|
||||
}
|
||||
}
|
||||
for room in [11, 13, 15, 17] {
|
||||
if position[room] != Space::Empty && position[room + 1] == Space::Empty {
|
||||
moves.push((swap(position, room, room + 1), position[room].cost()));
|
||||
}
|
||||
if position[room + 1] != Space::Empty && position[room] == Space::Empty {
|
||||
moves.push((swap(position, room, room + 1), position[room + 1].cost()));
|
||||
}
|
||||
if position[room] != Space::Empty && position[room - 9] == Space::Empty {
|
||||
moves.push((swap(position, room, room - 9), position[room].cost()));
|
||||
}
|
||||
if (position[room - 9] != Space::Empty && position[room] == Space::Empty)
|
||||
&& ((position[room - 9] == self.goal[room + 1]
|
||||
&& position[room + 1] == Space::Empty)
|
||||
|| (position[room - 9] == self.goal[room]
|
||||
&& position[room + 1] == self.goal[room + 1]))
|
||||
{
|
||||
moves.push((swap(position, room - 9, room), position[room - 9].cost()));
|
||||
}
|
||||
}
|
||||
for hallway in [1, 3, 5, 7, 9] {
|
||||
if position[hallway] != Space::Empty {
|
||||
if position[hallway - 1] == Space::Empty {
|
||||
moves.push((
|
||||
swap(position, hallway, hallway - 1),
|
||||
position[hallway].cost(),
|
||||
));
|
||||
}
|
||||
if position[hallway + 1] == Space::Empty {
|
||||
moves.push((
|
||||
swap(position, hallway, hallway + 1),
|
||||
position[hallway].cost(),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
if position[0] != Space::Empty && position[1] == Space::Empty {
|
||||
moves.push((swap(position, 0, 1), position[0].cost()));
|
||||
}
|
||||
if position[10] != Space::Empty && position[9] == Space::Empty {
|
||||
moves.push((swap(position, 9, 10), position[10].cost()));
|
||||
}
|
||||
|
||||
moves
|
||||
}
|
||||
}
|
||||
|
||||
fn least_energy(start: &[Space; 19], goal: &[Space; 19]) -> Option<usize> {
|
||||
let burrow = Burrow { goal: *goal };
|
||||
|
||||
let mut dist: HashMap<[Space; 19], usize> = HashMap::new();
|
||||
let mut heap = BinaryHeap::new();
|
||||
|
||||
dist.insert(*start, 0);
|
||||
heap.push(Step {
|
||||
cost: 0,
|
||||
position: *start,
|
||||
});
|
||||
|
||||
while let Some(Step { cost, position }) = heap.pop() {
|
||||
if &position == goal {
|
||||
return Some(cost);
|
||||
}
|
||||
|
||||
let d = dist.entry(position).or_insert(usize::MAX);
|
||||
if &cost > d {
|
||||
continue;
|
||||
}
|
||||
|
||||
println!("{:?}", Step { cost, position });
|
||||
|
||||
let moves = burrow.valid_moves(position);
|
||||
for (next_position, next_cost) in moves {
|
||||
let next_cost = next_cost + cost;
|
||||
let next = Step {
|
||||
cost: next_cost,
|
||||
position: next_position,
|
||||
};
|
||||
if &next_cost < dist.get(&next_position).unwrap_or(&usize::MAX) {
|
||||
heap.push(next);
|
||||
dist.insert(next_position, next_cost);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn main() {
|
||||
use Space::*;
|
||||
let start = [
|
||||
Empty, Empty, Empty, Empty, Empty, Empty, Empty, Empty, Empty, Empty, Empty, Amber, Amber,
|
||||
Bronze, Bronze, Copper, Copper, Desert, Desert,
|
||||
];
|
||||
let goal = [
|
||||
Empty, Empty, Empty, Empty, Empty, Empty, Empty, Empty, Empty, Empty, Empty, Desert,
|
||||
Bronze, Desert, Amber, Copper, Amber, Bronze, Copper,
|
||||
];
|
||||
println!("solution {}", least_energy(&start, &goal).unwrap());
|
||||
}
|
Loading…
Reference in New Issue
Block a user