Compare commits

..

No commits in common. "29528f23acfe595edb0e035cf52bb17a5bce5f4e" and "53930e66ac783a0d7b028d603b8e07d0c481583c" have entirely different histories.

15 changed files with 3 additions and 982 deletions

View File

@ -1,11 +0,0 @@
...........
.....###.#.
.###.##..#.
..#.#...#..
....#.#....
.##..S####.
.##..#...#.
.......##..
.##.#.####.
.##..##.##.
...........

View File

@ -1,11 +0,0 @@
...........
...........
...........
...........
...........
.....S.....
...........
...........
...........
...........
...........

View File

@ -1,105 +0,0 @@
#+title: Notes
* part 1
so we aren't looking for minimal distance.
but all plots which are end to any path of length 'steps left'
so, i have to follow all possible paths to the end?
or. length of 6 and all even - because i could be doing <- ->
but i could be doing loop around that would increase path len by odd number
let's just make direct recursive thing.
create set of all reachable by n,
* oh, the part 2.
i suppose this 'infinite' garden could be managed with my 'neighbors' work with 'out of field'
fairly easy
but what about sizes of the maps? are we releasing maps of previous iterations?
maybe if i directly pass references to prev and current,
and manually set 'prev' to target new it will be collected?
and then elements after these steps <em>26501365</em> would fit into memory?
** i guess maybe it would help if i had 'fully saturated' field
as my minimal 'skipping' thing
** so. store FieldCoord(fieldRow, fieldCol) for fields which were fully saturated at current step.
filter out neighbors, no need to enter fully saturated fields
when counting
on odd - around the S, on even - with S
but the neighboring fields would potentially (likely?) be in different phases
but i guess they are necessarily in different phases?
or. if width odd - necessarily
if width even - then what?
then S is not in the center
my input is 131 chars of width.
so neighboring are necessarily of different phase.
could compute phase of (0,0)
and adjust from that
** TODO remake 'ReachableBySteps' into 'CountReachableBySteps' returning int
** TODO make it take 'isInitialCountOdd' - to know phase of {0,0} field
current phase can be determined by initial phase and current N
if initial count is odd, and now it's odd number, we made even iterations, so (0,0) is in even state
if initial count is even, and now it's even number, we made even iterations, so (0,0) is in even state
** DONE make neighbors take set of saturated fields
and not produce points on those fields
** DONE for field calculate what would be amount of points in each phase
...........
.....###.#.
.###.##..#.
..#.#...#..
....#.#....
.##..S####.
.##..#...#.
.......##..
.##.#.####.
.##..##.##.
...........
*** getting 39 and 42
let's check
42 is even?
*** hmmm
EOEOEOEOEOE
OEOEO###O#O
E###E##OE#E
OE#E#EOE#EO
EOEO#O#OEOE
O##EOE####O
E##OE#EOE#E
OEOEOEO##EO
E##O#O####E
O##EO##E##O
EOEOEOEOEOE
*** yes, sounds good
** CANCELLED after getting all new points. get coords of all fields we're working on.
( there already should be no points in saturated fields )
for each such field, check if it is saturated.
- can be done by comparing the phase with amount of points on saturated
if field saturated - add the coord into set
and remove all the points
** CANCELLED on the last step, when n is 0
return len(startingAt) + (all saturated fields) * (amount of elems in their phase)
** calculating points in even 7356 and odd 7321 phases
* so need to scrap things and do a more analytics approach.
no blocks on horizontal & vertical from (S)
meaning diamond expands to left & right well
* 26501365 = 202300 * 131 + 65 where 131 is the dimension of the grid
* if there is a formula A*i^2 + B*i + C = D
where i is full iteration
* for initial steps :
2023/12/21 13:25:23 after steps 65. full iter 0. got count 3701
2023/12/21 13:25:24 after steps 196. full iter 1. got count 33108
2023/12/21 13:25:27 after steps 327. full iter 2. got count 91853
2023/12/21 13:25:42 after steps 458. full iter 3. got count 179936
* https://www.dcode.fr/newton-interpolating-polynomial
14669x^2 + 14738*x+3701

View File

