Calculator GUI Problem

Hi. So I made a calculator gui but there is an issue that I’m currently having. Whenever I input the second value for an operation as a decimal, the calculator returns an error message for the output.

The issue only occurs when the first two characters are 0. but it works completely fine when I input any other digit.

Video of the issue:
Edit: forgot to post video earlier. (See second post from me)

Local script:

local calculator_gui = script.Parent.Parent
local calculator = calculator_gui.Frame

local screen = calculator.ScreenFrame.Screen
local operationScreen = calculator.ScreenFrame.Operation
local keypad = calculator.Keypad

local operationPad = keypad.Operations
local numberPad = keypad.NumberKeys

local currentOperation = nil
local previousOperation = nil
local previousNumber = nil
local currentNumber = nil
local lastKeyPressed = nil

local canUse = true
local err = false
local answerGiven = false
local operationInProgress = false

local numberKeys = {}

local operations = {

	["add"] = {

		str = "+";

		func = function(a, b)
			return a + b
		end

	};

	["subtract"] = {

		str = "-";

		func = function(a, b)
			return a - b
		end

	};

	["multiply"] = {

		str = "x";

		func = function(a, b)
			return a * b
		end

	};

	["divide"] = {

		str = "/";

		func = function(a, b)
			return a/b
		end

	};

}

local otherKeys = {}
local operationKeys = {}

local output = {tostring(0)}

local err_msg = "Error. Press 'AC' key to clear."

for _, key in pairs(numberPad:GetChildren()) do
	if key:IsA("TextButton") and key.LayoutOrder <= 10 then
		table.insert(numberKeys, key)
	end
end

for _, key in pairs(numberPad:GetChildren()) do
	if key:IsA("TextButton") and key.LayoutOrder > 10 then
		table.insert(otherKeys, key)
	end
end

for _, key in pairs(operationPad:GetChildren()) do
	if key:IsA("TextButton") and (key.Name ~= "Clear") and (key.Name ~= "Answer") then
		table.insert(operationKeys, key)
	end
end

for _, key in pairs(numberKeys) do
	if key.LayoutOrder > 9 then
		key.Text = 0
	else
		key.Text = key.LayoutOrder
	end
end

table.sort(numberKeys, function(a, b)
	return a.LayoutOrder < b.LayoutOrder
end)

local function evaluate(a, b)

	local value

	if currentOperation == "+" then
		value = operations.add.func(a, b)
	elseif currentOperation == "-" then
		value = operations.subtract.func(a, b)
	elseif currentOperation == "x" then
		value = operations.multiply.func(a, b)
	elseif currentOperation == "/" then
		value = operations.divide.func(a, b)
	end

	return value

end

local function roundNumber(value)
	return math.round(value*1e10)/1e10
end

local function showOperation()
	
	if currentOperation ~= nil then
		return currentOperation
	else
		return ""
	end
	
end

local function performOperation(key)

	if canUse and not err then

		if table.find(numberKeys, key) then

			if lastKeyPressed == tostring(currentOperation) then
				currentNumber = nil
				previousNumber = tonumber(table.concat(output, ""))
				table.clear(output)
			end
			
			if answerGiven then
				answerGiven = false
				previousNumber = nil
				currentOperation = nil
				table.clear(output)
			end

			if (output[1] == "0") then
				table.remove(output, 1)
			end

			if key.LayoutOrder > 9 then
				table.insert(output, tostring(0))
				lastKeyPressed = 0
			else
				table.insert(output, tostring(key.LayoutOrder))
				lastKeyPressed = key.LayoutOrder
			end
			
			print(key.LayoutOrder)

		end

		if table.find(otherKeys, key) then
			
			if key.Name == "DecimalPoint" then
				
				if table.find(output, key.Text) == nil then
					
					if answerGiven or (lastKeyPressed == currentOperation) then
						answerGiven = false
						table.clear(output)
						table.insert(output, tostring(0)..key.Text)
					else
						table.insert(output, key.Text)
					end
					
				end
				
			end
			
			lastKeyPressed = "."
			
		end

		if table.find(operationKeys, key) then

			previousOperation = currentOperation

			local num = tonumber(table.concat(output, ""))

			if (num ~= nil) and (previousNumber ~= nil) then
				
				table.clear(output)
				
				local answer = evaluate(previousNumber, num)
				
				if tostring(answer):len() > 12 then
					answer = roundNumber(answer)
				end
				
				table.insert(output, answer)
				
			end

			currentOperation = operations[key.Name].str
			lastKeyPressed = currentOperation
			
			operationInProgress = true
			answerGiven = false

		end

		if key.Name == "Answer" then

			if (previousNumber ~= nil) and (currentOperation ~= nil) and (currentNumber == nil) then

				currentNumber = tonumber(table.concat(output, ""))

				local answer = evaluate(previousNumber, currentNumber)

				table.clear(output)

				if tostring(answer):len() > 12 then
					answer = roundNumber(answer)
				end
				
				if answer == math.huge then
					err = true
					canUse = false
					table.clear(output)
					answer = err_msg
				end
				
				table.insert(output, answer)

				previousNumber = nil

			elseif (currentNumber == nil) and (currentOperation == nil) then
				
				local answer = tonumber(table.concat(output, ""))
				
				table.clear(output)
				table.insert(output, answer)
				
			elseif answerGiven == true then
				return
			else
				err = true
				canUse = false
				table.clear(output)
				table.insert(output, err_msg)
			end
			
			lastKeyPressed = "="
			answerGiven = true
			operationInProgress = false

		end

	end

	if key.Name == "Clear" then
		
		table.clear(output)
		
		currentOperation = nil
		previousOperation = nil
		currentNumber = nil
		previousNumber = nil
		lastKeyPressed = nil
		
		answerGiven = false
		operationInProgress = false
		err = false
		canUse = true
		
		table.insert(output, tostring(0))
		
	end
	
	print(lastKeyPressed)
	print(table.concat(output, ""))

