Okay, although not the worst ever, Dice Game is pretty dull. With only two dice, no strategy, and no replay value, you might think this an odd program of the month. But for the young teenager that wrote it, it was pretty cool in 1983. Let’s dig in and see why.
It’s all about the code.
Back when I wrote Dice Game, I was still a newbie coder. My programs were less about substance—the game. Instead, it was about experimenting and learning. Dice may not be a fun game, but it is a well thought out program as this listing shows. At a high level, Dice progressed like so:
Print player’s roll
Print computer’s roll
Print who won
In many of my programs, I would have coded it from top to bottom. Code reuse and logical groupings were semi-foreign concepts to me. Yet, Dice Game, whether on purpose or by chance, manages to do both. Here is what the top of Dice looks like:
20 LET A=0
30 LET B=0
40 PRINT TAB 10;"DICE GAME"
50 GOSUB 560
60 PRINT "YOUR THROW="
70 GOSUB 160
80 PRINT "MY THROW="
90 GOSUB 220
100 IF A>B THEN PRINT ,,"YOU WI
110 IF A<B THEN PRINT ,,"I WIN"
120 IF A=B THEN PRINT ,,"TIE"
130 GOSUB 570
150 GOTO 10
Even if you don’t know BASIC, you shouldn’t have any problem reading that. The
A key press for you.
Let’s start with the key press. Here’s the code for reference:
560 PRINT ,,,,,,
570 IF INKEY$="" THEN GOTO 570
580 IF INKEY$="S" THEN STOP
Its purpose is simple, waiting for the player to press a key. You can also stop the game using S, but I doubt that would get used much. It is surprising I bothered to do this. Usually, I’d put in a
PAUSE or an
INKEY$ check where needed, but I can reason the stop routine is why I didn’t.
The hanger on in this is the
In hindsight, I could have moved the commas into the title routine at line 40 and avoided this altogether. Thinking about user experience, I should have added text about “pressing a key to continue.” Both would be subtle changes to Dice that wouldn’t diminish the intent.
Dice have six sides.
Now, the dice routine being broken out is not a surprise. I needed to print four die faces during the course of the game. Typing all that code would have been a bit of a hassle, especially on a slow computer with a membrane keyboard.
What’s interesting is what amounts to a switch statement at the start of the routine. Here’s what that looks like:
280 IF Z=1 THEN GOTO 340
290 IF Z=2 THEN GOTO 380
300 IF Z=3 THEN GOTO 420
310 IF Z=4 THEN GOTO 460
320 IF Z=5 THEN GOTO 500
330 IF Z=6 THEN GOTO 530
Z is the current die face being shown. These six lines of code check the value and then jump to the actually code to print it. A pretty straight forward solution to a common problem.
Now, as readable as that is, knowing how the ZX81 BASIC works I could have crunched that into a single line of code:
280 GOTO 300+40*Z
Although more efficient, it is harder to follow and reduces the readability. That is one of the pitfalls of programming. When does sacrificing readability for efficiency make sense?
A philosophical moment on coding.
Speaking about the readability, one thing I like about Dice Game is that it is obvious looking at the program what it is. At a glance, you get the gist of the program from all those
What that did, however, was lock the program into printing one die at a time, one after the other. To be fair, the complexity of printing a series of dice was beyond the scope of what I was attempting to do. Yet, spending the time doing so would have made the game much more enjoyable.
But, in doing so, Dice would have been harder to read. That is a bit of a problem. The more complex a problem, the harder it is represent in a simple way. Often times, you have to abstract the idea to reduce the complexity.
Dice Game does this by first reducing the code to a series of routines at the top. And then, calling more complex functions later in the program. This is a bit over kill for such a small program, but would become a lesson that I struggled with later in life.
In school, such brute force readability was often frowned upon. The expectation was to use interesting math and algorithms to develop efficient programs. The “keep it simple and readable” side of me rebelled back then. But, I get it. I do that a lot in the programs I write today; often to others detriment.
Worse, breaking up small routines into tiny functions peeves me to no end. Sure, code reuse and efficient routines are good, but there is a limit. My advice is to choose wisely and use comments to advise others of your choice.
A couple more options.
Before we leave the code discussion, I wanted to point out one more place I could have done a bit of code reuse. I ended up creating basically the same code for both the player’s and the computer’s roll.
160 FOR G=1 TO 2
170 LET Z=INT (RND*6+1)
180 LET A=A+Z
190 GOSUB 280
The only difference is what variable to add the dice to. A fix would have been to use a temporary variable. It would have been a more elegant solution.
From worst to first.
Okay, enough about the code. Let’s talk game! Dice Game suffers from being just a push a button, win or lose type game. Not bad, but where’s the drama? Where’s the fun? What it needs is something else to do.
In that respect, Stud One does a better job of being a game than Dice does. It added in betting which does a great job of adding tension to any game. You can adjust your strategy based on risk, gut, whatever. With Dice, you press a key. Boring.
If you wanted to make Dice game fun, you’d build in more complex logic. I should have added in features such as more dice, re-rolls, scoring, and so on. Yet, that would need a fair amount of thought into how the computer would play.
It isn’t impossible. I’ve seen some pretty sophisticated card games written for the ZX81. I even did that while developing a Tic-Tac-Toe game for the ZX81. Yet, that wasn’t the purpose of writing Dice.
Dice was all about the code. I was learning how to structure a program. I dabbled in code reuse and branching logic. Although not perfect, Dice laid a foundation that would get built upon in 30+ years of programming.