csanyk.com

video games, programming, the internet, and stuff

Managing complexity when implementing complex conditionals

Programming is in large part about managing complexity and imposing structure onto a problem domain in order to make it simple (simple enough for a machine to be able to do the solution).

Something struck me about a technique that I used when I was developing my game last weekend.

The code that handles the setup of the simulated atari 2600 console is full of conditionals:

if PowerPlug.is_plugged_in && (console.switch_power.position == POWER_ON) 
   && (TV.switch_power.position == POWER_ON) && Cartridge.is_plugged_in && 
   Joystick.is_plugged_in 
{
    //simulate the game 
}

So one thing that I had to deal with as I was building this was all the preliminary stuff, you know to create all the objects that needed to be checked in the conditional statement above. Rather than do that, all at once, and have a lot of conditions that could have bugs in them, any one of which could make the thing not work, and be hard to figure out since multiple bugs could end up canceling each other out, or mask one another in some way, I opted to simplify things at first:

if true
{
   //simulate the game
}

The advantage here is obvious. It’s simple, and you KNOW that conditional is always going to evaluate to true! So you can get right into working out the code inside the branch, without worrying for now about the conditional logic that would cause it to execute.

Once that was working, I added in stuff:

if PowerPlug.is_plugged_in
{
   //simulate the game
}
else
{
   if PowerPlug.was_plugged_in_previously
   {
     kill_game();
   }
}

Then from there it became easier to elaborate on the conditional:

if PowerPlug.is_plugged_in
{
   if Console.switch_power.position == POWER_ON
   {
      //simulate the game
   }
}
else
{
   if PowerPlug.was_plugged_in_previously
   {
      kill_game();
    }
}
 
//etc.

(Note, the above isn’t the exact code from my project, which is a bit messy at the moment as I have some refactoring to do, but it illustrates the point.)

I found that by coding it in this way, I could iterate and test each little piece of the logic easily, and make sure it was working before trying the next piece.

I found that doing it this way made it much, much easier to handle the complex nested if business, and as well I found it easier to know which branches of the complex conditional tree the next bit of code needed to belong in.

Now that I did it this way, it seems obvious, nothing of great insight… but 6 years ago I would have tried to code the whole thing out, and then pulled my hair out swearing at myself when it didn’t work as expected, and I had to untangle all the logic to figure out wtf it wasn’t working.

Back I would have thought then that a really superior version of me who I aspired to be would be able to code out all the conditions in one go without making a mistake. Today a really superior version of me knows better.

This is a good lesson to hang onto. And to pass on.

Of course, there’s also often ways to avoid having to code conditionals at all, but that’s a topic for another post.

Site changes

In the last few days, I’ve made a number of changes to this site. I wanted to explain them briefly.

Show »

Theme update

The site is now using a theme called Frontier, which replaces the Able theme that I’d been using for the last few years. The two are very similar in layout, but I think Frontier has superior typography and it is more configurable, and I think its responsive layout works a bit better on mobile devices.

Projects page replaces Releases

Releases felt like it needed some reorganization and dressing up. I’ve re-done the content, adding screen shots of the games that I’ve made, and updating the text descriptions. I’ve also moved the sidebar links to my GameMaker assets to the Releases page, and removed links to some of my older projects which by now are outdated and somewhat embarrassing because I’m a much better programmer now. If you really want to look at that stuff, the downloadable files are still available for now.

Graphic Design, Recommendations pages retired

In 2010 I took a class to learn Adobe Illustrator, and posted my homework there. It was intended that this would grow in time to become a full portfolio showing of my works. But then I ended up focusing more and more on programming. I hadn’t added anything to the Graphic Design page in years, and the content there felt stale for some time, so I’ve taken that page down. I may eventually get around to putting up a gallery page for my pixel art and other video game graphics.

I pulled the Recommendations page down because it wasn’t getting much traffic, and I haven’t maintained the content there as much as I thought I was going to.

Review: Lenovo ThinkPad P50

Back in March, I took ownership of a new Lenovo ThinkPad P50 laptop to replace my venerable and beloved T61p. I’ve had it almost 6 months now, so it’s been a good amount of time to become acquainted.

History

Originally purchased in 2007, my first T61p served me very well until last January, when the video card failed. I looked at the current ThinkPad lineup, and promptly went out and bought another T61p from a seller on eBay for around $250, and transferred my SSD to it. Over the years that I owned it, the T61p proved its value, with solid construction, great ergonomics, nice, roomy 1680×1050 screen resolution, and ease of service. Originally delivered with Windows Vista, I installed to WinXP Professional, and later upgraded to Windows 7 when it became available. I replaced a keyboard, upgraded the RAM from 4GB to 8GB, and replaced the HDD once, and then upgraded to an SSD a few years ago, when they got cheap enough. The second T61p had a faster CPU (2.4 GHz Core 2 Duo) and the beefier 256 MB Quadro GPU (up from 128 MB on my first) but was otherwise the same as my original 2.0 GHz workhorse.

The extra CPU speed definitely helped me get through the last year, and other than occasionally running out of memory due to RAM-hungry browsers and running with no swap file, the T61p still feels perfectly viable today as an everyday primary workstation. I’ve only had a few occasions in recent months where, possibly due to Windows 7 cruft, the machine has felt slow — occasionally I’ll get a svchost.exe process that uses up 100% CPU and makes the machine feel slow, but when that’s not happening, the machine has plenty of horsepower for web browsing, software development, graphic design work, and occasional gaming.

In looking for a replacement machine, my main concerns were not performance, but ergonomics.

I wanted a screen with at least the 1680×1050 resolution that I had come to realize was essential. I like to split the screen down the middle and have two windows open side by side, and 1680-wide gives me enough pixels to do that comfortably, while 1050 of height gives me enough lines of code on the screen that I can spend more time reading or typing, and less time scrolling through my project files.

I also had grown very attached to the T61p keyboard, with its near-perfect layout, and full-size scissor-switch keys, and the touchpad with physical buttons. Later generation ThinkPad machines had done away with physical buttons, changed from scissor switch keys to chiclet keys, and worst of all made senseless and wholly unnecessary changes to the keyboard layout, which I found completely unacceptable.

Even so, after almost 8 years on the same hardware, I did want the replacement laptop to feel like a true upgrade, and to have hardware that could feasibly hold up for as many years as I’d gotten from the mighty T61p.

In late 2015, I strongly considered purchasing a W540-series ThinkPad. I held off after seeing a W540 in person, when I saw that the touchpad itself was a clickable button, and there were no separate mouse buttons. Such a trackpad would be completely useless for precision clicking, and thus would require me to plug a mouse in to do any kind of precise work, which in turn would force me to sit at tables where I could use a mouse, and limit where I could easily do useful work comfortably. This would not do.

But then Lenovo released a minor refresh, W541S, which brought back the physical buttons, and looked like the best thing I’d seen from Lenovo in years. But this model was a bit lacking — where the full-size W540 could take 32 GB of RAM, the W541 was limited to just 16 GB — which, while adequate, didn’t feel as future proof as I would have liked.

