2017 Day 14 Complete!
This commit is contained in:
parent
3de38212ca
commit
1fc88a6ea3
238
2017/day14/day14.go
Normal file
238
2017/day14/day14.go
Normal file
@ -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
|
||||
}
|
1
2017/day14/input
Normal file
1
2017/day14/input
Normal file
@ -0,0 +1 @@
|
||||
vbqugkhl
|
91
2017/day14/problem
Normal file
91
2017/day14/problem
Normal file
@ -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
|
1
2017/day14/testinput
Normal file
1
2017/day14/testinput
Normal file
@ -0,0 +1 @@
|
||||
flqrgnkx
|
Loading…
Reference in New Issue
Block a user