Compare commits
	
		
			14 Commits
		
	
	
		
			53930e66ac
			...
			29528f23ac
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 29528f23ac | ||
|  | 8be2fa3844 | ||
|  | 45d03e5ab3 | ||
|  | 2b3c7f4ca6 | ||
|  | 3ede691333 | ||
|  | 7b34b52e5e | ||
|  | 99c2269df8 | ||
|  | b10a6250b1 | ||
|  | 4cb35dca33 | ||
|  | 840773fd16 | ||
|  | 9a22efd4b3 | ||
|  | f5ea9e725e | ||
|  | 6a7378c265 | ||
|  | 5b0f1ab750 | 
							
								
								
									
										11
									
								
								day21/example
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								day21/example
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | ........... | ||||||
|  | .....###.#. | ||||||
|  | .###.##..#. | ||||||
|  | ..#.#...#.. | ||||||
|  | ....#.#.... | ||||||
|  | .##..S####. | ||||||
|  | .##..#...#. | ||||||
|  | .......##.. | ||||||
|  | .##.#.####. | ||||||
|  | .##..##.##. | ||||||
|  | ........... | ||||||
							
								
								
									
										11
									
								
								day21/example1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								day21/example1
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | |||||||
|  | ........... | ||||||
|  | ........... | ||||||
|  | ........... | ||||||
|  | ........... | ||||||
|  | ........... | ||||||
|  | .....S..... | ||||||
|  | ........... | ||||||
|  | ........... | ||||||
|  | ........... | ||||||
|  | ........... | ||||||
|  | ........... | ||||||
							
								
								
									
										105
									
								
								day21/notes.org
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								day21/notes.org
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||||
							
								
								
									
										211
									
								
								day21/stepCounter.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								day21/stepCounter.go
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||||
|  | } | ||||||
							
								
								
									
										100
									
								
								day22/block.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								day22/block.go
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||||
|  | } | ||||||
							
								
								
									
										37
									
								
								day22/block_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								day22/block_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -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) | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										7
									
								
								day22/example
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								day22/example
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||||
							
								
								
									
										74
									
								
								day22/notes.org
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								day22/notes.org
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||||
							
								
								
									
										38
									
								
								day22/printingSpace.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								day22/printingSpace.go
									
									
									
									
									
										Normal file
									
								
							| @ -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) | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								day22/sandSlabs.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								day22/sandSlabs.go
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||||
|  | } | ||||||
							
								
								
									
										213
									
								
								day22/space.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										213
									
								
								day22/space.go
									
									
									
									
									
										Normal file
									
								
							| @ -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  | ||||||
|  | } | ||||||
							
								
								
									
										135
									
								
								day22/space_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								day22/space_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -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 | ||||||
|  | ) | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								go.sum
									
									
									
									
									
										Normal file
									
								
							| @ -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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user