2018 Day 24 Done
This commit is contained in:
		| @@ -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() | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
| } | ||||
|   | ||||
							
								
								
									
										52
									
								
								2018/day24/group.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								2018/day24/group.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
							
								
								
									
										44
									
								
								2018/day24/initiative.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								2018/day24/initiative.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 | ||||
| } | ||||
| @@ -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 | ||||
|   | ||||
							
								
								
									
										2
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								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 | ||||
|   | ||||
							
								
								
									
										4
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								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= | ||||
|   | ||||
		Reference in New Issue
	
	Block a user