Dart first impressions

I’m taking a introductory mobile development class this term, which is mainly taught in Flutter/Dart, so I’m in the initial stages of learning the Dart programming language at the moment. I enjoy learning new programming languages, though that’s not to say there aren’t some pain points at times (looking at you, JavaScript).

In practice, Dart is pretty tied up with Flutter, as it seems the main paradigm in which it’s used is in combination with Flutter for mobile development. That said, I won’t be talking a lot about Widgets and such, as I haven’t gotten too deep into the Flutter side of things yet. But, here’s a few initial impressions of the Dart programming language.

The language definitely feels modern, with lots of syntactic sugar and powerful methods/functions built in. It’s much more like programming in Python than C++, for instance. Just look at this gorgeously simple class constructor.

 Planet({required this.name, required this.description});

That’s it. The brackets signify that the contents are keyword arguments, and the this.name syntax assigns the argument to the corresponding class attribute automatically. Lovely! The required, of course, marks these as non-optional.

Dart is strongly typed, which I like. However, it can also infer types, so something like this is fine.

var x = 21;

It also has enough flexibility to allow non-specific types, as in code like the following.

dynamic getRandomListElement(List<dynamic> list) {
  if (list.isNotEmpty) {
    return list[Random().nextInt(list.length)];
  } else {
    return null;
  } 
}

This will work equally well on a list<int> or list<String>. Cool stuff.

Now, let’s talk about null safety. Dart is not messing around when it comes to null safety. I’m onboard with the basic idea of it, but it has caused some annoyances so far. For instance, the compiler will complain about the following code.

  Planet getNextLegDestination() {

    String answer = '';
    Planet planet;

    while (answer != 'Y' && answer != 'N') {
      answer = promptGetResponse(
        'Shall I randomly choose a planet for you to visit? (Y or N)'
      );
      if (answer == 'Y') {
        planet = hostSystem.getRandomPlanet();
      } else if (answer == 'N') {
        planet = hostSystem.getNamedPlanet();
      } else {
        print('Sorry, I didn\'t get that.');
      }
    }
    return planet;
  }

It’s convinced that the return planet; at the end is not null safe, even though the while loop can never cease without assigning a value to planet. My workaround was to do this instead, which required adding a default null planet attribute to another class.

Planet planet = hostSystem.invalidPlanet;
// Planet planet;

Another solution would be to mark variables as nullable (e.g., Planet? planet;), but this requires adapting variables types and return types all over the place. Having to have default, non-null assignments definitely seems like it will be problematic at times, especially when you have a complex class that maybe isn’t built to have a ‘blank’ instantiation. The whole thing ends up a bit awkward for me, but maybe I just need more time to get used to it. As the documentation states, “With null safety, your runtime null-dereference errors turn into edit-time analysis errors.”, which is definitely a good reason to get used to dealing with this.

For a few final thoughts, the official documentation is pretty good, but certainly not the best I’ve used. I also find it interesting that pretty much everything is an object — even int. I’m not sure how to feel about this!

Overall, I’m finding Dart easy to learn and use, though I don’t really have any information at this point about how fast it runs, or deeper details about its implementation. Grade so far: B+.

Song of the week: In the Shade of the Sun — Kapitan Korsakov

Learning new systems

This week I’ve been thinking a lot about independent learning. The more CS topics I learn about, the more I see how much I don’t know. There are so many languages, frameworks, systems, concepts, etc. to explore — being an expert on all of them is impossible.

One thing I hear a lot is that, in CS fields, you can’t think of your learning as done just because you’ve got a degree in your hand. These days, I don’t think any of us, regardless of field, have that luxury. The next job/role/position will always ask us to learn new things and conquer new concepts. This isn’t a bad thing. Learning can be fun! But, let’s not forget another piece of wisdom…

Fun and Failure both start out the same way." George Michael's  inspirational poster. #ArrestedDevel… | Inspirational posters, George  michael, Arrested development

If you know a surefire way to not fail at life and learning, please share it with the rest of the class. In the meantime, I’ll just have to do my pathetic best.

Step one: don’t get overwhelmed. There’s a saying I like about murdering an endangered species for crass, caloric concerns…

How Do You Eat An Elephant? – Ayat Saleh

When learning a new system, I like to start with a high-level overview. Getting the sky-high view helps me contextualize what I’m about to learn, where this system fits, what I might want to use it for, etc. Not exactly groundbreaking stuff, but hey, it works!

I’m not ashamed to admit that I often turn to Wikipedia for this. There are myriad useful articles with broad overviews of CS concepts, though I generally don’t find it quite as useful for learning how to use a new tool or framework.

A good book on the topic should include a good overview as well. I just started reading Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow by Aurélien Géron, and it’s chapter 1 overview of machine learning is the best overview I’ve read in a while. I felt a lot less stressed about diving into this large, complex, and nebulous topic after getting to grips with just a few broad strokes.

Step two: get your hands dirty. Playing with code examples and making toy, hello world programs and the like is a great way to remember what you’re learning and come up with new questions and avenues to explore. One great thing about them thar’ internets is that you can often find a good online tutorial that includes basic information along with the opportunity to practice immediately.

Step three: don’t worry about learning everything all at once. It’s not often practical to read a book on the new topic cover to cover, especially as we often find ourselves needing to learn about several new topics at once. I do enjoy learning all the little details and tricks you can find with a fuller approach, but it’s usually necessary to be a bit more focused.

Working on small, incremental steps to what I actually need to learn for my current project is a practical approach. Early on, I’ll often be knees-deep in a code editor, working at a glacial pace while looking something up for every other line of code. I’ll know I’ve gotten more comfortable once the official documentation no longer reads like lorem ipsum and I can refer to it freely without needing to refer to it constantly.

Step four: ????.

Step five: you’re an expert! Congrats! Wipe your chops, give a quick eulogy for the last extant elephant, and kick that imposter syndrome to the curb.

Song of the week: And Saints – Sleigh Bells

Game AI, please stop cheating…

…and git gud.

I’ve been noticing more and more, over my many years wasted spent playing the vidya games, that game AI is really dumb. The typical, as in universal, fix to enable difficulty is for the AI to just straight up cheat. But you don’t find a suitable chess opponent by playing someone a lot worse and giving them extra pieces. Wouldn’t it be nice if AI provided more difficulty by being smarter instead?

The dumbness problem is one I first acutely noticed in Total War: Empire. The AI, or, more accurately, the computer opponents controlled by scripts, were in a state of complete failure.

For strangers to the 4X genre, this is a game where you rule a nation, trying to build all the things, recruit all the armies, conquer all the cities, and eventually accumulate enough bits and bobbins to declare yourself the bestest of all nations, thereby winning the game.

To call the other, computer-controlled nations AI is a bit misleading, because they have no actual intelligence, and don’t really seek to emulate it in any meaningful way. But in any case, this is the term that’s stuck around for referring to your computer-controlled opponents, so I’ll keep using it. Also, the problem of dumb AI is no way unique to 4X games, but I’ll be focusing on them because they’re the best example of it in my opinion.

So, these AIs were having some issues. One nation, I believe it was France, in this game loosely based on the real-world colonial era (a lot less fun in real life than in game form, or so I hear) was marching an army to my border, then to its capital, then back, stuck in an endless loop of doing absolutely nothing. To be fair, the other AIs weren’t faring much better, mostly treading water in various unproductive ways while patiently waiting to be stomped by the smart-brained human player.

A notable engagement was my war with Spain, which had been stuck in limbo for a few dozen turns. In that time, nothing had really happened. I had a strong navy and had blockaded all their ports for several decades, starving their economy. I couldn’t be bothered with a land invasion to conquer their cities, so I figured I would blockade all their ports and take a diplomatic approach, essentially trying to extract concessions for a peace treaty.

The AI was not onboard with this plan. Instead, they decided that the proper cost of a peace treaty for the war they were disastrously losing, which they offered me every turn, should be that I pay them about 5 times more than everything in my treasury. While they made this demand over and over, they also marched their armies back and forth in their territories, seemingly stuck in their own loop.

The particular, highly visible AI failures I noticed in this game really made me pay attention to what the opponents were doing, and the more attention I payed, the more I realized that at no point in this game were any of the AI opponents capable of a remotely robust understanding of the state of the game or of responding to it appropriately. The 4X genre is especially interesting to me when it comes to thinking about game AI, because it’s a genre where there’s a clear need for really good AI, met by an absolute lack of anything that meets this challenge.

4X games are inherently very complicated. There’s a lot of moving parts to fiddle with, and you proceed to fiddle with them for a very long period of time, min-maxing your civilization, constantly angling towards victory. I have to imagine this makes it very hard to make a good AI, and indeed I’ve yet to encounter one.

In theory, human opponents would be ideal for anyone seeking a real challenge in these games. But not many of us can commit to playing campaigns that take 10s of hours with a group of friends, beholden to the whims of when everyone happens to be able to play. There are some options for more flexible multiplayer, but none of these have ever appealed to me much either. Imagine if we had an AI in these games that could actually compete.

To be fair, it is possible to achieve a reasonable amount of challenge. Setting the difficulty to max in Civilization, for example, is mostly going to provide a satisfactory challenge, at least for some amount of time. But in order to achieve this, the AI turns into a bunch of dirty cheaters.

To allow the rudimentary AI to compete, they get things like a tremendous head start at the beginning of the game, coupled with passive boosts to pretty much everything they do to the tune of 50-100% for the entire game. As a consequence of how these games work in practice, with a strong snowball effect, we should really consider these bonuses to be multiplicative, stacking on top of each other.

Starting with two cities means the AI can immediately build twice as much stuff. A 75% bonus to production on top of this means they can immediately build three times as much stuff. If they push this productive power into expansion, they ought to soon be able to produce 10 times as much stuff, or more, quickly leaving you in the dust. But eventually, using your human brain, with intelligent play, you’ll overtake them. It would be easy to think this makes you some sort of galaxy brained genius, but it’s more to do with their incompetence. It’s actually kind of insane how much they cheat, considering they’re still ultimately designed to lose.

For nongamers, please permit me a Sportsball metaphor. Imagine you’re playing a game of the Basketballs. You’re alone, and on the other side of the court is 10 NBA pros. They all have a couple extra arms, cuz that seems like it’d be helpful. Also, your basket is at a height of 5 feet instead of 10, every goal they score counts for double points, and they start at 20. But ultimately, you know you’re going to win because 3 of them are just spinning in circles in place, 2 others will endlessly pass the ball back and forth between them whenever they lay hands on it, another is glitched out with that little loading wheel over his face, and the rest seem unclear on what a basket is, what a ball is, and how can Basket Ball?

You know what would really push the envelope for 4X games, and perhaps all games? An AI that plays the game even slightly well instead of cheating. I would love to see machine learning in this context. Many games are clearly too complex for a team of humans to sit there and write good, scripted AI for. Or, at the very least, it’s not enough of a priority for the developers to be willing to spend the time and resources it would take. But machine learning could theoretically train smart, capable AIs while using an acceptable amount of development resources.

Also built in to the machine learning model is how the neural networks need to be trained. You’ll want multiple difficulty settings, of course, which could come in the form of the same AI at various stages in its training, with the most difficult being the most up-to-date. Some finessing would be required, sure, but it seems like a natural fit, at least from a high-level view.

Of course, there are obstacles as well. For instance, if the game is updated sufficiently, does the AI have to be retrained from scratch? Will even small updates degrade AI performance, as the AI is trained on an older version of the game? Is it feasible to train the AI in the actual game itself, or will that be too slow to institute the required number of iterations? And, how smart do we actually want the AI to be?

Still, for me, the potential for the application of machine learning to make game AI smarter is much more exciting than the next generation of graphics, VR, or any of the other technologies the industry seems the most interested in pushing and pursuing (cough, metaverse, cough, NFTs, cough). I just hope that someday soon I have the chance to write another post complaining that game AI is cheating by being too damn smart for my squishy human brain.

Song of the week: Civilian – Wye Oak