Light bulb at the brink

This is another one of my “lessons learnt from video games” article. The role playing game in question is Romancing Saga. To illustrate my point, I’m going to describe some of the game battle mechanics.

Brief gist of the game. You, the player, can control up to five characters. Characters can be recruited during game play. Characters can master a variety of weapons (such as the sword, broadsword, staff and even martial arts) and magic (one of my favourites is the “sunlight”. Simple, unassuming, cheerful and very anti-violence in name. Still does good damage too.).

Sunlight on lake with mountain background

The difference between Romancing Saga and other RPGs is the method of levelling up. Normal RPGs have an experience point system. The more monsters you kill, and the more vicious they are, the higher the experience points. Once you accumulate a particular number of experience points, you level up, where one or more of the following increases: strength, speed, intelligence, health points (reach 0 and it’s game over), magic points (for casting spells) and other kinds of character statistics.

Romancing Saga, on the other hand, has an incremental system. After every battle, there’s a possibility that one or more of the character’s statistics will increase. I’m going to focus on 2 particular stats, the WP and the JP. The WP determines how many weapon skills a character can unleash. The JP determines how many spells a character can cast. What do they stand for? I’ve only got a hunch. See image below.

Ji Shu kanji

The 2 Chinese characters, or kanji in Japanese, is pronounced “ji” and “shu” respectively (in Chinese). Their Japanese pronunciation are “wa za” and “jiu tsu” respectively. They refer loosely to technical skills and intellectual skills respectively. Can you see it now? Wa za points, or WP. Jiu tsu points, or JP.

I’m focusing on WP and JP because, along with HP (health points?), they fluctuate in battle, usually in the undesirable direction of down. And if you have a long series of battles ahead of you, you want your characters to start with as high a value for each as possible.

So I, uh, sometimes go bully some weaker monsters. I will start off my bullying spree by wasting every single point of WP and JP. Why? This could be some superstitious belief of mine, but I found that when I’ve got 0 WP and 0 JP, my characters seem to improve their base WP and JP more often.

It’s like the game felt that because I’ve got nothing left, I probably don’t have enough WP and JP to begin with, so rewards me with increases of base WP and JP. Then when I rest up (which I hardly ever do), I have higher base stats.

The light bulb

There’s another reason why I waste all my skill points away when I’m trying to level up. In Romancing Saga, you can learn new weapon skills right there in the heat of a battle. You could use a rapier to attack normally, and suddenly, a “kring” sounds, a light bulb appears, and your rapier wielder unleashes an elegant whip-like slice to the monster’s aorta, resulting in fantastic arterial spray (muahahaha). Or you could use a weapon skill, say a double slash, and you learn the next version, the triple slash. It is an awesome sight to behold when your characters are “kringing” left and right…

And… it seems that if you’ve got 0 WP, the light bulbs come a bit more often. It’s like the game senses you’ve got nothing left, and to help you continue the battles, it rewards you with new (and usually devastating) skills so you can vanquish the monsters and actually stay alive.

I love this light bulbing so much that when one of my characters master a weapon (no more skills of that weapon to learn), I switch weapons just so that character continues to “kring”. It’s that much fun.

The obscure kringer

In Romancing Saga 3, there’s this female character you can recruit. In the story, she’s very sick, and cannot leave her home for too long. She’s gentle and sweet and frail. When she joins your party, your first impression of her is that she’s strong in magic, but she’s too weak in other areas to function well. On an overall character evaluation, you might think she’s not a good addition to your party members.

That is probably what the game developers wanted you to believe.

You see, once you can actually get her to survive some battles, her JP starts shooting up. She can learn magic spells faster than anyone else. She can wipe out a group of monsters with a flick of her little finger. She can bring one of your characters back from the brink of death with her healing spell. As a powerful magic user, she’s unbeatable. Until she runs out of JP.

That’s when her secret comes out.

She, is the most prolific kringer I have ever had the pleasure of playing.

Give her a sword, and don’t think she might drop the piece of steel. She can learn up to 3 new skills in a single battle. That’s about an average of one new skill per attack in the entire battle. Not enough money to buy weapons? Start her on unarmed combat. She’ll master the mid level martial arts skills so fast you’d think she’s on steroids. And maybe because the game feels she’s too weak, and grants higher level skills to her. It’s just so amazing to watch.

Sure, her new skill doesn’t do a lot of damage compared to another character performing the same skill, since her strength isn’t high. But as battles go by, and her base stats go up, her polymath abilities to master both weapon skills and magic spells make her a compatible character to whatever group you have in mind.

And get this; her name is Muse.

So what’s the lesson?

You’re at your wit’s end at solving a problem, say finding that elusive bug that’s driving you crazy. Maybe you’re not really at your wit’s end? Give more, give everything you’ve got. Scrutinise every single line of code. Question every single for loop structure. Scan like an infrared sensor and inspect like a telescope.

And sometimes when you’re tired, your vision is blurry, your shoulders are slumped and you’ve got nothing left to give, your brain does something magical. A light bulb “krings”. Your brain presents you the simplest solution requiring the least amount of effort, because you’ve got nothing left.

You light bulbed at the brink.

The float, the finance and the folly

When I was studying mathematics in university, I was introduced to 3 number “lines”, for lack of a better word. They were the integers (denoted by Z with a double line at the slant), natural numbers (denoted by N with a double line at the slant) and real numbers (denoted by R with a double line at the vertical). There were others, such as complex numbers, rational and irrational numbers. Let’s keep this simple, shall we?

Mathematical symbol for natural, integer and real numbers

Yeah, that’s how I wrote those symbols. I particularly like writing the Z with the 2 disconnected strokes. Ah, those times of writing mathematical proofs… To forestall a question you might have, the I is used to denote imaginary numbers, that’s why Z is used for integers. As to why Z is used for integers, Z

stands for Zahlen (German for numbers)

Integers (or whole numbers) are numbers without fractional parts, such as 5 or 72 or -3, including zero. Natural numbers are numbers for counting, referring to zero and positive integers (sometimes referred to as non-negative integers). Depending on context, zero might not be included. Real numbers are every single existing number available. Numbers such as 1.23456 and 3.14159 and 1.414. They also include integers, and naturally include the natural numbers.

Where am I going with this?

When I learned programming, the idea of having 2 sets of variable types dealing with numbers, one of integral types and one of non-integral types (which I gave a basic introduction here and here), was very natural. On the one hand, we have byte, short, int and long. On the other, we have float and double. I also learned the limitations of each variable type and the appropriate usage of each type.

You should be familiar with the integral types. It’s the non-integral types, or the floating points that I’m worried about. You will note that, while the integrals can’t represent all integers (they have a limit, like 2 ^ 31), they do represent the particular integer value exactly. A 100 is definitely a 100, for example (unless you change the form of representation).

The float and double variable types present a problem. They only hold a number value that’s close to the value you want (most of the time). It’s something about the IEEE representation, the mantissa and the exponent. Research on your own; it’s good for your learning.

Real numbers can have a precision stretching up to infinity. Obviously, our float and double have a bit of a problem with that. Actually this reminds me of a song I remembered from a children’s show (from way back when I was a child):

Thaaaaaaattt’ss iiiiinnnfinnnity
Yooouu can count forever
There’ll always be one more

That’s infinity
Count from dusk till dawn
You’ll never reach infinity
It’ll just go on, and on, and on, and on, and on…

You know, maybe I’ll sing and record it down… you know what? Maybe not. I’ll spare you the agony…

Ok, where was I? Oh yes, precision.

Games don’t need it

More precisely, precision usually isn’t an issue in games. floats and doubles are used in games for storing values such as the (x,y,z) positional coordinate of a player for instance. They don’t have to exact. They just have to be relatively close to the exact value. It’s not like you’re going to notice a 0.00000005 unit left shift, or you rotated like 0.000003 radians clockwise more than is required.

This is why floats are preferable to doubles in games (I might be dated on this…), because they’re faster to add and multiply to, and you don’t need the extra precision.

Financial applications depend on it

If you work with financial applications, it’s a whole new story. The Singapore and American currency use the dollar and cents. 100 cents equal a dollar. It’s typical to use $12.34 to represent 12 dollars and 34 cents (my apologies to the comma-toting Europeans). So the dollar is correct (and exact) up to 2 decimal places.

Does anyone see a problem with using floats on this?

Sure, the float is more than capable of displaying just 2 decimal places. But it cannot represent the smallest unit of currency 0.01 exactly. To illustrate this, try the following piece of code:

float f = 0f;
int i;
for (i = 0; i < 100; ++i)
{
    f += 0.01f;
    Console.WriteLine(f.ToString("f8"));
}

It's in C#, and you should be able to translate to C or some other language you use. Note the output. 0.01 is not 0.01 when stored in a floating point variable type.

This presents some exceedingly infuriating debugging sessions while figuring out why certain values don't work out correctly. It's also why you cannot do equality checks with floating point values (I mentioned this in my recent newsletter, and if you're not on it, please go sign up).

If you're using C# or some other modern language, there should be a variable type for fixed-point numbers (fixed number of digits after radix [or the decimal point]), the decimal type being the one for C#. Or the numeric data type in databases, but stay away from the money type. I don't know, I find it funny to store my monetary values in a money variable type. *shudder*

If you're using C or some other language without fixed-point number variable types, then my advice is to avoid calculation with floating points as much as possible. Do them in the environment where they are still exact.

For example, you want to retrieve some values from the database and bind them to local program variables. Then you're going to do some calculation with the variables, and update them back into the database. Can you do the calculation entirely in the database environment?

You might not have grasped the significance of the code above. Sure, the values are still exactly represented for most of the 100 decimal values. Imagine adding, subtracting, multiplying and dividing those values tens of times, hundreds of times. Ever heard of rounding errors? Errors don't disappear, they accumulate. If you're lucky, they cancel each other out. If not...

Here's a question for you. Even though it's a folly to represent the 2-decimal-point currency values with a floating point variable, there are values which a float can represent exactly. Given the range of non-negative 2-decimal-point values less than 1, what are the values that can be represented exactly?

I'll publish my answer and reasoning in another (later) article. I also want to hear your answers too. Add your answer in a comment. Explain your reasoning too. Frankly, I'd much rather publish your answers, and add in some of my comments.

Mind Trap – Strange Ruins

He blinked. Ryan could feel the light falling on his eyelids. His head still hurt, so he kept his eyes closed.

Birds were singing. “That’s a good sign,” he thought.

There was a whiff of musty damp earth. He clenched his hands, and clutched a handful of leaves. Ryan took a deep breath, and coughed. Blinking his eyes slowly open, he surveyed his surroundings. He was propped sitting up against a tree. Slivers of sunlight slipped through the leafy canopy above. This was definitely not the city.

Panic gripped Ryan and he scrambled up. He coughed again.

“Where am I?”

“You couldn’t find anyone else?”
“It has to be him.”

Trying to calm down, Ryan hazily recalled the events of the evening before. Something about a taxi and the driver turning around to face him and spraying something into his face.

He had to start moving. In the distance, he could see a massive stone structure. He started walking. There was a soft crackling to his right. He only caught a glimmer of bluish light before it faded together with the sound.

After what seemed like an eternity, he reached what appeared to be the entrance to some ruins. Aztec, or maybe Incan. It didn’t matter. It looked pretty run-down. There was a tall white totem pole on the left of the ruins. At an equal distance reflected to the right, an ebony statue stood in stark contrast to the surroundings.

And straight ahead in the centre, sat a curiously squarish structure. Ryan moved closer and saw 2 stairways set in the structure, leading downwards, like twin nostrils of a slumbering giant. Brushing aside the unpleasant feeling of venturing into the nasal stone passages, he noticed some carvings above the stairways.

51 82 68 87 65 89
66 69 72 73 78 68
83 84 65 84 85 69

Ryan was still thinking about which of the two uninviting routes he’s going to try when he looked at those carvings again. Smiling again, he chose his route.

What was Ryan’s choice?

The answer will be published in a comment here after a week (on 23 May). Or if some genius reader adds in a comment. Whichever is earlier.

[UPDATE: Christopher has already solved the puzzle. View answer.]

Continue the adventure…

Heaps of by-products

Do you maintain many programs? Do you maintain many programs, each producing an inordinate amount of log files, output files, intermediate files and database records? Do your programs create heaps of digital by-products?

Hansel and Gretel

Are you paranoid? No? Then stop spawning unnecessary log files and other output. I’ve seen a simple requirement being mangled into several programs, and each program absolutely must create a log file and an output file for the next program to consume as input. There were database tables to check for sequencing purposes, holding tables for data and tables to store the progress of the programs. All for one simple requirement.

The original programmer might have wanted to modularise the requirement. Fine. But an entire program to take the place of a function?

Perhaps the programmer designed it that way so it’s easy to debug and trace errors. Hence the copious littering of log files to keep track of where the program executed. Like Hansel and Gretel leaving breadcrumbs. Then why were the log files not containing enough useful information?

Stop creating digital waste by-products for the sake of creating them. If that intermediate step doesn’t require a log file, don’t write one “just in case”, or just so you can “keep track”.

Disk space may be getting cheaper, but that’s not the point. The next programmer have to wade through heaps of rubbish just to find out what went wrong. And that’s without looking at the source code.

Databases do more than store data

“But what if I need intermediate output files?” you ask.

For?

“The Unix shell script can sort data records in a text file.”

So can a database. That’s what the “order by” clause is for.

“I need to concatenate records from multiple files.”

So can a database. That’s what tables are for, inserting and storing data.

“I need to check for duplicates, and the duplicates can be stored in a text file and I can use shell scripts to sort and…”

So can a database! In fact, a database can probably do a better job than whatever crazy algorithm you can come up with. Primary keys can prevent duplicates. If you still want to store and keep track of the duplicate records, a simple “group by” clause can retrieve the duplicates easily.

People seem to forget that databases can be used to do more than just store data. You can perform a good many different operations in a database environment.

“But wouldn’t a C program run through a file and sum up a number in a certain column based on certain criteria be faster to execute on the Unix machine?”

Perhaps. I don’t understand why the concern over performance and memory management, and that Unix C programs and shell scripts are better than anything done on Windows (no this isn’t a *nix/Windows comparison/war), and better than anything done by a database engine. Use the right tools.

It’s hard to parse a text file. Yes, I know all about the magical grep and other commands of the Unix environment. And there are many text files, with little to help narrow down searches.

In the database environment, I can sort records, do simple math calculations, do complicated update statements involving several tables. I can pump all bad records to another table in a single statement. I can remove bad records from a table in a single statement.

And I can search records, even by a specific column. How do you do that with a normal input text file? Use the right tools. I seem to have said this before…

Landfills and the Delete button

Physical waste is traditionally buried in landfills. We’re starting to run out of land. Digital waste is handled by the ubiquitous Delete button. And we seem to have no shortage of disk space.

Do not abuse this freedom in treating “stuff”. Just because you can create stuff in the digital landscape doesn’t mean you have to create trash.

Podcast: Why programmers write stupid code

Need I tell you, again, how my first recording failed abysmally? Probably not. And here I am, doing another audio recording. Plus the fact that I got a new headset and I want to play with it.

To be honest, I learned a few things. I speak quite fast normally, and when my speech gets into recorded form, my words just slurred together. I just think faster than I can write or speak.

Be clear. That was main goal this time. So I spoke slower and slightly louder. I did some post production work and here it is:

Download mp3 [~ 2:40 minutes ~ 1.22 MB]

Noticed that I haven’t said anything about the subject at hand. Well, here’s a synopsis of the recording.

  • Murder on the Orient Express by Agatha Christie
  • Courting danger in racing simulations
  • Why programmers write stupid code

You’ll have to listen to the recording to find out how all 3 points fit together. For the impatient ones out there who just wants to know the final answer, here’s a hint: First word of first four paragraphs.