I inquired with Lenovo customer service and was told a full-size W451 was coming soon, which would have the all-important physical touchpad buttons as well as capacity for 32 GB of RAM. I waited weeks and months, and asked again and was told that I had been misinformed, and that no such model was planned. I kept getting different stories from different reps, and got quite frustrated with not having solid information.

I briefly looked at the Dell XPS 15, which had fantastic specs — 4K IPS display, up to 32 GB of RAM, but again here I didn’t care for the buttonless touchpad.

Finally, in the second half of 2015 I started hearing about the new P-series ThinkPads, and became very interested in the P70. This system was a monster: up to 64 GB of RAM, 4K IPS display, the latest Intel Core i7 CPU, trackpad with physical buttons, and what looked to be an acceptable keyboard layout, though still not the return to perfection that I’d hoped for. I wasn’t crazy about lugging a 17″ laptop, but then a short time later I learned that they were also planning to offer a 15″ model, the P50. Comparing the specs between the two, it looked as though there really weren’t any compromises between the two, so at that point I was sold.

I waited and waited for the P50 to be released, but it kept being delayed. Eventually, in December they became available. As my second T61p was still going strong, I elected to hold off for a bit and wait to see what the initial reviews said. Then, last week, I received email informing me that Lenovo was having one of their EPP sales, which meant steep discounts. I clicked the link and specced out my dream machine: 3.7 GHz Xeon CPU, 4K IPS screen, 4 GB video card, a jaw-dropping 64 GB of RAM, and 512 GB SSD on a PCIe-NVMe bus, and after almost $1000 in discounts, it came to around $2200, which was well under budget for what I had originally put aside for the more expensive P70.

While that sounds like a lot of money for a laptop, I considered that I’d spent around $1900 for my T61p in 2007, and after using it for almost 8 years, that amortizes away to barely anything — less than $1/day. Considering how much I use the machine (regularly 8+ hours/day), and how productive it has made me, that’s an insanely good value. So when you think about it that way, it’s worth spending a lot of money to get something very good, as opposed to spend less and accept compromises, or have something lower end that won’t last as long whether due to durability or performance.

The Hardware

As purchased:

Battery 6cell 90Wh
System Unit P50 NVQ3 4G E3-1505M v5 vPro
Camera 720p HD 2D Camera Mic
AC Adapter and Power Cord 170W 2pin US
Processor Intel Xeon E3-1505M v5 MB
Color Sensor Color Sensor
Display 15.6 4K IPS Non-Touch
Fingerprint Fingerprint Reader
Graphic Card NVIDIA Quadro M2000M 4GB
Hard drive 1 512GB SSD PCIe-NVMe
HDD Config SSDx1
HDD Config 2 PCIe SSD
HDD Config 3 512GBSSD PCIe
HDD Total capacity 512GB
Keyboard Language KYB NumPad ENG
Publication Language PUB ENG
Total memory 64GB(16×4) DDR4 2133 SoDIMM
Pointing device 3+3BCP FPR CS
Preload Language W10P DG W7P64-ENG
Preload OS Win10 Pro64 DG Win7 Pro64
Preload Type Standard Image
Recovery Media W10P64 COUPON WW
Sub Series Variation P50 Quadro Workstation
TPM Setting Hardware dTPM Enabled
Display Panel P50 4K NT 2D MC CS WLWW
Selectable Warranty 1 Year Depot or Carry-in
WiFi wireless LAN adapters Intel 8260AC+BT 2×2 vPro

Price as purchased (incl tax and shipping): $2,271.02

I elected not to go with ECC RAM, which would have added about $450 to the cost, and the P50 doesn’t have a bay for an optical drive, so no DVD option unless I want to plug in an external. I haven’t burned, or even read, a DVD in years, though, so I think optical media is pretty close to obsolete.

Curiously, Lenovo do not offer a Blu-Ray drive option for their laptops that do offer an optical drive bay. The ultra-bay adapter for hot swappable hard drives is a nice option to have, but considering the P50 has an internal bay for a 2.5″ SATA device, and 2 PCIe NVMe slots, it wasn’t worth it to me to go to a P70, for almost $2000 more, just to get a DVD-RW/Ultrabay (although that $2000 would have also brought with it 8 GB video card).

Lenovo also just came out with a few more models in the P-series: the P40 Yoga, and P50S. I didn’t consider either of these as I was already eager to buy the P50 that I had selected, but after looking at their specs I have no regrets about picking the P50. The Yoga offers a more flexible screen hinge that allows for using the laptop in different configurations, but with less top-end specs, and the P50S is just a slimmer P50 with slightly less capability, and so I wasn’t really interested in either.

Initial impressions

Pros:

  • 64 GB of RAM! This is 8x the RAM of my old T61p (and 16x the advertised max RAM of the T61p). Knock on wood, but I may never run out of RAM ever again with this machine. 64GB ought to be enough for anybody;-)
  • PCIe NVMe performance. The SSD is very, very fast. I’ve been using SSD for a few years now. The T61p originally came with a spinning hard drive, but I upgraded from a 7200rpm hard drive to SSD after they became available at a price point I was willing to pay. I did notice some performance improvement, but the SATA3 SSD was bottlenecked by the SATA2 interface in the T61p, so I didn’t get the full benefit of the upgrade. By contrast, with the ThinkPad P50, read/write speeds on the PCIe NVMe SSD are amazing. After running Windows Update for the first time on the P50 and installing almost 90 updates, after rebooting the “configuring” that Windows 7 does after upgrades are installed, which normally takes several minutes, were completed in about 20-30 seconds. Waking out of hibernation is nearly instantaneous.
  • 4K IPS is a thing of beauty. The screen is exceptionally clean and sharp, with vibrant color even for an LCD screen. The LED backlight is very even, compared to the florescent tube backlight of older screens. IPS is definitely a much better display technology compared to TFT. I’ve had IPS displays on my desktop, but since I use my laptop much more, I haven’t really been able to appreciate it until now.
  • Speakers are much improved over T61p. One of the complaints I remember from reading reviews of the T61p was that its speakers weren’t very loud even at max volume. I didn’t find this to be a major complaint, and most of the time audio levels were adequate, but I did frequently find it difficult to hear the audio track in multimedia being played on the machine. It just depended on how loud the source was. With the P50, the speakers are much more capable.

