This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Cranium's profile picture

Help with mathematical operations

Started by Cranium, 12 December 2012 - 08:27 AM
Cranium #1
Posted 12 December 2012 - 09:27 AM
I am trying to make some simple(eventually complicated) calculations with a program. What I need to do is basically make a calculator. The problem I am having is how I am going to add numbers and operations together in a sequence.
I thought of using tables, where I would do something like this:

local oper = { 1, "+", 2}
local result = oper[1]..oper[2]..oper[3]
But of course that would only return the string value of all three concatenated. So no calculations.
I then thought about separating out different events, and then creating two separate tables for each side of the equation. I would then perform the calculation.

local tab1 = {}
local tab2 = {}
local operation = getOperation()
if operation == "add" and tab2[1] ~= nil then
    local result = tab1+tab2
elseif operation ~= "add" then
    table.insert(tab1, operation)
elseif operation == "add" and tab2[1] == nil then
    table.insert(tab2, operation)
end
But that seems waaaay to complicated to make work with every possible mathematical operation available in lua.

I need some way to type in a numeric value, being able to switch between operators, and equate as I go. I have no idea how I can do that. Does anyone know of a reliable method I can use to create these math operations?
PixelToast #2
Posted 12 December 2012 - 09:33 AM
you can use
print(({pcall(setfenv(loadstring("return "..table.concat({ ... }," ")),math))})[2])
.-.
wich is basically just an intupreter
Cranium #3
Posted 12 December 2012 - 09:43 AM
I've never used loadstring or pcall…. What do they do and how do I use this new spell?
PixelToast #4
Posted 12 December 2012 - 09:46 AM
I've never used loadstring or pcall…. What do they do and how do I use this new spell?
:o/> what?
loadstring just converts the string into a lua function
pcall catches errors

http://puu.sh/1zEfA
Cranium #5
Posted 12 December 2012 - 10:06 AM
Forgive me for saying, but that doesn't give me a very helpful description. I'll try the lua users wiki, but a more thorough explanation would be nice.
Cranium #6
Posted 12 December 2012 - 11:37 AM
I tried looking around for a suitable explanation. Could anyone give me some help learning pcall, loadstring, and setfenv?
I see that the function given works, by converting a string into a working code block, but I have no idea HOW it happened…
Xtansia #7
Posted 12 December 2012 - 12:13 PM
I went ahead an expanded the 'magic' line, with some additions and comments for you
Pastebin for better highlighting http://pastebin.com/XpPpe7sn
local tArgs = {...} -- Get the commandline arguments
local sExpr = table.concat(tArgs, " ")  -- Concatenate the args back to <arg1> <arg2> <arg..>
local fnMath, sErr = loadstring("return "..sExpr)   -- Load the expression provided via commandline arguments into a function block

if not fnMath then  -- If fnMath is nil we failed to load the function, print the error returned
	print("ERROR: "..sErr)
	return
end
--[[
	Given sExpr = "5+9/8*(98 - 45)"
	The above loadstring is equivalent to
	fnMath = function()
		return 5+9/8*(98 - 45)
	end
--]]

setfenv(fnMath, math) -- Set the functions environment 'root' in the math table instead of _G
--[[
	This allows for an expression like:  8 * 6 / sin(rad(36))
--]]

local bSucc, vRes = pcall(fnMath)   -- This calls the function in a 'safe' manner any errors thrown in fnMath won't error this program
--[[
	If no errors are thrown then bSucc will be true and vRes will contain the return value,
	Otherwise vRes will contain the error message
--]]

if not bSucc then   -- If bSucc is false we failed calling the function, print the error
	print("ERROR: "..vRes)
else
	print("Result: "..vRes)
end
Cranium #8
Posted 12 December 2012 - 12:29 PM
Thanks for the help! I am going to try to implement this into my program, so hopefully it will be easier than it looks.
KaoS #9
Posted 13 December 2012 - 03:24 AM
basically concatenate and then loadstring. I really don't know how you will get square root (you will have to implement an entirely different system which actually isn't too hard). I took a crack at it and came up with this


local tNums={["1"]={2,2},["2"]={4,2},["3"]={6,2},["4"]={2,4},["5"]={4,4},["6"]={6,4},["7"]={2,6},["8"]={4,6},["9"]={6,6}}
local tSigns={["+"]={8,2},["-"]={8,4},["/"]={8,6},["*"]={10,2},["="]={10,4}}
local current='0'
while true do
  term.clear()
  term.setCursorPos(2,8)
  print("current amount: "..current)
  for k,v in pairs(tNums) do
   term.setCursorPos(unpack(v))
   print(k)
  end
  for k,v in pairs(tSigns) do
   term.setCursorPos(unpack(v))
   print(k)
  end
  local evt={os.pullEvent()}
  if evt[1]=='mouse_click' then
   local num=(function()
    for k,v in pairs(tNums) do
	 if v[1]==evt[3] and v[2]==evt[4] then
	  return k
	 end
    end
   end)()
   local sign=(function() for k,v in pairs(tSigns) do if v[1]==evt[3] and v[2]==evt[4] then return k end end end)()
   if num then
    current=current..num
   elseif sign then
    current=loadstring('return '..current)()..(sign=="=" and '' or sign)
   end
  end
end
Cranium #10
Posted 14 December 2012 - 08:59 AM
Allright. I have been working on this extensively, and have reached an impasse. Any small operations(add, subtract, multiply, divide, power) all work just fine. But when using advanced functions in the math library, I always get attempt to index ?(a nil value).
This only occurs when I run the calculation, so I can't see where exactly the error is being thrown until AFTER I try the equation.
Could anyone take a look at what I am doing wrong?
Code here:
Spoiler

--[[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 = true


-- 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;
  
   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 == 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)
  for num, line in pairs{'+---+','|   |','+---+'} do
   term.setCursorPos(obj.x, obj.y + num - 1)
   write(line)
  end
  term.setCursorPos(obj.x+1, obj.y+1)
  term.setTextColor(obj.color)
  term.setBackgroundColor(obj.back)
  write(obj.label)
 end
end
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
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 1: "..sErr
 end
 setfenv(fnMath, math)
 local bSucc, vRes = pcall(fnMath)
 if not bSucc then
  return "ERROR 2: "..vRes
 else
  return vRes
 end
end
-- function loop
local equation = {"(", ")"}
while true do
 draw()
 display()
  term.setBackgroundColor(colors.lightGray)
  term.setTextColor(colors.white)
  term.setCursorPos(4,2)
  write(table.concat(equation))
 local events = {os.pullEvent()}
 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
	break
   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
  elseif events[3] >= 24 and events[3] <= 28 then
   if events[4] >= 7 and events[4] <= 9 then
	table.remove(equation)
   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 = true
	equation = {"(", ")"}
   elseif events[4] >= 16 and events[4] <= 18 then
	print(calculate(equation))
	sleep(10)
   end
  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
  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
	 --positive/negative
   end
  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
  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
 end
end
Better syntax highlighting here: http://pastebin.com/mH2NTgFJ
PixelToast #11
Posted 14 December 2012 - 09:38 AM
i dont see any errors .-.
and wth is this:
events[4] >= 16 and events[4] <= 18
i dont get it :s
why not just
events[4]==17
and if you need to have 16.1 work just
math.floor(events[4])==17
GravityScore #12
Posted 14 December 2012 - 09:46 AM
i dont see any errors .-.
and wth is this:
events[4] >= 16 and events[4] <= 18
i dont get it :s
why not just
events[4]==17
and if you need to have 16.1 work just
math.floor(events[4])==17

Because its => and <=, meaning events[4] could either be 16, 17, or 18 - not just 17 (if it were > and <, then events[4] could only be 17).
(not sure if this was a derpy moment…)
Cranium #13
Posted 14 December 2012 - 09:47 AM
Because it's not less than 18 and greater than 16. it's less than or EQUAL TO.
So it takes in 16,17 AND 18.
events[4] is the y position of the "mouse_click" event I am retreiving.
Cranium #14
Posted 14 December 2012 - 09:54 AM
I found that my errors occur when I am doing anything with the lua math library(math.pi, math.deg(), math.sqrt()). I don't really know how it's causing problems, because loadstring should work, right?
Xtansia #15
Posted 14 December 2012 - 02:48 PM
Because you're setting the loaded functions environment to math, you don't need the math. prefix for the functions, so math.sin(theta) becomes just sin(theta)
Cranium #16
Posted 14 December 2012 - 06:35 PM
So I would just remove the setfenv command because I don't need to, I see…
I removed it, and now it works like a charm. Full release upcoming!
Cranium #17
Posted 20 December 2012 - 10:52 AM
Alright. Not to drag up a really old topic, but I am having new trouble with the same program. I have added the equation functions, and added key input as well. The problem I have now, before I can release it, is the 'enter' key on the numpad. The key code is 156 but it does not register as the same action as actually pressing the equals sign on the screen. I don't understand why though.

New code here:
http://pastebin.com/mH2NTgFJ

Spoiler

--[[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;
 
   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)
  for num, line in pairs{'+---+','|   |','+---+'} do
   term.setCursorPos(obj.x, obj.y + num - 1)
   write(line)
  end
  term.setCursorPos(obj.x+1, obj.y+1)
  term.setTextColor(obj.color)
  term.setBackgroundColor(obj.back)
  write(obj.label)
end
end
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
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 1: "..sErr
end
--setfenv(fnMath, math)
local bSucc, vRes = pcall(fnMath)
if not bSucc then
  return "ERROR 2: "..vRes
else
  return vRes
end
end
local function rPrint(result)
 

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(table.concat(equation))
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, 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
local events = {os.pullEvent()}
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
    break
   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
  --
  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
    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, "(0-")
	 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] == 156 then
   result = tostring(calculate(equation)) --this will not calculate.
  end
