105 lines
2.0 KiB
Go
105 lines
2.0 KiB
Go
package day22
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"github.com/deckarep/golang-set/v2"
|
|
)
|
|
|
|
type XY struct {
|
|
X, Y uint
|
|
}
|
|
|
|
type Block struct {
|
|
NameNum int
|
|
XMin, XMax uint
|
|
YMin, YMax uint
|
|
Z uint
|
|
IsSettled bool
|
|
ZHeight uint
|
|
Supports mapset.Set[*Block]
|
|
SupportedBy mapset.Set[*Block]
|
|
}
|
|
|
|
func (b *Block) String() string {
|
|
return fmt.Sprintf("[Block %d - x:%d-%d, y:%d-%d, z:%d, h:%d, isSettled %t]",
|
|
b.NameNum, b.XMin, b.XMax, b.YMin, b.YMax, b.Z, b.ZHeight, b.IsSettled)
|
|
}
|
|
|
|
func AtoIOrPanic(a string) int {
|
|
n, err := strconv.Atoi(a)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return n
|
|
}
|
|
|
|
func ReadBlock(line string, num int) (b Block) {
|
|
b.NameNum = num
|
|
re := regexp.MustCompile(`(\d+),(\d+),(\d+)~(\d+),(\d+),(\d+)`)
|
|
matches := re.FindStringSubmatch(line)
|
|
|
|
x1, x2 := AtoIOrPanic(matches[1]), AtoIOrPanic(matches[4])
|
|
y1, y2 := AtoIOrPanic(matches[2]), AtoIOrPanic(matches[5])
|
|
z1, z2 := AtoIOrPanic(matches[3]), AtoIOrPanic(matches[6])
|
|
|
|
b.XMax = uint(max(x1, x2))
|
|
b.XMin = uint(min(x1, x2))
|
|
b.YMax = uint(max(y1, y2))
|
|
b.YMin = uint(min(y1, y2))
|
|
b.Z = uint(min(z1, z2))
|
|
b.ZHeight = uint(max(z1, z2)) - b.Z
|
|
|
|
b.Supports = mapset.NewSet[*Block]()
|
|
b.SupportedBy = mapset.NewSet[*Block]()
|
|
|
|
return
|
|
}
|
|
|
|
func (b *Block) getXY() (coords []XY) {
|
|
for x := b.XMin; x <= b.XMax; x++ {
|
|
for y := b.YMin; y <= b.YMax; y++ {
|
|
coords = append(coords, XY{X: x, Y: y})
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func ReadBlockFile(filename string) (blocks []*Block) {
|
|
bytes, err := os.ReadFile(filename)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
text := strings.TrimSpace(string(bytes))
|
|
for i, line := range strings.Split(text, "\n") {
|
|
block := ReadBlock(line, i)
|
|
blocks = append(blocks, &block)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func BlocksByZ(blocks []*Block) [][]*Block {
|
|
maxZ := uint(0)
|
|
for _, block := range blocks {
|
|
if block.Z > maxZ {
|
|
maxZ = block.Z
|
|
}
|
|
}
|
|
log.Print("found max z: ", maxZ)
|
|
|
|
result := make([][]*Block, maxZ+1)
|
|
|
|
for _, block := range blocks {
|
|
result[block.Z] = append(result[block.Z], block)
|
|
}
|
|
|
|
return result
|
|
}
|