Am I in a Terminal?

Sometimes, it can be useful to know if your program is running in a terminal. Since Python 3.3, this functionality has been available in the os module:

#!/usr/bin/env python3

# Test if this Python script is running in a terminal or not.

import os

    size = os.get_terminal_size()
    print("I am in a terminal of size {}x{}"
        .format(size[0], size[1]))
except OSError:
    print("I am not in a terminal.")

Here is an example of it in operation:

$ ./ 
I am in a terminal of size 80x24

$ ./ | tee
I am not in a terminal.

This is useful for many reasons. For example, scripts which have interactive “beautifications” like progress bars, no-freeze spinners, and animations should cease these antics when piped into the input of other programs or redirected to files. Additionally, programs being run from scripts can disable all performance-impacting interactivity, including interactive KeyboardInterrupt handling; if a user Ctrl+C’s a script, they want it to stop, immediately, not ask to quit.

Learning Japanese the Python Way

Now that I’m in college, I’m taking a lot of non-computer science classes, and one of them is Japanese. I’m just starting out, and I need to be able to rapidly read numbers in Japanese and think about them without translating them consciously. I could make a bunch of flash cards, or use a service like Quizlet… or I could write some Python!

For those of you who are unfamiliar, Japanese doesn’t have the ridiculous numerical system that English does. One through ten are defined, and eleven is simply (ten)(one). Twenty three, for example, is (two)(ten)(three) (に じゅう さん). This means that rather than having a long list of numbers and special cases, I can just have the numbers zero to ten “hard coded”.

After that, the program is pretty simple: if the number is less than 11, simply look it up. If it’s more than 11 but less than 20, build it with じゅう plus the second digit. If it’s larger than 20, build it with the first digit plus じゅう plus the second digit.

The interactive part is pretty simple too: it runs a loop that randomly generates numbers, checking that they haven’t been done before, translates them, and asks me to translate them back. If I succeed, it moves on; if not, it doesn’t record the number as having been completed, so I have to do it again at some point in the same run.

This simple program came out to 136 lines of very verbose and error-checked Python. It’s a good piece of code for a beginner to try and modify – for example, can you get it to incorporate the alternate form of four (し) as well as the primary form? Can you make one that teaches Kanji numbers? (I plan to do both of those things at some point.)

Why Linux on the PC Needs a Focus on Hardware Support

A few days ago, I had an interesting and somewhat frustrating experience with a friend of mine. Their laptop was dying, so they asked me to give them some suggestions for a new one.

Their requirements were a computer with a display that was good for reading, enough power to be responsive and able to multitask well, and rapidly accessible storage, but not necessarily a lot of it. Of course, I immediately thought of the System76 Lemur, which happened to be on sale at the time; however, after going through a whole list of pros and cons of Ubuntu with the friend, they told me that they wanted to go with Windows or Mac OS X as they “didn’t have time to tinker”.

They’re right, of course, but this really got under my skin. The thing is, if you’re not trying to game on Linux, there are absolutely no problems using it on a desktop in almost all cases. Desktop hardware is nicely standardized and “just works”. But on a laptop? Nope. It’s a crapshoot as to whether your wireless Internet and Bluetooth will work, or if your touchpad’s multi-touch will be usable. On my Dell Inspiron 7000-series laptop, which works almost flawlessly with Ubuntu GNOME, the wireless chipset will occasionally forget that any but a single network, to which I’m not connected, exists.

Why is this? Well, it’s because laptops are often very, very custom. They have custom form factor motherboards with non-standard sets of features. Battery life is often the primary concern rather than compliance, and release cycles are very tight, so if a new hardware system is developed, drivers are produced for the target platform (almost always Windows) and released there. The Linux community has to hack together our own after the fact.

Windows runs on most laptops, and has a lot of big issues. Privacy concerns, resource overutilization, extremely poor real-time performance, and a massive lack of customization are the obvious ones, along with a downright byzantine user interface without much power to back it up (in the consumer versions, that is). Mac OS X looks simple on the surface while still exposing the massive power of a UNIX to its power users and developers (although this is becoming progressively less true). On the other hand, it costs an absolute fortune to buy into that ecosystem, and that is where Linux comes in.

In reality, Linux is a modern UNIX like Mac OS X, and it is far more flexible and powerful, but to many people, it’s just “Windows that costs less”. What we need to be is a Mac OS X that can run anywhere. Linux needs to be simple on the surface, which most DEs accomplish brilliantly, while exposing the power of the underlying OS, which isn’t hard given a terminal emulator. Where Linux falls short is the “runs anywhere” part.

Porting Deucalion to Rust

A few months ago, I made a proof-of-concept for an RPG engine based on SFML and the Tiled map editor, called Deucalion. Over time, the source code became unwieldy, leaked a great deal of memory, and was nearly impossible to build. I ended up spending more time configuring build systems than actually working on the code, and I abandoned it in favor of SBrain and schoolwork.

