2018 Day 24 Done
This commit is contained in:
@@ -2,71 +2,160 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
helpers2017 "bitbucket.org/thezeez/advent-of-code-2017/helpers"
|
||||
)
|
||||
|
||||
type Battle struct {
|
||||
immune []*Army
|
||||
infect []*Army
|
||||
}
|
||||
type Battlefield map[int]Army
|
||||
|
||||
func NewBattle(immune, infect []*Army) *Battle {
|
||||
return &Battle{
|
||||
immune: immune,
|
||||
infect: infect,
|
||||
}
|
||||
}
|
||||
var (
|
||||
armyName = regexp.MustCompile(`^(.*):$`)
|
||||
groupImmunities = regexp.MustCompile(`immune to (.*?)[;)]`)
|
||||
groupWeaknesses = regexp.MustCompile(`weak to (.*?)[;)]`)
|
||||
groupDescription = regexp.MustCompile(`^(\d+) units each with (\d+) hit points.*with an attack that does (\d+) (\w+) damage at initiative (\d+)$`)
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
const (
|
||||
descriptionCount = iota + 1
|
||||
descriptionHitPoints
|
||||
descriptionDamage
|
||||
descriptionDamageType
|
||||
descriptionInitiative
|
||||
)
|
||||
|
||||
// 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++
|
||||
func PrepareForBattle(input []string) (Battlefield, Initiative) {
|
||||
var initiative Initiative
|
||||
battle := make(Battlefield)
|
||||
var currentArmy int
|
||||
|
||||
for _, line := range input {
|
||||
if armyName.MatchString(line) {
|
||||
if id, ok := StringArmies[armyName.FindStringSubmatch(line)[1]]; ok {
|
||||
currentArmy = id
|
||||
} else {
|
||||
panic(fmt.Errorf("unknown army: %s", armyName.FindStringSubmatch(line)[1]))
|
||||
}
|
||||
} else {
|
||||
if currentArmy <= 0 || currentArmy >= ArmyCount {
|
||||
panic(fmt.Errorf("tried to assign group to invalid army: %d", currentArmy))
|
||||
}
|
||||
description := groupDescription.FindStringSubmatch(line)
|
||||
if len(description) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
group := &Group{
|
||||
Units: helpers2017.IntOrPanic(description[descriptionCount]),
|
||||
HitPoints: helpers2017.IntOrPanic(description[descriptionHitPoints]),
|
||||
AttackDamage: helpers2017.IntOrPanic(description[descriptionDamage]),
|
||||
AttackType: description[descriptionDamageType],
|
||||
Initiative: helpers2017.IntOrPanic(description[descriptionInitiative]),
|
||||
}
|
||||
|
||||
immunities := groupImmunities.FindStringSubmatch(line)
|
||||
if len(immunities) > 0 {
|
||||
group.Immunities = strings.Split(immunities[1], ", ")
|
||||
}
|
||||
|
||||
weaknesses := groupWeaknesses.FindStringSubmatch(line)
|
||||
if len(weaknesses) > 0 {
|
||||
group.Weaknesses = strings.Split(weaknesses[1], ", ")
|
||||
}
|
||||
|
||||
battle[currentArmy] = append(battle[currentArmy], group)
|
||||
initiative = append(initiative, group)
|
||||
}
|
||||
}
|
||||
b.immune = b.immune[:i]
|
||||
i = 0
|
||||
for _, x := range b.infect {
|
||||
if x.units > 0 {
|
||||
b.infect[i] = x
|
||||
i++
|
||||
|
||||
return battle, initiative
|
||||
}
|
||||
|
||||
func (b Battlefield) FindTargets() {
|
||||
for army, groups := range b {
|
||||
sort.Sort(groups)
|
||||
for _, group := range groups {
|
||||
for enemyArmy, enemyGroups := range b {
|
||||
if army == enemyArmy || group.Units <= 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
var mostDamage int
|
||||
var targetGroup *Group
|
||||
|
||||
for _, enemyGroup := range enemyGroups {
|
||||
if enemyGroup.Units <= 0 || enemyGroup.Attacker != nil || group.DamageDealt(enemyGroup) == 0 || group.DamageDealt(enemyGroup) < mostDamage {
|
||||
continue
|
||||
}
|
||||
if group.DamageDealt(enemyGroup) == mostDamage && targetGroup != nil {
|
||||
if enemyGroup.EffectivePower() < targetGroup.EffectivePower() {
|
||||
continue
|
||||
}
|
||||
if enemyGroup.EffectivePower() == targetGroup.EffectivePower() && enemyGroup.Initiative < targetGroup.Initiative {
|
||||
continue
|
||||
}
|
||||
}
|
||||
mostDamage = group.DamageDealt(enemyGroup)
|
||||
targetGroup = enemyGroup
|
||||
}
|
||||
if targetGroup != nil {
|
||||
group.Target = targetGroup
|
||||
targetGroup.Attacker = group
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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 Battlefield) Clean() {
|
||||
for army := range b {
|
||||
c := b[army][:0]
|
||||
for _, g := range b[army] {
|
||||
if g.Units > 0 {
|
||||
c = append(c, g)
|
||||
}
|
||||
}
|
||||
b[army] = c
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Battle) IsOver() bool {
|
||||
return len(b.immune) == 0 || len(b.infect) == 0
|
||||
func (b Battlefield) Active() bool {
|
||||
for _, a := range b {
|
||||
if !a.Alive() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (b Battlefield) Result() (int, int) {
|
||||
var winner, units int
|
||||
|
||||
for army, groups := range b {
|
||||
if groups.Alive() {
|
||||
winner = army
|
||||
|
||||
for _, g := range groups {
|
||||
if g.Units > 0 {
|
||||
units += g.Units
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return winner, units
|
||||
}
|
||||
|
||||
func (b Battlefield) TotalUnits() int {
|
||||
var sum int
|
||||
for _, groups := range b {
|
||||
for _, group := range groups {
|
||||
if group.Units > 0 {
|
||||
sum += group.Units
|
||||
}
|
||||
}
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user