|
|
|
|
@ -105,6 +105,13 @@ func (tower *Tower) layout(brick *Brick, currZ int) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
brick.start.z = currZ
|
|
|
|
|
if brickHeight > 1 {
|
|
|
|
|
brick.end.z = currZ + brickHeight - 1
|
|
|
|
|
} else {
|
|
|
|
|
brick.end.z = currZ
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (tower *Tower) addBrick(brick *Brick) {
|
|
|
|
|
@ -137,11 +144,11 @@ func (tower *Tower) addBrick(brick *Brick) {
|
|
|
|
|
|
|
|
|
|
func (tower *Tower) Print() {
|
|
|
|
|
//for z := tower.maxHeight(); z >= 0; z-- {
|
|
|
|
|
for z := 8; z > 0; z-- {
|
|
|
|
|
for z := 20; z > 0; z-- {
|
|
|
|
|
for x := 0; x < tower.floorWidth; x++ {
|
|
|
|
|
for y := 0; y < tower.floorWidth; y++ {
|
|
|
|
|
if tower.floors[z][x][y] != nil {
|
|
|
|
|
fmt.Print(tower.floors[z][x][y].ID)
|
|
|
|
|
fmt.Print(string(byte('A') - 1 + byte(tower.floors[z][x][y].ID)%26))
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Print(".")
|
|
|
|
|
}
|
|
|
|
|
@ -184,3 +191,141 @@ func Part1(lines []string) (int, []*Brick) {
|
|
|
|
|
tower.Print()
|
|
|
|
|
return count, bricks
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
func Part2(lines []string) {
|
|
|
|
|
// place bricks like Part1
|
|
|
|
|
// and change z coord of each brick once it is layed out
|
|
|
|
|
bricks := parseBricks(lines)
|
|
|
|
|
tower := NewTower(500, 10)
|
|
|
|
|
|
|
|
|
|
for _, brick := range bricks {
|
|
|
|
|
fmt.Printf("Placing brick %d (%v)~(%v)\n", brick.ID, brick.start, brick.end)
|
|
|
|
|
tower.addBrick(brick)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// sort brick by z coord desc (highest first)
|
|
|
|
|
slices.SortFunc(bricks, func(a, b *Brick) int {
|
|
|
|
|
return b.start.z - a.start.z
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// for each brick
|
|
|
|
|
// if the brick above the current brick has just the current brick as support
|
|
|
|
|
// then add 1 + the total fall of the brick above (coming from the map "total fallen")
|
|
|
|
|
// Store the value in the map "total fallen" using the ID of the current brick
|
|
|
|
|
// end for
|
|
|
|
|
count := 0
|
|
|
|
|
for _, brick := range bricks {
|
|
|
|
|
for _, aboveBrick := range brick.supports {
|
|
|
|
|
if len(aboveBrick.supportedBy) == 0 {
|
|
|
|
|
log.Fatalln("Bug ", brick)
|
|
|
|
|
}
|
|
|
|
|
if len(aboveBrick.supportedBy) == 1 {
|
|
|
|
|
// will fall
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
func buildDropList(brick *Brick, droppedList *map[int]bool) {
|
|
|
|
|
// Do not drop if the bricks below have not all been removed
|
|
|
|
|
for _, supportedBy := range brick.supportedBy {
|
|
|
|
|
if !(*droppedList)[supportedBy.ID] {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
(*droppedList)[brick.ID] = true // the supported brick
|
|
|
|
|
|
|
|
|
|
for _, supportedBrick := range brick.supports {
|
|
|
|
|
dropAbove := true
|
|
|
|
|
for _, supportedBy := range supportedBrick.supportedBy {
|
|
|
|
|
if !(*droppedList)[supportedBy.ID] {
|
|
|
|
|
dropAbove = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if dropAbove {
|
|
|
|
|
buildDropList(supportedBrick, droppedList) // the drops from the supported brick
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Part2(lines []string) int {
|
|
|
|
|
bricks := parseBricks(lines)
|
|
|
|
|
tower := NewTower(500, 10)
|
|
|
|
|
|
|
|
|
|
for _, brick := range bricks {
|
|
|
|
|
//fmt.Printf("Placing brick %d (%v)~(%v)\n", brick.ID, brick.start, brick.end)
|
|
|
|
|
tower.addBrick(brick)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// for debugging
|
|
|
|
|
slices.SortFunc(bricks, func(a, b *Brick) int {
|
|
|
|
|
return a.ID - b.ID
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
sum := 0
|
|
|
|
|
for _, brick := range bricks {
|
|
|
|
|
singleSupport := false
|
|
|
|
|
|
|
|
|
|
for _, supportedBrick := range brick.supports {
|
|
|
|
|
if len(supportedBrick.supportedBy) == 0 {
|
|
|
|
|
log.Fatalln("Bug ", brick)
|
|
|
|
|
}
|
|
|
|
|
if len(supportedBrick.supportedBy) == 1 {
|
|
|
|
|
singleSupport = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
if singleSupport {
|
|
|
|
|
|
|
|
|
|
disintegrated := map[int]bool{brick.ID: true}
|
|
|
|
|
checkList := []*Brick{brick}
|
|
|
|
|
for len(checkList) > 0 {
|
|
|
|
|
// take first from checklist
|
|
|
|
|
check := checkList[0]
|
|
|
|
|
checkList = checkList[1:]
|
|
|
|
|
// for all bricks above, check ...
|
|
|
|
|
for _, above := range check.supports {
|
|
|
|
|
bricksRemoved := 0
|
|
|
|
|
// whether all bricks below it are disintegrated ...
|
|
|
|
|
for _, below := range above.supportedBy {
|
|
|
|
|
if disintegrated[below.ID] {
|
|
|
|
|
bricksRemoved++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if len(above.supportedBy) == bricksRemoved {
|
|
|
|
|
// then it would fall
|
|
|
|
|
checkList = append(checkList, above)
|
|
|
|
|
disintegrated[above.ID] = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// do not include the brick we are currently checking
|
|
|
|
|
fmt.Printf("Brick %d would drop %d other bricks\n", brick.ID, len(disintegrated)-1)
|
|
|
|
|
sum += len(disintegrated) - 1
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if singleSupport {
|
|
|
|
|
dropList := map[int]bool{}
|
|
|
|
|
dropList[brick.ID] = true
|
|
|
|
|
if brick.ID == 14 {
|
|
|
|
|
fmt.Println("debug")
|
|
|
|
|
}
|
|
|
|
|
for _, supportedBrick := range brick.supports {
|
|
|
|
|
buildDropList(supportedBrick, &dropList)
|
|
|
|
|
}
|
|
|
|
|
fmt.Printf("Brick %d would drop %d other bricks\n", brick.ID, len(dropList)-1)
|
|
|
|
|
sum += len(dropList) - 1
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tower.Print()
|
|
|
|
|
|
|
|
|
|
return sum
|
|
|
|
|
}
|
|
|
|
|
|