81f693cb52
Fucking bullshit. I'm starting to develop a hate for directions
330 lines
7.7 KiB
Go
330 lines
7.7 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"slices"
|
|
"sync"
|
|
|
|
"git.mstar.dev/mstar/aoc24/util"
|
|
"git.mstar.dev/mstar/goutils/sliceutils"
|
|
)
|
|
|
|
type Block struct {
|
|
Char rune
|
|
Counter int
|
|
}
|
|
|
|
type Coordinate struct {
|
|
X, Y int
|
|
}
|
|
|
|
type Area struct {
|
|
area [][]Block //Y, X
|
|
rwl sync.RWMutex
|
|
}
|
|
|
|
func convertLinesIntoBlockMap(lines []string) Area {
|
|
out := [][]Block{}
|
|
for _, line := range lines {
|
|
bordLine := []Block{}
|
|
for _, char := range line {
|
|
// All blocks have four different blocks bordering in the beginning
|
|
bordLine = append(bordLine, Block{char, 0})
|
|
}
|
|
out = append(out, bordLine)
|
|
}
|
|
|
|
return Area{out, sync.RWMutex{}}
|
|
}
|
|
|
|
func (c Coordinate) Left() Coordinate {
|
|
return Coordinate{c.X - 1, c.Y}
|
|
}
|
|
|
|
func (c Coordinate) Right() Coordinate {
|
|
return Coordinate{c.X + 1, c.Y}
|
|
}
|
|
|
|
func (c Coordinate) Up() Coordinate {
|
|
return Coordinate{c.X, c.Y - 1}
|
|
}
|
|
|
|
func (c Coordinate) Down() Coordinate {
|
|
return Coordinate{c.X, c.Y + 1}
|
|
}
|
|
|
|
func (a *Area) Get(x, y int) *Block {
|
|
if y < 0 || y >= len(a.area) || x < 0 || x >= len(a.area[0]) {
|
|
return nil
|
|
}
|
|
a.rwl.RLock()
|
|
defer a.rwl.RUnlock()
|
|
return &a.area[y][x]
|
|
}
|
|
|
|
func (a *Area) GetCoord(c Coordinate) *Block {
|
|
if c.Y < 0 || c.Y >= len(a.area) || c.X < 0 || c.X >= len(a.area[0]) {
|
|
return nil
|
|
}
|
|
a.rwl.RLock()
|
|
defer a.rwl.RUnlock()
|
|
return &a.area[c.Y][c.X]
|
|
}
|
|
|
|
func (a *Area) CountEdgesAtCoord(c Coordinate) int {
|
|
block := a.GetCoord(c)
|
|
if block == nil {
|
|
return 1
|
|
}
|
|
acc := 0
|
|
left := a.GetCoord(c.Left())
|
|
if left == nil || left.Char != block.Char {
|
|
acc++
|
|
}
|
|
right := a.GetCoord(c.Right())
|
|
if right == nil || right.Char != block.Char {
|
|
acc++
|
|
}
|
|
up := a.GetCoord(c.Up())
|
|
if up == nil || up.Char != block.Char {
|
|
acc++
|
|
}
|
|
down := a.GetCoord(c.Down())
|
|
if down == nil || down.Char != block.Char {
|
|
acc++
|
|
}
|
|
|
|
return acc
|
|
}
|
|
|
|
func (a *Area) CollectRegion(at Coordinate) []Coordinate {
|
|
coords := []Coordinate{at}
|
|
self := a.GetCoord(at)
|
|
self.Counter++
|
|
|
|
left := a.GetCoord(at.Left())
|
|
if left != nil && left.Char == self.Char && left.Counter != self.Counter {
|
|
coords = append(coords, a.CollectRegion(at.Left())...)
|
|
}
|
|
right := a.GetCoord(at.Right())
|
|
if right != nil && right.Char == self.Char && right.Counter != self.Counter {
|
|
coords = append(coords, a.CollectRegion(at.Right())...)
|
|
}
|
|
Up := a.GetCoord(at.Up())
|
|
if Up != nil && Up.Char == self.Char && Up.Counter != self.Counter {
|
|
coords = append(coords, a.CollectRegion(at.Up())...)
|
|
}
|
|
Down := a.GetCoord(at.Down())
|
|
if Down != nil && Down.Char == self.Char && Down.Counter != self.Counter {
|
|
coords = append(coords, a.CollectRegion(at.Down())...)
|
|
}
|
|
|
|
return coords
|
|
}
|
|
|
|
func (a *Area) GetAllAreas() [][]Coordinate {
|
|
areas := [][]Coordinate{}
|
|
for iy, line := range a.area {
|
|
inner:
|
|
for ix := range line {
|
|
tmp := a.CollectRegion(Coordinate{ix, iy})
|
|
for _, a := range areas {
|
|
if sliceutils.CompareUnordered(a, tmp) {
|
|
continue inner
|
|
}
|
|
}
|
|
areas = append(areas, tmp)
|
|
}
|
|
}
|
|
|
|
return areas
|
|
}
|
|
|
|
// Filter for coordinates where a section borders on a different section
|
|
func filterBorderLeft(coords []Coordinate, area *Area) []Coordinate {
|
|
return sliceutils.Filter(coords, func(t Coordinate) bool {
|
|
self := area.GetCoord(t)
|
|
other := area.GetCoord(t.Left())
|
|
return other == nil || self.Char != other.Char
|
|
})
|
|
}
|
|
|
|
func filterBorderRight(coords []Coordinate, area *Area) []Coordinate {
|
|
return sliceutils.Filter(coords, func(t Coordinate) bool {
|
|
self := area.GetCoord(t)
|
|
other := area.GetCoord(t.Right())
|
|
return other == nil || self.Char != other.Char
|
|
})
|
|
}
|
|
|
|
func filterBorderUp(coords []Coordinate, area *Area) []Coordinate {
|
|
return sliceutils.Filter(coords, func(t Coordinate) bool {
|
|
self := area.GetCoord(t)
|
|
other := area.GetCoord(t.Up())
|
|
return other == nil || self.Char != other.Char
|
|
})
|
|
}
|
|
|
|
func filterBorderDown(coords []Coordinate, area *Area) []Coordinate {
|
|
return sliceutils.Filter(coords, func(t Coordinate) bool {
|
|
self := area.GetCoord(t)
|
|
other := area.GetCoord(t.Down())
|
|
return other == nil || self.Char != other.Char
|
|
})
|
|
}
|
|
|
|
func splitSameX(coords []Coordinate) [][]Coordinate {
|
|
axis := [][]Coordinate{}
|
|
axisLabeled := map[int][]Coordinate{}
|
|
for _, coord := range coords {
|
|
axisLabeled[coord.X] = append(axisLabeled[coord.X], coord)
|
|
}
|
|
for _, subCoords := range axisLabeled {
|
|
axis = append(axis, subCoords)
|
|
}
|
|
return axis
|
|
}
|
|
|
|
func splitSameY(coords []Coordinate) [][]Coordinate {
|
|
axis := [][]Coordinate{}
|
|
axisLabeled := map[int][]Coordinate{}
|
|
for _, coord := range coords {
|
|
axisLabeled[coord.Y] = append(axisLabeled[coord.Y], coord)
|
|
}
|
|
for _, subCoords := range axisLabeled {
|
|
axis = append(axis, subCoords)
|
|
}
|
|
return axis
|
|
}
|
|
|
|
func countUniqueEdgesLeft(coords []Coordinate, area *Area) int {
|
|
acc := 0
|
|
leftBorders := filterBorderLeft(coords, area)
|
|
// fmt.Printf("All left borders: %v\n", leftBorders)
|
|
bordersLeftPerAxis := splitSameX(leftBorders)
|
|
// fmt.Printf("Same left: %v\n", bordersLeftPerAxis)
|
|
for _, borders := range bordersLeftPerAxis {
|
|
// acc++
|
|
slices.SortFunc(borders, func(a, b Coordinate) int { return a.Y - b.Y })
|
|
// fmt.Printf("Axis left: %v\n", borders)
|
|
prevY := -500
|
|
for _, coord := range borders {
|
|
if coord.Y-1 != prevY {
|
|
acc++
|
|
}
|
|
prevY = coord.Y
|
|
}
|
|
}
|
|
fmt.Printf("Left borders: %v\n", acc)
|
|
return acc
|
|
}
|
|
|
|
func countUniqueEdgesRight(coords []Coordinate, area *Area) int {
|
|
acc := 0
|
|
bordersLeftPerAxis := splitSameX(filterBorderRight(coords, area))
|
|
// fmt.Printf("Same right: %v\n", bordersLeftPerAxis)
|
|
for _, borders := range bordersLeftPerAxis {
|
|
slices.SortFunc(borders, func(a, b Coordinate) int { return a.Y - b.Y })
|
|
// acc++
|
|
prevX := -500
|
|
for _, coord := range borders {
|
|
if coord.Y-1 != prevX {
|
|
acc++
|
|
}
|
|
prevX = coord.Y
|
|
}
|
|
}
|
|
fmt.Printf("Right borders: %v\n", acc)
|
|
return acc
|
|
}
|
|
|
|
func countUniqueEdgesUp(coords []Coordinate, area *Area) int {
|
|
acc := 0
|
|
bordersLeftPerAxis := splitSameY(filterBorderUp(coords, area))
|
|
fmt.Printf("Same up: %v\n", bordersLeftPerAxis)
|
|
for _, borders := range bordersLeftPerAxis {
|
|
// acc++
|
|
slices.SortFunc(borders, func(a, b Coordinate) int { return a.X - b.X })
|
|
fmt.Printf("Sorted up axis: %v\n", borders)
|
|
prevX := -500
|
|
for _, coord := range borders {
|
|
if coord.X-1 != prevX {
|
|
acc++
|
|
fmt.Println("Up inc")
|
|
}
|
|
prevX = coord.X
|
|
}
|
|
}
|
|
fmt.Printf("Up borders: %v\n", acc)
|
|
return acc
|
|
}
|
|
|
|
func countUniqueEdgesDown(coords []Coordinate, area *Area) int {
|
|
acc := 0
|
|
bordersLeftPerAxis := splitSameY(filterBorderDown(coords, area))
|
|
for _, borders := range bordersLeftPerAxis {
|
|
// acc++
|
|
slices.SortFunc(borders, func(a, b Coordinate) int { return a.X - b.X })
|
|
fmt.Printf("Same down: %v\n", bordersLeftPerAxis)
|
|
prevX := -500
|
|
for _, coord := range borders {
|
|
if coord.X-1 != prevX {
|
|
fmt.Println("Bigdiff")
|
|
acc++
|
|
}
|
|
prevX = coord.X
|
|
}
|
|
}
|
|
fmt.Printf("Down borders: %v\n", acc)
|
|
return acc
|
|
}
|
|
|
|
func countUniqueEdges(coords []Coordinate, area *Area) int {
|
|
return countUniqueEdgesLeft(
|
|
coords,
|
|
area,
|
|
) + countUniqueEdgesRight(
|
|
coords,
|
|
area,
|
|
) + countUniqueEdgesUp(
|
|
coords,
|
|
area,
|
|
) + countUniqueEdgesDown(
|
|
coords,
|
|
area,
|
|
)
|
|
}
|
|
|
|
func main() {
|
|
area := convertLinesIntoBlockMap(util.FileContentToNonEmptyLines(util.LoadFileFromArgs()))
|
|
allAreas := area.GetAllAreas()
|
|
|
|
totalAcc := 0
|
|
for _, subArea := range allAreas {
|
|
tmp := 0
|
|
for _, coord := range subArea {
|
|
tmp += area.CountEdgesAtCoord(coord)
|
|
}
|
|
totalAcc += tmp * len(subArea)
|
|
}
|
|
fmt.Printf("Task 1: %d\n", totalAcc)
|
|
// fmt.Println(countUniqueEdges(allAreas[2], &area))
|
|
// return
|
|
edgesAcc := 0
|
|
for _, subArea := range allAreas {
|
|
tmp := countUniqueEdges(subArea, &area)
|
|
fmt.Printf(
|
|
"Area %s has %d edges with len %d\n",
|
|
string(area.GetCoord(subArea[0]).Char),
|
|
tmp,
|
|
len(subArea),
|
|
)
|
|
// fmt.Println(tmp * len(subArea))
|
|
edgesAcc += tmp * len(subArea)
|
|
}
|
|
fmt.Printf("Task 2: %d\n", edgesAcc)
|
|
}
|
|
|
|
// c2: l14 e22
|
|
// f3: l10 e12
|
|
// e7:
|