I forgot to GitAdd my old posts, so they’re gone for now, i’ll have copies in my Logseq, but have to work to get them back, will do that later.
Puzzle 1
- this seems easier than the last days, to be honest
- i’ll do the oop/clean code style again with custom types and such
- combining the coefficients of a line with operations is something “simple” i think
- we need to take two coefficients and an operation, the result will be the lhs coefficient for the next operation, etc. until we run out of ops, then we’ve got the result
- so far it’s pretty straight forward, my operation combination code works fine
- the only challenge is the permutation again… :(
- i had the type alias set to string, but int is much faster (also i’m not going for bool since i’m sure we’re adding the last operations in puzzle 2)
- also we have two operations, so we need 2^length combinations
- wow, i forgot the name of the
math.Pow()
function, which is an indication to how little i make use of it - now i’m sure i can do some modulo magic, right?
- maybe yeah, i’ve given them int values, why not give them
1
and2
and based on the index - before i think too much about it, let’s just try :D
- okay, i want to think about it
- maybe a bitmask with n bits? that should work, no it doesn’t, since we’re using the same space for two different values
- maybe we could convert the given iterator to a base_n number system and check each digit?! that SHOULD work, as it’ll go for base 2 (e.g. two spots): 00, 01, 10, 11
- this should be easy but i’m making it hard, wtf. now i’m learning to pad a string with variable size, because well, somehow.
- okay, i overthought it, did some fmt magic and now it’s working fine and fast, and i’ve got the correct result.
Puzzle 2
- uah?
- okay wtf, i was just tripping with the 7290 example, but now i’ve got it.
- huh, i was dumb, i added the result of the concatenation to the accumulator instead of setting the value
- this time my style helped with part 2, i think. it’s still pretty fast.
- and it was correct again. nice, today was easy, but i like my solution, so here we go:
Solution
package main
import (
"fmt"
"log"
"math"
"os"
"strconv"
"strings"
)
type Operation int
const (
OPERATION_ADD = Operation(0)
OPERATION_MULTIPLY = Operation(1)
OPERATION_CONCAT = Operation(2)
)
type Equation struct {
Result int
Coefficients []int
}
func (e *Equation) IsValid() bool {
// here we need to generate an operation slice of len e.Coefficients-1 and fill it with each combination
// of both operations (e.g., if len(ops) == 3, we have {+,+,+}, {+,+,*}, {+,*,*}, etc.
permutations := GenerateOperationPermutations(len(e.Coefficients) - 1)
for _, permutation := range permutations {
if e.Solve(permutation) {
return true
}
}
return false
}
// Solve method tries to solve the equation with the given operations in sequential order
func (e *Equation) Solve(ops []Operation) bool {
// this logic goes like this: take two coefficients and combine them over the operation
if len(ops) != len(e.Coefficients)-1 {
log.Printf("too few operations, got %v, expected %v", len(ops), len(e.Coefficients)-1)
return false
}
// log.Println("solving", ops)
// the amount of operations need to be len(e.Coefficients)-1
rhsIndex := 1
acc := e.Coefficients[0]
for _, op := range ops {
rhs := e.Coefficients[rhsIndex]
switch op {
case OPERATION_ADD:
acc = acc + rhs
case OPERATION_MULTIPLY:
acc = acc * rhs
case OPERATION_CONCAT:
ii, _ := strconv.Atoi(fmt.Sprintf("%v%v", acc, rhs))
acc = ii
}
rhsIndex++
}
return acc == e.Result
}
// GenerateOperationPermutations generates all permutations of all operations
// of the given length
func GenerateOperationPermutations(length int) [][]Operation {
// we need space for 2^length combinations
combs := int(math.Pow(3.0, float64(length)))
res := make([][]Operation, combs)
for i := 0; i < combs; i++ {
cmb := make([]Operation, length)
binaryString := fmt.Sprintf("%0*s", length, strconv.FormatInt(int64(i), 3))
for j, char := range binaryString {
cmb[j] = Operation(int(char - '0'))
}
res[i] = cmb
}
return res
}
func main() {
input, err := os.ReadFile("input")
if err != nil {
panic(err)
}
lines := strings.Split(string(input), "\n")
solveFirst(lines[:len(lines)-1])
solveSecond(lines[:len(lines)-1])
}
func solveFirst(input []string) {
res := 0
for _, line := range input {
eq := parseLine(line)
if eq.IsValid() {
res += eq.Result
}
}
log.Println("result:", res)
}
func solveSecond(input []string) {
// whoops
}
func parseLine(line string) *Equation {
splitLine := strings.Split(line, ":")
coeffs := strings.Split(splitLine[1], " ")
resInt, _ := strconv.Atoi(splitLine[0])
eq := &Equation{
Result: resInt,
Coefficients: make([]int, 0),
}
for _, coeff := range coeffs {
ii, _ := strconv.Atoi(coeff)
if ii != 0 {
eq.Coefficients = append(eq.Coefficients, ii)
}
}
return eq
}