day 22 part 1
This commit is contained in:
250
src/day22.rs
Normal file
250
src/day22.rs
Normal file
@@ -0,0 +1,250 @@
|
|||||||
|
use std::{cmp::max, collections::BinaryHeap};
|
||||||
|
|
||||||
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
|
||||||
|
#[aoc_generator(day22)]
|
||||||
|
fn parse(input: &str) -> Boss {
|
||||||
|
let ints: Vec<i32> = input
|
||||||
|
.lines()
|
||||||
|
.map(|line| line.split_once(": ").unwrap().1)
|
||||||
|
.map(|it| it.parse().unwrap())
|
||||||
|
.collect();
|
||||||
|
Boss {
|
||||||
|
health: ints[0],
|
||||||
|
damage: ints[1],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Hash, Eq, PartialEq, Debug)]
|
||||||
|
struct Boss {
|
||||||
|
health: i32,
|
||||||
|
damage: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Hash, Eq, PartialEq, Debug)]
|
||||||
|
struct Wizard {
|
||||||
|
health: i32,
|
||||||
|
mana: i32,
|
||||||
|
spent: i32,
|
||||||
|
rem_shield: i32,
|
||||||
|
rem_poison: i32,
|
||||||
|
rem_recharge: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Wizard {
|
||||||
|
fn armor(&self) -> i32 {
|
||||||
|
if self.rem_shield > 0 {
|
||||||
|
7
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cant_spell(&self) -> bool {
|
||||||
|
if !self.can_missile()
|
||||||
|
&& !self.can_drain()
|
||||||
|
&& !self.can_shield()
|
||||||
|
&& !self.can_poison()
|
||||||
|
&& !self.can_recharge()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_missile(&self) -> bool {
|
||||||
|
self.mana >= 53
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_drain(&self) -> bool {
|
||||||
|
self.mana >= 73
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_shield(&self) -> bool {
|
||||||
|
self.mana >= 113 && self.rem_shield < 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_poison(&self) -> bool {
|
||||||
|
self.mana >= 173 && self.rem_poison < 1
|
||||||
|
}
|
||||||
|
|
||||||
|
fn can_recharge(&self) -> bool {
|
||||||
|
self.mana >= 229 && self.rem_recharge < 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Hash, Eq, PartialEq, Debug)]
|
||||||
|
enum Party {
|
||||||
|
Wiz,
|
||||||
|
Bo,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Hash, Eq, PartialEq, Debug)]
|
||||||
|
struct State {
|
||||||
|
boss: Boss,
|
||||||
|
wizard: Wizard,
|
||||||
|
next: Party,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for State {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
other.wizard.spent.cmp(&self.wizard.spent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl PartialOrd for State {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State {
|
||||||
|
fn new(boss: Boss) -> State {
|
||||||
|
State {
|
||||||
|
boss,
|
||||||
|
wizard: Wizard {
|
||||||
|
health: 50,
|
||||||
|
mana: 500,
|
||||||
|
spent: 0,
|
||||||
|
rem_shield: 0,
|
||||||
|
rem_poison: 0,
|
||||||
|
rem_recharge: 0,
|
||||||
|
},
|
||||||
|
next: Party::Wiz,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn play_wiz(&self) -> RoundResult {
|
||||||
|
let mut next = self.apply_effects();
|
||||||
|
next.next = Party::Bo;
|
||||||
|
|
||||||
|
if self.winner().is_some() {
|
||||||
|
panic!("should not play if there is a winner!")
|
||||||
|
}
|
||||||
|
let mut nexts = vec![];
|
||||||
|
|
||||||
|
if self.wizard.can_missile() {
|
||||||
|
let mut s = next;
|
||||||
|
s.wizard.mana -= 53;
|
||||||
|
s.wizard.spent += 53;
|
||||||
|
s.boss.health -= 4;
|
||||||
|
nexts.push(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.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 self.wizard.can_shield() {
|
||||||
|
let mut s = next;
|
||||||
|
s.wizard.mana -= 113;
|
||||||
|
s.wizard.spent += 113;
|
||||||
|
s.wizard.rem_shield = 6;
|
||||||
|
nexts.push(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.wizard.can_poison() {
|
||||||
|
let mut s = next;
|
||||||
|
s.wizard.mana -= 173;
|
||||||
|
s.wizard.spent += 173;
|
||||||
|
s.wizard.rem_poison = 6;
|
||||||
|
nexts.push(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.wizard.can_missile() {
|
||||||
|
let mut s = next;
|
||||||
|
s.wizard.mana -= 229;
|
||||||
|
s.wizard.spent += 229;
|
||||||
|
s.wizard.rem_recharge = 5;
|
||||||
|
nexts.push(s);
|
||||||
|
}
|
||||||
|
nexts
|
||||||
|
}
|
||||||
|
|
||||||
|
fn play_boss(&self) -> RoundResult {
|
||||||
|
let armor = self.wizard.armor(); // calc before reducing counter
|
||||||
|
let mut next = self.apply_effects();
|
||||||
|
next.next = Party::Wiz;
|
||||||
|
if self.winner().is_some() {
|
||||||
|
panic!("should not play if there is a winner!")
|
||||||
|
}
|
||||||
|
next.wizard.health -= max(1, next.boss.damage - armor);
|
||||||
|
vec![next]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn apply_effects(&self) -> Self {
|
||||||
|
let mut next = *self;
|
||||||
|
if next.wizard.rem_shield > 0 {
|
||||||
|
next.wizard.rem_shield -= 1;
|
||||||
|
}
|
||||||
|
if next.wizard.rem_poison > 0 {
|
||||||
|
next.wizard.rem_poison -= 1;
|
||||||
|
next.boss.health -= 3;
|
||||||
|
}
|
||||||
|
if next.wizard.rem_recharge > 0 {
|
||||||
|
next.wizard.rem_recharge -= 1;
|
||||||
|
next.wizard.mana += 101;
|
||||||
|
}
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
fn winner(&self) -> Option<Party> {
|
||||||
|
if self.wizard.cant_spell() && self.next == Party::Wiz {
|
||||||
|
if self.boss.health < 1 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
return Some(Party::Bo);
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type RoundResult = Vec<State>;
|
||||||
|
const INTERACTIVE: bool = false;
|
||||||
|
|
||||||
|
#[aoc(day22, part1)]
|
||||||
|
fn part1(boss: &Boss) -> i32 {
|
||||||
|
let first = State::new(*boss);
|
||||||
|
let mut queue = BinaryHeap::new();
|
||||||
|
queue.push(first);
|
||||||
|
|
||||||
|
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 {
|
||||||
|
let _ = std::io::stdin().read_line(&mut String::new()).unwrap();
|
||||||
|
println!("{current:?}");
|
||||||
|
println!("{:#?}", nexts);
|
||||||
|
}
|
||||||
|
for n in nexts {
|
||||||
|
queue.push(n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic!("no solution found")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day22, part2)]
|
||||||
|
fn part2(_boss: &Boss) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
18
src/day23.rs
Normal file
18
src/day23.rs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
|
||||||
|
type Input = ();
|
||||||
|
|
||||||
|
#[aoc_generator(day22)]
|
||||||
|
fn parse(input: &str) -> Input {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day22, part1)]
|
||||||
|
fn part1(_: &Input) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day22, part2)]
|
||||||
|
fn part2(_: &Input) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
18
src/day24.rs
Normal file
18
src/day24.rs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
|
||||||
|
type Input = ();
|
||||||
|
|
||||||
|
#[aoc_generator(day22)]
|
||||||
|
fn parse(input: &str) -> Input {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day22, part1)]
|
||||||
|
fn part1(_: &Input) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day22, part2)]
|
||||||
|
fn part2(_: &Input) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
18
src/day25.rs
Normal file
18
src/day25.rs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
|
||||||
|
type Input = ();
|
||||||
|
|
||||||
|
#[aoc_generator(day22)]
|
||||||
|
fn parse(input: &str) -> Input {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day22, part1)]
|
||||||
|
fn part1(_: &Input) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day22, part2)]
|
||||||
|
fn part2(_: &Input) -> usize {
|
||||||
|
0
|
||||||
|
}
|
||||||
@@ -14,5 +14,6 @@ mod day18;
|
|||||||
mod day19;
|
mod day19;
|
||||||
mod day20;
|
mod day20;
|
||||||
mod day21;
|
mod day21;
|
||||||
|
mod day22;
|
||||||
|
|
||||||
aoc_lib! { year = 2015 }
|
aoc_lib! { year = 2015 }
|
||||||
|
|||||||
Reference in New Issue
Block a user