Compare commits
14 Commits
53930e66ac
...
29528f23ac
Author | SHA1 | Date |
---|---|---|
|
29528f23ac | |
|
8be2fa3844 | |
|
45d03e5ab3 | |
|
2b3c7f4ca6 | |
|
3ede691333 | |
|
7b34b52e5e | |
|
99c2269df8 | |
|
b10a6250b1 | |
|
4cb35dca33 | |
|
840773fd16 | |
|
9a22efd4b3 | |
|
f5ea9e725e | |
|
6a7378c265 | |
|
5b0f1ab750 |
|
@ -0,0 +1,11 @@
|
||||||
|
...........
|
||||||
|
.....###.#.
|
||||||
|
.###.##..#.
|
||||||
|
..#.#...#..
|
||||||
|
....#.#....
|
||||||
|
.##..S####.
|
||||||
|
.##..#...#.
|
||||||
|
.......##..
|
||||||
|
.##.#.####.
|
||||||
|
.##..##.##.
|
||||||
|
...........
|
|
@ -0,0 +1,11 @@
|
||||||
|
...........
|
||||||
|
...........
|
||||||
|
...........
|
||||||
|
...........
|
||||||
|
...........
|
||||||
|
.....S.....
|
||||||
|
...........
|
||||||
|
...........
|
||||||
|
...........
|
||||||
|
...........
|
||||||
|
...........
|
|
@ -0,0 +1,105 @@
|
||||||
|
#+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
|
|
@ -0,0 +1,211 @@
|
||||||
|
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
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
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
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
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
|
|
@ -0,0 +1,74 @@
|
||||||
|
#+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
|
|
@ -0,0 +1,38 @@
|
||||||
|
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)
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
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
|
||||||
|
}
|
|
@ -0,0 +1,213 @@
|
||||||
|
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
|
||||||
|
}
|
|
@ -0,0 +1,135 @@
|
||||||
|
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
9
go.mod
|
@ -1,3 +1,12 @@
|
||||||
module sunshine.industries/aoc2023
|
module sunshine.industries/aoc2023
|
||||||
|
|
||||||
go 1.21.4
|
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
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
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=
|
6
main.go
6
main.go
|
@ -4,15 +4,15 @@ import (
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"sunshine.industries/aoc2023/day20"
|
"sunshine.industries/aoc2023/day22"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
log.Print("> starting run:")
|
log.Print("> starting run:")
|
||||||
|
|
||||||
result := day20.Run()
|
result := day22.Run()
|
||||||
log.Printf("\n\nday20 result: %d\n****\n", result)
|
log.Printf("\n\nday22 result: %d\n****\n", result)
|
||||||
endTime := time.Now()
|
endTime := time.Now()
|
||||||
diff := endTime.Sub(startTime)
|
diff := endTime.Sub(startTime)
|
||||||
log.Printf("execution took %s", diff.String())
|
log.Printf("execution took %s", diff.String())
|
||||||
|
|
Loading…
Reference in New Issue