111 lines
2.4 KiB
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)
|
|
}
|