#include "aoc.h" #include #include namespace aoc2015 { static spell bosskill = {"bosskill", 0, 1, 8, 0, 0, 0, 0}; static spell spells[5] = { {"Magic Missile", 53, 1, 4, 0, 0, 0, 0}, {"Drain", 73, 1, 2, 2, 0, 0, 0}, {"Shield", 113, 6, 0, 0, 0, 7, 0}, {"Poison", 173, 6, 3, 0, 0, 0, 0}, {"Recharge", 229, 5, 0, 0, 101, 0, 0}, }; // spells wizard w can pick std::vector can_spell(const wizard& w) { std::vector is; for (int i = 0; i < 5; i++) { spell* s = w.wp->spells[i]; if (s != nullptr && s->tick == 0 && w.mana >= s->costs) { is.push_back(s); } } return is; } char * indent(int t) { static char idn[60] = {0}; memset(idn, 0, 60); for (int i = 0; i < ((t+1) / 2) * 2; i++) { idn[i] = ' '; } return idn; } void start_of_each_turn (int t, wizard& me, wizard& boss) { // printf("%sT[%d] boss[%d] player[%d] armor[%d] mana[%d]\n", indent(t), t, boss.points, me.points, me.armor, me.mana); for (int i = 0; i < 5; i++) { spell* s = boss.spells[i]; if (s->tick > 0) { // printf("%sT[%d] %s has tick %d\n", indent(t), t, s->name, s->tick); if (strcmp(s->name, "Magic Missile") == 0 && t % 2 == 0) { boss.points -= s->damage; } if (strcmp(s->name, "Drain") == 0 && t % 2 == 0) { boss.points -= s->damage; me.points += s->heals; } if (strcmp(s->name, "Shield") == 0) { me.armor = 7; } if (strcmp(s->name, "Poison") == 0) { boss.points -= s->damage; } if (strcmp(s->name, "Recharge") == 0) { me.mana += s->payback; } s->tick -= 1; } else { if (strcmp(s->name, "Shield") == 0) { me.armor = 0; } } } } void save_ticks(int ticks[], spell* spells[]) { for(int i = 0; i < 5; i++) { ticks[i] = spells[i]->tick; } } void undo_ticks(int ticks[], spell* spells[]) { for(int i = 0; i < 5; i++) { spells[i]->tick = ticks[i]; } } void fight(int turn, wizard me, wizard boss, int cost, std::vector& costs) { start_of_each_turn(turn, me, boss); if (turn > 18) return; // !!! THIS IS IMPORTANT !!! if (turn % 2 == 1) { // my turn // me.points -= 1; // part 2 if (me.points > 0) { auto ss = can_spell(me); for(auto& s : ss) { // printf("%sT[%d] choose %s =============\n", indent(turn), turn, s->name); s->tick = s->turns; me.mana -= s->costs; int ticks[5] = {0}; save_ticks(ticks, boss.spells); fight(turn+1, me, boss, cost + s->costs, costs); undo_ticks(ticks, boss.spells); me.mana += s->costs; s->tick = 0; } } } else { // boss turn if (boss.points <= 0) { // boss lose // printf("%sT[%d] player win %d\n", indent(turn), turn, cost); costs.push_back(cost); } else { me.points -= bosskill.damage - me.armor; fight(turn+1, me, boss, cost, costs); } } } std::pair day22(wizard me, wizard boss) { me.wp = &boss; boss.wp = &me; me.spells[0] = &bosskill; for (int i = 0; i < 5; i++) { boss.spells[i] = spells + i; } std::vector costs; fight(1, me, boss, 0, costs); int min{INT32_MAX}; for(auto& c : costs) { if (c < min) { min = c; } } return {min, 0}; } }