GUISSMO

QBasic Poker

At some point in time closer to when I was born than the present, I submitted a school project to my high school computer teacher. It was a poker game written in the ancient language QBasic.

It’s a language so old that:

Starting with Windows 2000, Microsoft no longer includes QBasic with their operating systems.

There’s a Yo Momma joke there somewhere.

Screenshot of Game

If you still don’t realize how old it is, here is a 17-year-old YouTube video singing about my life back then.

Anyway, I recently found the code while digging around my email. It was sent as a ZIP file.

Now it’s in a Git repo whose first commit is one year before Github existed.

Dusting It Off

It’s 2023. I cannot find a Windows 98 computer anymore. How do I even run this program?

After a quick Kagi search, there is this QB64 project that compiles QBasic. Perfect.

Following the installation instructions was a breeze, and I was quickly ready to play my old poker game.

But then, tragedy. Some sprites (or graphics) did not appear.

Fixing the Sprites

The code to load the sprites was thankfully in the first few lines of my code. It involved opening a text file with comma separated numbers.

CLS
SCREEN 13

OPEN "****.TXT" FOR INPUT AS #1
FOR y = 1 TO 200
  FOR x = 1 TO 301
    INPUT #1, c
    PSET (x, y), c
  NEXT
NEXT
CLOSE

DO WHILE INKEY$ = ""
LOOP

As a very mature 1414 year old, I used profanity for the filename of what would be the image which appears as soon as you load up the game.

Yes, the “image” is a TXT file, not an image file. Because in QBASIC, we don’t do images, we use PSETS. Pixel sets. The first few characters of the first few lines of ****.TXT should look like:

    02,    02,    02,    02,    02,    02,    02,    02,    02,
    02,    02,    02,    02,    02,    02,    02,    02,    02,

This sequence of 02s dictate the color of each PIXEL of our Welcome Image. In QBASIC, there are only 16 colors, and colors are represented by numbers. And 02 was green, representing the green upper-left corner of our Welcome Image.

The problem was that for some reason that only young me might know, some of the spaces were tabs. And that rendered the whole file invalid. Because of this, some images did not load at all.

After replacing all tabs with spaces, we were back in business:

Screenshot of Welcome Screen

If you’re interested in how to draw the fifteen other colors, I gotchu. Well, more like Quora gotchu.

00 - BLACK
01 - BLUE
02 - GREEN
03 - CYAN
04 - RED
05 - PURPLE
06 - BROWN / ORANGE
07 - LIGHT GREY
08 - DARK GREY
09 - LIGHT BLUE
10 - LIGHT GREEN
11 - CYAN
12 - LIGHT RED
13 - LIGHT PURPLE
14 - YELLOW / LIGHT ORANGE
15 - WHITE

The first 280+ lines of the BAS file consisted simply of for loops going through each TXT file (which represents an image). This loads the sprites for the game — the welcome image, the cards, the backdrop of the main screen.

Game Logic

The game goes as follows:

The first thing you have to do is to type a number from 11 to 55 and press Enter. It should accept your bet.

At around line 408408, the code makes 1010 random integers from 11 to 5252. The first five represent the five cards. The bottom five represent the replacement cards, should you decide not to hold some of the cards.

5
''''' randomizer '''''
c1 = INT(RND * 52) + 1
c2 = INT(RND * 52) + 1
c3 = INT(RND * 52) + 1
c4 = INT(RND * 52) + 1
c5 = INT(RND * 52) + 1
c6 = INT(RND * 52) + 1
c7 = INT(RND * 52) + 1
c8 = INT(RND * 52) + 1
c9 = INT(RND * 52) + 1
c0 = INT(RND * 52) + 1

I knew how to do loops back then, but I don’t think I bothered to Ask Jeeves how to do that in QBasic. So, we have verbose code to make sure all of these cards are distinct.


'''anti-duplicate'''
IF c1 = c2 OR c1 = c3 OR c1 = c4 OR c1 = c5 OR c1 = c6 OR c1 = c7 OR c1 = c8 OR c1 = c9 OR c1 = c0 OR c2 = c3 OR c2 = c4 OR c2 = c5 OR c2 = c6 OR c2 = c7 OR c2 = c8 OR c2 = c9 OR c2 = c0 OR c3 = c4 OR c3 = c5 OR c3 = c6 OR c3 = c7 OR c3 = c8 OR c3 = _
 c9 OR c3 = c0 OR c4 = c5 OR c4 = c6 OR c4 = c7 OR c4 = c8 OR c4 = c9 OR c4 = c0 OR c5 = c6 OR c5 = c7 OR c5 = c8 OR c5 = c9 OR c5 = c0 OR c6 = c7 OR c6 = c8 OR c6 = c9 OR c6 = c0 OR c7 = c8 OR c7 = c9 OR c7 = c0 OR c8 = c9 OR c8 = c0 OR c9 = c0  _