Cons:

  • Trust. The most important con to buying Lenovo these days is trusting them not to pre-install malware and rootkits. Lenovo have been found to do this three times in the last year, which for many is unacceptable. Fortunately, I did not find anything pre-installed on my P50 that I needed to remove. It seems that Lenovo responded to being found out and did the right thing in removing the offending software. It should never have been there to begin with, but at least they had removed it from their newly shipping products by the time I ordered mine.
    • Superfish, the SSL-circumventing private http destroyer, was not found on my machine.
    • I did need to disable “Lenovo Customer Feedback Program 64” using TaskSchedulerView.
    • Lenovo have released BIOS updates that omit the OneKey Optimizer malware that they once preloaded on ThinkPads. I wasn’t able to find information as to whether this was ever included in the BIOS for the P50 model; it’s possible it never was, as this model is more recent than the date Lenovo removed it from machines that had it.
  • Other Software I didn’t want
    • McAfee LiveSafe. I didn’t order this, but I had a subscription to it out of the box. I haven’t ever liked McAffee antivirus, since the late 1990’s I’ve been recommending against it.
    • Microsoft Office. Microsoft are really hard-selling their Office suite. It was something added to my build list by default, and I had to remove it. I got a reminder at check out asking me if I was sure I really didn’t want it. I debated it for a few minutes, but ultimately I don’t use Office very much anymore, and really prefer Google Docs for most everything, for many reasons. Still, I have something pre-installed — not sure if it’s Office 365 or 2016. Either way, it’s not getting used, and will be removed. I might install a viewer app so I can handle .doc files that people might send me, or I might install an old license of Office 2007 that is still perfectly fine, but I’m not sure I’ll even need to do that.
    • Windows 10 nagware: This isn’t Lenovo’s fault by any means, but Microsoft is also really hard-selling Windows 10. They want the world to upgrade from Windows 7. I don’t ever plan to. Microsoft’s treatment of user’s private data is completely disrespectful, and unacceptable. And I’m not interested in re-learning how to use and manage the new version. I haven’t ever touched Win8, even. And they keep trying to push Windows Updates on Win7 users which keep trying to push an upgrade to Windows 10. At this point, the only thing that’s keeping me tied to Windows is GameMaker: Studio, and if it weren’t for that I’d be happily running on some Linux distro, most likely Ubuntu. I’m hoping that sometime during the lifetime of this hardware, I’ll be able to make the switch and dump Microsoft for good.
  • 4K resolution problems – TL;DR solution: 2048 x 1152

    It turns out that displaying 4K resolution on a 15.4″ display results in very, very, very tiny fonts. Windows 7 does not handle this well at all. I almost returned the machine for an exchange to a 1920×1080 screen, but after playing with settings for a few days, there are a few workarounds, which I find acceptable, but none of which are perfect:

    1. Set font dpi to 200% or better. The control panel only shows options for 100%, 125%, and 150% at first, but you can set a “custom” dpi using a link at the right. The slider control for this tops out at 200%, but you can override this by typing in the value. I found that 250-300% was about where 12pt text started to get readable to me, but it’s still pretty small, and 10pt and lower is still ridiculously tiny. Unfortunately, this amount of magnification starts to break the containers that Windows puts text into, resulting in an ugly, disjointed Explorer GUI, and probably most applications as well.
    2. Use Windows Classic theme and size the text manually. I created a custom theme for this, so you don’t have to. Download Win7_4K and apply it. I basically doubled the size of all the font settings in the theme. Unfortunately, not everything in Windows uses the Theme settings, particularly older software or software developed by amateurs. But even Windows itself doesn’t make all of its font sizes customizable through this interface, even in Explorer windows there will still be some fonts that are ridiculously small. What terrible design. Microsoft should be embarrassed.
    3. Set display resolution to 2048 x 1152. OK, so native display resolution just doesn’t work well in this size display, at least the way Windows renders its GUI. The only other option is to set display resolution to a lower size. Both 2048×1152 and 1920×1080 look great, and other than not having the full resolution at your disposal, there’s not much of a downside.

Keyboard, mousepad

The P50 uses chiclet key switches, not scissor switches, but that’s acceptable. The basic keyboard layout is acceptable, although I still vastly prefer the T61p’s keyboard for many reasons.

The 10-key pad on the right side shifts the main keyboard left of center of the screen, which makes it a bit less comfortable to use, and the navigational keys aren’t as easy to find without taking my eyes off the screen to look for them. If I turn off numlock, though, it makes the 10-keys into Home, End, and arrow keys, which I like. I leave it off most of the time, unless I’m actually keying in a lot of numbers, and then I find it handy.

However, a huge negative with this keyboard is its rollover. If N-key rollover isn’t possible for technical reasons, I feel that at this price point a minimum of 6KRO should be expected. I can’t play games that use the keyboard for controls, because after just 2 buttons held down, a third key press is not reliably detected and reported to the OS. As a gamer and game developer, this matters, and is a huge, huge disappointment. If I gave laptop reviews a star rating, I’d penalize the P50 an entire star just for this issue. Maybe two stars. The built-in keyboard is that important to me.

The mousepad is off-center from the screen, but centered under the spacebar. It’s large enough that my palms will accidentally bump it occasionally, and this can be annoying, but it’s not a severe problem. I think I would like a slightly smaller mousepad, all the same.

The return of the physical buttons (three of them!) above and below the mousepad is what I like the most. It’s great to have physical buttons back in this generation of Thinkpad. The lack of them was why I refused to buy a W540 last year,. when I first considered replacing the T61p.

I still miss the “previous page” and “next page” keys from the T61p keyboard, located at the left and right of the Up Arrow key. On the P50, these have been replaced by Page Up and Page Down, which I definitely use a lot more frequently. But I do miss that Page Up and Page Down are no longer near Home/End. I also find that the cursor navigation keys are a bit harder to find by touch than they were on the T61p, where there they are at corners and edges, which made finding them very easy, even in the dark. On the P50, they’re to the right of the Right Ctrl key, but to the left of the 10key pad. If the machine didn’t have a 10key pad, and the layout was more like the T61p keyboard overall, and it had NKRO, I’d be completely in love. As it is, the keyboard is mostly decent, with the exception that it completely sucks for gaming.

BIOS tweaks

Looking in the UEFI BIOS, there’s a couple of nice configurable settings. Foremost, Lenovo have enabled the user to decide to switch the Fn and left Ctrl key. This was a popular 3rd party hack for the T61p BIOS, but I never bothered with it because I didn’t want to risk running an unofficial BIOS. Now that it’s an officially supported option, I’m happy to have Ctrl in the standard location where it belongs, even if the keycaps aren’t identically shaped so I can’t switch them physically.

Also, there’s a BIOS setting to change the top row of keys from being special functions or F-keys. By default, if you press the top row keys, they’ll do things like adjust volume or dim the screen. If you’re used to using the F-keys for shortcuts, Alt+F4 closes windows, and F5 is browser refresh — I use that all the time. For me, it’s essential to switch this in BIOS. I could also do it by hitting Fn+Esc, which sets the Function lock on, but then the Fn lock LED is lit all the time, and I’d rather not have it lit all the time, just to save what little bit of battery drain it might use if for no other reason.

