using System; using System.Collections.Generic; using System.IO; using System.Linq; namespace D21._1 { public class Program { public enum EnumDifficulty { Normal = 0, Hard = 1 } public static EnumDifficulty Difficulty { get; set; } static bool Attack(MonsterBoss boss, SpellSequence spellBook) { var heroe = new Heroe(); boss.Heal(); var activeEffects = new Queue<(Spell, int)>(); var spellSequence = spellBook; while (heroe.HitPoints > 0 && boss.HitPoints > 0 && spellSequence != null) { HeroeTakesTurn(boss, heroe, activeEffects, spellSequence); if (heroe.Mana <= 0 || heroe.HitPoints <= 0 || boss.HitPoints <= 0) break; BossTakesTurn(boss, heroe, activeEffects); spellSequence = spellSequence?.NextEntry; } return boss.HitPoints <= 0 && heroe.HitPoints > 0; } private static void BossTakesTurn(MonsterBoss boss, Heroe heroe, Queue<(Spell, int)> activeEffects) { ResolveActiveEffects(boss, heroe, activeEffects); if (boss.HitPoints <= 0) return; var batk = Math.Max(boss.Damage - heroe.Armor, 1); heroe.HitPoints -= batk; } public static void HeroeTakesTurn(MonsterBoss boss, Heroe heroe, Queue<(Spell, int)> activeEffects, SpellSequence spellSequence) { heroe.HitPoints -= (int) Difficulty; if (heroe.HitPoints <= 0) return; ResolveActiveEffects(boss, heroe, activeEffects); if (boss.HitPoints <= 0) return; var spell = spellSequence?.Spell; heroe.Mana -= spell?.Cost ?? 0; spell?.ActiveEffect(heroe, boss); if (spell?.EffectDuration.HasValue ?? false) activeEffects.Enqueue((spell, spell.EffectDuration.Value)); } private static void ResolveActiveEffects(MonsterBoss boss, Heroe heroe, Queue<(Spell, int)> activeEffects) { int active = activeEffects.Count; while (active-- > 0) { (Spell s, int duration) = activeEffects.Dequeue(); s.ApplyEffect(heroe, boss); if (--duration != 0) activeEffects.Enqueue((s, duration)); else s.WornOutEffect(heroe, boss); } } public static void TrySpellSequence(List spellBook, MonsterBoss boss, ref int best, int cost = 0, HashSet triedSpellSequence = null, SpellSequence spellSequence = null, int depth = 0) { if (depth > 9) return; if (triedSpellSequence == null) triedSpellSequence = new HashSet(); if (triedSpellSequence.Contains(spellSequence) == false) { if (Attack(boss, spellSequence) && cost < best) best = cost; triedSpellSequence.Add(spellSequence); } foreach (Spell spell in spellBook) { var firstOccurence = spellSequence?.Position(spell) ?? -1; if (spellSequence != null && spell.EffectDuration > 0 && firstOccurence != -1 && firstOccurence < (spell.EffectDuration - 1) / 2) continue; var newSpellSequence = new SpellSequence() { Spell = spell, NextEntry = spellSequence }; TrySpellSequence(spellBook, boss, ref best, cost + spell.Cost, triedSpellSequence, newSpellSequence, depth + 1); } } static void Main(string[] args) { if (args.Length < 1) throw new ArgumentException(); if (File.Exists(args[0]) == false) throw new FileNotFoundException(); var spellBook = BuildSpellBook(); MonsterBoss boss = ParseFile(args); int best = int.MaxValue; TrySpellSequence(spellBook, boss, ref best); Console.WriteLine($"Best spell sequence costs {best} MP"); } public static MonsterBoss ParseFile(string[] args) { int hp = 0, atk = 0; using (var file = File.OpenText(args[0])) { hp = int.Parse(file.ReadLine().Split(": ")[1]); atk = int.Parse(file.ReadLine().Split(": ")[1]); } return new MonsterBoss(hp) { Damage = atk }; } public static List BuildSpellBook() => new List { new MagicMissile(), new Drain(), new Shield(), new Poison(), new Recharge() }; } }