end
end
Cranium #18
Posted 20 December 2012 - 01:42 PM
I did attempt to debug a little, and found that key 156 is the only one that is not registering. Not sure if this is an error on my pc keyboard, or in the code. I do see that the screen will flash, as if I entered an invalid key. I tried using other keys, and they did work. Anyone have any idea as to why this is happening?

EDIT: Not sure if my computer is stupid, but when I printed events[2], and pressed the numpad 'enter', it returned 28 as the keycode, which is strange. This here says that it should be code 156, but I am returning the same one as if I were to hit 'return' next to the rest of the keyboard.

Could this be a bug?
Edited on 20 December 2012 - 12:49 PM
Cranium #19
Posted 20 December 2012 - 02:56 PM
I have tested with other computers. os.pullEvent() is indeed showing that the numpad enter key listed under key code 28. I don't know why, but I am reporting it.
Cranium #20
Posted 21 December 2012 - 10:03 AM
I have a new error that breaks the program. Anytime I use the calculate() function to calculate an equation that would result in infinity, it errors out the program trying to get the length of nil. I believe this has to do with my calculate function not catching infinity. But I don't know how I can do that.
I have tried matching the result with math.huge, but nothing works. I have no idea how to catch the error in trying to calculate infinity.
Orwell #21
Posted 21 December 2012 - 10:12 AM
Maybe compare it with 1/0?

local inf = 1/0
if input == inf then
  // input is infinite
end
Or did I understand you wrong?

Edit: 1/0 is exactly the same value as math.huge . So I must have misunderstood your question. :)/>
Cranium #22
Posted 21 December 2012 - 10:34 AM
Fixed it. math.huge apparently does not equal the variable inf. When comparing, I used

if tonumber(result) ~= inf then
  --do if it's a normal number
else
  --do if it is infinity
end
I'm going to be updating the code now.