|
|
@@ -0,0 +1,141 @@
|
|
|
+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<Spell> spellBook, MonsterBoss boss, ref int best, int cost = 0, HashSet<SpellSequence> triedSpellSequence = null, SpellSequence spellSequence = null, int depth = 0)
|
|
|
+ {
|
|
|
+ if (depth > 9) return;
|
|
|
+
|
|
|
+ if (triedSpellSequence == null) triedSpellSequence = new HashSet<SpellSequence>();
|
|
|
+ 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<Spell> BuildSpellBook() => new List<Spell>
|
|
|
+ {
|
|
|
+ new MagicMissile(),
|
|
|
+ new Drain(),
|
|
|
+ new Shield(),
|
|
|
+ new Poison(),
|
|
|
+ new Recharge()
|
|
|
+ };
|
|
|
+ }
|
|
|
+}
|