Merge pull request 'chore: add multi-worker version of day 5' (#2) from day05 into main
Reviewed-on: xuu/advent-of-code-2023#2
This commit is contained in:
		
						commit
						5828cf65e1
					
				
							
								
								
									
										117
									
								
								day05/main.go
									
									
									
									
									
								
							
							
						
						
									
										117
									
								
								day05/main.go
									
									
									
									
									
								
							@ -3,7 +3,6 @@ package main
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"bufio"
 | 
						"bufio"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"log/slog"
 | 
					 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"sort"
 | 
						"sort"
 | 
				
			||||||
	"strconv"
 | 
						"strconv"
 | 
				
			||||||
@ -11,11 +10,6 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func main() {
 | 
					func main() {
 | 
				
			||||||
	var level slog.Level
 | 
					 | 
				
			||||||
	if err := level.UnmarshalText([]byte(os.Getenv("DEBUG_LEVEL"))); err == nil && level != 0 {
 | 
					 | 
				
			||||||
		slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: level})))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if len(os.Args) != 2 {
 | 
						if len(os.Args) != 2 {
 | 
				
			||||||
		fmt.Fprintln(os.Stderr, "Usage: day05 FILE")
 | 
							fmt.Fprintln(os.Stderr, "Usage: day05 FILE")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -31,21 +25,24 @@ func main() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	fmt.Println("min location:", minLocation)
 | 
						fmt.Println("min location:", minLocation)
 | 
				
			||||||
	fmt.Println("min range location:", minRangeLocation)
 | 
						fmt.Println("min range location:", minRangeLocation)
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func run(scan *bufio.Scanner) (int, int) {
 | 
					func run(scan *bufio.Scanner) (int, int) {
 | 
				
			||||||
 | 
						log("begin...")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var seeds []int
 | 
						var seeds []int
 | 
				
			||||||
	var seedRanges []int
 | 
						var seedRanges [][2]int
 | 
				
			||||||
	lookup := map[string]*Lookup{}
 | 
						lookup := map[string]*Lookup{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for scan.Scan() {
 | 
						for scan.Scan() {
 | 
				
			||||||
		text := scan.Text()
 | 
							text := scan.Text()
 | 
				
			||||||
		if strings.HasPrefix(text, "seeds:") && len(seeds) == 0 {
 | 
							if strings.HasPrefix(text, "seeds:") && len(seeds) == 0 {
 | 
				
			||||||
			seeds, seedRanges = readSeeds(text)
 | 
								seeds, seedRanges = readSeeds(text)
 | 
				
			||||||
 | 
								log("seeds", len(seeds), "ranges", len(seedRanges))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		lookup = readMaps(scan)
 | 
							lookup = readMaps(scan)
 | 
				
			||||||
 | 
							log("lookups", len(lookup))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	find := NewFinder(
 | 
						find := NewFinder(
 | 
				
			||||||
@ -58,38 +55,21 @@ func run(scan *bufio.Scanner) (int, int) {
 | 
				
			|||||||
		lookup["humidity-to-location"],
 | 
							lookup["humidity-to-location"],
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	seedLocations := make([]int, len(seeds))
 | 
						return findMinLocation(seeds, find), FindMinRangeLocationMulti(seedRanges, find)
 | 
				
			||||||
	for i, s := range seeds {
 | 
					 | 
				
			||||||
		seedLocations[i] = find.Find(s)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	minLocation := min(seedLocations...)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	seedRangeLocations := make([]int, len(seedRanges))
 | 
					 | 
				
			||||||
	for i, s := range seedRanges {
 | 
					 | 
				
			||||||
		seedRangeLocations[i] = find.Find(s)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	minRangeLocation := min(seedRangeLocations...)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return minLocation, minRangeLocation
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func readSeeds(text string) ([]int, [][2]int) {
 | 
				
			||||||
func readSeeds(text string) ([]int, []int) {
 | 
						var seeds [] int 
 | 
				
			||||||
	var seeds, seedRanges []int
 | 
						var seedRanges [][2]int
 | 
				
			||||||
	sp := strings.Fields(strings.TrimPrefix(text, "seeds: "))
 | 
						sp := strings.Fields(strings.TrimPrefix(text, "seeds: "))
 | 
				
			||||||
	for i, s := range sp {
 | 
						for i, s := range sp {
 | 
				
			||||||
		n, _ := strconv.Atoi(s)
 | 
							n, _ := strconv.Atoi(s)
 | 
				
			||||||
		seeds = append(seeds, n)
 | 
							seeds = append(seeds, n)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if i%2 == 0 {
 | 
							if i%2 == 0 {
 | 
				
			||||||
			seedRanges = append(seedRanges, n)
 | 
								seedRanges = append(seedRanges, [2]int{n, 0})
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			lastN := seedRanges[len(seedRanges)-1]
 | 
								seedRanges[len(seedRanges)-1][1] = n
 | 
				
			||||||
			r := make([]int, n-1)
 | 
					 | 
				
			||||||
			for i := range r {
 | 
					 | 
				
			||||||
				r[i] = lastN + i + 1
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			seedRanges = append(seedRanges, r...)
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return seeds, seedRanges
 | 
						return seeds, seedRanges
 | 
				
			||||||
@ -123,6 +103,74 @@ func readMaps(scan *bufio.Scanner) map[string]*Lookup {
 | 
				
			|||||||
	return lookup
 | 
						return lookup
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func findMinLocation(seeds []int, find *Finder) int {
 | 
				
			||||||
 | 
						seedLocations := make([]int, len(seeds))
 | 
				
			||||||
 | 
						for i, s := range seeds {
 | 
				
			||||||
 | 
							seedLocations[i] = find.Find(s)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return min(seedLocations...)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func FindMinRangeLocation(ranges [][2]int, find *Finder) int {
 | 
				
			||||||
 | 
						results := 0
 | 
				
			||||||
 | 
						for _, r := range ranges {
 | 
				
			||||||
 | 
							results += r[1]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						seedLocations := make([]int, 0, results)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, s := range ranges {
 | 
				
			||||||
 | 
							for i := 0; i < s[1]; i++ {
 | 
				
			||||||
 | 
								seedLocations = append(seedLocations, find.Find(s[0] + i))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return min(seedLocations...)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func FindMinRangeLocationMulti(ranges [][2]int, find *Finder) int {
 | 
				
			||||||
 | 
						worker := func(id int, jobs <-chan [2]int, results chan<- []int) {
 | 
				
			||||||
 | 
							for s := range jobs {
 | 
				
			||||||
 | 
								res := make([]int, s[1])
 | 
				
			||||||
 | 
								for i := 0; i < s[1]; i++ {
 | 
				
			||||||
 | 
									res[i] = find.Find(s[0] + i)
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								results <- res
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						numWorkers := 16
 | 
				
			||||||
 | 
						jobsCh := make(chan [2]int, numWorkers)
 | 
				
			||||||
 | 
						resultsCh := make(chan []int, len(ranges))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for w := 0; w < numWorkers; w++ {
 | 
				
			||||||
 | 
							go worker(w, jobsCh, resultsCh)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						log("started workers", numWorkers)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						go func() {
 | 
				
			||||||
 | 
							for i, s := range ranges {
 | 
				
			||||||
 | 
								log("job", i, "send", s)
 | 
				
			||||||
 | 
								jobsCh <- s
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							close(jobsCh)
 | 
				
			||||||
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						results := 0
 | 
				
			||||||
 | 
						for _, r := range ranges {
 | 
				
			||||||
 | 
							results += r[1]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						log("expecting results", results)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						seedLocations := make([]int, 0, results)
 | 
				
			||||||
 | 
						expectResults := make([]struct{}, len(ranges))
 | 
				
			||||||
 | 
						for range expectResults {
 | 
				
			||||||
 | 
							r := <- resultsCh
 | 
				
			||||||
 | 
							seedLocations = append(seedLocations, r...)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return min(seedLocations...)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Range struct {
 | 
					type Range struct {
 | 
				
			||||||
	src  int
 | 
						src  int
 | 
				
			||||||
	dest int
 | 
						dest int
 | 
				
			||||||
@ -179,6 +227,9 @@ func (f *Finder) Find(n int) int {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func min(arr ...int) int {
 | 
					func min(arr ...int) int {
 | 
				
			||||||
 | 
						if len(arr) == 0 {
 | 
				
			||||||
 | 
							return 0
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	m := arr[0]
 | 
						m := arr[0]
 | 
				
			||||||
	for _, a := range arr[1:] {
 | 
						for _, a := range arr[1:] {
 | 
				
			||||||
		if m > a {
 | 
							if m > a {
 | 
				
			||||||
@ -187,3 +238,7 @@ func min(arr ...int) int {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	return m
 | 
						return m
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func log(v ...any) {
 | 
				
			||||||
 | 
						fmt.Fprintln(os.Stderr, v...)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -22,7 +22,7 @@ func TestExample(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	minLocation, minRangeLocation := run(scan)
 | 
						minLocation, minRangeLocation := run(scan)
 | 
				
			||||||
	is.Equal(minLocation, 35)
 | 
						is.Equal(minLocation, 35)
 | 
				
			||||||
	is.Equal(minRangeLocation, 47)
 | 
						is.Equal(minRangeLocation, 46)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func SkipTestSolution(t *testing.T) {
 | 
					func SkipTestSolution(t *testing.T) {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user