coomputer-craft/main/calculator.lua
ZareMate 846dac82fe .
2022-06-06 20:22:58 +02:00

564 lines
16 KiB
Lua

--[[Smart Calculator by Cranium]]--
local tX, tY = term.getSize()
local calc = {}
--equation states
calc.mode = false
calc.inverse = false
calc.hyp = false
calc.sqrt = false
calc.exp = false
calc.asin = false
calc.sin = false
calc.sinh = false
calc.atan = false
calc.tan = false
calc.tanh = false
calc.acos = false
calc.cos = false
calc.cosh = false
calc.log = false
calc.pos = false
-- characters
local charList = {
["0"] = {
".-.",
"| |",
"'-'"
},
["1"] = {
" . ",
"'| ",
"---"
},
["2"] = {
".-.",
".-'",
"'- "
},
["3"] = {
" -.",
" -|",
" -'"
},
["4"] = {
". .",
"'-|",
" '"
},
["5"] = {
".- ",
"'-.",
" -'"
},
["6"] = {
".-.",
"|-.",
"'-'"
},
["7"] = {
".-.",
" |",
" '"
},
["8"] = {
".-.",
"|-|",
"'-'"
},
["9"] = {
".-.",
"'-|",
" -'"
},
["."] = {
" ",
" ",
" . "
},
["-"] = {
" ",
" --",
" "
},
}
-- lay out the button labels
local labels = {
' + ', ' 1 ', ' 2 ', ' 3 ', '<--', 'sin', 'x^y', 'DEG', 'OFF',
' - ', ' 4 ', ' 5 ', ' 6 ', 'CLR', 'cos', 'srt', 'RAD', ' ',
' x ', ' 7 ', ' 8 ', ' 9 ', ' ', 'tan', 'Pi ', 'inv', ' ',
' / ', ' 0 ', '-/+', ' . ', ' = ', 'log', 'exp', 'hyp', ' '
}
-- generate the objects
local function objGen()
local _objects = {}
local width = 9
for i=1, #labels do
table.insert(_objects, {
x = (((i - 1)%width + 1)*5) - 1;
y = (math.ceil(i/width) * 3) + 4;
label = labels[i];
-- make operators different colors
color =
i == 1 and colors.blue or
i == 5 and colors.red or
i == 6 and colors.yellow or
i == 7 and colors.orange or
i == 8 and colors.white or
i == 9 and colors.red or
i == 10 and colors.blue or
i == 14 and colors.red or
i == 15 and colors.yellow or
i == 16 and colors.orange or
i == 17 and colors.white or
i == 18 and colors.white or
i == 19 and colors.blue or
i == 24 and colors.yellow or
i == 25 and colors.orange or
i == 26 and colors.white or
i == 27 and colors.white or
i == 28 and colors.blue or
i == 30 and colors.red or
i == 32 and colors.white or
i == 33 and colors.yellow or
i == 34 and colors.orange or
i == 35 and colors.white or
i == 36 and colors.white or
colors.lightGray;
-- controls the highlight colors for operators
back =
i == 6 and
calc.sin == true and colors.red or
calc.asin == true and colors.red or
calc.sinh == true and colors.red or
i == 8 and calc.mode == "deg" and colors.blue or
i == 15 and
calc.cos == true and colors.red or
calc.acos == true and colors.red or
calc.cosh == true and colors.red or
i == 16 and calc.sqrt == true and colors.lightBlue or
i == 17 and calc.mode == "rad" and colors.blue or
i == 24 and
calc.tan == true and colors.red or
calc.atan == true and colors.red or
calc.tanh == true and colors.red or
i == 26 and calc.inverse == true and colors.blue or
i == 30 and calc.pos == true and colors.white or
i == 33 and calc.log == true and colors.red or
i == 34 and calc.exp == true and colors.lightBlue or
i == 35 and calc.hyp == true and colors.blue or
colors.black;
})
end
return _objects
end
local function draw()
term.setBackgroundColor(colors.black)
term.clear()
local objects = objGen()
for i=1, #objects do
local obj = objects[i]
term.setTextColor(colors.gray)
term.setBackgroundColor(colors.black)
--draw the grid
for num, line in pairs{'+---+','| |','+---+'} do
term.setCursorPos(obj.x, obj.y + num - 1)
write(line)
end
--draw the button text and colors
term.setCursorPos(obj.x+1, obj.y+1)
term.setTextColor(obj.color)
term.setBackgroundColor(obj.back)
write(obj.label)
end
end
--draw border and screen
local function display()
term.setBackgroundColor(colors.black)
term.setTextColor(colors.gray)
term.setCursorPos(2,1)
write("+"..string.rep("-", tX - 4).."+")
for i = 2, tY - 1 do
term.setCursorPos(2,i)
write("|")
term.setCursorPos(tX - 1,i)
write("|")
end
term.setCursorPos(2,tY)
write("+"..string.rep("-", tX - 4).."+")
term.setBackgroundColor(colors.lightGray)
for i = 2, 6 do
term.setCursorPos(4,i)
write(string.rep(" ", tX - 6))
end
end
--run the equation passed by the user.
local function calculate(eq)
if table.concat(eq) == "()" then
eq = {"0"}
elseif table.concat(eq) == "(.)" then
eq = {"0"}
end
local sExpr = table.concat(eq)
local fnMath, sErr = loadstring("return "..sExpr)
if not fnMath then
return "ERROR! Check syntax!"
end
--setfenv(fnMath, math)
local bSucc, vRes = pcall(fnMath)
if not bSucc then
return "ERROR! Check syntax!"
else
return vRes
end
end
-- function loop
local equation = {"(", ")"}
local result = "0"
while true do
local rLen = 0
draw()
display()
term.setBackgroundColor(colors.lightGray)
term.setTextColor(colors.white)
term.setCursorPos(4,2)
--write the equation
write(table.concat(equation))
--write the result
if tonumber(result) ~= inf then
if string.len(result) >= 15 then
term.setCursorPos(5, 4)
term.setTextColor(colors.black)
write("= ")
for num in string.gmatch(result, ".") do
rLen = rLen + 1
local pX,pY = term.getCursorPos()
if pX >= 4 and pX <= 48 then
term.setCursorPos(rLen + 5, 4)
write(num)
else
term.setCursorPos(rLen + 5 - 48, 5)
write(num)
end
end
else
for num in string.gmatch(result, ".") do
rLen = rLen + 1
for i = 1, #charList[num] do
term.setTextColor(colors.black)
term.setCursorPos((rLen * 3) + 1, i + 3)
write(charList[num][i])
end
end
end
elseif result == nil then
term.setCursorPos(5, 4)
term.setTextColor(colors.black)
write("= ERROR")
else
term.setCursorPos(5, 4)
term.setTextColor(colors.black)
write("= INFINITY")
end
local events = {os.pullEvent()}
--mouse click filter
if events[1] == "mouse_click" and events[2] == 1 then
if events[3] >= 44 and events[3] <= 48 then
if events[4] >= 7 and events[4] <= 9 then
term.setBackgroundColor(colors.black)
term.clear()
term.setCursorPos(1,1)
os.reboot()
end
elseif events[3] >= 39 and events[3] <= 43 then
if events[4] >= 7 and events[4] <= 9 then
if calc.mode == false then
table.remove(equation, 1)
calc.mode = "deg"
table.insert(equation, 1, "math.deg(")
elseif calc.mode == "deg" then
table.remove(equation, 1)
calc.mode = false
elseif calc.mode == "rad" then
table.remove(equation, 1)
calc.mode = "deg"
table.insert(equation, 1, "math.deg(")
end
elseif events[4] >= 10 and events[4] <= 12 then
if calc.mode == false then
table.remove(equation, 1)
calc.mode = "rad"
table.insert(equation, 1, "math.rad(")
elseif calc.mode == "rad" then
table.remove(equation, 1)
calc.mode = false
elseif calc.mode == "deg" then
table.remove(equation, 1)
calc.mode = "rad"
table.insert(equation, 1, "math.rad(")
end
elseif events[4] >= 13 and events[4] <= 15 then
if calc.inverse == true and calc.hyp == false then
calc.inverse = false
elseif calc.inverse == false and calc.hyp == true then
calc.inverse = true
calc.hyp = false
elseif calc.inverse == false and calc.hyp == false then
calc.inverse = true
end
elseif events[4] >= 16 and events[4] <= 18 then
if calc.hyp == true and calc.inverse == false then
calc.hyp = false
elseif calc.hyp == false and calc.inverse == true then
calc.hyp = true
calc.inverse = false
elseif calc.hyp == false and calc.inverse == false then
calc.hyp = true
end
end
elseif events[3] >= 34 and events[3] <= 38 then
if events[4] >= 7 and events[4] <= 9 then
table.insert(equation, #equation, "^")
elseif events[4] >= 10 and events[4] <= 12 then
if calc.sqrt == false then
table.insert(equation, #equation, "math.sqrt(")
calc.sqrt = true
elseif calc.sqrt == true then
table.insert(equation, #equation, ")")
calc.sqrt = false
end
elseif events[4] >= 13 and events[4] <= 15 then
table.insert(equation, #equation, "math.pi")
elseif events[4] >= 16 and events[4] <= 18 then
if calc.exp == false then
table.insert(equation, #equation, "math.exp(")
calc.exp = true
elseif calc.exp == true then
table.insert(equation, #equation, ")")
calc.exp = false
end
end
elseif events[3] >= 29 and events[3] <= 33 then
if events[4] >= 7 and events[4] <= 9 then
if calc.inverse == true and calc.asin == false then
table.insert(equation, #equation, "math.asin(")
calc.asin = true
elseif calc.inverse == false and calc.hyp == false and calc.sin == false then
table.insert(equation, #equation, "math.sin(")
calc.sin = true
elseif calc.hyp == true and calc.sinh == false then
table.insert(equation, #equation, "math.sinh(")
calc.sinh = true
elseif calc.asin == true then
table.insert(equation, #equation, ")")
calc.asin = false
elseif calc.sin == true then
table.insert(equation, #equation, ")")
calc.sin = false
elseif calc.sinh == true then
table.insert(equation, #equation, ")")
calc.sinh = false
end
elseif events[4] >= 10 and events[4] <= 12 then
if calc.inverse == true and calc.acos == false then
table.insert(equation, #equation, "math.acos(")
calc.acos = true
elseif calc.inverse == false and calc.hyp == false and calc.cos == false then
table.insert(equation, #equation, "math.cos(")
calc.cos = true
elseif calc.hyp == true and calc.cosh == false then
table.insert(equation, #equation, "math.cosh(")
calc.cosh = true
elseif calc.acos == true then
table.insert(equation, #equation, ")")
calc.acos = false
elseif calc.cos == true then
table.insert(equation, #equation, ")")
calc.cos = false
elseif calc.cosh == true then
table.insert(equation, #equation, ")")
calc.cosh = false
end
elseif events[4] >= 13 and events[4] <= 15 then
if calc.inverse == true and calc.atan == false then
table.insert(equation, #equation, "math.atan(")
calc.atan = true
elseif calc.inverse == false and calc.hyp == false and calc.tan == false then
table.insert(equation, #equation, "math.tan(")
calc.tan = true
elseif calc.hyp == true and calc.tanh == false then
table.insert(equation, #equation, "math.tanh(")
calc.tanh = true
elseif calc.atan == true then
table.insert(equation, #equation, ")")
calc.atan = false
elseif calc.tan == true then
table.insert(equation, #equation, ")")
calc.tan = false
elseif calc.tanh == true then
table.insert(equation, #equation, ")")
calc.tanh = false
end
elseif events[4] >= 16 and events[4] <= 18 then
if calc.log == false then
table.insert(equation, #equation, "math.log10(")
calc.log = true
elseif calc.log == true then
table.insert(equation, ")")
calc.log = false
end
end
-- backspace, clear, equals
elseif events[3] >= 24 and events[3] <= 28 then
if events[4] >= 7 and events[4] <= 9 then
if table.concat(equation) ~= "()" then
table.remove(equation, #equation - 1)
end
elseif events[4] >= 10 and events[4] <= 12 then
calc.mode = false
calc.inverse = false
calc.hyp = false
calc.sqrt = false
calc.exp = false
calc.asin = false
calc.sin = false
calc.sinh = false
calc.atan = false
calc.tan = false
calc.tanh = false
calc.acos = false
calc.cos = false
calc.cosh = false
calc.log = false
calc.pos = false
equation = {"(", ")"}
result = "0"
elseif events[4] >= 16 and events[4] <= 18 then
if equation[#equation-1] == "+" or
equation[#equation-1] == "-" or
equation[#equation-1] == "*" or
equation[#equation-1] == "/" then
table.insert(equation, #equation, "0")
elseif equation[#equation-1] == "^" then
table.insert(equation, #equation, "1")
end
for i, v in pairs(calc) do
if calc[i] == true then
table.insert(equation, #equation, ")")
calc[i] = false
end
end
result = tostring(calculate(equation))
end
-- 3, 6, 9, decimal
elseif events[3] >= 19 and events[3] <= 23 then
if events[4] >= 7 and events[4] <= 9 then
table.insert(equation, #equation, "3")
elseif events[4] >= 10 and events[4] <= 12 then
table.insert(equation, #equation, "6")
elseif events[4] >= 13 and events[4] <= 15 then
table.insert(equation, #equation, "9")
elseif events[4] >= 16 and events[4] <= 18 then
table.insert(equation, #equation, ".")
end
-- 2, 5, 8, positive/negative
elseif events[3] >= 14 and events[3] <= 18 then
if events[4] >= 7 and events[4] <= 9 then
table.insert(equation, #equation, "2")
elseif events[4] >= 10 and events[4] <= 12 then
table.insert(equation, #equation, "5")
elseif events[4] >= 13 and events[4] <= 15 then
table.insert(equation, #equation, "8")
elseif events[4] >= 16 and events[4] <= 18 then
if calc.pos == false then
table.insert(equation, #equation, "(-")
calc.pos = true
elseif calc.pos == true then
table.insert(equation, #equation, ")")
calc.pos = false
end
end
-- 1, 4, 7, 0
elseif events[3] >= 9 and events[3] <= 13 then
if events[4] >= 7 and events[4] <= 9 then
table.insert(equation, #equation, "1")
elseif events[4] >= 10 and events[4] <= 12 then
table.insert(equation, #equation, "4")
elseif events[4] >= 13 and events[4] <= 15 then
table.insert(equation, #equation, "7")
elseif events[4] >= 16 and events[4] <= 18 then
table.insert(equation, #equation, "0")
end
-- add, subtract, multiply, divide
elseif events[3] >= 4 and events[3] <= 8 then
if events[4] >= 7 and events[4] <= 9 then
table.insert(equation, #equation, "+")
elseif events[4] >= 10 and events[4] <= 12 then
table.insert(equation, #equation, "-")
elseif events[4] >= 13 and events[4] <= 15 then
table.insert(equation, #equation, "*")
elseif events[4] >= 16 and events[4] <= 18 then
table.insert(equation, #equation, "/")
end
end
-- filter for keyboard presses
elseif events[1] == "key" then
if events[2] == 79 then
table.insert(equation, #equation, "1")
elseif events[2] == 80 then
table.insert(equation, #equation, "2")
elseif events[2] == 81 then
table.insert(equation, #equation, "3")
elseif events[2] == 75 then
table.insert(equation, #equation, "4")
elseif events[2] == 76 then
table.insert(equation, #equation, "5")
elseif events[2] == 77 then
table.insert(equation, #equation, "6")
elseif events[2] == 71 then
table.insert(equation, #equation, "7")
elseif events[2] == 72 then
table.insert(equation, #equation, "8")
elseif events[2] == 73 then
table.insert(equation, #equation, "9")
elseif events[2] == 82 then
table.insert(equation, #equation, "0")
elseif events[2] == 83 then
table.insert(equation, #equation, ".")
elseif events[2] == 78 then
table.insert(equation, #equation, "+")
elseif events[2] == 74 then
table.insert(equation, #equation, "-")
elseif events[2] == 55 then
table.insert(equation, #equation, "*")
elseif events[2] == 181 then
table.insert(equation, #equation, "/")
elseif events[2] == 14 then
if table.concat(equation) ~= "()" then
table.remove(equation, #equation - 1)
end
elseif events[2] == 28 or events[2] == 156 then
if equation[#equation-1] == "+" or
equation[#equation-1] == "-" or
equation[#equation-1] == "*" or
equation[#equation-1] == "/" then
table.insert(equation, #equation, "0")
elseif equation[#equation-1] == "^" then
table.insert(equation, #equation, "1")
end
for i, v in pairs(calc) do
if calc[i] == true then
table.insert(equation, #equation, ")")
calc[i] = false
end
end
result = tostring(calculate(equation))
end
end
end