From 574fdf38a402d1732f2074558880d5302b85d18c Mon Sep 17 00:00:00 2001 From: Davide Oddone Date: Fri, 8 Dec 2023 23:46:47 +0100 Subject: [PATCH 1/3] Non-working, archival purpose --- day07/cards.go | 2 +- day08/charpath.go | 95 +++++++++++++++++++++++++++++++++++++++++++++++ day08/inputs | 1 + 3 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 day08/charpath.go create mode 120000 day08/inputs diff --git a/day07/cards.go b/day07/cards.go index 4cd409c..67ce34b 100644 --- a/day07/cards.go +++ b/day07/cards.go @@ -259,7 +259,7 @@ func quicksort(a, h []int, hType int) []int { func main() { - file, err := os.Open("./inputs/day7_try") + file, err := os.Open("./inputs/day07_input") check(err) defer file.Close() diff --git a/day08/charpath.go b/day08/charpath.go new file mode 100644 index 0000000..c30a8c2 --- /dev/null +++ b/day08/charpath.go @@ -0,0 +1,95 @@ +package main + +import( + "fmt" + "bufio" + "os" + "sync" + "regexp" + "context" +) + +const LEFT = 'L' + +type Nodes struct { + mu sync.Mutex + commands []int32 + singleN []int32 + leftN []int32 + rightN []int32 + steps uint64 +} + +func check(e error) { + if e != nil { + panic(e) + } +} + +func PrintAndWait(x ...any) { + fmt.Print(x...) + fmt.Scanln() +} + +func (n *Nodes) toByteSingle(s string) { + // I've just received something like AAA + var temp int32 + for i := 0; i < len(s); i++ { + a := int32(s[i]) + temp += a << (i*8) + } + n.singleN = append(n.singleN, temp) +} + +func (n *Nodes) toByteDuet(s, r string) { + // I've just received something like AAA BBB + var tempL, tempR int32 + for i := 0; i < len(s); i++ { + tempL += int32(s[i]) << (i*8) + tempR += int32(s[i]) << (i*8) + } + n.leftN = append(n.leftN, tempL) + n.rightN = append(n.rightN, tempR) +} + +func (n *Nodes) findNext(direction int32, index int, ctx context.Context) { + +} + +func main() { + file, err := os.Open("./inputs/day08_test_input") + check(err) + defer file.Close() + // Struct with my node + n := Nodes{} + // Prepare the regex + repath := regexp.MustCompile("([A-Z]{3})") + + scanner := bufio.NewScanner(file) + scanner.Scan() + // First line, RL commands + strCommands := scanner.Text() + // Get every char inside the string just obtained + for i := 0; i < len(strCommands); i++ { + n.commands = append(n.commands, int32(strCommands[i])) + } + // One empty line + scanner.Scan() + // X = (Y, Z) + // We regex this one + for scanner.Scan() { + tempNodes := repath.FindAllString(scanner.Text(), -1) + n.toByteSingle(tempNodes[0]) + n.toByteDuet(tempNodes[1], tempNodes[2]) + } + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + // We start from 0, we find the match + for i, j := 0, 0; ; i++ { + // We do a circular loop + i = i % len(n.commands) + // A function that has the context as an argument + n.findNext(int32(i), j, ctx) + j++ + } +} diff --git a/day08/inputs b/day08/inputs new file mode 120000 index 0000000..a80bb2b --- /dev/null +++ b/day08/inputs @@ -0,0 +1 @@ +../inputs \ No newline at end of file From a17153662e830609d98d926690a9a0060f1e1c43 Mon Sep 17 00:00:00 2001 From: Davide Oddone Date: Sat, 9 Dec 2023 23:00:54 +0100 Subject: [PATCH 2/3] Working d8p1 --- .gitignore | 1 + day08/charpath.go | 124 +++++++++++++++++++++++++++++++--------------- 2 files changed, 85 insertions(+), 40 deletions(-) diff --git a/.gitignore b/.gitignore index f50f047..6b4b990 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ go.work # Problem data input*.txt +inputs/ diff --git a/day08/charpath.go b/day08/charpath.go index c30a8c2..ca4b812 100644 --- a/day08/charpath.go +++ b/day08/charpath.go @@ -1,23 +1,23 @@ package main -import( - "fmt" +import ( "bufio" + "fmt" "os" - "sync" "regexp" - "context" + "sync" ) const LEFT = 'L' type Nodes struct { - mu sync.Mutex - commands []int32 - singleN []int32 - leftN []int32 - rightN []int32 - steps uint64 + mu sync.Mutex + commands []int32 + singleN []int32 + leftN []int32 + rightN []int32 + index int + steps uint64 } func check(e error) { @@ -32,64 +32,108 @@ func PrintAndWait(x ...any) { } func (n *Nodes) toByteSingle(s string) { - // I've just received something like AAA - var temp int32 - for i := 0; i < len(s); i++ { - a := int32(s[i]) - temp += a << (i*8) - } + // I've just received something like AAA + var temp int32 + for i := len(s) - 1; i >= 0; i-- { + a := int32(s[i]) + temp += a << ((len(s) - 1 - i) * 8) + } n.singleN = append(n.singleN, temp) } func (n *Nodes) toByteDuet(s, r string) { - // I've just received something like AAA BBB - var tempL, tempR int32 - for i := 0; i < len(s); i++ { - tempL += int32(s[i]) << (i*8) - tempR += int32(s[i]) << (i*8) - } - n.leftN = append(n.leftN, tempL) - n.rightN = append(n.rightN, tempR) + // I've just received something like AAA BBB + var tempL, tempR int32 + for i := len(s) - 1; i >= 0; i-- { + tempL += int32(s[i]) << ((len(s) - 1 - i) * 8) + tempR += int32(r[i]) << ((len(s) - 1 - i) * 8) + //fmt.Printf("Received %c (%b), now I have %b | ", s[i], s[i], tempL) + //fmt.Printf("Received %c (%b), now I have %b\n", r[i], r[i], tempR) + //fmt.Scanln() + } + n.leftN = append(n.leftN, tempL) + n.rightN = append(n.rightN, tempR) } -func (n *Nodes) findNext(direction int32, index int, ctx context.Context) { - +func (n *Nodes) findNext(myN int32) { + //var wg sync.WaitGroup + for i := 0; i < len(n.singleN); i++ { + if myN^n.singleN[i] == 0 { + n.index = i + break + } + } } func main() { - file, err := os.Open("./inputs/day08_test_input") + file, err := os.Open("./inputs/day08_input") check(err) defer file.Close() // Struct with my node n := Nodes{} // Prepare the regex repath := regexp.MustCompile("([A-Z]{3})") - + // Build the END + var END = 'Z' + END += ('Z' << 8) + END += ('Z' << 16) + scanner := bufio.NewScanner(file) scanner.Scan() // First line, RL commands strCommands := scanner.Text() // Get every char inside the string just obtained for i := 0; i < len(strCommands); i++ { - n.commands = append(n.commands, int32(strCommands[i])) + n.commands = append(n.commands, int32(strCommands[i])) } // One empty line scanner.Scan() // X = (Y, Z) // We regex this one for scanner.Scan() { - tempNodes := repath.FindAllString(scanner.Text(), -1) - n.toByteSingle(tempNodes[0]) - n.toByteDuet(tempNodes[1], tempNodes[2]) + tempNodes := repath.FindAllString(scanner.Text(), -1) + n.toByteSingle(tempNodes[0]) + n.toByteDuet(tempNodes[1], tempNodes[2]) } - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() // We start from 0, we find the match - for i, j := 0, 0; ; i++ { - // We do a circular loop - i = i % len(n.commands) - // A function that has the context as an argument - n.findNext(int32(i), j, ctx) - j++ + // Let's start an infinite loop + // Circular index + i := 0 + // We start from the AAA element + START := 'A' + START += ('A' << 8) + START += ('A' << 16) + matching := START + // Store where AAA is + n.findNext(matching) + // By default, we will assume we are on the right + // If we are not, we are in the left + matching = n.rightN[n.index] + if n.commands[i]^LEFT == 0 { + matching = n.leftN[n.index] } + n.steps++ + // Infinite loop + for { + // Every step is in a single direction. For every step, we may need to + // scan len(n.singleN) elements. + // Circular loop + n.findNext(matching) + // Increment i after finding the match + i++ + i = i % len(n.commands) + // By default, we will assume we are on the right + matching = n.rightN[n.index] + //PrintAndWait() + // If we are not, we are in the left + if n.commands[i]^LEFT == 0 { + matching = n.leftN[n.index] + } + n.steps++ + // If we find ZZZ, end + if matching^END == 0 { + break + } + } + fmt.Printf("\nSteps: %d\n", n.steps) } From 64de63ddbeb7ac085db97959c0cbe269beda6762 Mon Sep 17 00:00:00 2001 From: Davide Oddone Date: Sun, 10 Dec 2023 00:46:26 +0100 Subject: [PATCH 3/3] Working d8p2 --- day08/charpath.go | 116 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 105 insertions(+), 11 deletions(-) diff --git a/day08/charpath.go b/day08/charpath.go index ca4b812..7f8ae28 100644 --- a/day08/charpath.go +++ b/day08/charpath.go @@ -4,6 +4,7 @@ import ( "bufio" "fmt" "os" + "time" "regexp" "sync" ) @@ -11,13 +12,14 @@ import ( const LEFT = 'L' type Nodes struct { - mu sync.Mutex - commands []int32 - singleN []int32 - leftN []int32 - rightN []int32 - index int - steps uint64 + mu sync.Mutex + commands []int32 + singleN []int32 + leftN []int32 + rightN []int32 + index int + steps uint64 + allSteps []int } func check(e error) { @@ -31,6 +33,28 @@ func PrintAndWait(x ...any) { fmt.Scanln() } +// https://siongui.github.io/2017/06/03/go-find-lcm-by-gcd/ +// greatest common divisor (GCD) via Euclidean algorithm +func GCD(a, b int) int { + for b != 0 { + t := b + b = a % b + a = t + } + return a +} + +// find Least Common Multiple (LCM) via GCD +func LCM(a, b int, integers ...int) int { + result := a * b / GCD(a, b) + + for i := 0; i < len(integers); i++ { + result = LCM(result, integers[i]) + } + + return result +} + func (n *Nodes) toByteSingle(s string) { // I've just received something like AAA var temp int32 @@ -47,25 +71,71 @@ func (n *Nodes) toByteDuet(s, r string) { for i := len(s) - 1; i >= 0; i-- { tempL += int32(s[i]) << ((len(s) - 1 - i) * 8) tempR += int32(r[i]) << ((len(s) - 1 - i) * 8) - //fmt.Printf("Received %c (%b), now I have %b | ", s[i], s[i], tempL) - //fmt.Printf("Received %c (%b), now I have %b\n", r[i], r[i], tempR) - //fmt.Scanln() } n.leftN = append(n.leftN, tempL) n.rightN = append(n.rightN, tempR) } -func (n *Nodes) findNext(myN int32) { +func (n *Nodes) findNext(myN int32) int { //var wg sync.WaitGroup + ind := 0 for i := 0; i < len(n.singleN); i++ { if myN^n.singleN[i] == 0 { + n.mu.Lock() n.index = i + n.mu.Unlock() + ind = i break } } + return ind +} + +func (n *Nodes) findAll(ind int, sp []int, wg *sync.WaitGroup) { + index := 0 + // We only go from the start + matching := n.rightN[sp[ind]] + if n.commands[0]^LEFT == 0 { + matching = n.leftN[sp[ind]] + } + index = n.findNext(matching) + n.allSteps[ind]++ + i := 0 + for { + // Every step is in a single direction. For every step, we may need to + // scan len(n.singleN) elements. + // Circular loop + index = n.findNext(matching) + // Increment i after finding the match + i++ + i = i % len(n.commands) + // By default, we will assume we are on the right + matching = n.rightN[index] + //PrintAndWait() + // If we are not, we are in the left + if n.commands[i]^LEFT == 0 { + matching = n.leftN[index] + } + n.allSteps[ind]++ + // If we find XXZ, end + temp := matching & 255 + if temp ^ 'Z' == 0 { + break + } + } + //fmt.Printf("I started from %d, matched at %d, taking %d steps.\n", sp[ind], index, n.allSteps[ind] ) + wg.Done() +} + +func timer(name string) func() { + start := time.Now() + return func() { + fmt.Printf("%s took %v\n", name, time.Since(start)) + } } func main() { + defer timer ("main")() file, err := os.Open("./inputs/day08_input") check(err) defer file.Close() @@ -136,4 +206,28 @@ func main() { } } fmt.Printf("\nSteps: %d\n", n.steps) + // Now, for the main event + // Let's get ready to rumble + startPoints := make([]int, 0) + for i := 0; i < len(n.singleN); i++ { + // Lets remove all bytes except last 8 + temp := n.singleN[i] & 255 + if (temp ^ 'A') == 0 { + startPoints = append(startPoints, i) + } + } + // Now, from the starting points, we should go and match until + // we find a path that ends in Z + n.allSteps = make([]int, len(startPoints)) + var wg sync.WaitGroup + for i := 0; i < len(startPoints); i++ { + wg.Add(1) + go n.findAll(i, startPoints, &wg) + } + wg.Wait() + result := 1 + for i := 0; i < len(n.allSteps); i++ { + result = LCM(result, n.allSteps[i]) + } + fmt.Printf("Steps: %d\n", result) }