Recently, though, the Rust game development story has gotten a lot better, and I’ve gotten a bit of free time. With the help of a friend of mine, Dan Janes, I’ve been porting the existing code to Rust and refining the design for the game-dev-facing API. It’s been interesting, since it’s my first time running a project on which I am not the sole contributor.

I’ve certainly run into some problems because of the relative immaturity of the Rust ecosystem – for example, many projects don’t use the standard Error trait, which makes using the handy macros that rely on it such as try! nearly impossible, but I’ve also found that as a whole, the community is very responsive to having these issues pointed out and solved.

Deucalion isn’t quite at the level it was before I decided to port it – I’m still struggling to get tilemaps to draw with decent performance, and a lot of design work needs to be done – but it’s doing better than I thought it would, and I’ve discovered some of the best features of Rust so far.

For example, while Rust doesn’t have exceptions (because exception handling requires a heavyweight runtime), the convention of returning Result<T, Error> from functions that might fail allows programs to act as if it did. Deucalion implements a single, shared error struct DeucalionError that encapsulates every possible error type (Currently IoError, LuaError, TiledError, NotImplementedError, and Other), allowing callers of risky functions to act according to the actual failure that occurred.

I also like the module system much more than I thought I would at first. While learning when and where to use mod vs use can be a bit of a hassle, the fact that multiple includes create an automatic compiler error is very welcome when compared with C++.

Rust is a great language, and its ecosystem is on its way to becoming as good as that of Python or Ruby. I’m excited for every step along the way.

Full Stack By Example 01: Dice

To begin, we’re going to make a simple dice roller application. We want a page that, given a number of dice, a number of sides, and a number of rolls, returns a list of random numbers in the proper distribution. For example, rolling 2 six-sided dice (2d6) is not the same as rolling a 12-sided die, since when rolling 2, 6 is much more likely than, say, 2 or 3, and 1 is impossible.

For this, we need to be able to generate random numbers. Python’s standard library gives us the useful function random.randint(lower, upper) from the random module, which will give us a random integer between lower and upper.

A fair six sided die will only ever give an integer between 1 and 6, evenly distributed: random.randint(1, 6).

We could make a dice roller like this:

import random
print("d4:", random.randint(1,4))
print("d6:", random.randint(1,6))
print("d12:", random.randint(1,12))

and it would work just fine, printing out random numbers every time it was run. Imagine, however, that we wanted to do more than one die of each type. This requires a little arithmetic.

Two six sided dice do not have an even chance of producing a number between 1 and 12; rather, it is impossible for them to produce 1 (as each die’s minimum is 1, and there are two of them), and it is much more likely that they will produce 7 than 12, because there are many combinations of rolls that produce 7, and only one that produces 12.

We can solve this simply by adding together calls to random.randint():

import random
print("3d6:", random.randint(1,6) + random.randint(1,6) + random.randint(1,6))

This totally works and has the correct distribution, but it’s kind of gross and requires a lot of retyping. This is where we go from simple technical knowledge to properly decomposing the problem, and you should try to do this without looking at the next answer: how would we modularize this solution, to be able to deal with and number of dice of any geometry (any number of sides)?

Don’t be afraid to try this on your own!


We could make a more general dice-roller with a function which takes as input the number of dice and the number of sides. At first, let’s deal with only the number of sides:

def roll_die(number_of_sides):
    " Simulate rolling a single die with number_of_sides sides"
    import random # We need randint from the random module
    # This is exactly what we were doing by hand before: a random number between 1 and the number of sides
    random_number = random.randint(1, number_of_sides)
    # Give back the number we generated
    return random_number

We now, however, have the problem of adding multiple dice. Again, we could do roll_die(6) + roll_die(6) + roll_die(6), but this is only marginally better; it looks much cleaner, but doing 1000d6 would still be somewhat problematic.

Luckily, if computers are good at one thing, it’s repeating instructions over and over. All we need to do is make a variable to keep track of the total, just like a person would do on a bit of paper if they had to roll a die a bunch of times. This is called an accumulator, because it’s accumulating a value over time, and that’s what I’ll call the variable. As with all variables, though, you can call it anything you like.

def roll_dice(number_of_dice, number_of_sides):
    " Return a random number in the same distribution as rolling number_of_dice dice of number_of_sides sides "
    import random # we need randint from the random module
    accumulator = 0 # This variable will "accumulate" a value as the loop runs 
    for roll_number in range(number_of_dice):
        # We don't actually use roll_number for anything, it's just a placeholder
        # You could use it for debugging messages if you want
        accumulator += roll_die(number_of_sides)
    return accumulator

First, this isolates the importing of the random module to where it belongs – we only use functions from random in this function, so the rest of the program doesn’t need to know about it.

Second, this function is very general. We could write print(roll_dice(3, 6)) to achieve the same result as above, or print(roll_dice(1024, 6)), or even print(roll_dice(1, 15)); the computer doesn’t care that fair 15-sided dice are physically impossible.

