package main import ( "fmt" "strings" ) const ( ArmyTypeImmune = 1 << iota ArmyTypeInfection ) type Army struct { id int tp int units int hp int immunities []string weaknesses []string damageType string strength int init int target *Army targettedBy *Army } func NewArmy(inp string, tp, id int) *Army { a := new(Army) a.tp = tp a.id = id // Pull the parenthetical out, if one is there var prnth, other string var inPrnth bool var ptsOfOther int for _, v := range strings.Fields(inp) { if len(v) > 0 && v[len(v)-1] == ')' { prnth = prnth + " " + v inPrnth = false continue } else if len(v) > 0 && v[0] == '(' { inPrnth = true prnth = v continue } if inPrnth { prnth = prnth + " " + v } else { if len(other) > 0 { other = other + " " } other = other + v ptsOfOther++ } } _, err := fmt.Sscanf(other, "%d units each with %d hit points with an attack that does %d %s damage at initiative %d", &a.units, &a.hp, &a.strength, &a.damageType, &a.init) if err != nil { panic(err) } // Now parse out immunities and weaknesses if len(prnth) > 3 { prnth = prnth[1 : len(prnth)-1] var inImmune bool for _, v := range strings.Fields(prnth) { if v == "immune" { inImmune = true continue } else if v == "weak" { inImmune = false continue } if v == "to" { continue } if v[len(v)-1] == ';' || v[len(v)-1] == ',' { v = v[:len(v)-1] } if inImmune { a.immunities = append(a.immunities, v) } else { a.weaknesses = append(a.weaknesses, v) } } } return a } func (a *Army) IsImmuneTo(val string) bool { for _, v := range a.immunities { if v == val { return true } } return false } func (a *Army) IsWeakTo(val string) bool { for _, v := range a.weaknesses { if v == val { return true } } return false } func (a *Army) Power() int { return a.units * a.strength } func (a *Army) FindTarget(group []*Army) { var tgt *Army var tgtDmg int for _, v := range group { if v.targettedBy != nil { continue } wrkDmg := a.CalculateDamage(v) if tgt == nil || wrkDmg > tgtDmg { tgt = v tgtDmg = wrkDmg } else if wrkDmg == tgtDmg { if v.Power() > tgt.Power() { tgt = v tgtDmg = wrkDmg } else if v.Power() == tgt.Power() { if v.init > tgt.init { tgt = v tgtDmg = wrkDmg } } } if Debug { var tpTxt string if a.tp == ArmyTypeImmune { tpTxt = "Immune System" } else { tpTxt = "Infection" } fmt.Printf("%s group %d would deal defending group %d %d damage\n", tpTxt, a.id, tgt.id, tgtDmg) } } if tgt != nil { a.target = tgt tgt.targettedBy = a } } func (a *Army) CalculateDamage(b *Army) int { if b.IsWeakTo(a.damageType) { return a.Power() * 2 } else if b.IsImmuneTo(a.damageType) { return 0 } return a.Power() } func (a *Army) Damage(b *Army) int { var unitsDefeated int dmg := a.CalculateDamage(b) for dmg > 0 { dmg -= b.hp if dmg > 0 && b.units > 0 { b.units-- unitsDefeated++ } } b.targettedBy = nil return unitsDefeated } func (a *Army) Fight() { if a.target != nil { var tpTxt string if a.tp == ArmyTypeImmune { tpTxt = "Immune System" } else if a.tp == ArmyTypeInfection { tpTxt = "Infection" } dmg := a.Damage(a.target) if Debug { fmt.Printf("%s group %d attacks defending group %d, killing %d units\n", tpTxt, a.id, a.target.id, dmg) } } } func (a Army) String() string { ret := fmt.Sprintf("%d units each with %d hit points ", a.units, a.hp) if len(a.weaknesses) > 0 { ret = ret + fmt.Sprintf("(weaknesses: %s) ", a.weaknesses) } if len(a.immunities) > 0 { ret = ret + fmt.Sprintf("(immunities: %s) ", a.immunities) } ret = ret + fmt.Sprintf("with an attack that does %d %s damage at initiative %d\n", a.strength, a.damageType, a.init, ) return ret } // Army Sorting type ByPower []*Army func (b ByPower) Len() int { return len(b) } func (b ByPower) Swap(i, j int) { b[i], b[j] = b[j], b[i] } func (b ByPower) Less(i, j int) bool { if b[i].Power() == b[j].Power() { return b[i].init < b[j].init } return b[i].Power() < b[j].Power() }