adventofcode/2015/day21/main.go

222 lines
4.6 KiB
Go

package main
import (
"fmt"
"os"
"strconv"
)
var enemyHp int
var enemyDmg int
var enemyDef int
var weaponsAvailable []weapon
var armorAvailable []armor
var ringsAvailable []ring
var currWeapon, cheapWeapon, highWeapon weapon
var currArmor, cheapArmor, highArmor armor
var currRing1, cheapRing1, highRing1 ring
var currRing2, cheapRing2, highRing2 ring
// My input: ./day21 100 8 2
func main() {
if len(os.Args) < 4 || os.Args[1] == "-help" {
fmt.Println("Usage: day21 <enemy hp> <enemy dmg> <enemy def")
os.Exit(1)
}
enemyHp = mustAtoi(os.Args[1])
enemyDmg = mustAtoi(os.Args[2])
enemyDef = mustAtoi(os.Args[3])
cheapest := -1
highest := -1
initShop()
for wi := range weaponsAvailable {
currWeapon = weaponsAvailable[wi]
for ai := range armorAvailable {
currArmor = armorAvailable[ai]
for r1i := range ringsAvailable {
currRing1 = ringsAvailable[r1i]
for r2i := range ringsAvailable {
if r2i == r1i {
continue
}
currRing2 = ringsAvailable[r2i]
if toTheDeath(false) {
if calcCost() < cheapest || cheapest == -1 {
cheapest = calcCost()
saveCheapest()
}
} else {
if calcCost() > highest || highest == -1 {
highest = calcCost()
saveHighest()
}
}
}
}
}
}
if cheapest >= 0 {
fmt.Println("Cheapest Victory: " + itoa(cheapest))
fmt.Println("Weapon: " + cheapWeapon.name)
fmt.Println("Armor: " + cheapArmor.name)
fmt.Println("Ring1: " + cheapRing1.name)
fmt.Println("Ring2: " + cheapRing2.name)
loadCheapest()
toTheDeath(true)
} else {
fmt.Println("No victory to be had.")
}
fmt.Println()
if highest >= 0 {
fmt.Println("Most Expensive Loss: " + itoa(highest))
fmt.Println("Weapon: " + highWeapon.name)
fmt.Println("Armor: " + highArmor.name)
fmt.Println("Ring1: " + highRing1.name)
fmt.Println("Ring2: " + highRing2.name)
loadHighest()
toTheDeath(true)
} else {
fmt.Println("No victory to be had.")
}
}
func loadCheapest() {
currWeapon = cheapWeapon
currArmor = cheapArmor
currRing1 = cheapRing1
currRing2 = cheapRing2
}
func saveCheapest() {
cheapWeapon = currWeapon
cheapArmor = currArmor
cheapRing1 = currRing1
cheapRing2 = currRing2
}
func loadHighest() {
currWeapon = highWeapon
currArmor = highArmor
currRing1 = highRing1
currRing2 = highRing2
}
func saveHighest() {
highWeapon = currWeapon
highArmor = currArmor
highRing1 = currRing1
highRing2 = currRing2
}
func toTheDeath(output bool) bool {
var pHp, pDmg, pDef, eHp, eDmg, eDef int
pHp = 100
pDmg += currWeapon.damage
pDmg += currRing1.damage
pDmg += currRing2.damage
pDef += currArmor.defense
pDef += currRing1.defense
pDef += currRing2.defense
eHp = enemyHp
eDmg = enemyDmg
eDef = enemyDef
for pHp > 0 && eHp > 0 {
pAtk := pDmg - eDef
if pAtk <= 1 {
pAtk = 1
}
eHp -= pAtk
eAtk := 1
if eHp > 0 {
eAtk = eDmg - pDef
if eAtk <= 1 {
eAtk = 1
}
pHp -= eAtk
}
}
if output {
fmt.Print(itoa(calcCost()) + ": ")
fmt.Print(itoa(pHp) + " to " + itoa(eHp) + " ")
fmt.Println("DMG(" + itoa(pDmg) + ") DEF(" + itoa(pDef) + ") ")
}
return pHp > 0
}
func calcCost() int {
return currWeapon.cost + currArmor.cost + currRing1.cost + currRing2.cost
}
func initShop() {
addWeapon("Dagger", 8, 4)
addWeapon("Shortsword", 10, 5)
addWeapon("Warhammer", 25, 6)
addWeapon("Longsword", 40, 7)
addWeapon("Greataxe", 74, 8)
addArmor("Leather", 13, 1)
addArmor("Chainmail", 31, 2)
addArmor("Splintmail", 53, 3)
addArmor("Bandedmail", 75, 4)
addArmor("Platemail", 102, 5)
addArmor("No Armor", 0, 0)
addRing("Damage +1", 25, 1, 0)
addRing("Damage +2", 50, 2, 0)
addRing("Damage +3", 100, 3, 0)
addRing("Defense +1", 20, 0, 1)
addRing("Defense +2", 40, 0, 2)
addRing("Defense +3", 80, 0, 3)
addRing("No Ring 1", 0, 0, 0)
addRing("No Ring 2", 0, 0, 0)
}
func addWeapon(n string, c, dmg int) {
weaponsAvailable = append(weaponsAvailable,
weapon{name: n, cost: c, damage: dmg})
}
func addArmor(n string, c, def int) {
armorAvailable = append(armorAvailable,
armor{name: n, cost: c, defense: def})
}
func addRing(n string, c, dmg, def int) {
ringsAvailable = append(ringsAvailable,
ring{name: n, cost: c, damage: dmg, defense: def})
}
type weapon struct {
name string
cost, damage int
}
type armor struct {
name string
cost, defense int
}
type ring struct {
name string
cost, damage, defense int
}
func itoa(i int) string {
return strconv.Itoa(i)
}
func mustAtoi(s string) int {
var i int
var err error
if i, err = strconv.Atoi(s); err != nil {
fmt.Println("Tried to atoi " + s)
os.Exit(1)
}
return i
}