day22, simple block code

This commit is contained in:
efim 2023-12-22 08:44:10 +00:00
parent 99c2269df8
commit 7b34b52e5e
6 changed files with 186 additions and 3 deletions

97
day22/block.go Normal file
View File

@ -0,0 +1,97 @@
package day22
import (
"fmt"
"log"
"os"
"regexp"
"strconv"
"strings"
)
type XY struct {
X, Y uint
}
type Block struct {
XMin, XMax uint
YMin, YMax uint
Z uint
IsSettled bool
ZHeight uint
Supports []*Block
}
func (b *Block) String() string {
return fmt.Sprintf("[Block x:%d-%d, y:%d-%d, z:%d, h:%d, isSettled %t]",
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) (b Block) {
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
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 _, line := range strings.Split(text, "\n") {
block := ReadBlock(line)
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
}

37
day22/block_test.go Normal file
View File

@ -0,0 +1,37 @@
package day22
import (
"strings"
"testing"
)
func TestReadBlock(t *testing.T) {
lines := `1,0,1~1,2,1
0,0,2~2,0,2
0,2,3~2,2,3
0,0,4~0,2,4
2,0,5~2,2,5
0,1,6~2,1,6
1,1,8~1,1,9`
for _, line := range strings.Split(lines, "\n") {
b := ReadBlock(line)
t.Logf("read %s into block %+v", line, b)
t.Logf("XY coords for %+v are : %+v", b, b.getXY())
}
}
func TestReadFile(t *testing.T) {
filename := "example"
// filename := "input"
blocks := ReadBlockFile(filename)
byZ := BlocksByZ(blocks)
for z, zBlocks := range byZ {
zBlocksLine := ""
for _, block := range zBlocks {
zBlocksLine += block.String()
}
t.Logf("for level %d blocks %+v", z, zBlocksLine)
}
}

7
day22/example Normal file
View File

@ -0,0 +1,7 @@
1,0,1~1,2,1
0,0,2~2,0,2
0,2,3~2,2,3
0,0,4~0,2,4
2,0,5~2,2,5
0,1,6~2,1,6
1,1,8~1,1,9

32
day22/notes.org Normal file
View File

@ -0,0 +1,32 @@
#+title: Notes
* ok. let's try this.
i'd want to have block type
with function to get it's XY coords
i'd want to settle blocks first.
but if i store enough data, for example block.supports slice i'll be able to anser first task.
(settledOnZ) i would want [][]*Block per level from 0 to up. with references to blocks that settled on that level
(maxSettledXY) and for going from 0 up i'll want XY of the top block settled with it's level. i guess i could store settled level in the block as well
then for settling blocks, i will need (sorted map if data is sparse?) go from 0 up,
order of processing for blocks on same z level is not important.
for each block get it's XY, check maxSettledXY if there's a block check it's Z,
for all block XY coords, find maximal settled Z, and refs to all blocks that are directly under with that same Z.
for the block set settledZ to Z+1, and for all those blocks add the block to 'supports'
add block to settledOnZ[Z+1]
for the second part, i can scan all the blocks, don't even need the settledOnZ, just check if it's 'supports' is empty
** DONE block type
store z, and have 'settledZ', maybe with default -1?
** DONE coords type, func to get XY coords of the block
** DONE now i guess what? do i want a sorted map? or just map from height to blocks on that hight?
let's read file, and calc max height present?
i suppose funciton to read file could also be initially entered via test, right?
** TODO now go through the z levels, block by block, doing setting.
i suppose i could organize setting methods around Space?
it will store (settledOnZ) and (maxSettledOnXY)
** i can already imagine secon part? what is the most volume that can be disintegrated? or what? most volume is just all

10
day22/sandSlabs.go Normal file
View File

@ -0,0 +1,10 @@
package day22
import (
"fmt"
)
func Run() int {
fmt.Print("oi, hello day 22")
return 0
}

View File

@ -4,15 +4,15 @@ import (
"log" "log"
"time" "time"
"sunshine.industries/aoc2023/day21" "sunshine.industries/aoc2023/day22"
) )
func main() { func main() {
startTime := time.Now() startTime := time.Now()
log.Print("> starting run:") log.Print("> starting run:")
result := day21.Run() result := day22.Run()
log.Printf("\n\nday21 result: %d\n****\n", result) log.Printf("\n\nday22 result: %d\n****\n", result)
endTime := time.Now() endTime := time.Now()
diff := endTime.Sub(startTime) diff := endTime.Sub(startTime)
log.Printf("execution took %s", diff.String()) log.Printf("execution took %s", diff.String())