-
Notifications
You must be signed in to change notification settings - Fork 8
/
calculator.py
72 lines (59 loc) · 2.74 KB
/
calculator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
"""Commands: "!calc"."""
import math
import re
import pyparsing
from bot.commands.abstract.command import Command
from bot.utilities.math_parser import NumericStringParser
from bot.utilities.permission import Permission
from bot.utilities.tools import replace_vars
PRECISION = 5
class Calculator(Command):
"""A chat calculator that can do some pretty advanced stuff like sqrt and trigonometry.
Example: !calc log(5^2) + sin(pi/4)
"""
perm = Permission.User
symbols = ["e", "pi", "sin", "cos", "tan", "abs", "trunc", "round", "sgn"]
def __init__(self, _):
"""Initialize variables."""
self.nsp = NumericStringParser()
self.responses = {}
def match(self, bot, user, msg, tag_info):
"""Match if the message starts with !calc."""
return msg.lower().startswith("!calc ")
def run(self, bot, user, msg, tag_info):
"""Evaluate second part of message and write the result."""
self.responses = bot.config.responses["Calculator"]
expr = msg.split(" ", 1)[1]
try:
result = self.nsp.eval(expr)
# This condition fixes floating point errors, like 0.1 + 0.2 = 0.300...004
# Rounds to <PRECISION> digits after the first non zero digit
# E.g.: 0.30000004 -> 0.3
# 0.000030030004 -> 0.00003003
if abs(result) < 1:
dist = abs(
int(math.log10(abs(result)))
) # How many zeroes are after ., before a non zero digit
result = round(result, PRECISION + dist)
else:
result = round(result, PRECISION)
reply = "{} = {}".format(expr, result)
bot.write(reply)
except ZeroDivisionError:
var = {"<USER>": bot.twitch.display_name(user)}
bot.write(replace_vars(self.responses["div_by_zero"]["msg"], var))
except OverflowError:
var = {"<USER>": bot.twitch.display_name(user)}
bot.write(replace_vars(self.responses["number_overflow"]["msg"], var))
except pyparsing.ParseException:
var = {"<USER>": bot.twitch.display_name(user)}
bot.write(replace_vars(self.responses["wrong_input"]["msg"], var))
except (TypeError, ValueError): # Not sure which Errors might happen here.
var = {"<USER>": bot.twitch.display_name(user), "<EXPRESSION>": expr}
bot.write(replace_vars(self.responses["default_error"]["msg"], var))
def check_symbols(self, msg):
"""Check whether s contains no letters, except e, pi, sin, cos, tan, abs, trunc, round, sgn."""
msg = msg.lower()
for s in self.symbols:
msg = msg.lower().replace(s, "")
return re.search("[a-zA-Z]", msg) is None