From 83313cc77bd9e89094c29d2f3be6c6375f0c52cc Mon Sep 17 00:00:00 2001 From: Brian Buller Date: Fri, 8 Nov 2019 12:40:42 -0600 Subject: [PATCH] 2018 Day 24 Done --- 2018/day24/army.go | 218 +++---------------------- 2018/day24/combat.go | 193 ++++++++++++++++------ 2018/day24/day24.go | 93 +++++++---- 2018/day24/group.go | 52 ++++++ 2018/day24/initiative.go | 44 +++++ 2018/day24/problem | 344 +++++++++++++++++++++++++-------------- go.mod | 2 + go.sum | 4 + 8 files changed, 548 insertions(+), 402 deletions(-) create mode 100644 2018/day24/group.go create mode 100644 2018/day24/initiative.go diff --git a/2018/day24/army.go b/2018/day24/army.go index 2afa327..97effdf 100644 --- a/2018/day24/army.go +++ b/2018/day24/army.go @@ -1,210 +1,44 @@ package main -import ( - "fmt" - "strings" -) +type Army []*Group const ( - ArmyTypeImmune = 1 << iota - ArmyTypeInfection + ArmyImmuneSystem = iota + 1 + ArmyInfection + ArmyCount ) -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 +var StringArmies = map[string]int{ + "Immune System": ArmyImmuneSystem, + "Infection": ArmyInfection, } -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) Swap(i, j int) { + a[i], a[j] = a[j], a[i] } -func (a *Army) IsImmuneTo(val string) bool { - for _, v := range a.immunities { - if v == val { +func (a Army) Len() int { + return len(a) +} + +func (a Army) Less(i, j int) bool { + if a[i].EffectivePower() > a[j].EffectivePower() { + return true + } + return a[i].EffectivePower() == a[j].EffectivePower() && a[i].Initiative > a[j].Initiative +} + +func (a Army) Alive() bool { + for _, g := range a { + if g.Units > 0 { 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) Boost(amount int) { + for _, g := range a { + g.AttackDamage += amount } } - -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() -} diff --git a/2018/day24/combat.go b/2018/day24/combat.go index e5248cd..f61ce6b 100644 --- a/2018/day24/combat.go +++ b/2018/day24/combat.go @@ -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 } diff --git a/2018/day24/day24.go b/2018/day24/day24.go index 1cad1a4..934f6d3 100644 --- a/2018/day24/day24.go +++ b/2018/day24/day24.go @@ -12,45 +12,57 @@ const ( func main() { inp := StdinToStringSlice() - immune, infect := ParseInput(inp) - - b := NewBattle(immune, infect) - //for !b.IsOver() { - if Debug { - b.PrintStatus() - fmt.Println("") - } - b.Fight() - //} - - fmt.Println("") - fmt.Println("The battle is over!") - b.PrintStatus() + fmt.Println(ConditionFight(inp)) + fmt.Println(ImmuneSystemBoost(inp)) } -func ParseInput(inp []string) ([]*Army, []*Army) { - var immune, infection []*Army - var tp, id int - for _, v := range inp { - if v == "" { - continue - } - if v == "Immune System:" { - tp, id = ArmyTypeImmune, 0 - continue - } else if v == "Infection:" { - tp, id = ArmyTypeInfection, 0 - continue - } - id++ - switch tp { - case ArmyTypeImmune: - immune = append(immune, NewArmy(v, tp, id)) - case ArmyTypeInfection: - infection = append(infection, NewArmy(v, tp, id)) - } +func ConditionFight(input []string) int { + battle, initiative := PrepareForBattle(input) + + for battle.Active() { + battle.FindTargets() + initiative.Attack() + + battle.Clean() + initiative.Clean() + } + + _, units := battle.Result() + return units +} + +func ImmuneSystemBoost(input []string) int { + var boost int + + for { + var stalemate bool + battle, initiative := PrepareForBattle(input) + + battle[ArmyImmuneSystem].Boost(boost) + + for battle.Active() { + before := battle.TotalUnits() + + battle.FindTargets() + initiative.Attack() + + if battle.TotalUnits() == before { + stalemate = true + break + } + battle.Clean() + initiative.Clean() + } + + if !stalemate { + winner, units := battle.Result() + if winner == ArmyImmuneSystem { + return units + } + } + + boost++ } - return immune, infection } func StdinToStringSlice() []string { @@ -61,3 +73,12 @@ func StdinToStringSlice() []string { } return input } + +func ContainsString(l []string, t string) bool { + for _, s := range l { + if s == t { + return true + } + } + return false +} diff --git a/2018/day24/group.go b/2018/day24/group.go new file mode 100644 index 0000000..fa5d8ec --- /dev/null +++ b/2018/day24/group.go @@ -0,0 +1,52 @@ +package main + +import ( + "fmt" + "strings" +) + +type Group struct { + Units int + HitPoints int + AttackDamage int + AttackType string + Initiative int + Immunities []string + Weaknesses []string + + Attacker *Group + Target *Group +} + +func (g Group) EffectivePower() int { + return g.Units * g.AttackDamage +} + +func (g Group) DamageDealt(e *Group) int { + if ContainsString(e.Immunities, g.AttackType) { + return 0 + } + if ContainsString(e.Weaknesses, g.AttackType) { + return g.EffectivePower() * 2 + } + return g.EffectivePower() +} + +func (g Group) String() string { + out := fmt.Sprintf("%d units each with %d hit points", g.Units, g.HitPoints) + if len(g.Immunities) > 0 || len(g.Weaknesses) > 0 { + out += " (" + if len(g.Immunities) > 0 { + out += "immune to " + strings.Join(g.Immunities, " and ") + if len(g.Weaknesses) > 0 { + out += "; " + } + } + if len(g.Weaknesses) > 0 { + out += "weak to " + strings.Join(g.Weaknesses, " and ") + } + out += ")" + } + out += fmt.Sprintf(" with an attack that does %d %s damage at initiative %d", g.AttackDamage, g.AttackType, g.Initiative) + return out +} diff --git a/2018/day24/initiative.go b/2018/day24/initiative.go new file mode 100644 index 0000000..bcb7c0a --- /dev/null +++ b/2018/day24/initiative.go @@ -0,0 +1,44 @@ +package main + +import ( + "sort" +) + +type Initiative []*Group + +func (in Initiative) Len() int { + return len(in) +} + +func (in Initiative) Swap(i, j int) { + in[i], in[j] = in[j], in[i] +} + +func (in Initiative) Less(i, j int) bool { + return in[i].Initiative > in[j].Initiative +} + +func (in Initiative) Attack() { + sort.Sort(in) + + for _, group := range in { + if group.Units > 0 && group.Target != nil && group.Target.Units > 0 { + group.Target.Units -= group.DamageDealt(group.Target) / group.Target.HitPoints + } + if group.Target != nil { + group.Target.Attacker = nil + group.Target = nil + } + } +} + +func (in *Initiative) Clean() { + c := (*in)[:0] + for _, g := range *in { + if g.Units > 0 { + c = append(c, g) + } + } + sort.Sort(c) + *in = c +} diff --git a/2018/day24/problem b/2018/day24/problem index 7d11b12..7f8dcb2 100644 --- a/2018/day24/problem +++ b/2018/day24/problem @@ -72,143 +72,242 @@ Advent of Code For example, consider the following armies: - 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 + 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 + 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 - If these armies were to enter combat, the following fights, including details during the target selection and attacking phases, would take place: + If these armies were to enter combat, the following fights, including + details during the target selection and attacking phases, would take place: - Immune System: - Group 1 contains 17 units - Group 2 contains 989 units - Infection: - Group 1 contains 801 units - Group 2 contains 4485 units + Immune System: Group 1 contains 17 units Group 2 contains 989 units Infection: + Group 1 contains 801 units Group 2 contains 4485 units - Infection group 1 would deal defending group 1 185832 damage - Infection group 1 would deal defending group 2 185832 damage - Infection group 2 would deal defending group 2 107640 damage - Immune System group 1 would deal defending group 1 76619 damage - Immune System group 1 would deal defending group 2 153238 damage - Immune System group 2 would deal defending group 1 24725 damage + Infection group 1 would deal defending group 1 185832 damage Infection group 1 + would deal defending group 2 185832 damage Infection group 2 would deal + defending group 2 107640 damage Immune System group 1 would deal defending + group 1 76619 damage Immune System group 1 would deal defending group 2 153238 + damage Immune System group 2 would deal defending group 1 24725 damage - Infection group 2 attacks defending group 2, killing 84 units - Immune System group 2 attacks defending group 1, killing 4 units - Immune System group 1 attacks defending group 2, killing 51 units - Infection group 1 attacks defending group 1, killing 17 units + Infection group 2 attacks defending group 2, killing 84 units Immune System + group 2 attacks defending group 1, killing 4 units Immune System group 1 + attacks defending group 2, killing 51 units Infection group 1 attacks + defending group 1, killing 17 units - Immune System: - Group 2 contains 905 units - Infection: - Group 1 contains 797 units + Immune System: Group 2 contains 905 units Infection: Group 1 contains 797 + units Group 2 contains 4434 units + + Infection group 1 would deal defending group 2 184904 damage Immune System + group 2 would deal defending group 1 22625 damage Immune System group 2 would + deal defending group 2 22625 damage + + Immune System group 2 attacks defending group 1, killing 4 units Infection + group 1 attacks defending group 2, killing 144 units + + Immune System: Group 2 contains 761 units Infection: Group 1 contains 793 + units Group 2 contains 4434 units + + Infection group 1 would deal defending group 2 183976 damage Immune System + group 2 would deal defending group 1 19025 damage Immune System group 2 would + deal defending group 2 19025 damage + + Immune System group 2 attacks defending group 1, killing 4 units Infection + group 1 attacks defending group 2, killing 143 units + + Immune System: Group 2 contains 618 units Infection: Group 1 contains 789 + units Group 2 contains 4434 units + + Infection group 1 would deal defending group 2 183048 damage Immune System + group 2 would deal defending group 1 15450 damage Immune System group 2 would + deal defending group 2 15450 damage + + Immune System group 2 attacks defending group 1, killing 3 units Infection + group 1 attacks defending group 2, killing 143 units + + Immune System: Group 2 contains 475 units Infection: Group 1 contains 786 + units Group 2 contains 4434 units + + Infection group 1 would deal defending group 2 182352 damage Immune System + group 2 would deal defending group 1 11875 damage Immune System group 2 would + deal defending group 2 11875 damage + + Immune System group 2 attacks defending group 1, killing 2 units Infection + group 1 attacks defending group 2, killing 142 units + + Immune System: Group 2 contains 333 units Infection: Group 1 contains 784 + units Group 2 contains 4434 units + + Infection group 1 would deal defending group 2 181888 damage Immune System + group 2 would deal defending group 1 8325 damage Immune System group 2 would + deal defending group 2 8325 damage + + Immune System group 2 attacks defending group 1, killing 1 unit Infection + group 1 attacks defending group 2, killing 142 units + + Immune System: Group 2 contains 191 units Infection: Group 1 contains 783 + units Group 2 contains 4434 units + + Infection group 1 would deal defending group 2 181656 damage Immune System + group 2 would deal defending group 1 4775 damage Immune System group 2 would + deal defending group 2 4775 damage + + Immune System group 2 attacks defending group 1, killing 1 unit Infection + group 1 attacks defending group 2, killing 142 units + + Immune System: Group 2 contains 49 units Infection: Group 1 contains 782 units Group 2 contains 4434 units - Infection group 1 would deal defending group 2 184904 damage - Immune System group 2 would deal defending group 1 22625 damage - Immune System group 2 would deal defending group 2 22625 damage + Infection group 1 would deal defending group 2 181424 damage Immune System + group 2 would deal defending group 1 1225 damage Immune System group 2 would + deal defending group 2 1225 damage - Immune System group 2 attacks defending group 1, killing 4 units - Infection group 1 attacks defending group 2, killing 144 units + Immune System group 2 attacks defending group 1, killing 0 units Infection + group 1 attacks defending group 2, killing 49 units - Immune System: - Group 2 contains 761 units - Infection: - Group 1 contains 793 units - Group 2 contains 4434 units - - Infection group 1 would deal defending group 2 183976 damage - Immune System group 2 would deal defending group 1 19025 damage - Immune System group 2 would deal defending group 2 19025 damage - - Immune System group 2 attacks defending group 1, killing 4 units - Infection group 1 attacks defending group 2, killing 143 units - - Immune System: - Group 2 contains 618 units - Infection: - Group 1 contains 789 units - Group 2 contains 4434 units - - Infection group 1 would deal defending group 2 183048 damage - Immune System group 2 would deal defending group 1 15450 damage - Immune System group 2 would deal defending group 2 15450 damage - - Immune System group 2 attacks defending group 1, killing 3 units - Infection group 1 attacks defending group 2, killing 143 units - - Immune System: - Group 2 contains 475 units - Infection: - Group 1 contains 786 units - Group 2 contains 4434 units - - Infection group 1 would deal defending group 2 182352 damage - Immune System group 2 would deal defending group 1 11875 damage - Immune System group 2 would deal defending group 2 11875 damage - - Immune System group 2 attacks defending group 1, killing 2 units - Infection group 1 attacks defending group 2, killing 142 units - - Immune System: - Group 2 contains 333 units - Infection: - Group 1 contains 784 units - Group 2 contains 4434 units - - Infection group 1 would deal defending group 2 181888 damage - Immune System group 2 would deal defending group 1 8325 damage - Immune System group 2 would deal defending group 2 8325 damage - - Immune System group 2 attacks defending group 1, killing 1 unit - Infection group 1 attacks defending group 2, killing 142 units - - Immune System: - Group 2 contains 191 units - Infection: - Group 1 contains 783 units - Group 2 contains 4434 units - - Infection group 1 would deal defending group 2 181656 damage - Immune System group 2 would deal defending group 1 4775 damage - Immune System group 2 would deal defending group 2 4775 damage - - Immune System group 2 attacks defending group 1, killing 1 unit - Infection group 1 attacks defending group 2, killing 142 units - - Immune System: - Group 2 contains 49 units - Infection: - Group 1 contains 782 units - Group 2 contains 4434 units - - Infection group 1 would deal defending group 2 181424 damage - Immune System group 2 would deal defending group 1 1225 damage - Immune System group 2 would deal defending group 2 1225 damage - - Immune System group 2 attacks defending group 1, killing 0 units - Infection group 1 attacks defending group 2, killing 49 units - - Immune System: - No groups remain. - Infection: - Group 1 contains 782 units - Group 2 contains 4434 units + Immune System: No groups remain. Infection: Group 1 contains 782 units Group 2 + contains 4434 units In the example above, the winning army ends up with 782 + 4434 = 5216 units. - You scan the reindeer's condition (your puzzle input); the white-bearded man looks nervous. As it stands now, how many units would the winning army have? + You scan the reindeer's condition (your puzzle input); the white-bearded man + looks nervous. As it stands now, how many units would the winning army have? - To begin, get your puzzle input. + Your puzzle answer was 16747. - Answer: _____________________ [ [Submit] ] +--- Part Two --- + + Things aren't looking good for the reindeer. The man asks whether more milk + and cookies would help you think. + + If only you could give the reindeer's immune system a boost, you might be + able to change the outcome of the combat. + + A boost is an integer increase in immune system units' attack damage. For + example, if you were to boost the above example's immune system's units by + 1570, the armies would instead look like this: + + Immune System: 17 units each with 5390 hit points (weak to radiation, + bludgeoning) with an attack that does 6077 fire damage at initiative 2 989 + units each with 1274 hit points (immune to fire; weak to bludgeoning, + slashing) with an attack that does 1595 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 + + With this boost, the combat proceeds differently: + + Immune System: Group 2 contains 989 units Group 1 contains 17 units Infection: + Group 1 contains 801 units Group 2 contains 4485 units + + Infection group 1 would deal defending group 2 185832 damage Infection group 1 + would deal defending group 1 185832 damage Infection group 2 would deal + defending group 1 53820 damage Immune System group 2 would deal defending + group 1 1577455 damage Immune System group 2 would deal defending group 2 + 1577455 damage Immune System group 1 would deal defending group 2 206618 + damage + + Infection group 2 attacks defending group 1, killing 9 units Immune System + group 2 attacks defending group 1, killing 335 units Immune System group 1 + attacks defending group 2, killing 32 units Infection group 1 attacks + defending group 2, killing 84 units + + Immune System: Group 2 contains 905 units Group 1 contains 8 units Infection: + Group 1 contains 466 units Group 2 contains 4453 units + + Infection group 1 would deal defending group 2 108112 damage Infection group 1 + would deal defending group 1 108112 damage Infection group 2 would deal + defending group 1 53436 damage Immune System group 2 would deal defending + group 1 1443475 damage Immune System group 2 would deal defending group 2 + 1443475 damage Immune System group 1 would deal defending group 2 97232 damage + + Infection group 2 attacks defending group 1, killing 8 units Immune System + group 2 attacks defending group 1, killing 306 units Infection group 1 attacks + defending group 2, killing 29 units + + Immune System: Group 2 contains 876 units Infection: Group 2 contains 4453 + units Group 1 contains 160 units + + Infection group 2 would deal defending group 2 106872 damage Immune System + group 2 would deal defending group 2 1397220 damage Immune System group 2 + would deal defending group 1 1397220 damage + + Infection group 2 attacks defending group 2, killing 83 units Immune System + group 2 attacks defending group 2, killing 427 units + + After a few fights... + + Immune System: Group 2 contains 64 units Infection: Group 2 contains 214 units + Group 1 contains 19 units + + Infection group 2 would deal defending group 2 5136 damage Immune System group + 2 would deal defending group 2 102080 damage Immune System group 2 would deal + defending group 1 102080 damage + + Infection group 2 attacks defending group 2, killing 4 units Immune System + group 2 attacks defending group 2, killing 32 units + + Immune System: Group 2 contains 60 units Infection: Group 1 contains 19 units + Group 2 contains 182 units + + Infection group 1 would deal defending group 2 4408 damage Immune System group + 2 would deal defending group 1 95700 damage Immune System group 2 would deal + defending group 2 95700 damage + + Immune System group 2 attacks defending group 1, killing 19 units + + Immune System: Group 2 contains 60 units Infection: Group 2 contains 182 units + + Infection group 2 would deal defending group 2 4368 damage Immune System group + 2 would deal defending group 2 95700 damage + + Infection group 2 attacks defending group 2, killing 3 units Immune System + group 2 attacks defending group 2, killing 30 units + + After a few more fights... + + Immune System: Group 2 contains 51 units Infection: Group 2 contains 40 units + + Infection group 2 would deal defending group 2 960 damage Immune System group + 2 would deal defending group 2 81345 damage + + Infection group 2 attacks defending group 2, killing 0 units Immune System + group 2 attacks defending group 2, killing 27 units + + Immune System: Group 2 contains 51 units Infection: Group 2 contains 13 units + + Infection group 2 would deal defending group 2 312 damage Immune System group + 2 would deal defending group 2 81345 damage + + Infection group 2 attacks defending group 2, killing 0 units Immune System + group 2 attacks defending group 2, killing 13 units + + Immune System: Group 2 contains 51 units Infection: No groups remain. + + This boost would allow the immune system's armies to win! It would be left + with 51 units. + + You don't even know how you could boost the reindeer's immune system or what + effect it might have, so you need to be cautious and find the smallest boost + that would allow the immune system to win. + + How many units does the immune system have left after getting the smallest + boost it needs to win? + + Your puzzle answer was 5923. + + Both parts of this puzzle are complete! They provide two gold stars: ** + + At this point, you should return to your Advent calendar and try another + puzzle. + + If you still want to see it, you can get your puzzle input. References @@ -228,4 +327,5 @@ References . https://adventofcode.com/2018/stats . https://adventofcode.com/2018/sponsors . https://www.youtube.com/watch?v=NDVjLt_QHL8&t=7 + . https://adventofcode.com/2018 . https://adventofcode.com/2018/day/24/input diff --git a/go.mod b/go.mod index f075442..18266f7 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,8 @@ module aoc require ( 9fans.net/go v0.0.0-20181112161441-237454027057 // indirect + bitbucket.org/thezeez/advent-of-code-2017 v0.0.0-20171225063809-1918042ef639 + bitbucket.org/thezeez/advent-of-code-2018 v0.0.0-20181225065213-533e12eb8451 // indirect github.com/alecthomas/gometalinter v2.0.11+incompatible // indirect github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf // indirect github.com/cosiner/argv v0.0.1 // indirect diff --git a/go.sum b/go.sum index 48d51bf..dfbff24 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,10 @@ 9fans.net/go v0.0.0-20150709035532-65b8cf069318/go.mod h1:diCsxrliIURU9xsYtjCp5AbpQKqdhKmf0ujWDUSkfoY= 9fans.net/go v0.0.0-20181112161441-237454027057 h1:OcHlKWkAMJEF1ndWLGxp5dnJQkYM/YImUOvsBoz6h5E= 9fans.net/go v0.0.0-20181112161441-237454027057/go.mod h1:diCsxrliIURU9xsYtjCp5AbpQKqdhKmf0ujWDUSkfoY= +bitbucket.org/thezeez/advent-of-code-2017 v0.0.0-20171225063809-1918042ef639 h1:DsF/Ldc/v0ftwLoE1WFJ1yAAkzK4XJ0Rx6Ww87AWFdo= +bitbucket.org/thezeez/advent-of-code-2017 v0.0.0-20171225063809-1918042ef639/go.mod h1:0hCXmcMGkJQ6c4PhTVJLrbCvsxRpLoq84HQE8u8fFeY= +bitbucket.org/thezeez/advent-of-code-2018 v0.0.0-20181225065213-533e12eb8451 h1:IFdtuKSjoogiNOcVqsANmYqy3jR2+AYdKolN6fDO2rg= +bitbucket.org/thezeez/advent-of-code-2018 v0.0.0-20181225065213-533e12eb8451/go.mod h1:EmAD0MqW6nbmxrTlT7Lvzjv22xm5tcKgu6k0sBIMf6Y= github.com/alecthomas/gometalinter v2.0.11+incompatible h1:toROE7pXPU/pUB4lh6ICqUKwpDtmkRCyJIr1nYqmKp0= github.com/alecthomas/gometalinter v2.0.11+incompatible/go.mod h1:qfIpQGGz3d+NmgyPBqv+LSh50emm1pt72EtcX2vKYQk= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=