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) }