From 3ede691333f979300ace0cbc122479e00f65bf3e Mon Sep 17 00:00:00 2001 From: efim Date: Fri, 22 Dec 2023 09:24:43 +0000 Subject: [PATCH] day22: initial block setting --- day22/block.go | 12 +++++---- day22/block_test.go | 2 +- day22/notes.org | 1 + day22/space.go | 56 +++++++++++++++++++++++++++++++++++++++ day22/space_test.go | 64 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 129 insertions(+), 6 deletions(-) create mode 100644 day22/space.go create mode 100644 day22/space_test.go diff --git a/day22/block.go b/day22/block.go index cfdd2e4..6e5e1c4 100644 --- a/day22/block.go +++ b/day22/block.go @@ -14,6 +14,7 @@ type XY struct { } type Block struct { + NameNum int XMin, XMax uint YMin, YMax uint Z uint @@ -23,8 +24,8 @@ type Block struct { } 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) + 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 { @@ -35,7 +36,8 @@ func AtoIOrPanic(a string) int { return n } -func ReadBlock(line string) (b Block) { +func ReadBlock(line string, num int) (b Block) { + b.NameNum = num re := regexp.MustCompile(`(\d+),(\d+),(\d+)~(\d+),(\d+),(\d+)`) matches := re.FindStringSubmatch(line) @@ -70,8 +72,8 @@ func ReadBlockFile(filename string) (blocks []*Block) { } text := strings.TrimSpace(string(bytes)) - for _, line := range strings.Split(text, "\n") { - block := ReadBlock(line) + for i, line := range strings.Split(text, "\n") { + block := ReadBlock(line, i) blocks = append(blocks, &block) } diff --git a/day22/block_test.go b/day22/block_test.go index 44601a5..350b340 100644 --- a/day22/block_test.go +++ b/day22/block_test.go @@ -15,7 +15,7 @@ func TestReadBlock(t *testing.T) { 1,1,8~1,1,9` for _, line := range strings.Split(lines, "\n") { - b := ReadBlock(line) + b := ReadBlock(line, 0) t.Logf("read %s into block %+v", line, b) t.Logf("XY coords for %+v are : %+v", b, b.getXY()) } diff --git a/day22/notes.org b/day22/notes.org index 9ec0991..2d31056 100644 --- a/day22/notes.org +++ b/day22/notes.org @@ -29,4 +29,5 @@ 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) +** TODO [#A] when i settle single block. the maxSettledOnXY - should use (z + height) ** 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/space.go b/day22/space.go new file mode 100644 index 0000000..2475cc6 --- /dev/null +++ b/day22/space.go @@ -0,0 +1,56 @@ +package day22 + +type Space struct { + MaxZ uint + SettledOnZ [][]*Block + MaxSettledOnXY map[XY]*Block + UnsettledByZ [][]*Block +} + +func NewSpace(blocksByZ [][]*Block) Space { + return Space{ + UnsettledByZ: blocksByZ, + MaxZ: uint(len(blocksByZ)), + MaxSettledOnXY: make(map[XY]*Block), + SettledOnZ: make([][]*Block, len(blocksByZ)), + } +} + +// settle all blocks in Z, remove Z from UnsettledByZ +func (s *Space)SettleZ(z uint) { + +} + +// for the block: +// check all XY in MaxSettledOnXY +// if there are any settled blocks on these XY, find max of their Z +// for all blocks with that Z - add block to their 'supports' +// set Z for block to Z+1, settled to true +// add block as highest settled for all the XY +// add block to MaxSettledOnXY +func (s *Space)SettleBlock(block *Block) { + underZMax := uint(0) + underZBlocks := make([]*Block, 0) + for _, xy := range block.getXY() { + underBlock, found := s.MaxSettledOnXY[xy] + // if block.NameNum + if found { + if underBlock.Z > underZMax { + underZBlocks = []*Block{underBlock} + underZMax = underBlock.Z + } else if underBlock.Z == underZMax { + underZBlocks = append(underZBlocks, underBlock) + } + } + s.MaxSettledOnXY[xy] = block + } + + for _, settledUnderblock := range underZBlocks { + settledUnderblock.Supports = append(settledUnderblock.Supports, block) + } + + block.Z = underZMax + 1 + block.IsSettled = true + + s.SettledOnZ[block.Z] = append(s.SettledOnZ[block.Z], block) +} diff --git a/day22/space_test.go b/day22/space_test.go new file mode 100644 index 0000000..748b67e --- /dev/null +++ b/day22/space_test.go @@ -0,0 +1,64 @@ +package day22 + +import "testing" + +func TestSpaceSettleSingle(t *testing.T) { + filename := "example" + blocks := ReadBlockFile(filename) + byZ := BlocksByZ(blocks) + + space := NewSpace(byZ) + t.Logf("read space %+v", space) + + block := blocks[2] + t.Logf("block before setting %+v", block) + space.SettleBlock(block) + t.Logf("space after settings %+v:\n%+v", block, space) +} + +func TestSpaceSettleSecondNearby(t *testing.T) { + filename := "example" + blocks := ReadBlockFile(filename) + byZ := BlocksByZ(blocks) + + space := NewSpace(byZ) + t.Logf("read space %+v", space) + + block1 := blocks[0] + block2 := blocks[3] + t.Logf("block 1 before setting %+v", block1) + space.SettleBlock(block1) + t.Logf("space after settling block 1 %+v", space) + t.Logf("block 2 before setting %+v", block2) + space.SettleBlock(block2) + t.Logf("space after settling block 2 %+v", space) + t.Logf("space after settling %+v", space) +} + +func TestSpaceSettleThirdOnTopFirst(t *testing.T) { + filename := "example" + blocks := ReadBlockFile(filename) + byZ := BlocksByZ(blocks) + + space := NewSpace(byZ) + t.Logf("read space %+v", space) + + block1 := blocks[0] + block2 := blocks[3] + block3 := blocks[2] // should overlap X & Y coords of block 1 + t.Logf("block 1 before setting %+v", block1) + space.SettleBlock(block1) + t.Logf("space after settling block 1 %+v", space) + t.Logf("block 2 before setting %+v", block2) + space.SettleBlock(block2) + t.Logf("space after settling block 2 %+v", space) + t.Logf("block 3 before setting %+v", block3) + space.SettleBlock(block3) + t.Logf("space after settling block 3 %+v", space) + t.Logf("space after settling %+v", space) + + t.Logf("blocks 1 & 3 should support it: %+v , %+v", block1.Supports, block2.Supports) + // because block 3 is 0-2, 2-2 + // and that overlaps 1-1, 0-2 AND 0-0, 0-2 + t.Logf("other blocks should not supt %+v", block3.Supports) +}