1
0
www.mikescher.com/www/statics/aoc/2018/24_solution-2.linq
2019-12-02 14:27:20 +01:00

148 lines
3.9 KiB
C#

<Query Kind="Program" />
class ArmyGroup
{
public string Source;
public int UnitCount;
public int HitPoints;
public List<string> Weakness = new List<string>();
public List<string> Immunity = new List<string>();
public string DamageType;
public int DamageValue;
public int Initiative;
public int EffectivePower => UnitCount * DamageValue;
public bool Alive => UnitCount>0;
public ArmyGroup NextTarget = null;
public bool IsTargeted = false;
}
void Main() => Enumerable.Range(0, int.MaxValue).Select(Calc).First(b=>b>0).Dump();
int Calc(int boost)
{
var groups = Load(File.ReadAllLines(Path.Combine(Path.GetDirectoryName(Util.CurrentQueryPath), @"24_input.txt")));
foreach(var g in groups.Where(p => p.Source=="ImmuneSystem")) g.DamageValue += boost;
for (int gen = 0; ; gen++)
{
if (!(groups.GroupBy(g => g.Source).All(g => g.Any(a => a.Alive)))) break;
bool dmg = Fight(groups);
if (!dmg) return 0;
}
return groups.Where(p => p.Source=="ImmuneSystem").Sum(p => p.UnitCount) - groups.Where(p => p.Source=="Infection").Sum(p => p.UnitCount);
}
List<ArmyGroup> Load(string[] lines)
{
return new[]
{
lines.Skip(1).TakeWhile(l => !string.IsNullOrWhiteSpace(l)).Select(l => LoadSingle("ImmuneSystem", l)),
lines.Skip(1).SkipWhile(l => !string.IsNullOrWhiteSpace(l)).Skip(2).Select(l => LoadSingle("Infection", l))
}
.SelectMany(p=>p)
.ToList();
}
ArmyGroup LoadSingle(string src, string line)
{
var ag = new ArmyGroup { Source=src };
var i1 = line.IndexOf(' ');
ag.UnitCount = int.Parse(line.Substring(0, i1).Trim());
line = line.Substring(i1).Trim().Substring(15).Trim();
var i6 = line.IndexOf(' ');
ag.HitPoints = int.Parse(line.Substring(0, i6).Trim());
line = line.Substring(i6).Trim().Substring(11).Trim();
var i2 = line.IndexOf(')');
if (i2 != -1)
{
var spec0 = line.Substring(1, i2).TrimEnd(')');
line = line.Substring(1).Substring(i2).Substring(1).Trim();
foreach (var spc in spec0.Split(';').Select(p => p.Trim()))
{
if (spc.StartsWith("weak to")) ag.Weakness.AddRange(spc.Substring("weak to".Length).Trim().Split(',').Select(p => p.Trim()));
if (spc.StartsWith("immune to")) ag.Immunity.AddRange(spc.Substring("immune to".Length).Trim().Split(',').Select(p => p.Trim()));
}
}
line = line.Substring(25).Trim();
var i3 = line.IndexOf(' ');
ag.DamageValue = int.Parse(line.Substring(0, i3).Trim());
line = line.Substring(i3).Trim().Trim();
var i4 = line.IndexOf(' ');
ag.DamageType = line.Substring(0, i4).Trim();
line = line.Substring(i4).Trim().Trim();
var i5 = line.LastIndexOf(' ');
ag.Initiative = int.Parse(line.Substring(i5).Trim());
return ag;
}
bool Fight(List<ArmyGroup> groups)
{
// PHASE 1
foreach (var g in groups) { g.IsTargeted=false; g.NextTarget=null; }
foreach (var g in groups.Where(g => g.Alive).OrderByDescending(g => g.EffectivePower).ThenByDescending(g => g.Initiative))
{
SelectTarget(g, groups);
}
// PHASE 2
bool d = false;
foreach (var g in groups.Where(g => g.Alive).OrderByDescending(g => g.Initiative).Where(g => g.NextTarget!=null))
{
var a = Attack(g, g.NextTarget);
if (a)d=true;
}
return d;
}
void SelectTarget(ArmyGroup att, List<ArmyGroup> groups)
{
att.NextTarget = groups
.Where(g => g.Alive)
.Where(g => g.Source != att.Source)
.Where(g => !g.IsTargeted)
.Where(g => CalcFullDamage(att, g)>0)
.OrderByDescending(g => CalcFullDamage(att, g))
.ThenByDescending(g => g.EffectivePower)
.ThenByDescending(g => g.Initiative)
.FirstOrDefault();
if (att.NextTarget != null) att.NextTarget.IsTargeted = true;
}
int CalcFullDamage(ArmyGroup att, ArmyGroup def)
{
if (att.UnitCount==0) return 0;
var dmg = att.EffectivePower;
if (def.Immunity.Contains(att.DamageType)) return 0;
if (def.Weakness.Contains(att.DamageType)) return dmg*2;
return dmg;
}
bool Attack(ArmyGroup att, ArmyGroup def)
{
var dmg = CalcFullDamage(att, def);
var kill = (int)(dmg / def.HitPoints);
def.UnitCount -= kill;
if (def.UnitCount<0) def.UnitCount = 0;
return kill>0;
}