day19, example
This commit is contained in:
parent
6efd55ae6a
commit
5f62ea45f7
|
@ -1,2 +1,4 @@
|
|||
/.direnv/
|
||||
/.go
|
||||
example
|
||||
/day19/input
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
#+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
|
|
@ -0,0 +1,233 @@
|
|||
package day19
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func Run() int {
|
||||
fmt.Println("hello day 19. sorting parts")
|
||||
filename := "day19/example"
|
||||
|
||||
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)
|
||||
|
||||
return countApproved
|
||||
}
|
||||
|
||||
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 = '>'
|
||||
)
|
||||
|
||||
type OperationData struct {
|
||||
AttrName string
|
||||
Operation Operation
|
||||
Num int
|
||||
SentToName string
|
||||
String string
|
||||
}
|
||||
|
||||
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 := 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.String = 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))
|
||||
}
|
18
main.go
18
main.go
|
@ -3,12 +3,24 @@ package main
|
|||
import (
|
||||
"log"
|
||||
|
||||
"sunshine.industries/aoc2023/day18"
|
||||
"sunshine.industries/aoc2023/day19"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.Print("> starting run:")
|
||||
|
||||
result := day18.Run()
|
||||
log.Printf("\n\nday18 result: %d\n****\n", result)
|
||||
// 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)
|
||||
|
||||
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…
Reference in New Issue