I didn’t find a default Numlock state setting in the BIOS, but I’d like the numlock to be disabled, so I can use the 10-key pad for its alternative function of navigating by cursor. Keeping the 10-key pad in this mode makes the keyboard layout slightly less annoying, since Home, End, Page Up, and Page Down, and another set of Arrow keys are all available through the 10-key keys. It’s just a single keystroke to toggle the numlock, but it’d be nice if it was always off after a reboot. Fortunately I don’t need to deal with this much, as I don’t reboot very often.

Warranty Service

In August, I had to send my P50 back to Lenovo for warranty service, after a column of pixels got stuck on.

P50 4K IPS screen with a column of stuck pixels

At 5 months, a column of pixels got stuck “on”. Lenovo fixed the issue under warranty, and the machine was out of my hands for a little over 48 hours. Very impressed.

Overall the experience was great, but contacting the right folks at Lenovo and getting a clear connection was not as easy as it should have been. After a few attempts I finally got a hold of the right department, they asked me some rudimentary troubleshooting questions, and once they understood the problem I was describing, they issued me a support ticket number and explained the process for the warranty repair.

The next day, a return shipping box was at my door. I removed my SSD, not wanting to risk that data being lost or falling into the wrong hands, packaged the laptop up and sent it in to them on a Wednesday, and it was returned to me Friday morning. Lenovo considers the SSD to be a “Customer Replaceable Unit” so there was no problem for me to do this, and it did not void my warranty. This made me very happy.

Considering they had told me to expect it to be gone 7 days, I was very happy with the turnaround time. I don’t know what the problem was with the screen, but I suspect that it may have just been that the video cable needed to be reseated. They did not replace the screen, but the problem is gone.

Overall Recommendation

This is a very high end midsize laptop with a ton of value and great features. Performance is outstanding, and the warranty support is even better. It’s pricey compared to lower end machines, but if you need a high end laptop, this is a very good one.

If it lasts me as long as my T61p did, it will have been well worth it. My T61p lasted me an incredible 8 years, and while I don’t think anyone expects that from a laptop (most are replaced in 2-4 years, typically) if I get 7 years out of the P50, that works out to less than a dollar per day. When you think about it that way, suddenly spending over $2.2k on a laptop seems very reasonable.

My only complaint with it is the keyboard. The keyboard is very good compared to most current laptops, but unfortunately it has terrible key rollover characteristics that make it a dud as a gaming machine. The keyboard layout may not be everything I wanted, but considering what we saw Lenovo putting on ThinkPads between the T6x generation and now, it’s nearly a return to their old form, and close enough to what I wanted that I can live with it, although I absolutely want Lenovo to deliver an NKRO keyboard with their next hardware revision.

Some users might feel that the lack of an optical drive/ultrabay is a disadvantage, and to them I would point them toward the ThinkPad P70.

The Dell XPS 13 and XPS 15 are also worth looking at in this performance class. But I think the P50 likely edges them out in most respects, but especially on the mousepad and keyboard. If you would prefer to avoid Lenovo for now due to the trust issues mentioned above, or other reasons, they might be more for you.

I haven’t tried out Linux on this machine yet, so I have no remarks as to it’s compatibility and stability with a Linux distro running on it.

YoYoGames discontinues sales of GameMaker for Mac

YoYoGames announced yesterday that they have discontinued sales of GameMaker for Mac (the GM7-based IDE for Mac OS X, not the build target module for GameMaker: Studio to allow building games for Mac OS X).

I don’t expect that this move surprises or disappoints many. This version was long out of date and did not include features from the 8.x and Studio 1.x sequences of the product, and had languished while YYG focused its resources on the success of GameMaker: Studio.

YoYoGames stressed that users who already own GameMaker for Mac are still supported and can install and use the product that they already own. YoYo say that they are still committed to supporting development on the OS X platform with a future release of GameMaker: Studio, but the expected release date for this is as yet unannounced.

One would hope that with the ending of sales for the old version, the replacement product might be coming soon.

It’s good to see YoYo communicating its intent with the product like this. The announcement was clear, addressed possible misconceptions, and came through an official outlet.

GameMaker EULA restricts developer creativity

[Editor’s Note: After a busy year or so of low posting frequency, during which I started but never completed many articles, I’ve been going through my old drafts, working to complete old articles that still hold relevance. So this is an old topic, though not out of date, which I started writing in May of 2015, and I don’t mean to stir up new debate over it, but it’s worth being aware of.]

YoYoGames has restrictions in the EULA for GameMaker which states in essence that users agree to allow YoYo the authority to determine whether a game produced by the user is in line with their moral standards, and the right to terminate your license if they wish should you produce something they deem objectionable, without explicitly spelling out what counts as objectionable.

An April 2015 discussion on the old GameMaker Community forums raised this issue, but is now hidden due to the closure of the Suggestion Box subforum, but still available through the Internet Archive’s Wayback machine.

To summarize the discussion, YYG don’t seem to be actively policing their policy, nor are they specific in explaining their standards for acceptable content in games. They seem to be treating the EULA clause as something they can invoke if they so choose, but not actively evaluating published games to ensure they don’t violate it. And currently they seem to be pretty lenient about what they deem acceptable — for example, they deem Hotline Miami to be clear of violating their standards. Accordingly, I don’t read YYG as bad actors here.

But this does give rise to what one would have to do in order to cross the line with respect to YoYo’s standards, and why have them in the first place. It seems the answer to the latter question is to allow YYG the contractual authority to nix a license more or less arbitrarily, in order to make clear that they do not have any relationship with a developer who they deem too offensive. Which is to say that if a game produced with GameMaker were developed and it generated negative publicity for YoYo, that’s probably ultimately what their standards boil down to.

YoYoGames motivation seems to be that they (understandably) do not wish to be associated in any way with a game that someone else develops, if that game is “deeply offensive” (whatever that means — it varies from person to person what offends them). Considering that many games these days address topics which many might find “controversial”, and thus may be offended by, it gives a developer pause. And even those games that are not exactly controversial routinely depict subject matter which upon a moment’s reflection make us wonder why they’re not considered offensive. A huge proportion of videogames depict violence in a casual, matter of fact, even joyous manner. But most games would be instantly get a Mature Audiences rating if they depicted nudity, even if the context isn’t sexual.

It’s tough to say what the guidelines are for producing a game that is free of these concerns, and YoYo weren’t very interested in stating their guidelines explicitly. “Use common sense” seems to be their question-begging non-answer. Common sense falls down in controversial cases precisely because they are controversial. There’s undoubtedly a whole classification of things that are offensive to marms and nuns but that teenage boys think is fine, but the only answer that matters in this case is, “is what’s considered offensive by YYG?” Debating “what is too offensive?” is an endless quagmire but “What does YYG consider too offensive?” is something that can have a start and an end to it, and is probably a succinct bulleted list, which people may be free to disagree with or not as they choose, but still helpless to change.