@ -1,211 +0,0 @@
package day21
import (
"fmt"
"log"
"os"
"strings"
)
func Run() int {
fmt.Print("hello day21")
filename := "day21/input"
field := ReadField(filename)
log.Print(field)
// for i := 6; i <= 10; i++ {
// reachableBySteps := field.ReachableBySteps(i, map[Coord]any{
// Coord{Row: field.RowStart, Col: field.ColStart}: struct{}{},
// })
// log.Print("reachable after steps : ", i, len(reachableBySteps))
// field.PrintCoord(reachableBySteps, 1)
// }
// initialSolutions := make(map[int]int)
// for fullIter := 0; fullIter < 4; fullIter++ {
// steps := 65 + fullIter * 131
// reachableBySteps := field.ReachableBySteps(steps, map[FieldPoint]any{
// FieldPoint{
// InField: Coord{Row: field.RowStart, Col: field.ColStart},
// }: struct{}{},
// })
// log.Printf("after steps %d. full iter %d. got count %d", steps, fullIter, len(reachableBySteps))
// initialSolutions[fullIter] = len(reachableBySteps)
// }
log.Println("will try to use the values to get coeff of Ax^2 + Bx + C = 0")
log.Println("then solve for x == 202300")
// f(x) = 14714x^2 + 14603x + 3791
// no.
// 14669x^2 + 14738*x+3701
x := 202300
result := 14669*x*x + 14738*x+3701
return result
}
// let's do dijkstra?
// i would need lots of space for edges?
// let's use a map with minimal distances?
// OR. just breath first traversal
type Field struct {
RowStart, ColStart int
symbols [][]rune
}
type Coord struct {
Row, Col int
}
type FieldPoint struct {
InField Coord
MetaField Coord
}
func (f Field) ReachableBySteps(n int, startingAt map[FieldPoint]any) map[FieldPoint]any {
if n%100 == 0 {
log.Println("going step: ", n)
}
if n == 0 {
return startingAt
}
// else collect directly available
oneStepExpanded := make(map[FieldPoint]any)
for cur := range startingAt {
for _, neighbor := range f.Neighbors(cur) {
oneStepExpanded[neighbor] = struct{}{}
}
}
// if n < 4 {
// log.Print("reachable after steps : ", n, len(oneStepExpanded))
// f.PrintCoord(oneStepExpanded, 5)
// }
return f.ReachableBySteps(n-1, oneStepExpanded)
}
func (f Field) Neighbors(c FieldPoint) (resut []FieldPoint) {
closeCoords := []FieldPoint{
{InField: Coord{Row: c.InField.Row + 1, Col: c.InField.Col}, MetaField: c.MetaField},
{InField: Coord{Row: c.InField.Row - 1, Col: c.InField.Col}, MetaField: c.MetaField},
{InField: Coord{Row: c.InField.Row, Col: c.InField.Col + 1}, MetaField: c.MetaField},
{InField: Coord{Row: c.InField.Row, Col: c.InField.Col - 1}, MetaField: c.MetaField},
}
for i, close := range closeCoords {
height := len(f.symbols)
width := len(f.symbols[0])
if close.InField.Row == height {
close.InField.Row = 0
close.MetaField.Row += 1
}
if close.InField.Row == -1 {
close.InField.Row = height - 1
close.MetaField.Row -= 1
}
if close.InField.Col == width {
close.InField.Col = 0
close.MetaField.Col += 1
}
if close.InField.Col == -1 {
// log.Printf("moving COL to lefter field from %d to %d", close.Col, width-1)
close.InField.Col = width - 1
close.MetaField.Col -= 1
}
closeCoords[i] = close
// but this is not it. i need to store the XX and YY
// so that points in other 'fields' would count separately. yuk
}
for _, close := range closeCoords {
if f.ValidCoord(close.InField.Row, close.InField.Col) {
symb := f.symbols[close.InField.Row][close.InField.Col]
if symb == '.' || symb == 'S' {
resut = append(resut, close)
}
}
}
// log.Print("getting neighbors for ", c, resut)
return
}
func (f Field) ValidCoord(row, col int) bool {
// log.Print("check valid ", row, col, row >= 0 && row < len(f.symbols) && col >= 0 && col < len(f.symbols[0]))
valid := row >= 0 && row < len(f.symbols) && col >= 0 && col < len(f.symbols[0])
if !valid {
panic(fmt.Sprint("getting invalid coord: ", row, col))
}
return valid
}
func (f Field) String() (result string) {
result += "\n"
for _, line := range f.symbols {
result += string(line)
result += "\n"
}
return
}
func ReadField(filename string) (result Field) {
bytes, err := os.ReadFile(filename)
if err != nil {
panic(err)
}
text := strings.TrimSpace(string(bytes))
lines := strings.Split(text, "\n")
rows := make([][]rune, len(lines))
for rowNum, line := range lines {
rows[rowNum] = []rune(line)
for colNum, symb := range line {
if symb == 'S' {
result.RowStart = rowNum
result.ColStart = colNum
}
}
}
result.symbols = rows
return
}
func (f Field) PrintCoord(coords map[FieldPoint]any, expandByField int) {
for fieldRow := -expandByField; fieldRow <= expandByField; fieldRow++ {
lines := make([]string, len(f.symbols))
for fieldCol := -expandByField; fieldCol <= expandByField; fieldCol++ {
for rowNum, row := range f.symbols {
for colNum, col := range row {
_, marked := coords[FieldPoint{InField: Coord{Row: rowNum, Col: colNum},
MetaField: Coord{Row: fieldRow, Col: fieldCol}}]
if marked {
lines[rowNum] += "O"
} else {
lines[rowNum] += string(col)
}
}
}
}
for _, line := range lines {
fmt.Println(line)
}
}
return
}