THEN
  GOTO 5
END IF

Don’t ask me why I used the label 5 because I don’t remember anymore.

From that point, I take each cX and reduce it MOD 13.


r1 = c1 MOD 13
r2 = c2 MOD 13
r3 = c3 MOD 13
r4 = c4 MOD 13
r5 = c5 MOD 13
r6 = c6 MOD 13
r7 = c7 MOD 13
r8 = c8 MOD 13
r9 = c9 MOD 13
r0 = c0 MOD 13

To detect straights later on, I decided that the rank must be 11 to 1313 and adjusted accordingly.

I then use a temporary variable cXt and get the suit.

c1t = c1
'''''suit getter'''''
DO WHILE c1t > 13
  c1t = c1t - 13
  s1 = s1 + 1
LOOP

Drawing the Cards: In More Ways Than One

Now that we have the rank and the suit of each card, it’s time to draw them! Draw them from where? The virtual deck which doesn’t really exist. Draw them to where? These coordinates apparently:

x1 = 72 - 26
x2 = 72 + 47 - 26
x3 = 72 + 94 - 26
x4 = 72 + 49 + 92 - 26
x5 = 72 + 188 - 26
y = 127

Drawing the cards on-screen is then simply a matter of using a switch statement, which in the olden times was called SELECT.

SELECT CASE s1
  CASE 1
    PUT (x1, y + 25), spade
  CASE 2
    PUT (x1, y + 25), diamond
  CASE 3
    PUT (x1, y + 25), club
  CASE 4
    PUT (x1, y + 25), heart
END SELECT
SELECT CASE r1
  CASE 1
    PUT (x1, y), ace
  ...
  CASE 13
    PUT (x1, y), king
END SELECT
SOUND 300, 5
SOUND 400, 5
SOUND 500, 5
SLEEP 2

And why not add some cute beeping sounds to make it seem like it wasn’t coded by a 1414 year old?

Keyboard Shortcuts

Once the cards have been dealt, you could use C, V, B, N, M to decide which cards to keep before getting one final deal.

At around line 811, the code reminded me how mature I was back then. Some things might never change.

GOTO hell

There used to be a b-word after hell but it’s 20232023 and I don’t want to get cancelled so let’s not.

Now, what the heck does hell do? Well, it listens to keypresses C, V, B, N, M. These keys correspond to you telling the program to hold the card it corresponds to.

hell:
  SELECT CASE UCASE$(INKEY$)
    CASE "C"
      SELECT CASE h1
        CASE 0
          h1 = 1
          SOUND 300, 1
          PUT (x1, y + 38), hold, PSET
        CASE 1
          h1 = 0
          GOTO uno
      END SELECT
    ...
    CASE CHR$(13)
      GOTO redeal
  END SELECT

GOTO hell

Once you’ve held the cards you want to keep, simply Press Enter and get redealt the other cards!

Checking for Combos

According to the code, if all the ranks of the cards are different, then go to stfu. Otherwise, wtf.

IF rA <> rB AND rA <> rC AND rA <> rD AND rA <> rE AND rB <> rC AND rB <> rD AND rB <> rE AND rC <> rD AND rC <> rE AND rD <> rE THEN
  GOTO stfu
ELSE
  GOTO wtf
END IF

Upon reading the code in stfu, it (expectedly) checks if there is a straight, a flush, or a straight (or royal flush).

On the other hand wtf, counts each rank to determine if we have full houses, two pairs, trios, etc.

I also found and corrected a 16-year-old bug. The logic for three-of-a-kind and four-of-a-kind was wrong. Now it should work!

Conclusion

My past self would never have expected that the next time I would ever be running this game again and that I would be doing it in a place 1000010000 kilometers away from the last place I ran it in a city I’ve never even heard of then.

GIF Recording of Game

Overall, I’m quite happy that my school project stood the test of time and still works. There are some minor bugs if you start pressing keys when you’re not supposed to. File an issue and maybe I’d fix it within the next dozen years.

Keep in touch! Feel free to contact me if you have any questions, comments, or suggestions.

Back to Top | Blog RSS Feed