Skip to content

Commit

Permalink
Merge pull request #751 from vaskoz/day371
Browse files Browse the repository at this point in the history
Day371
  • Loading branch information
vaskoz committed Nov 27, 2019
2 parents 3d75264 + 4331c8d commit 3a16197
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -365,5 +365,7 @@ problems from
* [Day 367](https://github.com/vaskoz/dailycodingproblem-go/issues/740)
* [Day 368](https://github.com/vaskoz/dailycodingproblem-go/issues/743)
* [Day 369](https://github.com/vaskoz/dailycodingproblem-go/issues/745)
* Day 370 - Never received an e-mail for this day.
* [Day 371](https://github.com/vaskoz/dailycodingproblem-go/issues/750)
* [Day 372](https://github.com/vaskoz/dailycodingproblem-go/issues/748)

82 changes: 82 additions & 0 deletions day371/problem.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package day371

import (
"errors"
"sort"
"strconv"
"strings"
)

var errNoAnswerPossible = errors.New("an answer doesn't exist")

type eqData struct {
vars map[string]int
total int
}

// SolveArithmeticEquations returns the answer to these equations
// or an error if no answer exists.
// Will panic on malformed input.
func SolveArithmeticEquations(equations string) (map[string]int, error) {
eqs := strings.Split(strings.TrimSpace(equations), "\n")
eqDatas := make([]eqData, 0, len(eqs))

for _, eq := range eqs {
sides := strings.Split(strings.TrimSpace(eq), "=")
if len(sides) != 2 {
panic("only one equal sign per line/equation")
}

lhs, rhs := strings.TrimSpace(sides[0]), strings.TrimSpace(sides[1])
vars := make(map[string]int)
total := 0

for _, v := range strings.Split(lhs, "+") {
if i, err := strconv.Atoi(v); err == nil {
total -= i
} else {
vars[v]++
}
}

for _, v := range strings.Split(rhs, "+") {
v = strings.TrimSpace(v)
if i, err := strconv.Atoi(v); err == nil {
total += i
} else {
vars[v]--
}
}

eqDatas = append(eqDatas, eqData{vars, total})
}

return solveArithmeticEquations(eqDatas)
}

func solveArithmeticEquations(equations []eqData) (map[string]int, error) {
ans := make(map[string]int)

sort.Slice(equations, func(i, j int) bool {
return len(equations[i].vars) < len(equations[j].vars)
})

for _, eq := range equations {
for v, coef := range eq.vars {
if a, exists := ans[v]; exists {
eq.total -= a * coef
delete(eq.vars, v)
}
}

if len(eq.vars) != 1 {
return nil, errNoAnswerPossible
}

for k, v := range eq.vars {
ans[k] = eq.total / v
}
}

return ans, nil
}
69 changes: 69 additions & 0 deletions day371/problem_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package day371

import (
"reflect"
"testing"
)

// nolint
var testcases = []struct {
equations string
expected map[string]int
expectedErr error
}{
{
`y = x + 1
5 = x + 3
10 = z + y + 2`,
map[string]int{
"x": 2,
"y": 3,
"z": 5,
},
nil,
},
{
`y = x + 1
10 = z + y + 2`,
nil,
errNoAnswerPossible,
},
{
`
foo+1+foo+1+foo = foo + 12
1 = bar+foo+2`,
map[string]int{
"foo": 5,
"bar": -6,
},
nil,
},
}

func TestSolveArithmeticEquations(t *testing.T) {
for _, tc := range testcases {
if result, err := SolveArithmeticEquations(tc.equations); !reflect.DeepEqual(result, tc.expected) ||
err != tc.expectedErr {
t.Errorf("Expected (%v,%v), got (%v,%v)", tc.expected, tc.expectedErr, result, err)
}
}
}

func TestSolveArithmeticEquationsBadInput(t *testing.T) {
defer func() {
if err := recover(); err == nil {
t.Errorf("Expected a panic when bad input")
}
}()
// nolint
SolveArithmeticEquations(`a+y=1 x+z=2
x=5`)
}

func BenchmarkSolveArithmeticEquations(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, tc := range testcases {
SolveArithmeticEquations(tc.equations) // nolint
}
}
}

0 comments on commit 3a16197

Please sign in to comment.