From 7b34b52e5efd9bd0a41723d08fa986133c855246 Mon Sep 17 00:00:00 2001 From: efim Date: Fri, 22 Dec 2023 08:44:10 +0000 Subject: [PATCH] day22, simple block code --- day22/block.go | 97 +++++++++++++++++++++++++++++++++++++++++++++ day22/block_test.go | 37 +++++++++++++++++ day22/example | 7 ++++ day22/notes.org | 32 +++++++++++++++ day22/sandSlabs.go | 10 +++++ main.go | 6 +-- 6 files changed, 186 insertions(+), 3 deletions(-) create mode 100644 day22/block.go create mode 100644 day22/block_test.go create mode 100644 day22/example create mode 100644 day22/notes.org create mode 100644 day22/sandSlabs.go diff --git a/day22/block.go b/day22/block.go new file mode 100644 index 0000000..cfdd2e4 --- /dev/null +++ b/day22/block.go @@ -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 +} diff --git a/day22/block_test.go b/day22/block_test.go new file mode 100644 index 0000000..44601a5 --- /dev/null +++ b/day22/block_test.go @@ -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) + } +} diff --git a/day22/example b/day22/example new file mode 100644 index 0000000..43a7fc5 --- /dev/null +++ b/day22/example @@ -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 diff --git a/day22/notes.org b/day22/notes.org new file mode 100644 index 0000000..9ec0991 --- /dev/null +++ b/day22/notes.org @@ -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 diff --git a/day22/sandSlabs.go b/day22/sandSlabs.go new file mode 100644 index 0000000..5964071 --- /dev/null +++ b/day22/sandSlabs.go @@ -0,0 +1,10 @@ +package day22 + +import ( + "fmt" +) + +func Run() int { + fmt.Print("oi, hello day 22") + return 0 +} diff --git a/main.go b/main.go index af91cde..e37738e 100644 --- a/main.go +++ b/main.go @@ -4,15 +4,15 @@ import ( "log" "time" - "sunshine.industries/aoc2023/day21" + "sunshine.industries/aoc2023/day22" ) func main() { startTime := time.Now() log.Print("> starting run:") - result := day21.Run() - log.Printf("\n\nday21 result: %d\n****\n", result) + result := day22.Run() + log.Printf("\n\nday22 result: %d\n****\n", result) endTime := time.Now() diff := endTime.Sub(startTime) log.Printf("execution took %s", diff.String())