Created
December 22, 2015 10:46
-
-
Save markheath/7e3fa33f54f012136083 to your computer and use it in GitHub Desktop.
Clumsy C# solution to advent of code day 22
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// n.b. Linqpad script | |
class QueueSpellChooser : ISpellChooser | |
{ | |
private Queue<Spell> spellQueue; | |
public QueueSpellChooser(IEnumerable<Spell> spells) | |
{ | |
spellQueue = new Queue<Spell>(spells); | |
} | |
public Spell GetNextSpell(PlayerStatus status) | |
{ | |
return spellQueue.Dequeue(); | |
} | |
public void WinningAmount(int amount) | |
{ | |
} | |
public void NewBattle() | |
{ | |
} | |
} | |
interface ISpellChooser | |
{ | |
void NewBattle(); | |
Spell GetNextSpell(PlayerStatus status); | |
void WinningAmount(int amount); | |
} | |
class SpellChooser : ISpellChooser | |
{ | |
public int bestWinningAmount = Int32.MaxValue; | |
public List<string> choices = new List<string>(); | |
private Random rand = new Random(); | |
public Spell GetNextSpell(PlayerStatus status) | |
{ | |
var options = spells.Where(s => s.Cost <= status.Mana && | |
s.Cost + status.ManaSpent < bestWinningAmount && | |
!status.IsSpellActive(s.Name)).ToList(); | |
if (options.Count == 0) return null; | |
var t = options[rand.Next(options.Count)].GetType(); | |
var spell = (Spell)Activator.CreateInstance(t); | |
choices.Add(spell.Name); | |
return spell; | |
} | |
public void NewBattle() | |
{ | |
choices.Clear(); | |
} | |
public void WinningAmount(int amount) | |
{ | |
if (amount < bestWinningAmount) | |
{ | |
Console.WriteLine("NEW BEST AMOUNT {0}", amount); | |
foreach(var choice in choices) | |
Console.WriteLine(choice); | |
bestWinningAmount = amount; | |
} | |
} | |
} | |
abstract class Spell | |
{ | |
public Spell(string name, int cost) | |
{ | |
Name = name; | |
Cost = cost; | |
} | |
public int Cost { get; } | |
public string Name { get; } | |
public abstract void Use(PlayerStatus self, PlayerStatus opponent, bool debug); | |
public abstract int Timer { get; } | |
} | |
class MagicMissile : Spell | |
{ | |
public MagicMissile() : base("Magic Missile", 53) { } | |
public override void Use(PlayerStatus self, PlayerStatus opponent, bool debug) | |
{ | |
if (debug) Console.WriteLine("Magic Missile deals 4 damage"); | |
opponent.AddHitPoints(-4); | |
} | |
public override int Timer { get { return 0; } } | |
} | |
class Drain : Spell | |
{ | |
public Drain() : base("Drain", 73) { } | |
public override void Use(PlayerStatus self, PlayerStatus opponent, bool debug) | |
{ | |
if (debug) Console.WriteLine ("Player casts Drain, dealing 2 damage, and healing 2 hit points"); | |
self.AddHitPoints(2); | |
opponent.AddHitPoints(-2); | |
} | |
public override int Timer { get { return 0; } } | |
} | |
class Shield : Spell | |
{ | |
public Shield() : base("Shield", 113) { } | |
private int timer = 6; | |
public override void Use(PlayerStatus self, PlayerStatus opponent, bool debug) | |
{ | |
if (timer == 6) | |
{ | |
if (debug) Console.WriteLine("Shield increases armor by 7"); | |
self.AddArmor(7); | |
} | |
if (timer == 1) | |
{ | |
if (debug) Console.WriteLine("Shield wears off, decreasing armor by 7"); | |
self.AddArmor(-7); | |
} | |
timer--; | |
} | |
public override int Timer { get { return timer; } } | |
} | |
class Poison : Spell | |
{ | |
public Poison() : base("Poison", 173) { } | |
private int timer = 6; | |
public override void Use(PlayerStatus self, PlayerStatus opponent, bool debug) | |
{ | |
if (debug) Console.WriteLine("Poison deals 3 damage"); | |
opponent.AddHitPoints(-3); | |
timer--; | |
} | |
public override int Timer { get { return timer; } } | |
} | |
class Recharge : Spell | |
{ | |
public Recharge() : base("Recharge", 229) { } | |
private int timer = 5; | |
public override void Use(PlayerStatus self, PlayerStatus opponent, bool debug = true) | |
{ | |
if (debug) Console.WriteLine("Recharge increases mana by 101"); | |
self.AddMana(101); | |
timer--; | |
} | |
public override int Timer { get { return timer; } } | |
} | |
static List<Spell> spells = new List<Spell>() | |
{ | |
new MagicMissile(), | |
new Drain(), | |
new Shield(), | |
new Recharge(), | |
new Poison(), | |
}; | |
bool Battle(PlayerStatus player, PlayerStatus boss, ISpellChooser spellChooser, bool hard, bool debug = false) | |
{ | |
spellChooser.NewBattle(); | |
while (player.HitPoints > 0 && boss.HitPoints > 0) | |
{ | |
if (debug) | |
{ | |
Console.WriteLine("-- Player turn --"); | |
Console.WriteLine($"Player has {player.HitPoints} hit points, {player.Armor} armor, {player.Mana} mana"); | |
Console.WriteLine($"Boss has {boss.HitPoints} hit points"); | |
} | |
if (hard) | |
{ | |
player.AddHitPoints(-1); | |
if (player.HitPoints <= 0) return false; | |
} | |
player.UseSpells(boss, debug); | |
var spell = spellChooser.GetNextSpell(player); | |
// can't afford any more spells (or this battle won't be cheapest) | |
if (spell == null) return false; | |
if (debug) Console.WriteLine($"Player casts {spell.Name}"); | |
player.AddSpell(spell, boss, debug); | |
if (debug) | |
{ | |
Console.WriteLine("-- Boss turn --"); | |
Console.WriteLine($"Player has {player.HitPoints} hit points, {player.Armor} armor, {player.Mana} mana"); | |
Console.WriteLine($"Boss has {boss.HitPoints} hit points"); | |
} | |
player.UseSpells(boss, debug); | |
if (boss.HitPoints > 0) player.HitBy(boss, debug); | |
} | |
var playerWins = player.HitPoints > 0; | |
if (playerWins) spellChooser.WinningAmount(player.ManaSpent); | |
return playerWins; | |
} | |
class PlayerStatus | |
{ | |
private List<Spell> activeSpells = new List<Spell>(); | |
public PlayerStatus(int hp, int d, int a, int m) | |
{ | |
HitPoints = hp; | |
Damage = d; | |
Armor = a; | |
Mana = m; | |
} | |
public int HitPoints { get; private set; } | |
public int Damage { get; private set; } | |
public int Armor { get; private set; } | |
public int Mana { get; private set; } | |
public int ManaSpent { get; private set; } | |
public void AddHitPoints(int hitPoints) | |
{ | |
HitPoints += hitPoints; | |
} | |
public void AddArmor(int armor) | |
{ | |
Armor += armor; | |
} | |
public void AddMana(int mana) | |
{ | |
Mana += mana; | |
} | |
public void AddSpell(Spell spell, PlayerStatus opponent, bool debug = false) | |
{ | |
Mana -= spell.Cost; | |
ManaSpent += spell.Cost; | |
if (Mana < 0) throw new ArgumentException("Can't afford this spell"); | |
if (spell.Timer == 0) | |
{ | |
spell.Use(this, opponent, debug); | |
} | |
else | |
{ | |
activeSpells.Add(spell); | |
} | |
} | |
public void UseSpells(PlayerStatus boss, bool debug = false) | |
{ | |
foreach (var spell in activeSpells) | |
{ | |
if (boss.HitPoints > 0) | |
{ | |
spell.Use(this, boss, debug); | |
if (debug) | |
Console.WriteLine($"{spell.Name}'s timer is now {spell.Timer}"); | |
} | |
} | |
activeSpells.RemoveAll(s => s.Timer == 0); | |
} | |
public void HitBy(PlayerStatus boss, bool debug = false) | |
{ | |
var bossDamage = Math.Max(1, boss.Damage - Armor); | |
if (debug) Console.WriteLine($"Boss attacks for {bossDamage} damage"); | |
HitPoints -= bossDamage; | |
} | |
public bool IsSpellActive(string spellName) | |
{ | |
return activeSpells.Any(s => s.Name == spellName); | |
} | |
} | |
void Main() | |
{ | |
var testPlayer = new PlayerStatus(10, 0, 0, 250); | |
var testBoss = new PlayerStatus(13, 8, 0, 0); | |
var spells = new Spell[] { new Poison(), new MagicMissile() }; | |
//Battle(testPlayer, testBoss, new QueueSpellChooser(spells), true).Dump(); | |
var testPlayer2 = new PlayerStatus(10, 0, 0, 250); | |
var testBoss2 = new PlayerStatus(14, 8, 0, 0); | |
var spells2 = new Spell[] { new Recharge(), new Shield(), new Drain(), new Poison(), new MagicMissile() }; | |
//Battle(testPlayer2, testBoss2, new QueueSpellChooser(spells2), true).Dump(); | |
var chooser = new SpellChooser(); | |
for (int n = 0; n < 10000; n++) | |
{ | |
var player = new PlayerStatus(50, 0, 0, 500); | |
var boss = new PlayerStatus(58, 9, 0, 500); | |
Battle(player, boss, chooser, true, false); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment