day 22 part 2
... asdf
This commit is contained in:
185
src/day22.rs
185
src/day22.rs
@@ -1,4 +1,7 @@
|
|||||||
use std::{cmp::max, collections::BinaryHeap};
|
use std::{
|
||||||
|
cmp::{max, min},
|
||||||
|
collections::BinaryHeap,
|
||||||
|
};
|
||||||
|
|
||||||
use aoc_runner_derive::{aoc, aoc_generator};
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
|
||||||
@@ -73,17 +76,11 @@ impl Wizard {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Hash, Eq, PartialEq, Debug)]
|
|
||||||
enum Party {
|
|
||||||
Wiz,
|
|
||||||
Bo,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Hash, Eq, PartialEq, Debug)]
|
#[derive(Clone, Copy, Hash, Eq, PartialEq, Debug)]
|
||||||
struct State {
|
struct State {
|
||||||
boss: Boss,
|
boss: Boss,
|
||||||
wizard: Wizard,
|
wizard: Wizard,
|
||||||
next: Party,
|
hard: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ord for State {
|
impl Ord for State {
|
||||||
@@ -91,6 +88,7 @@ impl Ord for State {
|
|||||||
other.wizard.spent.cmp(&self.wizard.spent)
|
other.wizard.spent.cmp(&self.wizard.spent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialOrd for State {
|
impl PartialOrd for State {
|
||||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
Some(self.cmp(other))
|
Some(self.cmp(other))
|
||||||
@@ -98,7 +96,7 @@ impl PartialOrd for State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
fn new(boss: Boss) -> State {
|
fn new(boss: Boss, hard: bool) -> State {
|
||||||
State {
|
State {
|
||||||
boss,
|
boss,
|
||||||
wizard: Wizard {
|
wizard: Wizard {
|
||||||
@@ -109,17 +107,29 @@ impl State {
|
|||||||
rem_poison: 0,
|
rem_poison: 0,
|
||||||
rem_recharge: 0,
|
rem_recharge: 0,
|
||||||
},
|
},
|
||||||
next: Party::Wiz,
|
hard,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn play_wiz(&self) -> RoundResult {
|
fn play_two_turns(&self) -> RoundResult {
|
||||||
let mut next = self.apply_effects();
|
let mut next = *self;
|
||||||
next.next = Party::Bo;
|
if self.hard {
|
||||||
|
next.wizard.health -= 1;
|
||||||
if self.winner().is_some() {
|
if next.winner() != Winner::Ongoing {
|
||||||
panic!("should not play if there is a winner!")
|
return vec![];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
let next = next.apply_effects();
|
||||||
|
// if next.winner() != Winner::Ongoing {
|
||||||
|
// return vec![next];
|
||||||
|
// }
|
||||||
|
|
||||||
|
if next.wizard.cant_spell() {
|
||||||
|
// next.wizard.health = -100;
|
||||||
|
// return vec![next];
|
||||||
|
return vec![];
|
||||||
|
}
|
||||||
|
|
||||||
let mut nexts = vec![];
|
let mut nexts = vec![];
|
||||||
|
|
||||||
if self.wizard.can_missile() {
|
if self.wizard.can_missile() {
|
||||||
@@ -155,25 +165,23 @@ impl State {
|
|||||||
nexts.push(s);
|
nexts.push(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.wizard.can_missile() {
|
if self.wizard.can_recharge() {
|
||||||
let mut s = next;
|
let mut s = next;
|
||||||
s.wizard.mana -= 229;
|
s.wizard.mana -= 229;
|
||||||
s.wizard.spent += 229;
|
s.wizard.spent += 229;
|
||||||
s.wizard.rem_recharge = 5;
|
s.wizard.rem_recharge = 5;
|
||||||
nexts.push(s);
|
nexts.push(s);
|
||||||
}
|
}
|
||||||
nexts
|
|
||||||
}
|
|
||||||
|
|
||||||
fn play_boss(&self) -> RoundResult {
|
for n in &mut nexts {
|
||||||
let armor = self.wizard.armor(); // calc before reducing counter
|
let armor = n.wizard.armor();
|
||||||
let mut next = self.apply_effects();
|
*n = n.apply_effects();
|
||||||
next.next = Party::Wiz;
|
if n.boss.health < 1 {
|
||||||
if self.winner().is_some() {
|
continue;
|
||||||
panic!("should not play if there is a winner!")
|
}
|
||||||
|
n.wizard.health -= max(1, n.boss.damage - armor);
|
||||||
}
|
}
|
||||||
next.wizard.health -= max(1, next.boss.damage - armor);
|
nexts
|
||||||
vec![next]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_effects(&self) -> Self {
|
fn apply_effects(&self) -> Self {
|
||||||
@@ -192,59 +200,114 @@ impl State {
|
|||||||
next
|
next
|
||||||
}
|
}
|
||||||
|
|
||||||
fn winner(&self) -> Option<Party> {
|
fn winner(&self) -> Winner {
|
||||||
if self.wizard.cant_spell() && self.next == Party::Wiz {
|
if self.wizard.health < 1 {
|
||||||
if self.boss.health < 1 {
|
Winner::Loose
|
||||||
return None;
|
} else if self.boss.health < 1 {
|
||||||
}
|
Winner::Win
|
||||||
return Some(Party::Bo);
|
} else {
|
||||||
|
Winner::Ongoing
|
||||||
}
|
}
|
||||||
if self.wizard.health > 0 && self.boss.health < 1 {
|
|
||||||
return Some(Party::Wiz);
|
|
||||||
}
|
|
||||||
if self.wizard.health < 1 && self.boss.health > 0 {
|
|
||||||
return Some(Party::Bo);
|
|
||||||
}
|
|
||||||
if self.wizard.health < 1 && self.boss.health < 1 {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Debug)]
|
||||||
|
enum Winner {
|
||||||
|
Win,
|
||||||
|
Loose,
|
||||||
|
Ongoing,
|
||||||
|
}
|
||||||
|
|
||||||
type RoundResult = Vec<State>;
|
type RoundResult = Vec<State>;
|
||||||
const INTERACTIVE: bool = false;
|
const INTERACTIVE: bool = false;
|
||||||
|
|
||||||
#[aoc(day22, part1)]
|
fn play(boss: Boss, hard: bool) -> i32 {
|
||||||
fn part1(boss: &Boss) -> i32 {
|
let first = State::new(boss, hard);
|
||||||
let first = State::new(*boss);
|
|
||||||
let mut queue = BinaryHeap::new();
|
let mut queue = BinaryHeap::new();
|
||||||
queue.push(first);
|
queue.push(first);
|
||||||
|
let mut min_mana = i32::MAX;
|
||||||
|
|
||||||
while let Some(current) = queue.pop() {
|
while let Some(current) = queue.pop() {
|
||||||
if let Some(winner) = current.winner() {
|
|
||||||
if winner == Party::Wiz {
|
|
||||||
return current.wizard.spent;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let nexts = match current.next {
|
|
||||||
Party::Wiz => current.play_wiz(),
|
|
||||||
Party::Bo => current.play_boss(),
|
|
||||||
};
|
|
||||||
if INTERACTIVE {
|
if INTERACTIVE {
|
||||||
let _ = std::io::stdin().read_line(&mut String::new()).unwrap();
|
let _ = std::io::stdin().read_line(&mut String::new()).unwrap();
|
||||||
println!("{current:?}");
|
println!("{current:?}");
|
||||||
println!("{:#?}", nexts);
|
println!("{:?}", current.winner());
|
||||||
}
|
}
|
||||||
|
let mut next = current;
|
||||||
|
if hard {
|
||||||
|
next.wizard.health -= 1;
|
||||||
|
if next.wizard.health < 1 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let next = next.apply_effects();
|
||||||
|
|
||||||
|
let mut nexts = vec![];
|
||||||
|
|
||||||
|
if next.wizard.can_missile() {
|
||||||
|
let mut s = next;
|
||||||
|
s.wizard.mana -= 53;
|
||||||
|
s.wizard.spent += 53;
|
||||||
|
s.boss.health -= 4;
|
||||||
|
nexts.push(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if next.wizard.can_drain() {
|
||||||
|
let mut s = next;
|
||||||
|
s.wizard.mana -= 73;
|
||||||
|
s.wizard.spent += 73;
|
||||||
|
s.boss.health -= 2;
|
||||||
|
s.wizard.health += 2;
|
||||||
|
nexts.push(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if next.wizard.can_shield() {
|
||||||
|
let mut s = next;
|
||||||
|
s.wizard.mana -= 113;
|
||||||
|
s.wizard.spent += 113;
|
||||||
|
s.wizard.rem_shield = 6;
|
||||||
|
nexts.push(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if next.wizard.can_poison() {
|
||||||
|
let mut s = next;
|
||||||
|
s.wizard.mana -= 173;
|
||||||
|
s.wizard.spent += 173;
|
||||||
|
s.wizard.rem_poison = 6;
|
||||||
|
nexts.push(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if next.wizard.can_recharge() {
|
||||||
|
let mut s = next;
|
||||||
|
s.wizard.mana -= 229;
|
||||||
|
s.wizard.spent += 229;
|
||||||
|
s.wizard.rem_recharge = 5;
|
||||||
|
nexts.push(s);
|
||||||
|
}
|
||||||
|
|
||||||
for n in nexts {
|
for n in nexts {
|
||||||
queue.push(n);
|
let armor = n.wizard.armor();
|
||||||
|
let mut n = n.apply_effects();
|
||||||
|
if n.boss.health < 1 {
|
||||||
|
min_mana = min(min_mana, n.wizard.spent);
|
||||||
|
queue.retain(|s| s.wizard.spent > min_mana);
|
||||||
|
} else {
|
||||||
|
n.wizard.health -= max(1, n.boss.damage - armor);
|
||||||
|
if n.wizard.health > 0 && n.wizard.spent < min_mana {
|
||||||
|
queue.push(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic!("no solution found")
|
return min_mana;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day22, part1)]
|
||||||
|
fn part1(boss: &Boss) -> i32 {
|
||||||
|
play(*boss, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[aoc(day22, part2)]
|
#[aoc(day22, part2)]
|
||||||
fn part2(_boss: &Boss) -> usize {
|
fn part2(boss: &Boss) -> i32 {
|
||||||
0
|
play(*boss, true) // 1295 too high
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user