From 52beb4196f20a0969837b3a788943a04fcb781db Mon Sep 17 00:00:00 2001 From: efim Date: Tue, 19 Dec 2023 11:00:59 +0000 Subject: [PATCH] day19, struggling part2, not quite yet --- day19/intervals.go | 57 ++++++++++++++++ day19/notes.org | 16 +++++ day19/sortingParts.go | 152 ++++++++++++++++++++++++++++++++++++------ 3 files changed, 205 insertions(+), 20 deletions(-) create mode 100644 day19/intervals.go diff --git a/day19/intervals.go b/day19/intervals.go new file mode 100644 index 0000000..2bec938 --- /dev/null +++ b/day19/intervals.go @@ -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 +} diff --git a/day19/notes.org b/day19/notes.org index 444e9e4..6956293 100644 --- a/day19/notes.org +++ b/day19/notes.org @@ -25,3 +25,19 @@ 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 diff --git a/day19/sortingParts.go b/day19/sortingParts.go index 35ecd4f..825f165 100644 --- a/day19/sortingParts.go +++ b/day19/sortingParts.go @@ -28,9 +28,20 @@ func Run() int { log.Printf("yay, got sorters\n%+v\nand details\n%+v", sorters, details) - countApproved := CountApprovedDetails(details, sorters) + // countApproved := CountApprovedDetails(details, sorters) + result := 0 - return countApproved + 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, "qqz", sorters) + log.Print("got and checked ", andChecked) + + return result } func CountApprovedDetails(details []DetailData, sorters map[string]SorterData) int { @@ -39,7 +50,7 @@ func CountApprovedDetails(details []DetailData, sorters map[string]SorterData) i approvedDetails := make(chan DetailData) - go func(){ + go func() { wg.Wait() close(approvedDetails) }() @@ -49,7 +60,7 @@ func CountApprovedDetails(details []DetailData, sorters map[string]SorterData) i done := make(chan any) - go func(){ + go func() { for detail := range approvedDetails { log.Println("got approved ", detail) count += 1 @@ -74,28 +85,30 @@ func CountApprovedDetails(details []DetailData, sorters map[string]SorterData) i }(d) } - <- done + <-done return acceptedScore } type Operation rune -const (LessThan Operation = '<' + +const ( + LessThan Operation = '<' MoreThan Operation = '>' ) type OperationData struct { - AttrName string - Operation Operation - Num int + AttrName string + Operation Operation + Num int SentToName string - String string + String string } type SorterData struct { - Name string + Name string DefaultState string - Operations []OperationData + Operations []OperationData } func ReadSorters(sortersText string) map[string]SorterData { @@ -104,7 +117,7 @@ func ReadSorters(sortersText string) map[string]SorterData { lines := strings.Split(sortersText, "\n") for _, line := range lines { - sorter := ReadSorterLine(line) + sorter := SimplifyOperation( ReadSorterLine(line) ) result[sorter.Name] = sorter } @@ -120,12 +133,12 @@ func ReadSorterLine(line string) (result SorterData) { result.Name = firstSplit[1] operationLines := strings.Split(firstSplit[2], ",") - operations := make([]OperationData, len(operationLines) - 1) + operations := make([]OperationData, len(operationLines)-1) result.Operations = operations - result.DefaultState = operationLines[len(operationLines) - 1] + result.DefaultState = operationLines[len(operationLines)-1] - for i, line := range operationLines[:len(operationLines) - 1] { + for i, line := range operationLines[:len(operationLines)-1] { operations[i] = ReadOperationLine(line) } @@ -182,7 +195,7 @@ func ReadDetailsPart(text string) (result []DetailData) { func ReadDetailLine(line string) (result DetailData) { attrs := make(map[string]int) result.Attrs = attrs - line = line[1:len(line)-1] + line = line[1 : len(line)-1] attrsLine := strings.Split(line, ",") re := regexp.MustCompile(`(?P\D)=(?P\d+)`) for _, attrLine := range attrsLine { @@ -200,7 +213,7 @@ func ReadDetailLine(line string) (result DetailData) { func ProcessDetail(d DetailData, sorters map[string]SorterData) (isAccepted bool) { curSorterName := "in" - for (curSorterName != "A" && curSorterName != "R") { + for curSorterName != "A" && curSorterName != "R" { sorter, found := sorters[curSorterName] if !found { panic(fmt.Sprint("error finding soter ", curSorterName)) @@ -210,7 +223,7 @@ func ProcessDetail(d DetailData, sorters map[string]SorterData) (isAccepted bool return curSorterName == "A" } -func (s SorterData)NextSorterNameFor(d DetailData) string { +func (s SorterData) NextSorterNameFor(d DetailData) string { for _, operation := range s.Operations { if operation.IsDetailPassing(d) { return operation.SentToName @@ -220,7 +233,7 @@ func (s SorterData)NextSorterNameFor(d DetailData) string { return s.DefaultState } -func (o OperationData)IsDetailPassing(d DetailData) bool { +func (o OperationData) IsDetailPassing(d DetailData) bool { detailValue := d.Attrs[o.AttrName] switch o.Operation { case LessThan: @@ -231,3 +244,102 @@ func (o OperationData)IsDetailPassing(d DetailData) bool { 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) AttrIntervals { + result := AttrIntervals{ + "x": [][]int{}, + "m": [][]int{}, + "a": [][]int{}, + "s": [][]int{}, + } + + if sorterName == "A" { + return i + } + if sorterName == "R" { + return result + } + + 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) + + result = MergeAuthIntervals(result, ofThoseAreAccepted) + log.Printf(">> %s; results so far are %+v", sorterName, result) + + intervalsFailingAndPassedToNextCheck := operation.getFailingIntervals(i) + 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) + result = MergeAuthIntervals(result, intervalsAfterDefault) + log.Printf(">> %s; results after default %+v", sorterName, result) + + return result +} + +func MergeAuthIntervals(a AttrIntervals, b AttrIntervals) AttrIntervals { + result := AttrIntervals{ + "x": [][]int{}, + "m": [][]int{}, + "a": [][]int{}, + "s": [][]int{}, + } + + for key := range result { + aAttrIntervals := a[key] + bAttrIntervals := b[key] + allIntervals := append(aAttrIntervals, bAttrIntervals...) + result[key] = merge(allIntervals) + } + + return result +}