I surmise that there are things that are commonly topics addressed by the medium of videogames, such as violence and war and crime that are not included in the “truly offensive” category, but that a game could step over the line by being too explicit in its depictions of these things, or by appearing to advocate for doing these things in real life, or by appealing to the player’s “prurient interests” in such depictions. The “common sense” approach seems to be a way for YoYo to say, “We don’t want to say because it’d probably just give horrible people a to-do list, but if everyone could avoid things such as explicit torture, rape, and so on, that’d be great.”

Still, the fact that someone else can tell me what I can or can’t put into a game that I’ve designed, is inherently offensive to me. I think it unlikely that I’d produce something that would cause YoYo to take notice and strip me of my license, but the fact that they can, and that they think that it’s right for them to have such power, is offensive to me. To me, there is a boundary where their responsibility ends and my responsibility takes over, and I should be responsible for my creations; once the tool they’ve produced is in my hands I don’t need their sense of responsibility for their creations to encroach upon my creativity.

It’s tough to see why YoYoGames would be associated with a game that was developed by someone else, even if they happened to use GameMaker. One reason might be their logo is used as the default splash screen and application icon when a game is built with GameMaker. These are removable by the developer, but are often left as-is by amateur developers. But there, a simpler remedy would be to compel game developers to remove YYG logos from games that they do not wish to be associated with at their request. Or, if YYG wanted to, they could ban games that they deem unfit from being sold or otherwise distributed through their online store, while not taking away the developer’s liberty to release the game through other means, or to continue using GameMaker to develop other games.

YoYo declined to change the policy, taking a “take it or leave it” attitude, and then closed the forum topic to quash further discussion. It seems to be the YoYo forums general policy to kill topics when moderators deem that further discussion is “pointless” since they are firm about not changing their minds. Obviously that’s not the case, as there may be much to discuss whether or not YoYo change their minds, and getting YoYo to change their minds is not always the aim of discussing some topic on the forums. Really, it’s about stopping discussions that may lead to users expressing views deemed critical or negative to YoYoGames, which they (wrongly, in my opinion) feel is harmful or threatens their brand.

Which, since it’s their forum, that’s their prerogative, but I can’t say that I like or agree with the practice. And now that they’ve restricted access to that particular forum, the topic is no longer visible. And this is one of the reasons why I have my own website where I can exercise my right to free speech without censorship.

Appreciating MegaMania

Megamania, published in 1982 by Activision for the Atari VCS and designed and programmed by Steve Cartwright, is one of the all time great video games, and is a standout on the Atari 2600 console and in the vertical fixed shooter genre. Inspired by the Sega arcade game Astro Blaster, but vastly better, it is an extremely well refined shooter for its time, and is a fun and challenging game to this day.

Above: Astro Blaster, an 1981 arcade game by Sega that bears some resemblance to Activision’s 1982 hit on the Atari VCS, Megamania.

Astro Blaster had many features, including digitized speech, that made it technically impressive for its day, but the design did not integrate the features particularly well, making the game overly complicated and clunky. By comparison, Megamania offers a stripped down, almost poetic experience, with elegant symmetry and proportions. Far from a ripoff of an original game, if anything it’s a refinement. Megamania expresses its beauty through minimalism and an elegant orderliness to its structure. This game is all about action and motion, and the original version just gets these things right. There is a rhythm to the game that a good player will develop a feel for, and learn to use to his advantage.

A major hit for Activision on the 2600, Megamania was later ported to the Atari 5200, and Atari 8-bit computer line, but the original remains the best play experience despite modest graphical improvements in the later releases. I’ll be discussing the original VCS version of the game for the rest of this article.

Here’s how Megamania looked on the Atari 2600:

Due to the hardware limitations of the 2600, the player is permitted only one shot on the screen at a time. The player can steer the shot with their ship as it travels upward, giving them the ability to guide their missile into the target. Somehow, despite their varied and erratic motion, the enemies often seem to line up just right so that if you’re in the right position and have the right timing, your next shot will rapidly find your next target, enabling you to clear the wave quickly and resulting in great satisfaction. But if you’re off target, the same proportions of speed and distance that line up your shots on target will cause you to miss frustratingly. It’s an elegant symmetry that provides both challenge (when the player’s timing is off) and reward (when it is on) with the same few, simple mathematical relationships, giving the game a subtle beauty.

The object in Megamania is to survive wave after wave of zany household objects that come at you from the top of the screen, as you shoot up at them for points. Your ship has an energy meter that slowly winds down, providing a time limit to complete the wave; when you complete a wave, your remaining energy meter is converted to bonus points, then refills, and the next wave begins. The waves repeat in cycles, in the following order: Hamburgers, Cookies, Bugs, Radial Tires, Diamonds, Steam Irons, Bow Ties, and Dice.

megamania enemies

There are two variations in the play mechanics, having to do with the way your shots behave:

  • In variation 1, the ship will fire continuously as long as the fire button is held down, and the shots are steerable, moving in line with the player as the player moves. This generates the rhythm that makes the game so fun, as I will show with some detailed explanation to follow.
  • In variation 2, the player must press the fire button each time to fire a shot, and the shot moves vertically only; once it leaves the gun it cannot be guided by the player.

Variation 2 requires more hand-eye coordination and greater attention from the player, and is therefore much more challenging, but I find that the feel of the game is not nearly as immersive as when you are able to steer your shots. In variation one, you feel at one with both your ship and its missile, and while you steer your shots to hit your target, you must simultaneously dodge to keep your ship safe. This creates an inherent conflict that causes the player to constantly be making decisions at a subconscious level. In variation 2, once your shot is launched, you have no further influence over it, and can only watch until it hits something or leaves the screen, leaving you only to avoid enemies and their fire until you can fire again yourself. And since there is no auto-fire in variation 2, the subtly clever timing that results from the relationship between the distance and position of the enemies, their speed, and the speed of your missile, is lost.

The sound effects, while rudimentary, are strong, and fill the game with noise from start to finish, despite being limited to your laser shot, enemy destruction, the energy meter countdown and refresh, and player death. The enemies, rather than explode, disappear with a brassy, synthesized “clang!” , while you fizzle away into nothingness when you are hit by a missile or collide with an enemy. The effects are blaring, loud and harsh, but with the volume turned down low they serve well.

The wave cycle in Megamania is particularly well paced, with a fantastic challenge curve, and a structure that reminds me of a sonnet or a fugue. Certain waves (metaphorically) “rhyme” with others, being similar in their motion patterns. Patterns established in earlier waves are elaborated upon in subsequent “rhyming” waves.

The odd-numbered waves (Hamburgers, Bugs, Diamonds, and Bow Ties) all move horizontally from left to right across the screen. In the first cycle, their motion is constant, while in the second and subsequent waves, their motion pauses periodically for a few seconds, then suddenly accelerates before settling down to normal, and then repeats. Starting with the Bugs wave, the horizontal scrolling waves add a vertical undulation to their motion, which becomes more pronounced with Diamonds and Bow Ties. Diamonds and Bow Ties “rhyme” further with each other by having a “winking” or “spinning” appearance. These are the easiest waves to clear, as the enemies pose no collision risk to the player, who can only be destroyed by enemy shots or running out of energy in these levels. As the first, third, fifth, and seventh levels in the wave cycle, they provide a breather between the more challenging waves. Each odd-numbered wave may be seen as an elaboration of the previous in the series: Hamburgers move horizontally; bugs move horizontally, and with a slight undulating vertical dip; diamonds move horizontally, have a more pronounced dip, and spin; and bow ties move horizontally, have the most dramatic undulation, and spin.

