question 7
This commit is contained in:
1 parent
cab7c95b59
commit
13c4a4fb4a
2 files changed
+200
No files matched your search
@@ -0,0 +1,197 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const mockInput = "190: 10 19\n3267: 81 40 27\n83: 17 5\n156: 15 6\n7290: 6 8 6 15\n161011: 16 10 13\n192: 17 8 14\n21037: 9 7 18 13\n292: 11 6 16 20"
|
||||
|
||||
type ProblemRow struct {
|
||||
res int
|
||||
numbers []int
|
||||
}
|
||||
|
||||
func parseRow(s string) *ProblemRow {
|
||||
colonIdx := strings.Index(s, ":")
|
||||
res, _ := strconv.Atoi(s[0:colonIdx])
|
||||
numbers := toSliceOfInt(strings.Split(s[colonIdx+2:], " "))
|
||||
|
||||
return &ProblemRow{res, numbers}
|
||||
}
|
||||
|
||||
func parseProblemInput(input string) []*ProblemRow {
|
||||
ret := make([]*ProblemRow, 0)
|
||||
for _, row := range strings.Split(input, "\n") {
|
||||
ret = append(ret, parseRow(row))
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func toSliceOfInt(split []string) []int {
|
||||
ret := make([]int, len(split))
|
||||
for i := 0; i < len(split); i++ {
|
||||
ret[i], _ = strconv.Atoi(split[i])
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
type Operand int8
|
||||
|
||||
const (
|
||||
PRODUCT Operand = iota
|
||||
SUM
|
||||
CONCAT
|
||||
)
|
||||
|
||||
type OperandNode struct {
|
||||
value Operand
|
||||
nextNode *NumberNode
|
||||
}
|
||||
|
||||
func (n *OperandNode) String() string {
|
||||
opp := "+"
|
||||
if n.value == PRODUCT {
|
||||
opp = "*"
|
||||
}
|
||||
if n.value == CONCAT {
|
||||
opp = "||"
|
||||
}
|
||||
return fmt.Sprintf("%s %s", opp, n.nextNode.String())
|
||||
}
|
||||
|
||||
type NumberNode struct {
|
||||
value int
|
||||
nextNode *OperandNode
|
||||
}
|
||||
|
||||
func (n *NumberNode) String() string {
|
||||
rest := ""
|
||||
if n.nextNode != nil {
|
||||
rest = n.nextNode.String()
|
||||
}
|
||||
return fmt.Sprintf("%d %s", n.value, rest)
|
||||
}
|
||||
|
||||
func process(node *NumberNode) int {
|
||||
if node.nextNode == nil {
|
||||
return node.value
|
||||
}
|
||||
if node.nextNode.value == SUM {
|
||||
newValue := node.value + node.nextNode.nextNode.value
|
||||
nextNext := node.nextNode.nextNode.nextNode
|
||||
newNode := &NumberNode{newValue, nextNext}
|
||||
return process(newNode)
|
||||
}
|
||||
if node.nextNode.value == PRODUCT {
|
||||
newValue := node.value * node.nextNode.nextNode.value
|
||||
nextNext := node.nextNode.nextNode.nextNode
|
||||
newNode := &NumberNode{newValue, nextNext}
|
||||
return process(newNode)
|
||||
}
|
||||
|
||||
if node.nextNode.value == CONCAT {
|
||||
newValue := concatInts(node.value, node.nextNode.nextNode.value)
|
||||
nextNext := node.nextNode.nextNode.nextNode
|
||||
newNode := &NumberNode{newValue, nextNext}
|
||||
return process(newNode)
|
||||
}
|
||||
|
||||
panic("Unknown Operand")
|
||||
}
|
||||
|
||||
func concatInts(value, value2 int) int {
|
||||
n := 1
|
||||
for n <= value2 {
|
||||
n = n * 10
|
||||
}
|
||||
return value2 + n*value
|
||||
|
||||
}
|
||||
|
||||
func createNodes(numbers []int, operands []Operand) *NumberNode {
|
||||
if len(numbers)-1 != len(operands) {
|
||||
panic("Number of operands must be 1 minus number of numbers")
|
||||
}
|
||||
var firstVNode *NumberNode = nil
|
||||
var previousONode *OperandNode = nil
|
||||
for i := 0; i < len(operands); i++ {
|
||||
oNode := &OperandNode{operands[i], nil}
|
||||
vNode := &NumberNode{numbers[i], oNode}
|
||||
if firstVNode == nil {
|
||||
firstVNode = vNode
|
||||
}
|
||||
if previousONode != nil {
|
||||
previousONode.nextNode = vNode
|
||||
}
|
||||
previousONode = oNode
|
||||
}
|
||||
previousONode.nextNode = &NumberNode{numbers[len(numbers)-1], nil}
|
||||
return firstVNode
|
||||
}
|
||||
|
||||
func createAllPossibleChain(numbers []int, operands ...Operand) <-chan *NumberNode {
|
||||
out := make(chan *NumberNode)
|
||||
go func() {
|
||||
for operators := range allPossibleOperators(len(numbers)-1, operands...) {
|
||||
out <- createNodes(numbers, operators)
|
||||
}
|
||||
close(out)
|
||||
}()
|
||||
return out
|
||||
}
|
||||
|
||||
func allPossibleOperators(n int, operands ...Operand) <-chan []Operand {
|
||||
out := make(chan []Operand)
|
||||
go func() {
|
||||
defer close(out)
|
||||
if n == 0 {
|
||||
out <- []Operand{}
|
||||
return
|
||||
}
|
||||
for _, operand := range operands {
|
||||
for prefix := range allPossibleOperators(n-1, operands...) {
|
||||
out <- append(prefix, operand)
|
||||
}
|
||||
}
|
||||
}()
|
||||
return out
|
||||
}
|
||||
|
||||
func problem7A(input string) int {
|
||||
ret := 0
|
||||
for _, problemRow := range parseProblemInput(input) {
|
||||
if isSolvable(problemRow, SUM, PRODUCT) {
|
||||
ret += problemRow.res
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func problem7B(input string) int64 {
|
||||
var ret int64 = 0
|
||||
for _, problemRow := range parseProblemInput(input) {
|
||||
if isSolvable(problemRow, PRODUCT, SUM, CONCAT) {
|
||||
ret += int64(problemRow.res)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func isSolvable(row *ProblemRow, operands ...Operand) bool {
|
||||
fmt.Println("")
|
||||
for node := range createAllPossibleChain(row.numbers, operands...) {
|
||||
if process(node) == row.res {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
fmt.Printf("The answer to question 7A is %d \n", problem7A(realInput))
|
||||
fmt.Printf("The answer to question 7B is %d \n", problem7B(mockInput))
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user