Decomposing and generalizing problems problems is a very important skill – much more important, in fact, understanding any individual language.

In the next post, we’ll create a simple web service that rolls dice for anyone who accesses it.


I Repaired My Headphones

Hardware manufacturers are missing out on a huge potential source of revenue: the thrifty tech user market. No, really. Let me explain.

I just woke up to find that my favorite pair of headphones was making only one sound, and it wasn’t the one I was putting in as an electrical signal. It was rattling.

Feeling adventurous, I popped the around-the-ear pads off and – lo and behold! – found four Torx screws. I removed them, found that the drivers had separated from their sockets, and put them back in. I also glued them in with a bit of hot snot, since the drivers happened to be a little deeper than their sockets, giving me a nice lip around which I could run the hot glue gun.

These headphones cost about $25. They’re not expensive and they’re not fancy, but they’re repairable. I bought them for that, in a sort of shallow sense: they’re advertised as having a 3.5mm accepting jack on the left ear, which means that the cable can be replaced. I abuse my headphones constantly, and I’ve already replaced the 3.5mm cable twice.

My only question is, why didn’t they advertise to me that the insides were trivial to repair as well? Every other pair of around-ear headphones I’ve owned has been ultrasonically welded, not affixed with screws; the drivers have been glued to the frame, not inserted into a socket that’s integral to the frame; and the around-the-ear cups have been either glued on or attached with a huge lip that’s nearly impossible to remove.

In Idoru, Gibson predicted that, by around now, we would have reverted to a model of non-disposable, easily repairable electronics. I’d pay so much more for headphones that were advertised not just with shots of the outside but with schematics and examples of how easy repairs are. I’d be willing to wait longer for my shipment if I didn’t think I’d need to buy a new pair of headphones next month.

I want headphones made by the Sandbenders out of coral and turquoise and the interior surface of renewable nuts, and I’d be willing to pay a lot for them, not for aesthetic reasons but because I know I won’t have to replace them for a long, long time.

The Problem with Insurgency

This post contains mentions of racism and rape after the READ MORE link.

I love the game Insurgency, but I don’t enjoy playing it anymore, and I’m not sure when I’ll be able to go back to it.

Let me start with the positive side. It’s an excellent concept, essentially adrenaline made into a multiplayer shooter game. One or two shots and you’re dead, but getting those one or two shots on target is very, very difficult. Respawn waves both aid coordination and create a sense of tactics, even in an uncoordinated team. Low-bandwidth, near-zero-latency voice chat lowers the barrier to actually coordinating, too, which creates a better chance of a given team working as a team than in almost any other game I’ve played, with the possible exception of Rust. The variety and excellent modelling of weapons, weapon attachments, and support devices allows a variety of strategies to be executed, and the enforcement of (relatively) realistic squad allocation rules forces players to try different playstyles. The maps are well designed, and despite the age of the Source engine, the graphics are impressive and the gameplay is low-latency and fluid.

Continue reading “The Problem with Insurgency”

A Story About My Personal Trainer

OK, I’m going to tell you a story.
This is a story about a woman who runs her own small business as a personal trainer. She uses Microsoft Publisher to create her at-home training programmes and Excel for keeping track of payments, et cetera. She has a Win XP computer from 2004.

I upgraded said computer to Windows 7 at XP EOL and replaced her ancient GPU so that she could use two monitors. I also got her to use LibreOffice Calc instead of MS Excel, but she loves her Publisher, so we decided it wasn’t worth switching to Linux. This has been working just fine for several years, and there was no reason to believe she’d have to spend a cent on the thing for years to come. Until last week.

Last week, @Microsoft decided it would be fitting to install Windows 10 without her permission. (And don’t give me the excuse that she implicitly accepted it by closing the window or whatever, that’s bullshit. She was very clear on that.) Her Publisher immediately stopped working and she phoned me. I told her not to worry and scheduled a visit so that I could reinstall 7. I backed up her user directory and went to install Windows 7. The key I’d sold her didn’t work. I phoned Microsoft and was told to wait, then told that the key was not valid. Luckily, I had another key, so I used that one to install Windows 7. I ran Ninite, jimmied the ancient CD-ROM drive to install Publisher, and restored the backup. All was going well. She paid me for the new Windows license and my time, and took her computer back to her house, plugged it in, and began working.

Twenty minutes later, the computer froze and she was forced to hard reboot. It is now not working, and she’ll have to bring it by _again_ so I can figure out what bootloader rubbish Windows 10 did that is causing it to have some kind of intermittent fault. In the mean time, she’s basically unable to work.

When we say “user choice”, this is what we mean. Not some nebulous idea of “freedom” or extreme Stallman-level trust, but rather the ability to choose whether you want to risk screwing up your perfectly working system with an upgrade. And, @Microsoft? This is unacceptable, period.

(originally posted on my Twitter, here: