From f06d8a6c07f4d59a13070c867cc13adbc74ea9b5 Mon Sep 17 00:00:00 2001 From: Brian Buller Date: Wed, 21 Dec 2016 11:15:25 -0600 Subject: [PATCH] Day 21 Complete Added String Permutation helper to helpers file --- 2016/day21/input | 100 +++++++++++++++++++++++++++++++++++++++++ 2016/day21/main.go | 110 +++++++++++++++++++++++++++++++++++++++++++++ 2016/day21/problem | 69 ++++++++++++++++++++++++++++ helpers.go | 17 +++++++ 4 files changed, 296 insertions(+) create mode 100644 2016/day21/input create mode 100644 2016/day21/main.go create mode 100644 2016/day21/problem diff --git a/2016/day21/input b/2016/day21/input new file mode 100644 index 0000000..e542e65 --- /dev/null +++ b/2016/day21/input @@ -0,0 +1,100 @@ +swap letter e with letter h +swap letter f with letter g +move position 6 to position 3 +reverse positions 1 through 6 +swap letter b with letter a +swap letter a with letter f +rotate based on position of letter e +swap position 7 with position 2 +rotate based on position of letter e +swap letter c with letter e +rotate based on position of letter f +rotate right 6 steps +swap letter c with letter f +reverse positions 3 through 7 +swap letter c with letter b +swap position 1 with position 2 +reverse positions 3 through 6 +swap letter c with letter a +rotate left 0 steps +swap position 3 with position 0 +swap letter b with letter e +reverse positions 4 through 7 +move position 1 to position 4 +swap position 6 with position 3 +rotate left 6 steps +rotate right 0 steps +move position 7 to position 3 +move position 3 to position 4 +swap position 3 with position 2 +reverse positions 1 through 6 +move position 7 to position 5 +reverse positions 4 through 5 +rotate based on position of letter g +swap position 4 with position 2 +reverse positions 1 through 5 +rotate based on position of letter h +rotate based on position of letter f +rotate based on position of letter b +swap position 1 with position 4 +swap letter b with letter h +rotate based on position of letter e +swap letter a with letter c +swap position 3 with position 5 +rotate right 6 steps +rotate based on position of letter c +move position 2 to position 0 +swap letter b with letter e +swap letter g with letter e +rotate based on position of letter d +swap position 6 with position 5 +swap letter b with letter c +rotate based on position of letter e +rotate based on position of letter f +rotate based on position of letter f +move position 7 to position 0 +rotate right 1 step +rotate right 7 steps +swap position 5 with position 6 +move position 6 to position 7 +rotate based on position of letter e +swap position 3 with position 1 +swap position 4 with position 3 +swap letter f with letter a +swap position 5 with position 2 +rotate based on position of letter e +rotate left 3 steps +rotate left 1 step +rotate based on position of letter b +rotate left 6 steps +rotate based on position of letter b +rotate right 7 steps +swap position 0 with position 2 +swap position 7 with position 5 +rotate left 3 steps +reverse positions 4 through 5 +move position 2 to position 5 +swap letter c with letter f +swap letter g with letter e +rotate left 6 steps +swap position 4 with position 6 +rotate based on position of letter h +rotate left 2 steps +swap letter c with letter a +rotate right 3 steps +rotate left 6 steps +swap letter b with letter f +swap position 6 with position 5 +reverse positions 3 through 4 +reverse positions 2 through 7 +swap position 7 with position 4 +rotate based on position of letter d +swap position 5 with position 3 +swap letter c with letter b +swap position 7 with position 6 +rotate based on position of letter c +reverse positions 0 through 7 +reverse positions 2 through 4 +rotate based on position of letter f +reverse positions 1 through 4 +rotate right 7 steps diff --git a/2016/day21/main.go b/2016/day21/main.go new file mode 100644 index 0000000..79ee29f --- /dev/null +++ b/2016/day21/main.go @@ -0,0 +1,110 @@ +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) +} diff --git a/2016/day21/problem b/2016/day21/problem new file mode 100644 index 0000000..52e8c26 --- /dev/null +++ b/2016/day21/problem @@ -0,0 +1,69 @@ +Advent of Code + +--- Day 21: Scrambled Letters and Hash --- + + The computer system you're breaking into uses a weird scrambling function to store its passwords. It shouldn't be much trouble to create + your own scrambled password so you can add it to the system; you just have to implement the scrambler. + + The scrambling function is a series of operations (the exact list is provided in your puzzle input). Starting with the password to be + scrambled, apply each operation in succession to the string. The individual operations behave as follows: + + • swap position X with position Y means that the letters at indexes X and Y (counting from 0) should be swapped. + • swap letter X with letter Y means that the letters X and Y should be swapped (regardless of where they appear in the string). + • rotate left/right X steps means that the whole string should be rotated; for example, one right rotation would turn abcd into dabc. + • rotate based on position of letter X means that the whole string should be rotated to the right based on the index of letter X + (counting from 0) as determined before this instruction does any rotations. Once the index is determined, rotate the string to the + right one time, plus a number of times equal to that index, plus one additional time if the index was at least 4. + • reverse positions X through Y means that the span of letters at indexes X through Y (including the letters at X and Y) should be + reversed in order. + • move position X to position Y means that the letter which is at index X should be removed from the string, then inserted such that + it ends up at index Y. + + For example, suppose you start with abcde and perform the following operations: + + • swap position 4 with position 0 swaps the first and last letters, producing the input for the next step, ebcda. + • swap letter d with letter b swaps the positions of d and b: edcba. + • reverse positions 0 through 4 causes the entire string to be reversed, producing abcde. + • rotate left 1 step shifts all letters left one position, causing the first letter to wrap to the end of the string: bcdea. + • move position 1 to position 4 removes the letter at position 1 (c), then inserts it at position 4 (the end of the string): bdeac. + • move position 3 to position 0 removes the letter at position 3 (a), then inserts it at position 0 (the front of the string): abdec. + • rotate based on position of letter b finds the index of letter b (1), then rotates the string right once plus a number of times + equal to that index (2): ecabd. + • rotate based on position of letter d finds the index of letter d (4), then rotates the string right once, plus a number of times + equal to that index, plus an additional time because the index was at least 4, for a total of 6 right rotations: decab. + + After these steps, the resulting scrambled password is decab. + + Now, you just need to generate a new scrambled password and you can access the system. Given the list of scrambling operations in your + puzzle input, what is the result of scrambling abcdefgh? + + Your puzzle answer was ________. + +--- Part Two --- + + You scrambled the password correctly, but you discover that you can't actually modify the password file on the system. You'll need to + un-scramble one of the existing passwords by reversing the scrambling process. + + What is the un-scrambled version of the scrambled password fbgdceah? + + Your puzzle answer was ________. + +References + + Visible links + . http://adventofcode.com/ + . http://adventofcode.com/2016/about + . http://adventofcode.com/2016/support + . http://adventofcode.com/2016/events + . http://adventofcode.com/2016/settings + . http://adventofcode.com/2016/auth/logout + . http://adventofcode.com/2016 + . http://adventofcode.com/2016 + . http://adventofcode.com/2016/leaderboard + . http://adventofcode.com/2016/stats + . http://adventofcode.com/2016/sponsors + . http://adventofcode.com/2016/sponsors + . https://en.wikipedia.org/wiki/File_system_permissions + . https://en.wikipedia.org/wiki/Passwd + . http://adventofcode.com/2016 + . http://adventofcode.com/2016/day/21/input diff --git a/helpers.go b/helpers.go index 5e74900..c7f4ce5 100644 --- a/helpers.go +++ b/helpers.go @@ -84,6 +84,23 @@ func PrintProgress(curr, total int) { } } +func StringPermutations(str string) []string { + return stringPermHelper(str, 0) +} + +func stringPermHelper(str string, i int) []string { + ret := []string{str} + if i != len(str) { + r := []rune(str) + for j := i; j < len(r); j++ { + r[i], r[j] = r[j], r[i] + ret = append(ret, stringPermHelper(string(r), i+1)...) + r[i], r[j] = r[j], r[i] + } + } + return ret +} + // Some character code stuff for prettier output const ( BorderNS = "\u2502"