Compare commits

...

10 Commits

Author SHA1 Message Date
Stefan Harmuth
e160010441 new idea for d19p2 actually works
2015 finished!
2021-10-24 13:55:06 +02:00
Stefan Harmuth
7b7f4f563b day22; finally 2021-10-24 12:32:52 +02:00
Stefan Harmuth
3b22bfcc37 day22 - working fight simulation 2021-01-16 15:46:32 +01:00
Stefan Harmuth
00c6eb8a77 day25 2021-01-16 07:54:48 +01:00
Stefan Harmuth
896bc7b328 day24 - input files 2021-01-16 07:40:29 +01:00
Stefan Harmuth
32486160f0 day24 2021-01-15 08:39:54 +01:00
Stefan Harmuth
4328f27544 day23 2021-01-15 07:37:05 +01:00
Stefan Harmuth
cffbd23a11 structs get *not* handed over do funcs as references (good!) 2021-01-14 08:09:53 +01:00
Stefan Harmuth
f67d5f141c day22 - unfinished 2021-01-12 10:11:12 +01:00
Stefan Harmuth
3d2f91644c day22 - unfinished 2021-01-11 17:17:03 +01:00
14 changed files with 511 additions and 50 deletions

View File

@ -1,6 +1,8 @@
package day19
import (
"fmt"
"os"
"strings"
"tools"
)
@ -42,63 +44,57 @@ func Part1(puzzle tools.AoCPuzzle) interface{} {
return len(outcomes)
}
func getPossibleTransformations(from tools.Set, replacments map[string]tools.Set, maxLen int) tools.Set {
returnSet := tools.NewSet()
var result string
for interfaceMolecule := range from {
currentMolecule := interfaceMolecule.(string)
for i := range currentMolecule {
if transSet, ok := replacments[string(currentMolecule[i])]; ok {
for replacement := range transSet {
result = currentMolecule[:i] + replacement.(string)
if i < len(currentMolecule)-1 {
result += currentMolecule[i+1:]
}
if len(result) <= maxLen {
returnSet.Add(result)
}
}
}
if i < len(currentMolecule)-1 {
if transSet, ok := replacments[currentMolecule[i:i+2]]; ok {
for replacment := range transSet {
result = currentMolecule[:i] + replacment.(string)
if i < len(currentMolecule)-2 {
result += currentMolecule[i+2:]
}
if len(result) <= maxLen {
returnSet.Add(result)
}
}
}
}
}
}
return returnSet
}
func Part2(puzzle tools.AoCPuzzle) interface{} {
input := puzzle.GetInputArray()
molecule := input[len(input)-1]
replacementStrings := input[:len(input)-2]
replacements := make(map[string]tools.Set)
for _, line := range replacementStrings {
parts := strings.Split(line, " => ")
if _, ok := replacements[parts[0]]; !ok {
replacements[parts[0]] = tools.NewSet()
replacements := make(map[string]string)
replacementLengths := make(map[int][]string)
var maxLen, minLen int
for _, s := range replacementStrings {
parts := strings.Split(s, " => ")
if _, ok := replacements[parts[1]]; ok {
fmt.Println("Double target string found!")
os.Exit(1)
} else {
replacements[parts[1]] = parts[0]
x := len(parts[1])
if x > maxLen {
maxLen = x
}
if x < minLen {
minLen = x
}
if _, ok := replacementLengths[x]; ok {
replacementLengths[x] = append(replacementLengths[x], parts[1])
} else {
replacementLengths[x] = []string{parts[1]}
}
}
replacements[parts[0]].Add(parts[1])
}
currentMolecules := tools.NewSet()
currentMolecules.Add("e")
transformCount := 0
for !currentMolecules.Contains(molecule) {
transformCount++
currentMolecules = getPossibleTransformations(currentMolecules, replacements, len(molecule))
steps := 0
foundSomething := false
for len(molecule) > 1 {
foundSomething = false
for x := maxLen; x >= minLen; x-- {
for _, replacement := range replacementLengths[x] {
if strings.Contains(molecule, replacement) {
molecule = strings.Replace(molecule, replacement, replacements[replacement], 1)
foundSomething = true
steps++
break
}
}
if foundSomething {
break
}
}
if !foundSomething {
break
}
}
return transformCount
return steps
}

216
day22/day.go Normal file
View File

@ -0,0 +1,216 @@
package day22
import (
"math"
"strconv"
"strings"
"tools"
)
/*
Spells:
Magic Missile - 53 Mana - 4 Damage
Drain - 73 Mana - 2 Damage, 2 Heal
Shield - 113 Mana - 7 Armor for 6 turns
Poison - 173 Mana - 3 Damage per turn for 6 turns
Recharge - 229 Mana - 101 Mana per turn for 5 turns
*/
type Entity struct {
hitpoints int
mana int
armor int
damage int
}
var spells = map[string]string{
"mm": "Magic Missile",
"d": "Drain",
"s": "Shield",
"rc": "Recharge",
"p": "Poison",
}
var minWinningMana int
func applyEffects(player, boss Entity, effects map[string]int) (Entity, Entity, map[string]int) {
for e, t := range effects {
t--
switch e {
case "rc":
player.mana += 101
// fmt.Println("Recharge provides 101 mana; it's timer is now ", t)
case "p":
boss.hitpoints -= 3
// fmt.Println("Poison deals 3 damage; it's timer is now ", t)
case "s":
if t == 0 {
player.armor -= 7
}
// fmt.Println("Shield's timer is now ", t)
}
if t == 0 {
// fmt.Println(spells[e], " wears off.")
delete(effects, e)
} else {
effects[e] = t
}
}
return player, boss, effects
}
func turn(player, boss Entity, effects map[string]int, spell string, hardmode bool) (Entity, Entity, map[string]int, int, int) {
// return values: -1 player dead; 0 both alive; 1 boss dead
/*
fmt.Println("-- Player Turn --")
fmt.Println("- Player has ", player.hitpoints, "hit points, ", player.armor, " armor, ", player.mana, " mana")
fmt.Println("- Boss has ", boss.hitpoints, " hit points")
*/
if hardmode {
player.hitpoints -= 1
if player.hitpoints <= 0 {
return player, boss, effects, 0, -1
}
}
// Apply effects, if any
player, boss, effects = applyEffects(player, boss, effects)
// Player cast spell -- which one?
if _, ok := effects[spell]; ok {
// cannot cast already active effect; how to fail?
// just pretend the player died ...
return player, boss, effects, 0, -1
}
var manaUsed int
switch spell {
case "mm":
// fmt.Println("Player casts Magic Missile; dealing 4 damage.")
boss.hitpoints -= 4
manaUsed = 53
case "d":
// fmt.Println("Player casts Drain; dealing 2 damage and healing 2 hit points.")
player.hitpoints += 2
boss.hitpoints -= 2
manaUsed = 73
case "p":
// fmt.Println("Player casts Poison.")
effects[spell] = 6
manaUsed = 173
case "s":
// fmt.Println("Player casts Shield.")
player.armor += 7
manaUsed = 113
effects[spell] = 6
case "rc":
// fmt.Println("Player casts recharge.")
manaUsed = 229
effects[spell] = 5
}
player.mana -= manaUsed
if player.mana <= 0 {
return player, boss, effects, manaUsed, -1
}
// Check Boss health
if boss.hitpoints <= 0 {
return player, boss, effects, manaUsed, 1
}
/*
fmt.Println("-- Boss Turn --")
fmt.Println("- Player has ", player.hitpoints, "hit points, ", player.armor, " armor, ", player.mana, " mana")
fmt.Println("- Boss has ", boss.hitpoints, " hit points")
*/
// Apply effects, if any
player, boss, effects = applyEffects(player, boss, effects)
// Check Boss health
if boss.hitpoints <= 0 {
return player, boss, effects, manaUsed, 1
}
bossDamage := int(math.Max(1.0, float64(boss.damage-player.armor)))
// fmt.Println("Boss attacks for ", bossDamage, " damage.")
// Check Player health
player.hitpoints -= bossDamage
if player.hitpoints <= 0 {
return player, boss, effects, manaUsed, -1
}
return player, boss, effects, manaUsed, 0
}
func findLowestManaUsed(player, boss Entity, effects map[string]int, manaUsed int, spellsUsed string, hardmode bool, depth int) (int, string) {
minManaUsed := math.MaxInt32
var minSpellsUsed string
for s := range spells {
var thisManaUse, state int
thisPlayer := player
thisBoss := boss
thisEffects := make(map[string]int)
thisSpells := spellsUsed + "," + s
for e, t := range effects {
thisEffects[e] = t
}
thisPlayer, thisBoss, thisEffects, thisManaUse, state = turn(thisPlayer, thisBoss, thisEffects, s, hardmode)
switch state {
case -1:
continue
case 0:
if thisManaUse+manaUsed < minWinningMana {
thisManaUse, thisSpells = findLowestManaUsed(thisPlayer, thisBoss, thisEffects, thisManaUse+manaUsed, thisSpells, hardmode, depth+1)
} else {
continue
}
case 1:
if manaUsed+thisManaUse < minWinningMana {
minWinningMana = manaUsed + thisManaUse
}
}
if thisManaUse < minManaUsed {
minManaUsed = thisManaUse
minSpellsUsed = thisSpells
}
}
return minManaUsed + manaUsed, minSpellsUsed
}
func Part1(puzzle tools.AoCPuzzle) interface{} {
player := Entity{50, 500, 0, 0}
boss := Entity{0, 0, 0, 0}
bossData := puzzle.GetInputArray()
for _, line := range bossData {
parts := strings.Split(line, ": ")
switch parts[0] {
case "Hit Points":
boss.hitpoints, _ = strconv.Atoi(parts[1])
case "Damage":
boss.damage, _ = strconv.Atoi(parts[1])
}
}
effects := make(map[string]int)
minWinningMana = math.MaxInt32
findLowestManaUsed(player, boss, effects, 0, "", false, 0)
return minWinningMana
}
func Part2(puzzle tools.AoCPuzzle) interface{} {
player := Entity{50, 500, 0, 0}
boss := Entity{0, 0, 0, 0}
bossData := puzzle.GetInputArray()
for _, line := range bossData {
parts := strings.Split(line, ": ")
switch parts[0] {
case "Hit Points":
boss.hitpoints, _ = strconv.Atoi(parts[1])
case "Damage":
boss.damage, _ = strconv.Atoi(parts[1])
}
}
effects := make(map[string]int)
minWinningMana = math.MaxInt32
findLowestManaUsed(player, boss, effects, 0, "", true, 0)
return minWinningMana
}

65
day23/day.go Normal file
View File

@ -0,0 +1,65 @@
package day23
import (
"strconv"
"strings"
"tools"
)
func run(code []string, registers map[string]int) {
instptr := 0
for instptr < len(code) {
instrparts := strings.Split(code[instptr], " ")
switch instrparts[0] {
case "hlf": // half a register
registers[instrparts[1]] /= 2
instptr++
case "tpl": // tripple a register
registers[instrparts[1]] *= 3
instptr++
case "inc": // increase register by 1
registers[instrparts[1]]++
instptr++
case "jmp": // jump to instruction
jumpamount, _ := strconv.Atoi(instrparts[1])
instptr += jumpamount
case "jie": // jump to instruction if register is even
if registers[string(instrparts[1][0])]%2 == 0 {
jumpamount, _ := strconv.Atoi(instrparts[2])
instptr += jumpamount
} else {
instptr++
}
case "jio": // jump to instruction if register is one
if registers[string(instrparts[1][0])] == 1 {
jumpamount, _ := strconv.Atoi(instrparts[2])
instptr += jumpamount
} else {
instptr++
}
}
}
}
func Part1(puzzle tools.AoCPuzzle) interface{} {
code := puzzle.GetInputArray()
registers := map[string]int{
"a": 0,
"b": 0,
}
run(code, registers)
return registers["b"]
}
func Part2(puzzle tools.AoCPuzzle) interface{} {
code := puzzle.GetInputArray()
registers := map[string]int{
"a": 1,
"b": 0,
}
run(code, registers)
return registers["b"]
}

44
day24/day.go Normal file
View File

@ -0,0 +1,44 @@
package day24
import (
"math"
"tools"
)
func findMinQE(packageWeights []int, weightPerCompartment int) int {
var results [][]int
for i := 1; i < len(packageWeights); i++ {
for _, comb := range tools.CombinationsInt(packageWeights, i) {
if tools.Sum(comb...) == weightPerCompartment {
results = append(results, comb)
}
}
if len(results) > 0 {
break
}
}
minQE := math.MaxInt64
for _, result := range results {
thisQE := tools.Mul(result...)
if thisQE < minQE {
minQE = thisQE
}
}
return minQE
}
func Part1(puzzle tools.AoCPuzzle) interface{} {
packageWeights := puzzle.GetInputArrayInt()
weightPerCompartment := tools.Sum(packageWeights...) / 3
return findMinQE(packageWeights, weightPerCompartment)
}
func Part2(puzzle tools.AoCPuzzle) interface{} {
packageWeights := puzzle.GetInputArrayInt()
weightPerCompartment := tools.Sum(packageWeights...) / 4
return findMinQE(packageWeights, weightPerCompartment)
}

36
day25/day.go Normal file
View File

@ -0,0 +1,36 @@
package day25
import (
"strconv"
"strings"
"tools"
)
func Part1(puzzle tools.AoCPuzzle) interface{} {
inputParts := strings.Split(puzzle.GetInputArray()[0], " ")
wantedX, _ := strconv.Atoi(inputParts[18][:len(inputParts[18])-1])
wantedY, _ := strconv.Atoi(inputParts[16][:len(inputParts[16])-1])
codeNumber := 20151125
x := 1
y := 1
maxY := 1
for {
codeNumber = codeNumber * 252533 % 33554393
y--
x++
if y == 0 {
y = maxY + 1
maxY = y
x = 1
}
if x == wantedX && y == wantedY {
return codeNumber
}
}
}
func Part2(puzzle tools.AoCPuzzle) interface{} {
return "d25p2 always only checks if you solved everything else"
}

2
inputs/22 Normal file
View File

@ -0,0 +1,2 @@
Hit Points: 55
Damage: 8

2
inputs/22_test Normal file
View File

@ -0,0 +1,2 @@
Hit Points: 14
Damage: 8

47
inputs/23 Normal file
View File

@ -0,0 +1,47 @@
jio a, +18
inc a
tpl a
inc a
tpl a
tpl a
tpl a
inc a
tpl a
inc a
tpl a
inc a
inc a
tpl a
tpl a
tpl a
inc a
jmp +22
tpl a
inc a
tpl a
inc a
inc a
tpl a
inc a
tpl a
inc a
inc a
tpl a
tpl a
inc a
inc a
tpl a
inc a
inc a
tpl a
inc a
inc a
tpl a
jio a, +8
inc b
jie a, +4
tpl a
inc a
jmp +2
hlf a
jmp -7

4
inputs/23_test Normal file
View File

@ -0,0 +1,4 @@
inc a
jio a, +2
tpl a
inc a

29
inputs/24 Normal file
View File

@ -0,0 +1,29 @@
1
2
3
7
11
13
17
19
23
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97
101
103
107
109
113

10
inputs/24_test Normal file
View File

@ -0,0 +1,10 @@
1
2
3
4
5
7
8
9
10
11

1
inputs/25 Normal file
View File

@ -0,0 +1 @@
To continue, please consult the code grid in the manual. Enter the code at row 2978, column 3083.

1
inputs/25_test Normal file
View File

@ -0,0 +1 @@
To continue, please consult the code grid in the manual. Enter the code at row 6, column 6.

View File

@ -22,6 +22,10 @@ import (
"aoc2015/day19"
"aoc2015/day20"
"aoc2015/day21"
"aoc2015/day22"
"aoc2015/day23"
"aoc2015/day24"
"aoc2015/day25"
"flag"
"fmt"
"os"
@ -60,6 +64,10 @@ func initDayFunctions() {
19: {1: day19.Part1, 2: day19.Part2},
20: {1: day20.Part1, 2: day20.Part2},
21: {1: day21.Part1, 2: day21.Part2},
22: {1: day22.Part1, 2: day22.Part2},
23: {1: day23.Part1, 2: day23.Part2},
24: {1: day24.Part1, 2: day24.Part2},
25: {1: day25.Part1, 2: day25.Part2},
}
}