I Finally Got Off My Own Ass and Learned How To Make a Calculator

Update (21 DEC 2022): If you’re here for why BDSP’s calculator malfunctioned, I am unable to provide a solution- however, this video by pimanrules, in my opinion, does

When it comes down to it, anything with a CPU inside is arguably just a massively overpowered calculator. They are capable of solving large amounts of complex equations in very little time, as well as store those results for later- without this trait, software would not operate; or at least, not as we know it.

So how the heck did this happen?

A friend had showed me this clip some time ago. I thought it was hilarious- but when I stopped to think about what’s going on… What caused that calculator to freak out so, actually?

Someone told me that the first thing you learn to make as a software developer is a calculator. That sounds sensical. It’s a small, simple project that handily teaches you some of the most fundamental basics of programming- storing information and performing arithmethics. What, me? No, never even thought about it.

And so, through sheer curiosity and the power of procrastination, I set out to learn how to create a digital calculator!

This article won’t go too deeply into the specifics- they’re simple enough that you’re probably not here for them, no matter which end of the experience spectrum you’re at.

Arithmethics With a Computer

As always with my projects, I like to set out with specific goals in mind- a Minimum Viable Product checklist, if you will. I tend to keep this short and quick, because if there’s something I want to add in later, I can just add it in.

As this is new territory to me, I’m going to start with only one goal.

GOALS

  • Perform arithmethics; pass the following test:
    • 1+1 = 2

My tool of choice will be LÖVE, a Lua framework meant for game development. I chose this because it’s what I have on this computer right now and I’m too lazy to get anything else. Also, the basics should be the near identical in every language/framework/engine, anyways.

I had no idea where to start, so I did the most obvious thing that came to mind.

print(1+1)
--
-- Prints: 2

Well, that was easy.

Going (Slightly) Further Beyond

I guess I’ll go ahead and do more things, if only so that I have enough content to justify writing a blog about it.

GOALS

  • Have an interactive UI
  • Pass the following tests:
    • 1+1 = 2
    • 9-2 = 7
    • 5x3 = 15
    • 10/5 = 2
    • 10/4 = 2.5
    • 7/3 = 2.33333~

First, I imported two third-party libraries: HUMP’s class library and baton. Look, it’s just how I prefer things, okay.

local Class = require("class")
local baton = require("baton")

I started by making buttons. I doodled some quick button assets, and made them query mouse position and react when clicked.

Checking that buttons do, indeed, work.

Then, I turned them into calculator number buttons. They just concatenate their value to a string.

They are now calculator buttons.

It seems like the framerate makes it look like the buttons aren’t giving visual feedback, sometimes. They do- you’ll just have to take my word for it. Or don’t. I’ll have source linked below.

Then, I made it so there are two “buffer” values I can store the numbers in, and a third “operand buffer”- I use these to store numbers and apply the calculations, like so.

function applyOperand()
    if opBuffer == "add" then numBuffer[1] = numBuffer[2] + numBuffer[1] end
    if opBuffer == "sub" then numBuffer[1] = numBuffer[2] - numBuffer[1] end
    if opBuffer == "mul" then numBuffer[1] = numBuffer[2] * numBuffer[1] end
    if opBuffer == "div" then numBuffer[1] = numBuffer[2] / numBuffer[1] end
    displayThis = numBuffer[1]
end

The keen-eyed might have noticed a peculiarity. I mentioned that I stored my numbers as concatenated strings- so how am I able to do mathematical operations on them?

The answer is: Lua is what is called a “weak-type” language. I do not specify what a value’s type is when declaring it, and Lua automagically converts between data types whenever it detects that I’m trying to do something weird (in this case, doing mathematical operations on words).

Well, it seems to be working. Let’s go through the tests.

Going through the tests.

It all seems to be in order. It’s a little unpolished, but really, who would actually use this calculator, anyways? There are certain mathematical issues that might read its head, such as floating point errors, but those are far beyond the scope of this dumb half-day project. In case you’re curious, the solutions are: math lookup tables and arbitrary precision libraries.

That’s all well and good, but… am I forgetting something?

So what actually happened?

I had made a (somewhat) functional calculator, but I still have absolutely no idea what’s going on with the calculator we took a look at in the beginning. So why don’t we take a look?

Unfortunately, I do not own a copy of this game- therefore, I can only go off of the information presented in this thread, as well as information publicly available. Let’s see what we know:

  • Pokémon BD/SP is created in Unity, using C#
  • Not everyone is experiencing this glitch
  • Reportedly, the original report came from someone playing in the German locale
    • The original reporter also tried switching to the English locale, which fixed the issue- upon resetting to the German locale, the calculator broke again?

Was this something coming from the German system locale, then? Do they handle decimal points differently? But that doesn’t explain most of the garbled results. I can see a different system to handling decimals outputting 10/4 = 002, but not 2.3654 = 4.3654, for example.

Before continuing, I wrote a quick function for running tests, and also a table.copy function I took off of SO by Norman Ramsey because of course I did.

function testThis(toBuffer,operand,expectation)
	numBuffer = table.copy(toBuffer)
    opBuffer = operand
    applyOperand()
    local isPassing = nil
    if numBuffer[1] == expectation then isPassing = true
    else isPassing = false end
    print("Testing for " .. toBuffer[2] .. opBuffer .. toBuffer[1] .. "=" .. expectation .. " ... " .. tostring(isPassing))
    allClear()
end

function table.copy(t)
    local u = { }
    for k, v in pairs(t) do u[k] = v end
    return setmetatable(u, getmetatable(t))
end

This function will use the system I put in place to make calculations, then print whether or not the results are as expected. For example:

-- This checks whether 5 - 3 = 2
testThis({"3","5"}, "sub", 2)
--
-- Prints: Testing for 5sub3=2 ... true

I wrote a series of tests based on the results provided by the video.

  • Pass the following tests:
    • 10/5 = 2
    • 10/4 = 002
    • 7/3 = ??????????
    • 2.3654 = 4.3654
    • 4.3654 * 2 = 47308
testThis({"5","10"}, "div", 2)
testThis({"4","10"}, "div", 002)
testThis({"3","7"}, "div", "??????????")
testThis({"1","2.3654"}, "mul", 4.3654)
testThis({"2","4.3654"}, "mul", 47308)
--
-- Prints: 
Testing for 10div5=2 ... true
Testing for 10div4=2 ... false
Testing for 7div3=?????????? ... false
Testing for 2.3654mul1=4.3654 ... false
Testing for 4.3654mul2=47308 ... false

That said, I had no idea where to start, so I did the most obvious thing that came to mind.

Well... That's one way of doing it.

--
-- Prints:
Testing for 105=2 ... true
Testing for 104=2 ... true
Testing for 73=?????????? ... true
Testing for 2.36541=4.3654 ... true
Testing for 4.36542=47308 ... true

LGTM!

Source Code

.love file
A .love file is just a zip archive. Rename the file to calculator.zip to examine the code. It is very messy and I apologize beforehand.