Compare commits
	
		
			No commits in common. "29528f23acfe595edb0e035cf52bb17a5bce5f4e" and "53930e66ac783a0d7b028d603b8e07d0c481583c" have entirely different histories.
		
	
	
		
			29528f23ac
			...
			53930e66ac
		
	
		
| @ -1,11 +0,0 @@ | |||||||
| ........... |  | ||||||
| .....###.#. |  | ||||||
| .###.##..#. |  | ||||||
| ..#.#...#.. |  | ||||||
| ....#.#.... |  | ||||||
| .##..S####. |  | ||||||
| .##..#...#. |  | ||||||
| .......##.. |  | ||||||
| .##.#.####. |  | ||||||
| .##..##.##. |  | ||||||
| ........... |  | ||||||
| @ -1,11 +0,0 @@ | |||||||
| ........... |  | ||||||
| ........... |  | ||||||
| ........... |  | ||||||
| ........... |  | ||||||
| ........... |  | ||||||
| .....S..... |  | ||||||
| ........... |  | ||||||
| ........... |  | ||||||
| ........... |  | ||||||
| ........... |  | ||||||
| ........... |  | ||||||
							
								
								
									
										105
									
								
								day21/notes.org
									
									
									
									
									
								
							
							
						
						
									
										105
									
								
								day21/notes.org
									
									
									
									
									
								
							| @ -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 |  | ||||||
| @ -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 |  | ||||||
| } |  | ||||||
							
								
								
									
										100
									
								
								day22/block.go
									
									
									
									
									
								
							
							
						
						
									
										100
									
								
								day22/block.go
									
									
									
									
									
								
							| @ -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 |  | ||||||
| } |  | ||||||
| @ -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) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| @ -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 |  | ||||||
| @ -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 |  | ||||||
| @ -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) |  | ||||||
| } |  | ||||||
| @ -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 |  | ||||||
| } |  | ||||||
							
								
								
									
										213
									
								
								day22/space.go
									
									
									
									
									
								
							
							
						
						
									
										213
									
								
								day22/space.go
									
									
									
									
									
								
							| @ -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  |  | ||||||
| } |  | ||||||
| @ -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
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								go.mod
									
									
									
									
									
								
							| @ -1,12 +1,3 @@ | |||||||
| 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 |  | ||||||
| ) |  | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								go.sum
									
									
									
									
									
								
							| @ -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= |  | ||||||
							
								
								
									
										6
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								main.go
									
									
									
									
									
								
							| @ -4,15 +4,15 @@ import ( | |||||||
| 	"log" | 	"log" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"sunshine.industries/aoc2023/day22" | 	"sunshine.industries/aoc2023/day20" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func main() { | func main() { | ||||||
| 	startTime := time.Now() | 	startTime := time.Now() | ||||||
| 	log.Print("> starting run:") | 	log.Print("> starting run:") | ||||||
| 
 | 
 | ||||||
| 	result := day22.Run() | 	result := day20.Run() | ||||||
| 	log.Printf("\n\nday22 result: %d\n****\n", result) | 	log.Printf("\n\nday20 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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user