end

for _, key in pairs(keypad:GetDescendants()) do

	if key:IsA("TextButton") then
		key.MouseButton1Click:Connect(function()
			performOperation(key)
		end)
	end

end

while wait() do
	screen.Text = table.concat(output, "")
end

Thank you for reading. Any help or suggestions are appreciated!

Edit: the issue only occurs when I input the decimal without inputting zero first (The zero is automatically placed.)

2 Likes

Hmm… I can’t see the video, do you mind sending it again?

1 Like

Sorry, tried to upload it at first but I forgot that it was too large to upload.
Edit: it’s kind of laggy, but the output in studio shows which buttons are pressed in order.

Upload the Gui and I’ll look at it. Other than that, too much to put together a mock version that will work with this script.

1 Like

Ok, I’ll take a look at it. Give me a bit.

1 Like

ok … in your script remove the lines:

if table.find(otherKeys, key) then
	if key.Name == "DecimalPoint" then
		if table.find(output, key.Text) == nil then
			if answerGiven or (lastKeyPressed == currentOperation) then
				answerGiven = false
				table.clear(output)
				table.insert(output, tostring(0)..key.Text)
			else
				table.insert(output, key.Text)
			end
		end
	end
	lastKeyPressed = "."
end

And replace that with this:

if table.find(otherKeys, key) then
	if key.Name == "DecimalPoint" then
		if answerGiven or (lastKeyPressed == currentOperation) then
			answerGiven = false
			table.clear(output)
			table.insert(output, "0.")
		else
			local currentOutput = table.concat(output, "")
			if currentOutput == "0" or currentOutput == "" then
				table.clear(output)
				table.insert(output, "0.")
			elseif not currentOutput:find("%.") then
				table.insert(output, key.Text)
			end
		end
	end
	lastKeyPressed = "."
end

And if that is wrong here is the full script (after a bit of reformatting).

Full Script
local calculator_gui = script.Parent.Parent
local calculator = calculator_gui.Frame

local screen = calculator.ScreenFrame.Screen
local operationScreen = calculator.ScreenFrame.Operation
local keypad = calculator.Keypad

local operationPad = keypad.Operations
local numberPad = keypad.NumberKeys

local currentOperation = nil
local previousOperation = nil
local previousNumber = nil
local currentNumber = nil
local lastKeyPressed = nil

local canUse = true
local err = false
local answerGiven = false
local operationInProgress = false

local numberKeys = {}

local operations = {
	["add"] = {str = "+"; func = function(a, b) return a + b end};
	["subtract"] = {str = "-"; func = function(a, b) return a - b end};
	["multiply"] = {str = "x"; func = function(a, b) return a * b end};
	["divide"] = {str = "/"; func = function(a, b) return a/b end};
}

local otherKeys = {}
local operationKeys = {}

local output = {tostring(0)}

local err_msg = "Error. Press 'AC' key to clear."

for _, key in pairs(numberPad:GetChildren()) do
	if key:IsA("TextButton") and key.LayoutOrder <= 10 then
		table.insert(numberKeys, key)
	end
end

for _, key in pairs(numberPad:GetChildren()) do
	if key:IsA("TextButton") and key.LayoutOrder > 10 then
		table.insert(otherKeys, key)
	end
end

for _, key in pairs(operationPad:GetChildren()) do
	if key:IsA("TextButton") and (key.Name ~= "Clear") and (key.Name ~= "Answer") then
		table.insert(operationKeys, key)
	end
end

for _, key in pairs(numberKeys) do
	if key.LayoutOrder > 9 then
		key.Text = 0
	else
		key.Text = key.LayoutOrder
	end
end

table.sort(numberKeys, function(a, b)
	return a.LayoutOrder < b.LayoutOrder
end)

