Compare commits
	
		
			4 Commits
		
	
	
		
			1afaff0021
			...
			e771ac9d9b
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | e771ac9d9b | ||
|  | 52beb4196f | ||
|  | 5f62ea45f7 | ||
|  | 6efd55ae6a | 
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,2 +1,4 @@ | |||||||
| /.direnv/ | /.direnv/ | ||||||
| /.go | /.go | ||||||
|  | example | ||||||
|  | /day19/input | ||||||
|  | |||||||
| @ -7,12 +7,13 @@ import ( | |||||||
| 	"slices" | 	"slices" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"strings" | 	"strings" | ||||||
|  | 	"sync" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func Run() int { | func Run() int { | ||||||
| 	log.Println("hello day 18") | 	log.Println("hello day 18") | ||||||
| 	log.Println("problem of lagoon bgins") | 	log.Println("problem of lagoon bgins") | ||||||
| 	filename := "day18/example" | 	filename := "day18/input" | ||||||
| 	instructions := ReadInstructionas2(filename) | 	instructions := ReadInstructionas2(filename) | ||||||
| 	h, w := calcHeightWidth(instructions) | 	h, w := calcHeightWidth(instructions) | ||||||
| 	log.Printf("read %+v instructions", instructions) | 	log.Printf("read %+v instructions", instructions) | ||||||
| @ -210,8 +211,10 @@ type Cell struct { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type BorderSymbol rune | type BorderSymbol rune | ||||||
| // '' always left to right | 
 | ||||||
| const (Vertical BorderSymbol = '|' | // ” always left to right | ||||||
|  | const ( | ||||||
|  | 	Vertical BorderSymbol = '|' | ||||||
| 	ToDown   BorderSymbol = '7' | 	ToDown   BorderSymbol = '7' | ||||||
| 	ToUp     BorderSymbol = 'J' | 	ToUp     BorderSymbol = 'J' | ||||||
| 	FromUp   BorderSymbol = 'F' | 	FromUp   BorderSymbol = 'F' | ||||||
| @ -225,6 +228,7 @@ type Field struct { | |||||||
| 	MinRow, MaxRow, MinCol, MaxCol int | 	MinRow, MaxRow, MinCol, MaxCol int | ||||||
| 	BordersFromLeft                map[int]map[int]BorderSymbol | 	BordersFromLeft                map[int]map[int]BorderSymbol | ||||||
| } | } | ||||||
|  | 
 | ||||||
| func (f *Field) confirmCoord(c Coord) { | func (f *Field) confirmCoord(c Coord) { | ||||||
| 	// log.Printf("configming coord %+v", c) | 	// log.Printf("configming coord %+v", c) | ||||||
| 
 | 
 | ||||||
| @ -337,7 +341,6 @@ func getTurnAsIfGoingFromLeft(directionFrom, directionTo Direction)  []BorderSym | |||||||
| 		symbol = FromUp | 		symbol = FromUp | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 	// panic(fmt.Sprint("got strange from %s to %s", directionFrom.String(), directionTo.String())) | 	// panic(fmt.Sprint("got strange from %s to %s", directionFrom.String(), directionTo.String())) | ||||||
| 	return []BorderSymbol{symbol} | 	return []BorderSymbol{symbol} | ||||||
| } | } | ||||||
| @ -376,14 +379,36 @@ func (f *Field) String() string { | |||||||
| 	s += "\"" | 	s += "\"" | ||||||
| 	return s | 	return s | ||||||
| } | } | ||||||
| func (f *Field) digInsides() (countInside int) { | func (f *Field) digInsides() (result int) { | ||||||
|  | 	lineSum := make(chan int) | ||||||
|  | 
 | ||||||
|  | 	var wg sync.WaitGroup | ||||||
|  | 	rowsCount := f.MaxRow - f.MinRow | ||||||
|  | 	wg.Add(rowsCount) | ||||||
|  | 
 | ||||||
|  | 	done := make(chan bool) | ||||||
|  | 
 | ||||||
|  | 	go func() { | ||||||
|  | 		wg.Wait() | ||||||
|  | 		close(lineSum) | ||||||
|  | 	}() | ||||||
|  | 
 | ||||||
|  | 	go func() { | ||||||
|  | 		for rowInternalCount := range lineSum { | ||||||
|  | 			result += rowInternalCount | ||||||
|  | 		} | ||||||
|  | 		close(done) | ||||||
|  | 	}() | ||||||
|  | 
 | ||||||
| 	for row := f.MinRow; row < f.MaxRow; row++ { | 	for row := f.MinRow; row < f.MaxRow; row++ { | ||||||
|  | 		go func(row int){ | ||||||
| 			if row%10000 == 0 { | 			if row%10000 == 0 { | ||||||
| 				log.Printf("processed rows %d out of %d", row, f.MaxRow) | 				log.Printf("processed rows %d out of %d", row, f.MaxRow) | ||||||
| 			} | 			} | ||||||
| 			specialBorders := f.BordersFromLeft[row] | 			specialBorders := f.BordersFromLeft[row] | ||||||
| 			if len(specialBorders) == 0 { | 			if len(specialBorders) == 0 { | ||||||
| 			continue | 				wg.Done() | ||||||
|  | 				return | ||||||
| 			} | 			} | ||||||
| 			type BorderItem struct { | 			type BorderItem struct { | ||||||
| 				border BorderSymbol | 				border BorderSymbol | ||||||
| @ -431,7 +456,8 @@ func (f *Field) digInsides() (countInside int) { | |||||||
| 						// 	ToBeDug: true, | 						// 	ToBeDug: true, | ||||||
| 						// } | 						// } | ||||||
| 					} | 					} | ||||||
| 				countInside += diff | 					lineSum <- diff | ||||||
|  | 					// countInside += diff | ||||||
| 				} | 				} | ||||||
| 
 | 
 | ||||||
| 				if specialBorder.border == Vertical { | 				if specialBorder.border == Vertical { | ||||||
| @ -440,8 +466,14 @@ func (f *Field) digInsides() (countInside int) { | |||||||
| 
 | 
 | ||||||
| 				prevBorder = specialBorder | 				prevBorder = specialBorder | ||||||
| 			} | 			} | ||||||
|  | 
 | ||||||
|  | 			wg.Done() | ||||||
|  | 		}(row) | ||||||
| 	} | 	} | ||||||
| 	return | 
 | ||||||
|  | 	<-done | ||||||
|  | 
 | ||||||
|  | 	return result | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // func (f *Field) digInsides() (countInside int) { | // func (f *Field) digInsides() (countInside int) { | ||||||
|  | |||||||
| @ -34,3 +34,18 @@ day18 result: 952408144115 | |||||||
| 
 | 
 | ||||||
| 952408144115 | 952408144115 | ||||||
| *** YES. | *** YES. | ||||||
|  | *** about 1M for 4 minutes | ||||||
|  | ** so, my input is ~16M rows | ||||||
|  | 3.5 seconds per 10k | ||||||
|  | ** well, maybe i can parallel. | ||||||
|  | *** parallel example | ||||||
|  | day18 result: 952407566854 | ||||||
|  | *** and with separate done channel from the summing goroutine | ||||||
|  | 952408144115 | ||||||
|  | **** YES | ||||||
|  | ** and | ||||||
|  | 2023/12/18 23:35:31 border is 195341588; inside is 148441957805559 | ||||||
|  | 2023/12/18 23:35:31 | ||||||
|  | 
 | ||||||
|  | day18 result: 148442153147147 | ||||||
|  | * i should have used a formula. maybe then it would taken less than 4 hours | ||||||
|  | |||||||
							
								
								
									
										5
									
								
								day19/example1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								day19/example1
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | |||||||
|  | in{x<4000:R,m<4000:R,A} | ||||||
|  | px{a<4000:R,A} | ||||||
|  | qqz{s>2770:R,m<1801:A,R} | ||||||
|  | 
 | ||||||
|  | {x=787,m=2655,a=1222,s=2876} | ||||||
							
								
								
									
										57
									
								
								day19/intervals.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								day19/intervals.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,57 @@ | |||||||
|  | package day19 | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"sort" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func merge(intervals [][]int) [][]int { | ||||||
|  |     const start, end = 0, 1 | ||||||
|  | 
 | ||||||
|  |     var merged [][]int | ||||||
|  | 
 | ||||||
|  |     if len(intervals) > 1 { | ||||||
|  |         sort.Slice(intervals, func(i, j int) bool { | ||||||
|  |             return intervals[i][start] < intervals[j][start] | ||||||
|  |         }) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     for _, interval := range intervals { | ||||||
|  |         last := len(merged) - 1 | ||||||
|  |         if last < 0 || interval[start] > merged[last][end] { | ||||||
|  |             merged = append(merged, | ||||||
|  |                 []int{start: interval[start], end: interval[end]}, | ||||||
|  |             ) | ||||||
|  |         } else if interval[end] > merged[last][end] { | ||||||
|  |             merged[last][end] = interval[end] | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return merged[:len(merged):len(merged)] | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func applyLessThan(intervals [][]int, n int) [][]int { | ||||||
|  | 	var lessers [][]int | ||||||
|  | 	for _, interval := range intervals { | ||||||
|  | 		from := interval[0] | ||||||
|  | 		if from >= n { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		lessers = append(lessers, []int{from, n-1}) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return lessers | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func applyMoreThan(intervals [][]int, n int) [][]int { | ||||||
|  | 	var greaters [][]int | ||||||
|  | 	for _, interval := range intervals { | ||||||
|  | 		to := interval[1] | ||||||
|  | 		if to <= n { | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		greaters = append(greaters, []int{n+1, to}) | ||||||
|  | 	} | ||||||
|  | 	// log.Printf(">>>> in applyMoreThan %d to %+v ; result %+v", n, intervals, greaters) | ||||||
|  | 
 | ||||||
|  | 	return greaters | ||||||
|  | } | ||||||
							
								
								
									
										47
									
								
								day19/notes.org
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								day19/notes.org
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,47 @@ | |||||||
|  | #+title: Notes | ||||||
|  | * testing things | ||||||
|  | 
 | ||||||
|  | 	testSorter := day19.ReadSorterLine("qqz{s>2770:qs,m<1801:hdj,R}") | ||||||
|  | 	log.Printf("my test sorter is %+v", testSorter) | ||||||
|  | 
 | ||||||
|  | 	testOperation := day19.ReadOperationLine("s>2770:qs") | ||||||
|  | 	log.Println(testOperation) | ||||||
|  | ** testing simplification | ||||||
|  | 	 lnx{m>1548:A,A} | ||||||
|  | 	 qqz{s>2770:qs,m<1801:hdj,R} | ||||||
|  | 	 kt{m>2215:R,x>3386:A,x<3107:R,R} | ||||||
|  | 
 | ||||||
|  | 	testSorter := day19.ReadSorterLine("kt{m>2215:R,x>3386:A,x<3107:R,R}") | ||||||
|  | 	log.Printf("my test sorter is %+v", testSorter) | ||||||
|  | 
 | ||||||
|  | 	simplified := day19.SimplifyOperation(testSorter) | ||||||
|  | 	log.Printf("> simplivied %+v", simplified) | ||||||
|  | * i probably don't need 'actual actors' | ||||||
|  | just a generic function that takes 'detail' and 'sorterData' | ||||||
|  | then applies sorterData to the detail, | ||||||
|  | and calls itself with new sorter | ||||||
|  | 
 | ||||||
|  | with special cases for "R" and "A" | ||||||
|  | 
 | ||||||
|  | so. have funciton from OpeartionData & Detail -> true/false | ||||||
|  | if true take the destination, if false, check next | ||||||
|  | * well. only way to do this is with intervals | ||||||
|  | 
 | ||||||
|  | so, sorter check takes in interval. | ||||||
|  | 
 | ||||||
|  | then for each of the rule, | ||||||
|  | call first rule with full interval, | ||||||
|  | deduct first rule (for those that don't match) and pass to second. | ||||||
|  | deduct second and pass to next | ||||||
|  | 
 | ||||||
|  | A will return full | ||||||
|  | R will return empty | ||||||
|  | 
 | ||||||
|  | and results from each rule application should be joined | ||||||
|  | 
 | ||||||
|  | so. i need interval deduction | ||||||
|  | and i need interval join | ||||||
|  | * found a bug in always using initial intervals to calculate 'failing' after each step | ||||||
|  | 2023/12/19 11:45:14 got and checked 167409079868000 | ||||||
|  | 
 | ||||||
|  | In the above example, there are 167409079868000 distinct combinations of ratings that will be accepted. | ||||||
							
								
								
									
										341
									
								
								day19/sortingParts.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										341
									
								
								day19/sortingParts.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,341 @@ | |||||||
|  | package day19 | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"log" | ||||||
|  | 	"os" | ||||||
|  | 	"regexp" | ||||||
|  | 	"strconv" | ||||||
|  | 	"strings" | ||||||
|  | 	"sync" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func Run() int { | ||||||
|  | 	fmt.Println("hello day 19. sorting parts") | ||||||
|  | 	filename := "day19/input" | ||||||
|  | 
 | ||||||
|  | 	bytes, err := os.ReadFile(filename) | ||||||
|  | 	if err != nil { | ||||||
|  | 		panic(fmt.Sprint("cannot read file ", filename)) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	text := string(bytes) | ||||||
|  | 
 | ||||||
|  | 	split := strings.Split(text, "\n\n") | ||||||
|  | 
 | ||||||
|  | 	sorters := ReadSorters(split[0]) | ||||||
|  | 	details := ReadDetailsPart(split[1]) | ||||||
|  | 
 | ||||||
|  | 	log.Printf("yay, got sorters\n%+v\nand details\n%+v", sorters, details) | ||||||
|  | 
 | ||||||
|  | 	// countApproved := CountApprovedDetails(details, sorters) | ||||||
|  | 	result := 0 | ||||||
|  | 
 | ||||||
|  | 	fullIntervals := AttrIntervals{ | ||||||
|  | 		"x": [][]int{[]int{1, 4000}}, | ||||||
|  | 		"m": [][]int{[]int{1, 4000}}, | ||||||
|  | 		"a": [][]int{[]int{1, 4000}}, | ||||||
|  | 		"s": [][]int{[]int{1, 4000}}, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	andChecked := processInterval(fullIntervals, "in", sorters) | ||||||
|  | 	log.Print("got and checked ", andChecked) | ||||||
|  | 	result = andChecked | ||||||
|  | 
 | ||||||
|  | 	return result | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func CountApprovedDetails(details []DetailData, sorters map[string]SorterData) int { | ||||||
|  | 	var wg sync.WaitGroup | ||||||
|  | 	wg.Add(len(details)) | ||||||
|  | 
 | ||||||
|  | 	approvedDetails := make(chan DetailData) | ||||||
|  | 
 | ||||||
|  | 	go func() { | ||||||
|  | 		wg.Wait() | ||||||
|  | 		close(approvedDetails) | ||||||
|  | 	}() | ||||||
|  | 
 | ||||||
|  | 	count := 0 | ||||||
|  | 	acceptedScore := 0 | ||||||
|  | 
 | ||||||
|  | 	done := make(chan any) | ||||||
|  | 
 | ||||||
|  | 	go func() { | ||||||
|  | 		for detail := range approvedDetails { | ||||||
|  | 			log.Println("got approved ", detail) | ||||||
|  | 			count += 1 | ||||||
|  | 			for _, attrValue := range detail.Attrs { | ||||||
|  | 				acceptedScore += attrValue | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		close(done) | ||||||
|  | 	}() | ||||||
|  | 
 | ||||||
|  | 	for _, d := range details { | ||||||
|  | 		go func(d DetailData) { | ||||||
|  | 			log.Print("> starting for ", d) | ||||||
|  | 			isAccepted := ProcessDetail(d, sorters) | ||||||
|  | 			if isAccepted { | ||||||
|  | 				log.Println("> accepting ", d) | ||||||
|  | 				approvedDetails <- d | ||||||
|  | 			} else { | ||||||
|  | 				log.Println("> rejecting ", d) | ||||||
|  | 			} | ||||||
|  | 			wg.Done() | ||||||
|  | 		}(d) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	<-done | ||||||
|  | 
 | ||||||
|  | 	return acceptedScore | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type Operation rune | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	LessThan Operation = '<' | ||||||
|  | 	MoreThan Operation = '>' | ||||||
|  | ) | ||||||
|  | func (o Operation)String() string { | ||||||
|  | 	return string(o) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type OperationData struct { | ||||||
|  | 	AttrName   string | ||||||
|  | 	Operation  Operation | ||||||
|  | 	Num        int | ||||||
|  | 	SentToName string | ||||||
|  | 	InitialString     string | ||||||
|  | } | ||||||
|  | func (od OperationData)String() string { | ||||||
|  | 	return od.InitialString | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type SorterData struct { | ||||||
|  | 	Name         string | ||||||
|  | 	DefaultState string | ||||||
|  | 	Operations   []OperationData | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func ReadSorters(sortersText string) map[string]SorterData { | ||||||
|  | 	result := make(map[string]SorterData) | ||||||
|  | 	sortersText = strings.TrimSpace(sortersText) | ||||||
|  | 	lines := strings.Split(sortersText, "\n") | ||||||
|  | 
 | ||||||
|  | 	for _, line := range lines { | ||||||
|  | 		sorter := SimplifyOperation( ReadSorterLine(line) ) | ||||||
|  | 		result[sorter.Name] = sorter | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return result | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // qqz{s>2770:qs,m<1801:hdj,R} | ||||||
|  | func ReadSorterLine(line string) (result SorterData) { | ||||||
|  | 	re1 := regexp.MustCompile(`(?P<NAME>\D+){(?P<OPERATIONS>.+)}`) | ||||||
|  | 
 | ||||||
|  | 	firstSplit := re1.FindStringSubmatch(line) | ||||||
|  | 
 | ||||||
|  | 	result.Name = firstSplit[1] | ||||||
|  | 
 | ||||||
|  | 	operationLines := strings.Split(firstSplit[2], ",") | ||||||
|  | 	operations := make([]OperationData, len(operationLines)-1) | ||||||
|  | 	result.Operations = operations | ||||||
|  | 
 | ||||||
|  | 	result.DefaultState = operationLines[len(operationLines)-1] | ||||||
|  | 
 | ||||||
|  | 	for i, line := range operationLines[:len(operationLines)-1] { | ||||||
|  | 		operations[i] = ReadOperationLine(line) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	log.Printf("mathed %s got %+v; operations : %+v\n", line, firstSplit, operations) | ||||||
|  | 
 | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // s>2770:qs | ||||||
|  | func ReadOperationLine(line string) (result OperationData) { | ||||||
|  | 	result.InitialString = line | ||||||
|  | 	re := regexp.MustCompile(`(?P<ATTRNAME>\D)(?P<OPERATION>[\>\<])(?P<NUMBER>\d+):(?P<TARGET>\D+)`) | ||||||
|  | 	split := re.FindStringSubmatch(line) | ||||||
|  | 	log.Printf("matching operation %s into %+v\n", line, split) | ||||||
|  | 	result.AttrName = split[1] | ||||||
|  | 	result.Operation = Operation([]rune(split[2])[0]) | ||||||
|  | 	result.SentToName = split[4] | ||||||
|  | 	num, err := strconv.Atoi(split[3]) | ||||||
|  | 	if err != nil { | ||||||
|  | 		panic(fmt.Sprintf("error getting number %s in line %s. %s", split[3], line, err)) | ||||||
|  | 	} | ||||||
|  | 	result.Num = num | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // drop last operations which target same 'next' as default. these check are not necessary | ||||||
|  | func SimplifyOperation(sorter SorterData) SorterData { | ||||||
|  | 	actualLast := len(sorter.Operations) - 1 | ||||||
|  | 	for i := actualLast; i >= 0; i-- { | ||||||
|  | 		if sorter.Operations[i].SentToName != sorter.DefaultState { | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  | 		actualLast -= 1 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	sorter.Operations = sorter.Operations[:actualLast+1] | ||||||
|  | 
 | ||||||
|  | 	return sorter | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type DetailData struct { | ||||||
|  | 	Attrs map[string]int | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func ReadDetailsPart(text string) (result []DetailData) { | ||||||
|  | 	text = strings.TrimSpace(text) | ||||||
|  | 	for _, line := range strings.Split(text, "\n") { | ||||||
|  | 		result = append(result, ReadDetailLine(line)) | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // {x=787,m=2655,a=1222,s=2876} | ||||||
|  | func ReadDetailLine(line string) (result DetailData) { | ||||||
|  | 	attrs := make(map[string]int) | ||||||
|  | 	result.Attrs = attrs | ||||||
|  | 	line = line[1 : len(line)-1] | ||||||
|  | 	attrsLine := strings.Split(line, ",") | ||||||
|  | 	re := regexp.MustCompile(`(?P<ATTR>\D)=(?P<NUM>\d+)`) | ||||||
|  | 	for _, attrLine := range attrsLine { | ||||||
|  | 		split := re.FindStringSubmatch(attrLine) | ||||||
|  | 		attrName := split[1] | ||||||
|  | 		num, err := strconv.Atoi(split[2]) | ||||||
|  | 		if err != nil { | ||||||
|  | 			panic(fmt.Sprint("error parsing detail ", line)) | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		attrs[attrName] = num | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func ProcessDetail(d DetailData, sorters map[string]SorterData) (isAccepted bool) { | ||||||
|  | 	curSorterName := "in" | ||||||
|  | 	for curSorterName != "A" && curSorterName != "R" { | ||||||
|  | 		sorter, found := sorters[curSorterName] | ||||||
|  | 		if !found { | ||||||
|  | 			panic(fmt.Sprint("error finding soter ", curSorterName)) | ||||||
|  | 		} | ||||||
|  | 		curSorterName = sorter.NextSorterNameFor(d) | ||||||
|  | 	} | ||||||
|  | 	return curSorterName == "A" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s SorterData) NextSorterNameFor(d DetailData) string { | ||||||
|  | 	for _, operation := range s.Operations { | ||||||
|  | 		if operation.IsDetailPassing(d) { | ||||||
|  | 			return operation.SentToName | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return s.DefaultState | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (o OperationData) IsDetailPassing(d DetailData) bool { | ||||||
|  | 	detailValue := d.Attrs[o.AttrName] | ||||||
|  | 	switch o.Operation { | ||||||
|  | 	case LessThan: | ||||||
|  | 		return detailValue < o.Num | ||||||
|  | 	case MoreThan: | ||||||
|  | 		return detailValue > o.Num | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	panic(fmt.Sprint("unknown operation. ", o, d)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type AttrIntervals map[string][][]int | ||||||
|  | 
 | ||||||
|  | func (o OperationData) getPassingIntervals(i AttrIntervals) AttrIntervals { | ||||||
|  | 	result := make(AttrIntervals, 0) | ||||||
|  | 	for key, value := range i { | ||||||
|  | 		result[key] = value | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	operationKey := o.AttrName | ||||||
|  | 	operatedIntervals := result[operationKey] | ||||||
|  | 
 | ||||||
|  | 	switch o.Operation { | ||||||
|  | 	case LessThan: | ||||||
|  | 		result[operationKey] = applyLessThan(operatedIntervals, o.Num) | ||||||
|  | 	case MoreThan: | ||||||
|  | 		result[operationKey] = applyMoreThan(operatedIntervals, o.Num) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return result | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (o OperationData) getFailingIntervals(i AttrIntervals) AttrIntervals { | ||||||
|  | 	result := make(AttrIntervals, 0) | ||||||
|  | 	for key, value := range i { | ||||||
|  | 		result[key] = value | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	operationKey := o.AttrName | ||||||
|  | 	operatedIntervals := result[operationKey] | ||||||
|  | 
 | ||||||
|  | 	switch o.Operation { | ||||||
|  | 	case LessThan: | ||||||
|  | 		result[operationKey] = applyMoreThan(operatedIntervals, o.Num-1) | ||||||
|  | 	case MoreThan: | ||||||
|  | 		result[operationKey] = applyLessThan(operatedIntervals, o.Num+1) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return result | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func  processInterval(i AttrIntervals, sorterName string, sorters map[string]SorterData) (combinationsAccepted int) { | ||||||
|  | 	if sorterName == "A" { | ||||||
|  | 		mul := 1 | ||||||
|  | 		for key, attrIntervals := range i { | ||||||
|  | 			allowedValuesOfAttr := 0 | ||||||
|  | 			for _, interval := range attrIntervals { | ||||||
|  | 				from := interval[0] | ||||||
|  | 				to := interval[1] | ||||||
|  | 				len := to - from + 1 | ||||||
|  | 				allowedValuesOfAttr += len | ||||||
|  | 				log.Printf("for %s allowed attrs are %d", key, allowedValuesOfAttr) | ||||||
|  | 			} | ||||||
|  | 			mul *= allowedValuesOfAttr | ||||||
|  | 		} | ||||||
|  | 		log.Printf("exit recursion for %s. Accept interval %+v . result %d. max is %d", sorterName, i, mul, 40000 * 4000 * 4000 * 4000) | ||||||
|  | 		return mul | ||||||
|  | 	} | ||||||
|  | 	if sorterName == "R" { | ||||||
|  | 		return 0 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	s := sorters[sorterName] | ||||||
|  | 	log.Printf("> starting interval check for %s (%+v) on %+v", sorterName, s, i) | ||||||
|  | 	intervalsPassingOnThisStep := i | ||||||
|  | 
 | ||||||
|  | 	for _, operation := range s.Operations { | ||||||
|  | 		intervalsPassing := operation.getPassingIntervals(intervalsPassingOnThisStep) | ||||||
|  | 		log.Printf(">> %s; in operation %+v. passing are %+v", sorterName, operation, intervalsPassing) | ||||||
|  | 		ofThoseAreAccepted := processInterval(intervalsPassing, operation.SentToName, sorters) | ||||||
|  | 
 | ||||||
|  | 		combinationsAccepted += ofThoseAreAccepted | ||||||
|  | 		log.Printf(">> %s; results so far are %d", sorterName, combinationsAccepted) | ||||||
|  | 
 | ||||||
|  | 		intervalsFailingAndPassedToNextCheck := operation.getFailingIntervals(intervalsPassingOnThisStep) | ||||||
|  | 		log.Printf(">> %s; failing for the next step %+v", sorterName, intervalsFailingAndPassedToNextCheck) | ||||||
|  | 		intervalsPassingOnThisStep = intervalsFailingAndPassedToNextCheck | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	log.Printf(">> %s; about to go into DEFAULT", sorterName) | ||||||
|  | 	intervalsAfterDefault := processInterval(intervalsPassingOnThisStep, s.DefaultState, sorters) | ||||||
|  | 	log.Printf(">> %s; after defaul. passing are %+v", sorterName, intervalsAfterDefault) | ||||||
|  | 	combinationsAccepted += intervalsAfterDefault | ||||||
|  | 	log.Printf(">> %s; results after default %d", sorterName, combinationsAccepted) | ||||||
|  | 
 | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
							
								
								
									
										18
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								main.go
									
									
									
									
									
								
							| @ -3,12 +3,24 @@ package main | |||||||
| import ( | import ( | ||||||
| 	"log" | 	"log" | ||||||
| 
 | 
 | ||||||
| 	"sunshine.industries/aoc2023/day18" | 	"sunshine.industries/aoc2023/day19" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func main() { | func main() { | ||||||
| 	log.Print("> starting run:") | 	log.Print("> starting run:") | ||||||
| 
 | 
 | ||||||
| 	result := day18.Run() | 	// lnx{m>1548:A,A} | ||||||
| 	log.Printf("\n\nday18 result: %d\n****\n", result) | 	// qqz{s>2770:qs,m<1801:hdj,R} | ||||||
|  | 	// kt{m>2215:R,x>3386:A,x<3107:R,R} | ||||||
|  | 	testSorter := day19.ReadSorterLine("kt{m>2215:R,x>3386:A,x<3107:R,R}") | ||||||
|  | 	log.Printf("my test sorter is %+v", testSorter) | ||||||
|  | 
 | ||||||
|  | 	simplified := day19.SimplifyOperation(testSorter) | ||||||
|  | 	log.Printf("> simplivied %+v", simplified) | ||||||
|  | 
 | ||||||
|  | 	detail := day19.ReadDetailLine("{x=787,m=2655,a=1222,s=2876}") | ||||||
|  | 	log.Printf("> detail %+v", detail) | ||||||
|  | 
 | ||||||
|  | 	result := day19.Run() | ||||||
|  | 	log.Printf("\n\nday19 result: %d\n****\n", result) | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user