View File

@ -1,100 +0,0 @@
package day22
import (
"fmt"
"log"
"os"
"regexp"
"strconv"
"strings"
)
type XY struct {
X, Y uint
}
type Block struct {
NameNum int
XMin, XMax uint
YMin, YMax uint
Z uint
IsSettled bool
ZHeight uint
Supports []*Block
SupportedBy []*Block
}
func (b *Block) String() string {
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 {
n, err := strconv.Atoi(a)
if err != nil {
panic(err)
}
return n
}
func ReadBlock(line string, num int) (b Block) {
b.NameNum = num
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 i, line := range strings.Split(text, "\n") {
block := ReadBlock(line, i)
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
}

View File

@ -1,37 +0,0 @@
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, 0)
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)
}
}

View File

@ -1,7 +0,0 @@
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

View File

@ -1,74 +0,0 @@
#+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?
** DONE 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)
** DONE [#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
* part 1, wrong answer.
i guess try to go, setting the input? block after block and try to check the calculations?
what i want to check:
how maxSettledOnXY works, how linking works. maybe i'll find a problem in few steps =C
** can't see anything just glancing around.
maybe then trying to pick a block and track what's under it?
* ok. let's try to brute force?
for each block, remove it?
create new space and try to settle it
** this is shit. why blocks move up?
2023/12/22 12:12:24 >>> starting for block [Block 1 - x:0-2, y:0-0, z:1, h:0, isSettled true] (supports [[Block 3 - x:0-0, y:0-2, z:3, h:0, isSettled true] [Block 4 - x:2-2, y:0-2, z:3, h:0, isSettled true] [Block 3 - x:0-0, y:0-2, z:2, h:0, isSettled true] [Block 4 - x:2-2, y:0-2, z:2, h:0, isSettled true]])
2023/12/22 12:12:24 block [Block 2 - x:0-2, y:2-2, z:2, h:0, isSettled true] moved from 1 to 2
2023/12/22 12:12:24 block [Block 3 - x:0-0, y:0-2, z:3, h:0, isSettled true] moved from 2 to 3
2023/12/22 12:12:24 block [Block 4 - x:2-2, y:0-2, z:3, h:0, isSettled true] moved from 2 to 3
2023/12/22 12:12:24 block [Block 5 - x:0-2, y:1-1, z:4, h:0, isSettled true] moved from 3 to 4
2023/12/22 12:12:24 block [Block 6 - x:1-1, y:1-1, z:5, h:1, isSettled true] moved from 4 to 5
2023/12/22 12:12:24 for block [Block 1 - x:0-2, y:0-0, z:1, h:0, isSettled true] new space has 5 moved
* ok. brute force with copying slices worked.
now i want to debug.
for each brick, when there is 0 falling, i want to check what are it's surroundings
** my initial was : 567
** checking example of badly determined:
>> for block [Block 291 - x:6-8, y:7-7, z:75, h:0, isSettled false]
checking under coord {X:6 Y:7}. found under [Block 698 - x:6-8, y:7-7, z:35, h:0, isSettled true]. ( 'overriding' ) with 35 ; maxZ 35
directly supporting blocks are [[Block 698 - x:6-8, y:7-7, z:35, h:0, isSettled true]]
checking under coord {X:7 Y:7}. found under [Block 698 - x:6-8, y:7-7, z:35, h:0, isSettled true]. ( 'adding' ) with 35 ; maxZ 35
directly supporting blocks are [[Block 698 - x:6-8, y:7-7, z:35, h:0, isSettled true] [Block 698 - x:6-8, y:7-7, z:35, h:0, isSettled true]]
checking under coord {X:8 Y:7}. found under [Block 698 - x:6-8, y:7-7, z:35, h:0, isSettled true]. ( 'adding' ) with 35 ; maxZ 35
directly supporting blocks are [[Block 698 - x:6-8, y:7-7, z:35, h:0, isSettled true] [Block 698 - x:6-8, y:7-7, z:35, h:0, isSettled true] [Block 698 - x:6-8, y:7-7, z:35, h:0, isSettled true]]
>> after settring block [Block 291 - x:6-8, y:7-7, z:36, h:0, isSettled true]. supported by [[Block 698 - x:6-8, y:7-7, z:35, h:0, isSettled true] [Block 698 - x:6-8, y:7-7, z:35, h:0, isSettled true] [Block 698 - x:6-8, y:7-7, z:35, h:0, isSettled true]]
** ouch. duplicates in slices. because there's no easy set thingy
not doing this was my bug.
#+begin_src go
slices.SortFunc(block.SupportedBy, func(a *Block, b *Block) int {
return cmp.Compare(a.NameNum, b.NameNum)
})
block.SupportedBy = slices.Compact(block.SupportedBy)
#+end_src

View File

@ -1,38 +0,0 @@
package day22
import (
"math"
"github.com/tidwall/pinhole"
)
func TestPinhole() {
p := pinhole.New()
p.DrawCube(-0.3, -0.3, -0.3, 0.3, 0.3, 0.3)
p.Rotate(math.Pi/3, math.Pi/2, 0)
p.SavePNG("cube.png", 500, 500, nil)
}
func PrintSpace(s Space, filename string) {
// pinhole is from -1 to 1. let's use from 0 to 1.
// so coord should be divided by max height, and let's hope that they are not too wide
rotation := []float64{math.Pi/3, math.Pi/6, 0}
p := pinhole.New()
p.DrawRect(-1, -1, 1, 1, 0)
for _, zLevel := range s.SettledOnZ {
for _, block := range zLevel {
p.DrawCube(float64(block.XMin) / float64(s.MaxZ),
float64(block.YMin) / float64(s.MaxZ),
float64(block.Z) / float64(s.MaxZ),
float64(block.XMax + 1) / float64(s.MaxZ),
float64(block.YMax + 1) / float64(s.MaxZ),
float64(block.Z + block.ZHeight + 1) / float64(s.MaxZ))
}
}
p.Rotate(rotation[0], rotation[1], rotation[2])
p.SavePNG(filename, 1920, 1080, nil)
}

View File

@ -1,18 +0,0 @@
package day22
import (
"fmt"
)
func Run() int {
fmt.Print("oi, hello day 22")
filename := "day22/example"
blocks := ReadBlockFile(filename)
byZ := BlocksByZ(blocks)
space := NewSpace(byZ)
space.SettleAll()
result := space.CountFreeBlocks()
return result
}

View File

@ -1,213 +0,0 @@
package day22
import (
// "fmt"
"cmp"
"log"
"slices"
// "time"
)
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) AgainCountFreeBlocks() (result int) {
for _, row := range s.SettledOnZ {
for _, block := range row {
thisSupports := block.Supports
canDisintegrate := true
for _, blockThisSupports := range thisSupports {
if len(blockThisSupports.SupportedBy) == 1 {
// we cannot disintigrate this block
canDisintegrate = false
}
}
if canDisintegrate {
result += 1
}
}
}
return
}
func (s *Space) InitialCollectGoodToDisintegrate() (result []Block) {
allBlocks := make(map[*Block]any)
for _, row := range s.SettledOnZ {
for _, block := range row {
allBlocks[block] = struct{}{}
if len(block.SupportedBy) == 1 {
onlySupport := block.SupportedBy[0]
log.Printf("in block %+v. only support is %+v", block, onlySupport)
log.Printf("should be NOT OK to remove %+v", onlySupport)
delete(allBlocks, onlySupport)
}
}
}
for block := range allBlocks {
result = append(result, *block)
}
return
}
func (s *Space) CountFreeBlocks() (result int) {
return len(s.InitialCollectGoodToDisintegrate())
}
func (s *Space) ThirdTimeCollectGoodToDisintegrate() (blocks []Block) {
// for each block create a new space without it. try to settle and check if 0 moved
log.Println(">>>>> starting hardcode count <<<<<")
for rowNum, row := range s.SettledOnZ {
for blockNum, block := range row {
// log.Printf(">>> starting for block %+v (supports %+v)\n", block, block.Supports)
newUnsettled := slices.Clone(s.SettledOnZ)
for rowNum, row := range newUnsettled {
newUnsettled[rowNum] = slices.Clone(row)
}
newUnsettled[rowNum] = slices.Delete(newUnsettled[rowNum], blockNum, blockNum+1)
// and now copy the blocks
for rowNum, row := range newUnsettled {
for blockNum, block := range row {
newBlock := *block
newUnsettled[rowNum][blockNum] = &newBlock
}
}
newSpace := NewSpace(newUnsettled)
moved := newSpace.SettleAll()
if moved > 0 {
// log.Printf("for block %+v new space has %d moved\n\n", block, moved)
} else {
// log.Printf("for block %+v new space has %d moved\n\n", block, moved)
blocks = append(blocks, *block)
}
}
}
return
}
func (s *Space) ThirdTimeCountFreeBlocks() (result int) {
return len(s.ThirdTimeCollectGoodToDisintegrate())
}
func (s *Space) CountChainReactoins() (result int) {
for rowNum, row := range s.SettledOnZ {
for blockNum, _ := range row {
newUnsettled := slices.Clone(s.SettledOnZ)
for rowNum, row := range newUnsettled {
newUnsettled[rowNum] = slices.Clone(row)
}
newUnsettled[rowNum] = slices.Delete(newUnsettled[rowNum], blockNum, blockNum+1)
// and now copy the blocks
for rowNum, row := range newUnsettled {
for blockNum, block := range row {
newBlock := *block
newUnsettled[rowNum][blockNum] = &newBlock
}
}
newSpace := NewSpace(newUnsettled)
moved := newSpace.SettleAll()
result += moved
}
}
return
}
func (s *Space) SettleAll() (totalMoved int) {
for i := uint(1); i <= s.MaxZ; i++ {
movedAfterLayer := s.SettleZ(i)
totalMoved += movedAfterLayer
}
return
}
// settle all blocks in Z, remove Z from UnsettledByZ
func (s *Space) SettleZ(z uint) (totalMoved int) {
blocksToSettle := s.UnsettledByZ[int(z)]
for _, block := range blocksToSettle {
hasMoved := s.SettleBlock(block)
if hasMoved {
totalMoved += 1
}
}
s.UnsettledByZ[int(z)] = nil
return
}
// 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) (hasMoved bool) {
initialZ := block.Z
underZMax := uint(0)
underZBlocks := make([]*Block, 0)
// fmt.Printf("\n>> for block %s\n", block)
for _, xy := range block.getXY() {
underBlock, found := s.MaxSettledOnXY[xy]
// if block.NameNum
if found {
underBlockMaxZ := underBlock.Z + underBlock.ZHeight
// action := " 'skipping' "
if underBlockMaxZ > underZMax {
underZBlocks = []*Block{underBlock}
underZMax = underBlockMaxZ
// action = " 'overriding' "
} else if underBlockMaxZ == underZMax {
underZBlocks = append(underZBlocks, underBlock)
// action = " 'adding' "
}
// fmt.Printf("checking under coord %+v. found under %+v. (%s) with %d ; maxZ %d\n directly supporting blocks are %+v\n",
// xy, underBlock, action, underBlockMaxZ, underZMax, underZBlocks)
} else {
// fmt.Printf("checking under coord %+v. nothing under\n", xy)
}
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)
// fmt.Printf(">> after settring block %s. supported by %+v\n\n", block, block.SupportedBy)
slices.SortFunc(block.SupportedBy, func(a *Block, b *Block) int {
return cmp.Compare(a.NameNum, b.NameNum)
})
block.SupportedBy = slices.Compact(block.SupportedBy)
// time.Sleep(500 * time.Millisecond)
hasMoved = initialZ != block.Z
// if hasMoved {
// log.Printf("block %+v moved from %d to %d", block, initialZ, block.Z)
// }
return
}

View File

@ -1,135 +0,0 @@
package day22
import (
"slices"
"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)
}
func TestSpaceExampleSettleAll(t *testing.T) {
filename := "example"
blocks := ReadBlockFile(filename)
byZ := BlocksByZ(blocks)
space := NewSpace(byZ)
space.SettleAll()
t.Logf("settled space %+v", space)
// maybe i can check via console.
i := 2
t.Logf("level %d is : %+v", i, space.SettledOnZ[i])
// it looks ok for the example.
// let's hope?
t.Logf("for example, free blocks amount is %d", space.CountFreeBlocks())
// oh, i need 'supported'?
// how do i need to count the task question
// i guess we can start with set of all blocks, then?
// run over all, if some block is only supported by some underBlock - remove that underblock
}
func TestPinholeStart(t *testing.T) {
TestPinhole()
}
func TestExampleSpacePrint(t *testing.T) {
filename := "example"
blocks := ReadBlockFile(filename)
byZ := BlocksByZ(blocks)
space := NewSpace(byZ)
// PrintSpace(space, "before-settping.png")
space.SettleAll()
PrintSpace(space, "after-settping.png")
}
func TestCompareInitialAndBruteforce(t *testing.T) {
filename := "input"
blocks := ReadBlockFile(filename)
byZ := BlocksByZ(blocks)
space := NewSpace(byZ)
space.SettleAll()
initialBlocks := space.InitialCollectGoodToDisintegrate()
correct := space.ThirdTimeCollectGoodToDisintegrate()
t.Log("len of initial solution : ", len(initialBlocks))
t.Log("len of correct solution : ", len(correct))
for _, disintegratableInInitial := range initialBlocks {
indexInCorrect := slices.IndexFunc(correct, func(e Block) bool {
return e.NameNum == disintegratableInInitial.NameNum
})
if indexInCorrect == -1 {
t.Logf("> found %+v. falsly marked as disintegratable\n\n", disintegratableInInitial)
}
}
}

9
go.mod
View File

@ -1,12 +1,3 @@
module sunshine.industries/aoc2023
go 1.21.4
require github.com/tidwall/pinhole v0.0.0-20210130162507-d8644a7c3d19
require (
github.com/fogleman/gg v1.3.0 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/google/btree v1.1.2 // indirect
golang.org/x/image v0.14.0 // indirect
)

10
go.sum
View File

@ -1,10 +0,0 @@
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/tidwall/pinhole v0.0.0-20210130162507-d8644a7c3d19 h1:PH18rfaiwA/34DAtuREBTrrByvZeLHqhfYh4SG7jYg4=
github.com/tidwall/pinhole v0.0.0-20210130162507-d8644a7c3d19/go.mod h1:5VfbOBfzaI6Y0XiGSkz7hiXgKtwYaDBI3plwKGsLonM=
golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4=
golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=

View File

@ -4,15 +4,15 @@ import (
"log"
"time"
"sunshine.industries/aoc2023/day22"
"sunshine.industries/aoc2023/day20"
)
func main() {
startTime := time.Now()
log.Print("> starting run:")
result := day22.Run()
log.Printf("\n\nday22 result: %d\n****\n", result)
result := day20.Run()
log.Printf("\n\nday20 result: %d\n****\n", result)
endTime := time.Now()
diff := endTime.Sub(startTime)
log.Printf("execution took %s", diff.String())