Add rpn parser and infix solver

pull/1/head^2
DustyP 5 years ago
parent d66a25a525
commit 1ddc4d4c36

@ -3,6 +3,7 @@ package exts
import ( import (
"fmt" "fmt"
"strconv" "strconv"
"strings"
"djpianalto.com/goff/djpianalto.com/goff/utils" "djpianalto.com/goff/djpianalto.com/goff/utils"
"github.com/dustinpianalto/disgoman" "github.com/dustinpianalto/disgoman"
@ -50,10 +51,34 @@ func deinterleave(ctx disgoman.Context, args []string) {
} }
} }
func rpn(ctx disgoman.Context, args []string) { func generateRPNCommand(ctx disgoman.Context, args []string) {
rpn, err := utils.GenerateRPN(args) rpn, err := utils.GenerateRPN(args)
if err != nil { if err != nil {
ctx.Send(err.Error()) ctx.Send(err.Error())
return
} }
ctx.Send(rpn) ctx.Send(rpn)
} }
func parseRPNCommand(ctx disgoman.Context, args []string) {
res, err := utils.ParseRPN(args)
if err != nil {
ctx.Send(err.Error())
return
}
ctx.Send(fmt.Sprintf("The result is: %v", res))
}
func solveCommand(ctx disgoman.Context, args []string) {
rpn, err := utils.GenerateRPN(args)
if err != nil {
ctx.Send(err.Error())
return
}
res, err := utils.ParseRPN(strings.Split(rpn, " "))
if err != nil {
ctx.Send(err.Error())
return
}
ctx.Send(fmt.Sprintf("The result is: %v", res))
}

@ -187,12 +187,31 @@ func AddCommandHandlers(h *disgoman.CommandManager) {
Invoke: deinterleave, Invoke: deinterleave,
}) })
_ = h.AddCommand(&disgoman.Command{ _ = h.AddCommand(&disgoman.Command{
Name: "rpn", Name: "RPN",
Aliases: []string{}, Aliases: []string{"rpn"},
Description: "Convert infix to rpn", Description: "Convert infix to rpn",
OwnerOnly: false, OwnerOnly: false,
Hidden: false, Hidden: false,
RequiredPermissions: 0, RequiredPermissions: 0,
Invoke: rpn, Invoke: generateRPNCommand,
}) })
_ = h.AddCommand(&disgoman.Command{
Name: "ParseRPN",
Aliases: []string{'PRPN'},
Description: "Parse RPN string and return the result",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: parseRPNCommand,
})
_ = h.AddCommand(&disgoman.Command{
Name: "solve",
Aliases: []string{"math"},
Description: "Solve infix equation and return the result",
OwnerOnly: false,
Hidden: false,
RequiredPermissions: 0,
Invoke: solveCommand,
})
} }

@ -0,0 +1,95 @@
package utils
import (
"errors"
"fmt"
"math"
"strconv"
)
type Stack []float64
func (s *Stack) IsEmpty() bool {
return len(*s) == 0
}
func (s *Stack) Push(op float64) {
*s = append(*s, op)
}
func (s *Stack) Pop() (float64, bool) {
if s.IsEmpty() {
return 0, false
}
index := len(*s) - 1
element := (*s)[index]
*s = (*s)[:index]
return element, true
}
func (s *Stack) PopTwo() (float64, float64, bool) {
if s.IsEmpty() || len(*s) < 2 {
return 0, 0, false
}
index := len(*s) - 1
b := (*s)[index]
a := (*s)[index-1]
*s = (*s)[:index-1]
return a, b, true
}
func (s *Stack) Top() float64 {
if s.IsEmpty() {
return 0
}
return (*s)[len(*s)-1]
}
func ParseRPN(args []string) (float64, error) {
s := Stack{}
for _, token := range args {
switch token {
case "+":
if a, b, ok := s.PopTwo(); ok {
s.Push(a + b)
} else {
return 0, fmt.Errorf("not enough operands on stack for +: %v", s)
}
case "-":
if a, b, ok := s.PopTwo(); ok {
s.Push(a - b)
} else {
return 0, fmt.Errorf("not enough operands on stack for -: %v", s)
}
case "*":
if a, b, ok := s.PopTwo(); ok {
s.Push(a * b)
} else {
return 0, fmt.Errorf("not enough operands on stack for *: %v", s)
}
case "/":
if a, b, ok := s.PopTwo(); ok {
s.Push(a / b)
} else {
return 0, fmt.Errorf("not enough operands on stack for /: %v", s)
}
case "%":
if a, b, ok := s.PopTwo(); ok {
s.Push(math.Mod(a, b))
} else {
return 0, fmt.Errorf("not enough operands on stack for %: %v", s)
}
default:
f, err := strconv.ParseFloat(token, 64)
if err != nil {
return 0, err
}
s.Push(f)
}
}
if res, ok := s.Pop(); ok {
return res, nil
}
return 0, errors.New("no result")
}
Loading…
Cancel
Save