2018 day 24 More work

This commit is contained in:
Brian Buller 2019-11-08 11:52:19 -06:00
parent 4a7a0e872e
commit 10af09b200
4 changed files with 263 additions and 57 deletions

View File

@ -1,6 +1,17 @@
package main package main
import (
"fmt"
"strings"
)
const (
ArmyTypeImmune = 1 << iota
ArmyTypeInfection
)
type Army struct { type Army struct {
id int
tp int tp int
units int units int
hp int hp int
@ -9,11 +20,14 @@ type Army struct {
damageType string damageType string
strength int strength int
init int init int
target *Army
targettedBy *Army
} }
func NewArmy(inp string, tp int) *Army { func NewArmy(inp string, tp, id int) *Army {
a := new(Army) a := new(Army)
a.tp = tp a.tp = tp
a.id = id
// Pull the parenthetical out, if one is there // Pull the parenthetical out, if one is there
var prnth, other string var prnth, other string
@ -45,13 +59,15 @@ func NewArmy(inp string, tp int) *Army {
} }
// Now parse out immunities and weaknesses // Now parse out immunities and weaknesses
if len(prnth) > 3 { if len(prnth) > 3 {
prnth = prnth[1:len(prnth)-1] prnth = prnth[1 : len(prnth)-1]
var inImmune bool var inImmune bool
for _, v := range strings.Fields(prnth) { for _, v := range strings.Fields(prnth) {
if v == "immune" { if v == "immune" {
inImmune = true inImmune = true
continue
} else if v == "weak" { } else if v == "weak" {
inImmune = false inImmune = false
continue
} }
if v == "to" { if v == "to" {
continue continue
@ -69,12 +85,126 @@ func NewArmy(inp string, tp int) *Army {
return a 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 { func (a *Army) Power() int {
return a.units * a.strength 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 // Army Sorting
type ByPower []Army type ByPower []*Army
func (b ByPower) Len() int { return len(b) } 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) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
func (b ByPower) Less(i, j int) { b[i].Power() < b[j].Power() } 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()
}

View File

@ -1,10 +1,72 @@
package main package main
// All Battle Logic is in here import (
func Battle(army1, army2 []Army) { "fmt"
allCombatants = append(army1, army2...) "sort"
sort.Sort(ByPower(allCombatants)) )
for _, v := range allCombatants {
fmt.Print("%d %d %d (%d)\n", v.tp, v.units, v.hp, v.Power()) type Battle struct {
immune []*Army
infect []*Army
}
func NewBattle(immune, infect []*Army) *Battle {
return &Battle{
immune: immune,
infect: infect,
} }
} }
func (b *Battle) PrintStatus() {
fmt.Println("Immune System:")
for _, v := range b.immune {
fmt.Printf("Group %d contains %d units\n", v.id, v.units)
}
fmt.Println("Infection:")
for _, v := range b.infect {
fmt.Printf("Group %d contains %d units\n", v.id, v.units)
}
}
// All Battle Logic is in here
func (b *Battle) Fight() {
allCombatants := append(b.immune, b.infect...)
sort.Sort(ByPower(allCombatants))
for k := len(allCombatants) - 1; k >= 0; k-- {
b.FindTargetFor(allCombatants[k])
}
if Debug {
fmt.Println("")
}
for k := len(allCombatants) - 1; k >= 0; k-- {
allCombatants[k].Fight()
}
i := 0
for _, x := range b.immune {
if x.units > 0 {
b.immune[i] = x
i++
}
}
b.immune = b.immune[:i]
i = 0
for _, x := range b.infect {
if x.units > 0 {
b.infect[i] = x
i++
}
}
b.infect = b.infect[:i]
}
func (b *Battle) FindTargetFor(a *Army) {
if a.tp == ArmyTypeImmune {
a.FindTarget(b.infect)
} else if a.tp == ArmyTypeInfection {
a.FindTarget(b.immune)
}
}
func (b *Battle) IsOver() bool {
return len(b.immune) == 0 || len(b.infect) == 0
}

View File

@ -4,43 +4,50 @@ import (
"bufio" "bufio"
"fmt" "fmt"
"os" "os"
"strings"
) )
const ( const (
ArmyTypeImmune = 1 << iota Debug = true
ArmyTypeInfection
) )
func main() { func main() {
inp := StdinToStringSlice() inp := StdinToStringSlice()
immune, infect := ParseInput(inp) immune, infect := ParseInput(inp)
for _, v := range immune {
fmt.Println("++ ", v.immunities) b := NewBattle(immune, infect)
fmt.Println("-- ", v.weaknesses) //for !b.IsOver() {
if Debug {
b.PrintStatus()
fmt.Println("")
} }
_, _ = immune, infect b.Fight()
//}
fmt.Println("")
fmt.Println("The battle is over!")
b.PrintStatus()
} }
func ParseInput(inp []string) ([]Army, []Army) { func ParseInput(inp []string) ([]*Army, []*Army) {
var immune, infection []Army var immune, infection []*Army
var tp int var tp, id int
for _, v := range inp { for _, v := range inp {
if v == "" { if v == "" {
continue continue
} }
if v == "Immune System:" { if v == "Immune System:" {
tp = ArmyTypeImmune tp, id = ArmyTypeImmune, 0
continue continue
} else if v == "Infection:" { } else if v == "Infection:" {
tp = ArmyTypeInfection tp, id = ArmyTypeInfection, 0
continue continue
} }
id++
switch tp { switch tp {
case ArmyTypeImmune: case ArmyTypeImmune:
immune = append(immune, *NewArmy(v, tp)) immune = append(immune, NewArmy(v, tp, id))
case ArmyTypeInfection: case ArmyTypeInfection:
infection = append(infection, *NewArmy(v, tp)) infection = append(infection, NewArmy(v, tp, id))
} }
} }
return immune, infection return immune, infection

7
2018/day24/testinput Normal file
View File

@ -0,0 +1,7 @@
Immune System:
17 units each with 5390 hit points (weak to radiation, bludgeoning) with an attack that does 4507 fire damage at initiative 2
989 units each with 1274 hit points (immune to fire; weak to bludgeoning, slashing) with an attack that does 25 slashing damage at initiative 3
Infection:
801 units each with 4706 hit points (weak to radiation) with an attack that does 116 bludgeoning damage at initiative 1
4485 units each with 2961 hit points (immune to radiation; weak to fire, cold) with an attack that does 12 slashing damage at initiative 4