2023-11-07 22:34:25 +00:00
|
|
|
using MoreLinq.Extensions;
|
|
|
|
|
2022-12-03 05:55:49 +00:00
|
|
|
namespace AOC2015;
|
2022-11-11 18:42:42 +00:00
|
|
|
|
|
|
|
/// <summary>
|
2022-12-03 05:41:38 +00:00
|
|
|
/// Day 22: <a href="https://adventofcode.com/2015/day/22"/>
|
2022-11-11 18:42:42 +00:00
|
|
|
/// </summary>
|
2023-09-20 18:38:58 +00:00
|
|
|
public sealed class Day22() : Day(2015, 22, "Wizard Simulator 20XX")
|
2022-11-11 18:42:42 +00:00
|
|
|
{
|
2023-12-01 07:30:47 +00:00
|
|
|
private static readonly List<Spell> Spells =
|
|
|
|
[
|
2023-11-07 22:34:25 +00:00
|
|
|
new("Magic Missile", Mana: 53, Damage: 4),
|
|
|
|
new("Drain", Mana: 73, Damage: 2, Heal: 2),
|
|
|
|
new("Shield", Mana: 113, Armor: 7, Duration: 6),
|
|
|
|
new("Poison", Mana: 173, Damage: 3, Duration: 6),
|
|
|
|
new("Recharge", Mana: 229, ManaCharge: 101, Duration: 5)
|
2023-12-01 07:30:47 +00:00
|
|
|
];
|
2023-11-07 22:34:25 +00:00
|
|
|
|
2024-05-09 18:45:14 +00:00
|
|
|
private Dictionary<string, int> _boss = new();
|
2023-11-07 22:34:25 +00:00
|
|
|
|
2023-12-01 18:21:24 +00:00
|
|
|
private record Spell(
|
|
|
|
// ReSharper disable once NotAccessedPositionalProperty.Local
|
2023-12-01 07:30:47 +00:00
|
|
|
string Name,
|
|
|
|
int Mana,
|
|
|
|
int Duration = 0,
|
|
|
|
int Damage = 0,
|
|
|
|
int Heal = 0,
|
|
|
|
int Armor = 0,
|
|
|
|
int ManaCharge = 0
|
|
|
|
);
|
2023-11-07 22:34:25 +00:00
|
|
|
|
2024-05-09 18:45:14 +00:00
|
|
|
private struct GameState(bool hardMode = false, int roundNumber = 0, int totalManaSpent = 0, int playerHealth = 50,
|
|
|
|
int playerMana = 500, int bossHealth = 0, int bossDamage = 0, Dictionary<Spell, int>? activeSpells = null)
|
2023-11-07 22:34:25 +00:00
|
|
|
{
|
|
|
|
public GameResult DoTurn(Spell spell)
|
|
|
|
{
|
2024-05-09 18:45:14 +00:00
|
|
|
roundNumber++;
|
2023-11-07 22:34:25 +00:00
|
|
|
|
|
|
|
CastSpell(spell);
|
|
|
|
|
|
|
|
ProcessActiveSpells();
|
2024-05-09 18:45:14 +00:00
|
|
|
if (bossHealth <= 0) return GameResult.Win;
|
2023-11-07 22:34:25 +00:00
|
|
|
|
2024-05-09 18:45:14 +00:00
|
|
|
playerHealth -= Math.Max(1, bossDamage - activeSpells?.Sum(x => x.Key.Armor) ?? 0);
|
|
|
|
if (playerHealth <= 0) return GameResult.Loss;
|
2023-11-07 22:34:25 +00:00
|
|
|
|
2024-05-09 18:45:14 +00:00
|
|
|
if (hardMode)
|
2023-11-07 22:34:25 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
ProcessActiveSpells();
|
2024-05-09 18:45:14 +00:00
|
|
|
return bossHealth <= 0 ? GameResult.Win : GameResult.Continue;
|
2023-11-07 22:34:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void CastSpell(Spell spell)
|
|
|
|
{
|
2024-05-09 18:45:14 +00:00
|
|
|
totalManaSpent += spell.Mana;
|
|
|
|
playerMana -= spell.Mana;
|
2023-11-07 22:34:25 +00:00
|
|
|
if (spell.Duration == 0) ProcessSpell(spell);
|
2024-05-09 18:45:14 +00:00
|
|
|
else activeSpells?.Add(spell, spell.Duration);
|
2023-11-07 22:34:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void ProcessActiveSpells()
|
|
|
|
{
|
2024-05-09 18:45:14 +00:00
|
|
|
if (activeSpells is null) return;
|
|
|
|
|
|
|
|
activeSpells.Keys.ForEach(ProcessSpell);
|
|
|
|
foreach (var (spell, duration) in activeSpells.ToList())
|
2023-11-07 22:34:25 +00:00
|
|
|
{
|
2024-05-09 18:45:14 +00:00
|
|
|
if (duration == 1) activeSpells.Remove(spell);
|
|
|
|
else activeSpells[spell]--;
|
2023-11-07 22:34:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void ProcessSpell(Spell spell)
|
|
|
|
{
|
2024-05-09 18:45:14 +00:00
|
|
|
bossHealth -= spell.Damage;
|
|
|
|
playerHealth += spell.Heal;
|
|
|
|
playerMana += spell.ManaCharge;
|
2023-11-07 22:34:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-01 18:21:24 +00:00
|
|
|
private enum GameResult
|
2023-11-07 22:34:25 +00:00
|
|
|
{
|
|
|
|
Win,
|
|
|
|
Loss,
|
|
|
|
Continue
|
|
|
|
}
|
|
|
|
|
|
|
|
private GameState ProcessStates(GameState initialState)
|
|
|
|
{
|
|
|
|
var stateQueue = new Queue<GameState>();
|
|
|
|
stateQueue.Enqueue(initialState);
|
|
|
|
|
2024-05-09 18:45:14 +00:00
|
|
|
GameState bestGame = new(bossHealth: _boss["Hit Points"], bossDamage: _boss["Damage"]);
|
2023-11-07 22:34:25 +00:00
|
|
|
|
|
|
|
while (stateQueue.Count > 0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
return initialState;
|
|
|
|
}
|
|
|
|
|
2023-12-01 07:30:47 +00:00
|
|
|
public override void ProcessInput() =>
|
2023-11-07 22:34:25 +00:00
|
|
|
_boss = Input.ToDictionary(k => k.Split(": ")[0], v => int.Parse(v.Split(": ")[1]));
|
2022-11-11 18:42:42 +00:00
|
|
|
|
2023-12-01 07:30:47 +00:00
|
|
|
public override object Part1() =>
|
2024-05-09 18:45:14 +00:00
|
|
|
ProcessStates(new(bossHealth: _boss["Hit Points"], bossDamage: _boss["Damage"]));
|
2022-11-11 18:42:42 +00:00
|
|
|
|
|
|
|
public override object Part2() => "";
|
2023-12-01 07:30:47 +00:00
|
|
|
}
|