Advent-of-Code-2023/day22/space.go

90 lines
2.2 KiB
Go

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)
}