chore: add multi-worker version of day 5 #2
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…
Reference in New Issue
Block a user