adventofcode/2016/day21/main.go

111 lines
2.4 KiB
Go

package main
import (
"fmt"
"strings"
"../../"
)
func main() {
pw := "fbgdceah" // Part 2 Puzzle input
input := aoc.StdinToStringSlice()
if aoc.ArgIsSet("-1") {
pw = "abcdefgh" // Part 1 Puzzle input
pw = scramblePassword(pw, input)
fmt.Println(scramblePassword(pw, input))
return
}
fmt.Println(unscramblePassword(pw, input))
}
func unscramblePassword(pw string, inst []string) string {
// Brute force it.
// Just get all permutations of the runes and return the one
// for which the instructions return the input
tst := aoc.StringPermutations(pw)
for i := range tst {
if scramblePassword(tst[i], inst) == pw {
return tst[i]
}
}
return ""
}
func scramblePassword(pw string, inst []string) string {
for i := range inst {
pts := strings.Fields(inst[i])
switch pts[0] + " " + pts[1] {
case "swap position":
pw = swapPos(pw, aoc.Atoi(pts[2]), aoc.Atoi(pts[5]))
case "swap letter":
pw = swapLetter(pw, pts[2], pts[5])
case "reverse positions":
pw = reverse(pw, aoc.Atoi(pts[2]), aoc.Atoi(pts[4]))
case "rotate left":
pw = rotate(pw, aoc.Atoi(pts[2])*-1)
case "rotate right":
pw = rotate(pw, aoc.Atoi(pts[2]))
case "rotate based":
rotIdx := strings.Index(pw, pts[6])
if rotIdx >= 4 {
rotIdx++
}
rotIdx++
pw = rotate(pw, rotIdx)
case "move position":
pw = move(pw, aoc.Atoi(pts[2]), aoc.Atoi(pts[5]))
}
}
return pw
}
func swapPos(pw string, x, y int) string {
r := []rune(pw)
r[x], r[y] = r[y], r[x]
return string(r)
}
func swapLetter(pw string, x, y string) string {
xPos := strings.Index(pw, x)
yPos := strings.Index(pw, y)
return swapPos(pw, xPos, yPos)
}
func rotate(pw string, steps int) string {
r := []rune(pw)
var x rune
for steps < 0 {
// Left rotate (shift & push)
x, r = r[0], r[1:]
r = append(r, x)
steps++
}
for steps > 0 {
// Right rotate (pop & unshift)
x, r = r[len(r)-1], r[:len(r)-1]
r = append([]rune{x}, r...)
steps--
}
return string(r)
}
func reverse(pw string, beg, end int) string {
revStr := pw[beg : end+1]
runes := []rune(revStr)
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
runes[i], runes[j] = runes[j], runes[i]
}
return pw[:beg] + string(runes) + pw[end+1:]
}
func move(pw string, x, y int) string {
r := []rune(pw)
// Cut element at x
mov := r[x]
r = append(r[:x], r[x+1:]...)
// Insert at y
r = append(r[:y], append([]rune{mov}, r[y:]...)...)
return string(r)
}