local function evaluate(a, b)
	local value
	if currentOperation == "+" then
		value = operations.add.func(a, b)
	elseif currentOperation == "-" then
		value = operations.subtract.func(a, b)
	elseif currentOperation == "x" then
		value = operations.multiply.func(a, b)
	elseif currentOperation == "/" then
		value = operations.divide.func(a, b)
	end
	return value
end

local function roundNumber(value)
	return math.round(value*1e10)/1e10
end

local function showOperation()
	if currentOperation ~= nil then
		return currentOperation
	else
		return ""
	end
end

local function performOperation(key)
	if canUse and not err then
		if table.find(numberKeys, key) then
			if lastKeyPressed == tostring(currentOperation) then
				currentNumber = nil
				previousNumber = tonumber(table.concat(output, ""))
				table.clear(output)
			end
			if answerGiven then
				answerGiven = false
				previousNumber = nil
				currentOperation = nil
				table.clear(output)
			end
			if (output[1] == "0") then
				table.remove(output, 1)
			end
			if key.LayoutOrder > 9 then
				table.insert(output, tostring(0))
				lastKeyPressed = 0
			else
				table.insert(output, tostring(key.LayoutOrder))
				lastKeyPressed = key.LayoutOrder
			end
		end
		if table.find(otherKeys, key) then
			if key.Name == "DecimalPoint" then
				if answerGiven or (lastKeyPressed == currentOperation) then
					answerGiven = false
					table.clear(output)
					table.insert(output, "0.")
				else
					local currentOutput = table.concat(output, "")
					if currentOutput == "0" or currentOutput == "" then
						table.clear(output)
						table.insert(output, "0.")
					elseif not currentOutput:find("%.") then
						table.insert(output, key.Text)
					end
				end
			end
			lastKeyPressed = "."
		end
		if table.find(operationKeys, key) then
			previousOperation = currentOperation
			local num = tonumber(table.concat(output, ""))
			if (num ~= nil) and (previousNumber ~= nil) then
				table.clear(output)
				local answer = evaluate(previousNumber, num)
				if tostring(answer):len() > 12 then
					answer = roundNumber(answer)
				end
				table.insert(output, answer)
			end
			currentOperation = operations[key.Name].str
			lastKeyPressed = currentOperation
			operationInProgress = true
			answerGiven = false
		end
		if key.Name == "Answer" then
			if (previousNumber ~= nil) and (currentOperation ~= nil) and (currentNumber == nil) then
				currentNumber = tonumber(table.concat(output, ""))
				local answer = evaluate(previousNumber, currentNumber)
				table.clear(output)
				if tostring(answer):len() > 12 then
					answer = roundNumber(answer)
				end
				if answer == math.huge then
					err = true
					canUse = false
					table.clear(output)
					answer = err_msg
				end
				table.insert(output, answer)
				previousNumber = nil
			elseif (currentNumber == nil) and (currentOperation == nil) then
				local answer = tonumber(table.concat(output, ""))
				table.clear(output)
				table.insert(output, answer)
			elseif answerGiven == true then
				return
			else
				err = true
				canUse = false
				table.clear(output)
				table.insert(output, err_msg)
			end
			lastKeyPressed = "="
			answerGiven = true
			operationInProgress = false
		end
	end
	if key.Name == "Clear" then
		table.clear(output)
		currentOperation = nil
		previousOperation = nil
		currentNumber = nil
		previousNumber = nil
		lastKeyPressed = nil
		answerGiven = false
		operationInProgress = false
		err = false
		canUse = true
		table.insert(output, tostring(0))
	end
end

for _, key in pairs(keypad:GetDescendants()) do
	if key:IsA("TextButton") then
		key.MouseButton1Click:Connect(function()
			performOperation(key)
		end)
	end
end

while wait() do
	screen.Text = table.concat(output, "")
end

Yes, I cheated a bit and just reset/cleared the input table. Because you did have this all right. It was just a display error at that point.

I just found out what I was doing wrong and it came from here:

Turns out I set previousNumber only for when a number key is pressed and not the decimal point. And it was supposed to be:

if table.find(operationKeys, key) then

			previousOperation = currentOperation

			local num = tonumber(table.concat(output, ""))

			if (num ~= nil) and (previousNumber ~= nil) then

				table.clear(output)

				local answer = evaluate(previousNumber, num)

				if tostring(answer):len() > 12 then
					answer = roundNumber(answer)
				end

				table.insert(output, answer)

			end
			
			previousNumber = num
			currentOperation = operations[key.Name].str
			lastKeyPressed = currentOperation

			operationInProgress = true
			answerGiven = false

		end

Apologies for wasting your time by the way.

I didn’t want to mess with your code too much as I saw it was working right, so I went for the easy reformat fix. Also in testing your reply, this isn’t fixing the problem you stated without the function changes I made also.

1 Like