2019-11-08 03:30:41 +00:00
package main
2019-11-08 17:52:19 +00:00
import (
"fmt"
"strings"
)
const (
ArmyTypeImmune = 1 << iota
ArmyTypeInfection
)
2019-11-08 03:30:41 +00:00
type Army struct {
2019-11-08 17:52:19 +00:00
id int
tp int
units int
hp int
immunities [ ] string
weaknesses [ ] string
damageType string
strength int
init int
target * Army
targettedBy * Army
2019-11-08 03:30:41 +00:00
}
2019-11-08 17:52:19 +00:00
func NewArmy ( inp string , tp , id int ) * Army {
2019-11-08 03:30:41 +00:00
a := new ( Army )
a . tp = tp
2019-11-08 17:52:19 +00:00
a . id = id
2019-11-08 03:30:41 +00:00
// 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 )
}
2019-11-08 17:52:19 +00:00
// 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 )
}
}
}
2019-11-08 03:30:41 +00:00
return a
}
2019-11-08 17:52:19 +00:00
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
}
2019-11-08 03:30:41 +00:00
func ( a * Army ) Power ( ) int {
return a . units * a . strength
}
2019-11-08 17:52:19 +00:00
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
}
2019-11-08 03:30:41 +00:00
// Army Sorting
2019-11-08 17:52:19 +00:00
type ByPower [ ] * Army
func ( b ByPower ) Len ( ) int { return len ( b ) }
2019-11-08 03:30:41 +00:00
func ( b ByPower ) Swap ( i , j int ) { b [ i ] , b [ j ] = b [ j ] , b [ i ] }
2019-11-08 17:52:19 +00:00
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 ( )
}