package day22 import "log" 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) - 1), MaxSettledOnXY: make(map[XY]*Block), SettledOnZ: make([][]*Block, len(blocksByZ)), } } func (s *Space)CountFreeBlocks() (result int) { allBlocks := make(map[*Block]any) for _, row := range s.SettledOnZ { for _, block := range row { allBlocks[block] = struct{}{} if len(block.SupportedBy) == 1 { log.Printf("in block %+v. only support is %+v", block, block.SupportedBy) log.Printf("should be NOT OK to remove %+v", block.SupportedBy) delete(allBlocks, block.SupportedBy[0]) } } } result = len(allBlocks) return } func (s *Space)SettleAll() { for i := uint(1); i <= s.MaxZ; i++ { s.SettleZ(i) } } // settle all blocks in Z, remove Z from UnsettledByZ func (s *Space)SettleZ(z uint) { blocksToSettle := s.UnsettledByZ[int(z)] for _, block := range blocksToSettle { s.SettleBlock(block) } s.UnsettledByZ[int(z)] = nil } // 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 { underBlockMaxZ := underBlock.Z + underBlock.ZHeight if underBlockMaxZ > underZMax { underZBlocks = []*Block{underBlock} underZMax = underBlockMaxZ } else if underBlockMaxZ == underZMax { underZBlocks = append(underZBlocks, underBlock) } } s.MaxSettledOnXY[xy] = block } for _, settledUnderblock := range underZBlocks { settledUnderblock.Supports = append(settledUnderblock.Supports, block) block.SupportedBy = append(block.SupportedBy, settledUnderblock) } block.Z = underZMax + 1 block.IsSettled = true s.SettledOnZ[block.Z] = append(s.SettledOnZ[block.Z], block) }