The even numbered waves all feature objects that pass vertically through the screen.

Wave 2, cookies, introduces the player to vertical motion gradually, as the cookies move primarily horizontally, while doing a two-step drop periodically, and reverse their horizontal motion as well. Cookies move in unison, all moving left or all moving right at the same time. Wave 4, radial tires, kinetically “rhymes” with cookies, but the radial tires dip more quickly, and the wave introduces a more complex motion where alternating rows of tires move left or right simultaneously. These levels are particularly dangerous, as in later cycles they descend increasingly rapidly, but a skilled player will learn, after the panic subsides, to make small, economical moves, and let the shots line up and rapidly take out strings of enemies quickly. At this point the levels remain challenging, but reliably beatable by a skilled player. You’ll die quickly if you get out of rhythm and fail to clear out enough enemies to give you adequate space to dodge, or if the computer gets lucky with one of its shots, but if you’re on your toes and in the zone you should be able to clear these waves with only an occasional death.

The next two even-numbered waves are of special difficulty, although their unique patterns do not “rhyme” with each other.

Wave 6, Steam Irons, uses a deceptive and tricky pattern. Three columns of steam irons descend, pausing and then sweeping irregularly from side to size at a speed that is very difficult for the player to track, as they seem to deftly weave right around your shots, and then descend again. The spacing of the formation is such that the player must shoot out at least one from each column, or else that column becomes an unbreakable chain when the column reaches bottom and wraps around to the top again, providing insufficient space between the rows to allow the player to squeeze in and get a shot off. If the player fails to take out at least one steam iron from each column, it is guaranteed that he will die at least once before completing the wave. The interesting thing about wave six is that it is the one wave in the entire game where the behavior pattern never varies, no matter how many times the player cycles through the game, the steam irons always move the same. Despite the lack of increasing challenge, the behavior is so frustrating and erratic that players often ascribe a sinister artificial intelligence to the steam irons. They are a constant threat to the player, no matter their skill level.

Wave 8, Dice, are special in that they are the only wave that is always the same color, yellow, no matter how many cycles the player completes. Dice are also unique in that they are the only objects that do not fire any shots at the player, and are therefore dangerous only due to collisions. Yet this is more than enough to make dice the most challenging wave to survive. The first dice wave is also the only level in the game where the objects move straight down. While their speed in the first cycle may seem overwhelming, their simple vertical motion makes it a fairly safe level. Simply stand your ground beneath a falling pair of dice and shoot, and your shot will surely find its mark, protecting you. But in the second and subsequent cycles, the dice move horizontally as well, in rows that alternate left and right, and create an almost bullet hell-ish level where dodging takes a great deal of finesse. The player has to move constantly on the dice levels to avoid fatal collisions, making it the most strenuous and challenging level, a climactic finish to the wave cycle. A skilled player can still beat the level without getting hit, but it requires great concentration and timing.

If we think of the eight waves that make up the wave cycle as a stanza in a poem, then the “rhyme scheme” suggested by the structure of the eight waves is as follows: A, B, A, B, A, C, A, D. The difficulty curve of a cycle is interesting, in that it does not simply progress in a linear fashion, but instead plots two different curves: the odd-numbered waves follow a more linear progression, while the even-numbered waves follow a steeper progression. This gives the challenge curve a continually escalating trend line while still affording the player a “breather” between two more difficult levels.

megamania difficulty curve

After three or four cycles, the difficulty does not ramp up further, and the game turns into an endurance match to see how many cycles the player can endure. If you can make it to 999,999 points, the game ends, effectively a killscreen.

One of the more interesting things to realize about the mechanics of Megamania is that (with the exception of the first Dice wave) the horizontal speed of all the enemies in the game matches the player’s horizontal speed. After the first cycle in the odd-numbered waves when the enemies accelerate to double time. The rest of the time, the horizontal speed of the enemy objects always matches the player’s horizontal speed exactly. This, combined with the shot-steering in variation 1 makes tracking the enemy objects easier, since you, your shot, and the enemy all move at the same speed, it is trivial to line up and guide the shot into the enemy on the odd-numbered waves. It also means that if you are behind an enemy, there is no way to catch up. Interestingly, players often don’t realize this, and novices and even moderately experienced players will persist in trying, to no avail, to catch up with an enemy that is just past the reach of their fire. Once you realize that it is impossible to catch up, and stop chasing, the player gains an insight that will lead them to higher skill levels — it is very common for a player chasing an enemy that they cannot possibly hit to accidentally run into an enemy missile, or run out of room at the edge of the screen and get pinned. But once you learn to avoid these two common causes of death, you become better at dodging, and the game opens up and becomes easier.

Another important realization is that the positioning of the enemies often is such that when you connect with a shot to destroy one, your very next shot will also connect with another enemy if you don’t move. It’s very common to chain together “string” of two, three or even more hits in a row, in very rapid sequence. This is key to success, and especially critical on the later cycles on the even-numbered waves, where the falling enemies present a collision danger, and taking a chain of them out immediately when the wave begins is crucial to carving out enough space to enable you to dodge and survive. When you realize this, the game becomes less about chasing aggressively and aiming, and more about being in the right position, and letting the enemies come to you. This is where the auto fire feature of variation 1 comes in to play, as once you have connected with a target, you are likely to hit again with your very next shot, and may start a chain of hits just by holding position and keeping the fire button pressed.

A final note of strategy helps with avoiding being shot by enemy missiles. Only two enemy missiles are capable being on the screen at any given point in time. What’s more, there are only two enemies at any given time who are capable of firing. If you see an enemy shooting bullets, you should avoid it and concentrate on eliminating the enemies that are not shooting, as they are less of a thread and easier to safely destroy. Don’t go under them when they stop moving, and wait for them to move again before tracking them. Then, take out the shooting enemies when they are moving, by matching pace with them. Enemy shots do not steer, so if you move in sync directly below a horizontally-moving enemy that enemy cannot hit you, and you cannot miss them. The most dangerous time in the odd-numbered stages is when are moving against their motion, from right to left, since this is the only time when you are likely to hit an enemy missiles.

Wrapping a formation of enemies

Another point of refinement that I find interesting is in the way the enemy objects wrap around the edge of the screen. Enemies in Megamania move together in large formations, but the way they wrap around the edge of the screen is interesting.

