191 lines
3.5 KiB
Go
191 lines
3.5 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"sort"
|
||
|
"strings"
|
||
|
|
||
|
h "git.bullercodeworks.com/brian/adventofcode/helpers"
|
||
|
)
|
||
|
|
||
|
func main() {
|
||
|
inp := h.StdinToStringSlice()
|
||
|
part1(inp)
|
||
|
fmt.Println()
|
||
|
part2(inp)
|
||
|
}
|
||
|
|
||
|
func part1(input []string) {
|
||
|
var bricks [][]int
|
||
|
|
||
|
for _, line := range input {
|
||
|
values := strings.Split(strings.ReplaceAll(line, "~", ","), ",")
|
||
|
var brick []int
|
||
|
for _, v := range values {
|
||
|
num := 0
|
||
|
fmt.Sscanf(v, "%d", &num)
|
||
|
brick = append(brick, num)
|
||
|
}
|
||
|
bricks = append(bricks, brick)
|
||
|
}
|
||
|
|
||
|
sort.Slice(bricks, func(i, j int) bool {
|
||
|
return bricks[i][2] < bricks[j][2]
|
||
|
})
|
||
|
|
||
|
for index, brick := range bricks {
|
||
|
maxZ := 1
|
||
|
for _, check := range bricks[:index] {
|
||
|
if overlaps(brick, check) {
|
||
|
maxZ = max(maxZ, check[5]+1)
|
||
|
}
|
||
|
}
|
||
|
brick[5] -= brick[2] - maxZ
|
||
|
brick[2] = maxZ
|
||
|
}
|
||
|
|
||
|
sort.Slice(bricks, func(i, j int) bool {
|
||
|
return bricks[i][2] < bricks[j][2]
|
||
|
})
|
||
|
|
||
|
kSupportsV := make(map[int]map[int]struct{})
|
||
|
vSupportsK := make(map[int]map[int]struct{})
|
||
|
|
||
|
for i := range bricks {
|
||
|
kSupportsV[i] = make(map[int]struct{})
|
||
|
vSupportsK[i] = make(map[int]struct{})
|
||
|
}
|
||
|
|
||
|
for j, upper := range bricks {
|
||
|
for i, lower := range bricks[:j] {
|
||
|
if overlaps(lower, upper) && upper[2] == lower[5]+1 {
|
||
|
kSupportsV[i][j] = struct{}{}
|
||
|
vSupportsK[j][i] = struct{}{}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
total := 0
|
||
|
|
||
|
for i := range bricks {
|
||
|
satisfies := true
|
||
|
for j := range kSupportsV[i] {
|
||
|
if len(vSupportsK[j]) < 2 {
|
||
|
satisfies = false
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
if satisfies {
|
||
|
total++
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fmt.Println("# Part 1")
|
||
|
fmt.Println(total)
|
||
|
}
|
||
|
|
||
|
func part2(input []string) {
|
||
|
var bricks [][]int
|
||
|
|
||
|
for _, line := range input {
|
||
|
values := strings.Split(strings.ReplaceAll(line, "~", ","), ",")
|
||
|
var brick []int
|
||
|
for _, v := range values {
|
||
|
num := 0
|
||
|
fmt.Sscanf(v, "%d", &num)
|
||
|
brick = append(brick, num)
|
||
|
}
|
||
|
bricks = append(bricks, brick)
|
||
|
}
|
||
|
sort.SliceStable(bricks, func(i, j int) bool {
|
||
|
return bricks[i][2] < bricks[j][2]
|
||
|
})
|
||
|
for index, brick := range bricks {
|
||
|
maxZ := 1
|
||
|
for _, check := range bricks[:index] {
|
||
|
if overlaps(brick, check) {
|
||
|
maxZ = max(maxZ, check[5]+1)
|
||
|
}
|
||
|
}
|
||
|
brick[5] -= brick[2] - maxZ
|
||
|
brick[2] = maxZ
|
||
|
}
|
||
|
sort.SliceStable(bricks, func(i, j int) bool {
|
||
|
return bricks[i][2] < bricks[j][2]
|
||
|
})
|
||
|
|
||
|
kSupportsV := make(map[int]map[int]struct{})
|
||
|
vSupportsK := make(map[int]map[int]struct{})
|
||
|
for i := range bricks {
|
||
|
kSupportsV[i] = make(map[int]struct{})
|
||
|
vSupportsK[i] = make(map[int]struct{})
|
||
|
}
|
||
|
|
||
|
for j, upper := range bricks {
|
||
|
for i, lower := range bricks[:j] {
|
||
|
if overlaps(lower, upper) && upper[2] == lower[5]+1 {
|
||
|
kSupportsV[i][j] = struct{}{}
|
||
|
vSupportsK[j][i] = struct{}{}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
total := 0
|
||
|
for i := range bricks {
|
||
|
q := make([]int, 0)
|
||
|
for j := range kSupportsV[i] {
|
||
|
if len(vSupportsK[j]) == 1 {
|
||
|
q = append(q, j)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
falling := make(map[int]struct{})
|
||
|
for _, j := range q {
|
||
|
falling[j] = struct{}{}
|
||
|
}
|
||
|
falling[i] = struct{}{}
|
||
|
|
||
|
for len(q) > 0 {
|
||
|
j := q[0]
|
||
|
q = q[1:]
|
||
|
for k := range kSupportsV[j] {
|
||
|
if _, ok := falling[k]; !ok {
|
||
|
if isSubset(vSupportsK[k], falling) {
|
||
|
q = append(q, k)
|
||
|
falling[k] = struct{}{}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
total += len(falling) - 1
|
||
|
}
|
||
|
fmt.Println("# Part 2")
|
||
|
fmt.Println(total)
|
||
|
}
|
||
|
|
||
|
func isSubset(set1, set2 map[int]struct{}) bool {
|
||
|
for key := range set1 {
|
||
|
if _, ok := set2[key]; !ok {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
func overlaps(a, b []int) bool {
|
||
|
return max(a[0], b[0]) <= min(a[3], b[3]) && max(a[1], b[1]) <= min(a[4], b[4])
|
||
|
}
|
||
|
|
||
|
func max(a, b int) int {
|
||
|
if a > b {
|
||
|
return a
|
||
|
}
|
||
|
return b
|
||
|
}
|
||
|
|
||
|
func min(a, b int) int {
|
||
|
if a < b {
|
||
|
return a
|
||
|
}
|
||
|
return b
|
||
|
}
|