diff --git a/2017/day14/day14.go b/2017/day14/day14.go new file mode 100644 index 0000000..158b0e3 --- /dev/null +++ b/2017/day14/day14.go @@ -0,0 +1,238 @@ +package main + +import ( + "bufio" + "errors" + "fmt" + "log" + "os" + "strconv" + "strings" +) + +func main() { + doPart := 2 + inp := "vbqugkhl" // My puzzle input + if len(os.Args) > 1 { + if os.Args[1] == "-1" { + doPart = 1 + } else { + inp = strings.ToLower(os.Args[1]) + } + } + if doPart == 1 { + part1(inp) + } else { + part2(inp) + } +} + +func part1(inp string) { + var diskRows []string + for i := 0; i < 128; i++ { + diskRows = append(diskRows, KnotHash(fmt.Sprintf("%s-%d", inp, i))) + } + var usedSquares int + for i := range diskRows { + bin := GetBinaryString(diskRows[i]) + usedSquares += strings.Count(bin, "1") + } + fmt.Println(usedSquares, "used squares") +} + +var diskGrid map[string]bool +var groups map[string]int + +func part2(inp string) { + diskGrid = make(map[string]bool) + groups = make(map[string]int) + + fmt.Println("Building DiskGrid...") + var grpCnt int + for i := 0; i < 128; i++ { + row := GetBinaryString(KnotHash(fmt.Sprintf("%s-%d", inp, i))) + for j := range row { + diskGrid[cs(i, j)] = (row[j] == '1') + if row[j] == '1' { + groups[cs(i, j)] = grpCnt + grpCnt++ + } + } + } + + var iters int + red := true + for red { + red = ReduceGroups() + iters++ + } + fmt.Println("Reduced", iters, "times") + fmt.Println(GetGroupCount(), "regions") +} + +func ReduceGroups() bool { + var ret bool + for x := 0; x < 128; x++ { + for y := 0; y < 128; y++ { + if oV, oOk := diskGrid[cs(x, y)]; oOk && oV { + if dV, dOk := diskGrid[cs(x, y-1)]; dOk && dV && groups[cs(x, y-1)] != groups[cs(x, y)] { + CombineBlockGroups(cs(x, y), cs(x, y-1)) + ret = true + } + if dV, dOk := diskGrid[cs(x-1, y)]; dOk && dV && groups[cs(x-1, y)] != groups[cs(x, y)] { + CombineBlockGroups(cs(x, y), cs(x-1, y)) + ret = true + } + if dV, dOk := diskGrid[cs(x+1, y)]; dOk && dV && groups[cs(x+1, y)] != groups[cs(x, y)] { + CombineBlockGroups(cs(x+1, y), cs(x, y)) + ret = true + } + if dV, dOk := diskGrid[cs(x, y+1)]; dOk && dV && groups[cs(x, y+1)] != groups[cs(x, y)] { + CombineBlockGroups(cs(x, y+1), cs(x, y)) + ret = true + } + } + } + } + return ret +} + +func CombineBlockGroups(b1, b2 string) { + if groups[b1] < groups[b2] { + groups[b1] = groups[b2] + } else { + groups[b2] = groups[b1] + } +} + +func GetGroupCount() int { + var gps []int + for i := range groups { + var have bool + for j := range gps { + if groups[i] == gps[j] { + have = true + break + } + } + if !have { + gps = append(gps, groups[i]) + } + } + return len(gps) +} + +func FindGroup(x, y int) (int, error) { + key := cs(x, y) + if v, ok := groups[key]; ok { + return v, nil + } + return -1, errors.New("Not in a group") +} + +func PrintUsageChunk(stX, stY, endX, endY int, showGroups bool) { + for x := stX; x < endX; x++ { + for y := stY; y < endY; y++ { + spot := "." + if v, ok := groups[cs(x, y)]; ok { + if showGroups { + v = v % 16 + spot = fmt.Sprintf("%x", v) + } else { + spot = "#" + } + } + fmt.Printf(spot) + } + fmt.Println("") + } + +} + +// Get a map coordinate string for x, y +func cs(x, y int) string { + return fmt.Sprint(x, "-", y) +} + +// Get the x, y coordinate from a string +func sc(c string) (int, int) { + pts := strings.Split(c, "-") + return Atoi(pts[0]), Atoi(pts[1]) +} + +func KnotHash(inp string) string { + var idx, skip int + var list []int + for i := 0; i < 256; i++ { + list = append(list, i) + } + inpBts := []byte(inp) + inpBts = append(inpBts, []byte{17, 31, 73, 47, 23}...) + for j := 0; j < 64; j++ { + for i := range inpBts { + idx, skip, list = khRound(int(inpBts[i]), idx, skip, list) + } + } + // Now calculate the dense hash + var dense []byte + for i := 0; i < len(list); i += 16 { + dense = append(dense, xorList(list[i:i+16])) + } + return fmt.Sprintf("%x", dense) +} + +func khRound(i, idx, skip int, list []int) (int, int, []int) { + // if idx+i overflows, pull from the front + var revList []int + for j := idx; j < idx+i; j++ { + revList = append([]int{list[j%256]}, revList...) + } + for j := 0; j < len(revList); j++ { + list[(idx+j)%256] = revList[j] + } + + idx += i + skip + skip++ + return idx, skip, list +} + +func xorList(inp []int) byte { + var ret byte + for i := range inp { + ret ^= byte(inp[i]) + } + return ret +} + +func GetBinaryString(inp string) string { + var bin string + for i := range inp { + var v int + if inp[i] >= '0' && inp[i] <= '9' { + v = int(inp[i] - '0') + } else if inp[i] >= 'a' && inp[i] <= 'f' { + v = int(inp[i] - 'a' + 10) + } + nibble := fmt.Sprintf("%04s", strconv.FormatInt(int64(v), 2)) + bin += nibble + } + return bin +} + +func StdinToString() string { + var input string + scanner := bufio.NewScanner(os.Stdin) + for scanner.Scan() { + input = scanner.Text() + } + return input +} + +func Atoi(i string) int { + var ret int + var err error + if ret, err = strconv.Atoi(i); err != nil { + log.Fatal("Invalid Atoi") + } + return ret +} diff --git a/2017/day14/input b/2017/day14/input new file mode 100644 index 0000000..879ef41 --- /dev/null +++ b/2017/day14/input @@ -0,0 +1 @@ +vbqugkhl diff --git a/2017/day14/problem b/2017/day14/problem new file mode 100644 index 0000000..6102be8 --- /dev/null +++ b/2017/day14/problem @@ -0,0 +1,91 @@ +Advent of Code + +--- Day 14: Disk Defragmentation --- + + Suddenly, a scheduled job activates the system's disk defragmenter. Were the situation different, you might sit and watch it for a while, but today, you just + don't have that kind of time. It's soaking up valuable system resources that are needed elsewhere, and so the only option is to help it finish its task as soon + as possible. + + The disk in question consists of a 128x128 grid; each square of the grid is either free or used. On this disk, the state of the grid is tracked by the bits in a + sequence of knot hashes. + + A total of 128 knot hashes are calculated, each corresponding to a single row in the grid; each hash contains 128 bits which correspond to individual grid + squares. Each bit of a hash indicates whether that square is free (0) or used (1). + + The hash inputs are a key string (your puzzle input), a dash, and a number from 0 to 127 corresponding to the row. For example, if your key string were + flqrgnkx, then the first row would be given by the bits of the knot hash of flqrgnkx-0, the second row from the bits of the knot hash of flqrgnkx-1, and so on + until the last row, flqrgnkx-127. + + The output of a knot hash is traditionally represented by 32 hexadecimal digits; each of these digits correspond to 4 bits, for a total of 4 * 32 = 128 bits. To + convert to bits, turn each hexadecimal digit to its equivalent binary value, high-bit first: 0 becomes 0000, 1 becomes 0001, e becomes 1110, f becomes 1111, and + so on; a hash that begins with a0c2017... in hexadecimal would begin with 10100000110000100000000101110000... in binary. + + Continuing this process, the first 8 rows and columns for key flqrgnkx appear as follows, using # to denote used squares, and . to denote free ones: + + ##.#.#..--> + .#.#.#.# + ....#.#. + #.#.##.# + .##.#... + ##..#..# + .#...#.. + ##.#.##.--> + | | + V V + + In this example, 8108 squares are used across the entire 128x128 grid. + + Given your actual key string, how many squares are used? + + Your puzzle answer was ________. + +--- Part Two --- + + Now, all the defragmenter needs to know is the number of regions. A region is a group of used squares that are all adjacent, not including diagonals. Every used + square is in exactly one region: lone used squares form their own isolated regions, while several adjacent squares all count as a single region. + + In the example above, the following nine regions are visible, each marked with a distinct digit: + + 11.2.3..--> + .1.2.3.4 + ....5.6. + 7.8.55.9 + .88.5... + 88..5..8 + .8...8.. + 88.8.88.--> + | | + V V + + Of particular interest is the region marked 8; while it does not appear contiguous in this small view, all of the squares marked 8 are connected when + considering the whole 128x128 grid. In total, in this example, 1242 regions are present. + + How many regions are present given your key string? + + Your puzzle answer was _____. + + Both parts of this puzzle are complete! They provide two gold stars: ** + + At this point, you should return to your advent calendar and try another puzzle. + + Your puzzle input was vbqugkhl. + +References + + Visible links + . http://adventofcode.com/ + . http://adventofcode.com/2017/about + . http://adventofcode.com/2017/support + . http://adventofcode.com/2017/events + . http://adventofcode.com/2017/settings + . http://adventofcode.com/2017/auth/logout + . http://adventofcode.com/2017 + . http://adventofcode.com/2017 + . http://adventofcode.com/2017/leaderboard + . http://adventofcode.com/2017/stats + . http://adventofcode.com/2017/sponsors + . http://adventofcode.com/2017/sponsors + . https://en.wikipedia.org/wiki/Defragmentation + . https://www.youtube.com/watch?v=kPv1gQ5Rs8A&t=37 + . http://adventofcode.com/2017/day/10 + . http://adventofcode.com/2017 diff --git a/2017/day14/testinput b/2017/day14/testinput new file mode 100644 index 0000000..e0ffae2 --- /dev/null +++ b/2017/day14/testinput @@ -0,0 +1 @@ +flqrgnkx