What I find innovative in this is that it doesn’t matter how large the formation is — looking at the odd-numbered waves, if you don’t shoot any of the enemies, they will form an unbroken chain as the first to appear wrap immediately behind the last. If you shoot a few, leaving holes in the formation, the holes persist and are not closed up — except if you shrink the formation at the leading or trailing edge. When that happens, the formation wraps sooner, closing the gap between the last still-extant enemy in the formation and the first. Thus, when the last Hamburger, Bug, Diamond, or Bow Tie is left in the wave, when it reaches the right edge of the screen, it wraps immediately to the left, rather than waiting for the space taken up by the no-longer-existing members of its formation. This is important because it avoids wasting the player’s time, as the energy meter winds down while no enemies are visible on the screen.

The tight, precise nature of the motion of the enemies makes Megamania a satisfying and exciting play experience, and feels complete despite a relatively small feature set. Megamania demonstrate that refinement and polish matter far more than feature count.

KB Tester utility helps you see what value to check for when a key is pressed.

KBTester is a utility/demo I made to help out with coding your keyboard_check routines. It is born out of frustration and necessity for handling certain inputs from a very fundamental input device for computer games, the standard keyboard, which are not supported out of the box.

If you program keyboard input in your games, you’ll find that, for most keys on a computer’s keyboard, you can use vk_constants and ord(letter)… but for some odd reason YYG didn’t create a vk_constant for every key on the keyboard, and don’t plan to. Not only that, but there are certain keys that don’t return the right value for ord() to work with keyboard_check.

For example, say you want to check if the period key is pressed. You might think that you can do keyboard_check(vk_period) but to your surprise, there is no vk_period constant defined in GML. So, then it must be that you need to do keyboard_check(ord(“.”)) only… it doesn’t work!

That’s because ord(“.”) returns a value of 46. But for some reason, if you want keboard_check() to return true when the period key is pressed, you need to check for the value 190. Why? Why are certain keys on the standard keyboard treated as second-class citizens? Because, sadly it’s not in YYG’s vision to improve keyboard support.

To paraphrase a certain “Evil YoYo Games Employee” who commented on my suggestions for ways the current keyboard support badly needs to be improved:

<paraphrase>Why should we improve keyboard support when you can just research what codes map to your keyboard keys, make an extension that has a few constants in it, and then hope that these will work with all keyboards and all target platforms? Just code it once and then put it up on the Marketplace. Now that the marketplace exists to provide stopgap coverage of GM:S shortcomings, we don’t have to pay our own programmers to fix those holes anymore.</paraphrase>

So, I guess we’re supposed to figure out the numbers and then code some constants for the missing vk_constants, and use those. This, despite the helpfile recommending against using hardcoded numeric values in keyboard_check because you never know if it’ll work on the target platform if it’s not Windows/Mac/Ubuntu:

NOTE: These functions are designed for Windows/Mac/Ubuntu desktop platforms only. You may find some of the in-built variables and constants aren’t valid on other platforms and many of the functions won’t work on mobiles.
Now, each key is normally defined by a number, called the ascii code, and you can directly input this number into these functions and they will work fine… But, as it’s a bit difficult to remember so many numbers and the relationship that they have with your keyboard, GameMaker: Studio has a series of constants for the most used keyboard special keys and a special function ord() to return the number from ordinary typed characters (either letters or numbers).

The implication is that, YYG seem to be saying, “Despite the promise of GM:S to be a development environment that supports multiple target platforms, we didn’t see the need to ensure that your code will run the same on all target platforms we support, or all region/localities, or with all keyboard layouts. After looking into it we decided it was too hard for us to deal with, so we’re passing it along to you to figure out for yourself. So just be aware that these may or may not work on all platforms, and that’s all the info we’re going to give you about that. You’re on your own to figure out how to solve keyboard input from any platforms that don’t work with our keyboard input functions.”

Well, for whatever reason, YYG doesn’t provide FULL keyboard coverage between ord() and vk_constants, and it’s not in their vision to address this shortcoming, so I guess you’re going to have to go out and find some reference that will tell you what numbers represent what key, and then hope they still work.

In the meantime, you can use KBTester, press a key, and get the answer without having to hunt the info down on the internet and hope it’s correct. If you’re having trouble getting keyboard_check to work, and need to verify that the magic number you’re using is indeed the right one, you can run KBTester. Press the key you want to use, and KBTester will tell you the value that GameMaker sees when it is pressed.

Recipe: really good very cute boyfriend stir fry

When I’m cooking at home, I like to do stir fry dishes in my wok. Recently I have been doing this, and have been finding that I have been feeling extra-well, and more energized on days after I have the following for dinner.

So maybe it’ll help you too. It is easy to make, reheats well, and you end up with an amount of food that you can turn into about four or five good meals.

really good very cute boyfriend stir fry

Ingredients:

  • rice
  • tofu
  • broccoli crowns
  • white onion
  • green onion
  • canned water chestnuts
  • canned baby corn
  • snow peas
  • crimini mushrooms
  • baby bean sprouts
  • sesame oil
  • teriyaki sauce
  • hoisin sauce
  • soy sauce

Equipment:

  • Rice cooker
  • Wok
  • wood spoon
  • large pot with lid

Preparation:

Rice.

Start the rice first, because it takes the longest. Depending on the type of rice you use, it will take a varying amount of water and cook time, so I can’t get too specific on this. Just watch carefully the first few times you’re cooking the rice and learn what works with a specific variety.

Some people say you should soak and rinse the rice before cooking. I don’t really bother with that; just a couple minutes of soaking, while I’m chopping the vegetables, and no rinsing.

Press tofu.

Take the tofu out of the container, and press it between two plates with a weight on top. This will squeeze out excess water, resulting in firmer tofu. After pressing for about 20-30 minutes, you can cut it into cubes. You can get away with less press time if you want, but less than 10-15 minutes is not recommended.

Chop vegetables.

Chop the different vegetables up into bite-size pieces. If you want you can save some time by buying pre-sliced vegetables. I usually get pre-sliced mushrooms, water chestnuts, and baby corn.

For the green onions, you just want the pieces to be about a quarter of an inch long.

The water chestnuts and baby corn come pre-sliced in cans, but you’ll need to strain them.

Cooking

Note: With a few exceptions, I don’t really bother with measuring ingredients. Learning to cook isn’t about following precise steps exactly every single time. It’s about exploring and experimenting and being observant and understanding.

Measuring makes it easier to repeat a result, but only if the ingredients are constant. The thing with vegetables and other ingredients is, they’re not very constant. They vary depending on season and freshness.

So the amount of oil or sauce or temperature or cook time that might be good for one session might not work for another, or according to your taste.

You develop a feel for this over time. Vary and experiment until you feel like you know what you’re doing and know what works for you. Use your eyeballs and your head. Use your tongue. This recipe will tell you what I look for when I’m cooking and how I estimate, not how to be scientific and rigid with your cooking method.

  1. Start the rice cooker about 10 minutes before you start cooking the rest of the vegetables.

    I’ve found the type of rice I usually cook takes about 20-25 min to be done, and the wok items take about 10-12 minutes or so to do.I use a rice cooker that I bought at a drug store for $10 like 17 years ago, nothing special (but it’s a really well made and well designed appliance and I’m happy with it).

    Some people use super fancy rice cookers made in Japan, that cost $150+ and use sophisticated sensors and computer programming with AI and fuzzy logic to do perfect rice every time with no fuss. There’s nothing wrong with that. At all. The Japanese know WTF they’re doing with their rice. Someday maybe I’ll buy one myself.

    With my rice cooker, it just has a setting for “warm” and a setting for “cook”. It’s supposed to switch automatically to “warm” after the water boils off. I’m not sure how it knows to do this, I expect maybe it’s by weight but who knows.

    But usually it’s wrong, so I have learned to watch it and flip the switch manually. I just need to keep an eye on it, checking on it after about 15 minutes to see how much water has evaporated.There’s a narrow window (maybe a minute or two, tops) between the water boiling away and the rice at the bottom of the pan starting to burn. That’s what you watch for. When the rice is done, the water should be boiled away leaving moist steamy grains of rice that may stick together or not depending on the variety and whether you washed and rinsed it.
    Sometimes, I see little holes in the rice, that look almost like someone took a bunch of chopsticks and stuck them in the rice, then pulled them out when the rice firmed up enough to stick that way. These holes are created by the streams of steam bubbles coming up through the boiling water. You don’t see them until toward the end when the rice is ready, and they don’t always form. But if you do see them it’s a good sign that the rice is ready.

    My rice cooker has a second stage to it, a basket that goes on the top of the cooking bowl, which you can steam vegetables, dumplings, or other food in. I put the broccoli in here. If your cooker has this feature, you can do that too, if not just stir fry it in the wok.

    Broccoli is done cooking when it is still bright green and stiff and crunchy. It is overdone when it starts to wilt, turns a darker green with a brownish tinge, or gets mushy. Basically, you just want the broccoli to be hot, not to break down the cells of the plant that make it crunchy and crisp.

    Fortunately it takes about the same amount of time to steam the broccoli as it does to cook the rice. But you may need to pull the broccoli a little early. Just lift the lid and check on it after about 10 minutes and see if it looks good.

    I don’t put anything on the broccoli while it’s steaming, just let it steam on its own. After it’s done steaming, I’ll throw it in the wok for a few seconds to a minute, taking care not to overcook it, to get some flavor from the sauces and oil.

    As soon as the rice cooker is set up and going, I turn my attention to the wok and the vegetables.

  2. Throw some sesame oil into your wok, and ignite the burner under it. Gas stove top is the only way to fly here. A “splash” of oil, enough to coat the cooking surface and leave a slight puddle is sufficient. You’re not deep frying, so you don’t need to cover the ingredients in oil, you just need enough to keep them from burning to the cooking surface of the wok. As you run through adding the different ingredients, you may need to add a little more oil at times.

    Tilt the wok so the oil flows over the entire inner surface, as close to the edge as you can get without spilling the oil. Then put the wok on the burner and let the oil flow back down to the center and get good and hot. If it starts smoking, it’s ready, but it’s also ready before then. It only takes a minute or so to heat up good and hot. Woks are made from thin metal that heats up quickly, and don’t retain the heat very long. It should be hot enough to start cooking very quickly.

  3. Now, cook the vegetables and tofu in the wok. Wait, tofu’s a vegetable too, right? Whatever, just cook the vegetables.

    Starting with the thickest, sturdiest vegetables, working my way down to the flimsiest, I cook each ingredient with a little bit of teriyaki and hoisin sauce, and throw on a little soy sauce as well.

    The sauces help flavor the food as well as keep it from drying out while it’s cooking in the oil. Oil heats up much hotter than the boiling point of water, so it can really dry out food from the outside in and turn it crispy. That’s what deep frying is all about — drying out the surface of the food, making it crispy. But with stir frying, you want to preserve the moisture in the food, and just give it a light coating of oil so it won’t stick to the wok. The oil helps transfer the heat into the food. But you don’t want it to dry out or it will burn. So you add a little sauce to help balance moisture and add flavor.

    It’s easy to use too much sauce, but there’s no strict guideline on how much to use. When I first started my wok experiments, I used too much, and my food didn’t taste like the food it was, all I could taste was the sauce. Now, I use less, and it flavors the food, the sauce doesn’t mask the food and become the entire flavor.

    You don’t want a deep pool of sauce at the bottom of the wok that the food is boiling in; you want a coating of sauce that you can stir the food in.

    Soy sauce is the most watery of the three, and adds moisture to the food while also adding a salty flavor. Teriyaki is sweet. Hoisin is sweet and a little hot. I find these blend well together, but you can experiment with other types of sauces. Fish sauce, oyster sauce, sate sauce are all worth looking at, as well as others.

    If you want to you can also toss in other spices, such as ginger or dried chili peppers, or whatever else you want. These can add even more flavor. But resist the temptation to overwhelm the dish with these flavors. Strong spicy dishes can taste great, but if you dial back and let the spice accent the food flavor rather than smother it, it’s even better.

    I know lots of people like to flip and toss and catch their food with the wok, and this is considered the correct way to use a wok, but I don’t find this to be all that necessary. I just stir it with a large flat wooden spoon/spatula thing, and it works just as well, without risk of spilling the food or straining my wrist. If you enjoy flipping the food around and being a showboat, knock yourself out.

    The purpose of stirring the food is to move it around so it doesn’t stick to the wok and burn. Also it helps even out hot spots so that everything cooks to an even temperature. Also it helps distribute the spice and sauce over the whole surface of each piece of food. Also, it helps the food flip over so it gets cooked from all sides, not just the side it happened to land on when it landed in the wok. And if you’re cooking more than one ingredient together, it helps them to mix. That’s it.

    As each ingredient is cooking, I sample a piece every now and then to see how it’s doing. Once it’s done how I like it, I transfer the food from the wok to the pot, and put the lid on it to keep things warm. I work my way through the ingredients, doing the thicker, sturdier foods first, and cooking them longer, and the lighter ingredients last, cooking them briefer. Items like baby corn, water chestnuts, onions, mushrooms, and tofu all take longer, several minutes, and can be done together if they fit in the wok, or done separately if there’s too much. Broccoli takes long too, unless it’s already steamed, in which case it just needs a short bath in the sauces. Items like spinach leaves, green onion, and baby bean sprouts don’t take long at all, and can be thrown in toward the end for a minute or less.

    Tofu is done when it starts to brown on the edges and develop a bit of a skin. If it’s not pressed enough to remove enough moisture, it may not brown on the edges or develop a skin, so keep that in mind. If you want to, you can do meat instead of tofu: chicken, beef, shrimp, or something else. Be sure to cook chicken thoroughly.

    Once all the ingredients are done, mix them up in the pot and then scoop it out and serve with the rice.

csanyk.com © 2016
%d bloggers like this: