Crazy Solitaire

I started this project to check if Commander X16s graphical capabilities are sufficient to make a great looking, full color in High res mode Solitaire game. The game logic itself should not be a problem and in retrospect I wish I wrote this in C but since I started in Assembly I persevered and finished it in pure Assembly code.


I will release full source code after I clean it up, it is currently too messy for public.

Project Specs

  • 640 x 480 pixel High resolution mode
  • detailed custom graphics for displaying cards
  • smooth movement of cards (pixel)
  • Fully mouse controlled game play as well as menus and options

Game Foundation

I wrote a playable, text based prototype very quickly. Game rules are simple enough and keyboard inputs could be parsed very quickly. Compared to the time spent on designing graphics and coding graphical front end it was almost insignificant.

First decision that had to be made was how to store card information in a compact and clean way. In order to represent all the cards we need to be able to identify:

  • 4 suits - Heart, Spade, Diamond and Club
  • 12 ranks - Ace, 2 through 10, Jack, Queen and King
  • Displayed or Hidden flag

I decided that valid values for suits and ranks start with 1 and 0 is not valid value. So I needed 3 bits for Suit, 4 bits for Rank and remaining 1 bit for Hidden, so we can perfectly store one card per byte like this:

To store the data in the memory we have to reserve space. Because we have plenty of space we can just block 52 bytes per stackfor cards and byte 0 is used as counter of how many cards are stored in that particular stack.

The rest of the logic is a simple series of functions to validate the validity of the move and then perform the actual move from one stack to another. Each type of stacks has specific rules that are easy to implement, for example:

Four foundation stack on the top:

  • Can only start with Ace
  • Each next card must be of the same suit and must be one rank higher than previous one
Seven columns at the bottom:
  • If stack is empty then only King can be placed
  • If it is not empty then the next card must be one rank lower and different color e.g. red on black or black on red

After we implement all these rules the game is practically finished. Only thing remaining is to determine if all 52 cards are placed in four Foundation stacks.

The real trouble starts when we add Graphical User Interface…

Graphics

Initial thoughts

I initially did some basic calculations based on the size of the screen (640x480) and estimated that the width of a single card should probably be 64 pixels and to make it proportional it needed to be 96 pixels high. So I would need 2 sprites per card, each 64x64 pixels in size. That shouldn’t be a problem, right, after all Commander X16 supports up to 128 sprites. Well not so fast. I wanted nice 16 color sprites and quick calculation grounded me very quickly. Each 64x64 sprite in 16 colors takes up 2048 bytes. For 52 cards, 2 sprites each taking 2048 bytes would require 212,992 bytes. Obviously that would not work.

Second option I was considering was to just use graphics mode. However that will not work either. 640x480 at 16 colors requires 153,600 bytes of VRAM, which is also not possible since VERA only comes with 128K of memory.

The only way to pull this off was by using tile mode. I wrote a prototype graphics engine completely using tiles and it didn’t look too bad, just card movement not being pixel perfect was bothering me so at the end I settled for a compromise.

Solution


The only way to implement this in a way that is possible and gives satisfactory results is using a combination of tile mode for static cards and sprites for cards when they are moving. That provided two challenges. Is it possible to design cards graphics in such a way that they look nice and not clearly that they are bound by tiles and can we define sprites on the fly every time we grab a card or stack of cards without noticeable lag.

I think it works very nicely.

So here is how it works:

  • Layer 0 - 128 x 30 tiles with 4 bits per pixel for 16 colors - This layer is used for table background, Commander X16 logo outline, score, timer and controls.
  • Layer 1 - 128 x 30 tiles with 4 bits per pixel for 16 colors. This layer is used static cards
  • Sprite 0 - is used for mouse pointer
  • Sprites 1-5 are used for a stack of cards when they are moving on the screen either by the player following the mouse movement or by themselves flying to their destination.

I also designed two tile sheets.

  • Background tiles (BTILES.BIN) 128x128 pixels containing all the tiles for background and Options menu.
  • Card tiles (TILES.BIN) 128x512 pixels containing all 52 cards and 4 back designs.

So the total VRAM space needed is:

  • Layer 0 - 7,680 bytes but we allocate full 8,192 bytes
  • Layer 1 - 7,680 bytes but we allocate full 8,192 bytes
  • Background tiles - 8,192 bytes
  • Card tiles - 32,768 bytes
  • Sprites 1-5 - 10,240 bytes

So in total we need 66K out 128K available, we have a solution.

To make it more clear, the end result works like this:


After all those decisions were made it was a lot of tedious coding and calculating screen positions in pixels and tiles, moving data back and forth between CPU memory and VRAM.

One thing that surprised me the most was that Commander X16 is able to handle all those graphics manipulations very quickly. I was concerned that relatively narrow channel between CPU and VERA will be a bottleneck but it works very quickly and I didn’t even need to optimize the code too much.

Options and Scoring

Game support some of the standard modes of play and therefore a Options menu was needed. To display it I had to use Layer 0, because I didn't want to duplicate fonts again in tile set for Layer 1 (cards). Therefore the Layer 1 is hidden during the Options menu and then displayed again after we come back to game.



Terminology

Solitaire is classic game and there are many variations as well as ways of naming things. I use following:

Stock - is the stack of cards that we pick from at the top left part of the desk/screen. At the beginning of the game 24 cards are placed on Stock

Waste - is the stack right next to Stock where cards are placed after they are flipped from the Stock. It is called Waste because, depending on the difficulty mode you might be allowed to only recycle them once or there times. Only in Easy mode you have unlimited number of recyclings.

Foundation - those are four locations where we are placing finished stacks of cards fo the same suit from Ace to King. Once all four Foundation stacks are complete the game is won.

Tableau - those are seven stacks at the bottom of the desk/screen. They are used to strategically store cards with goal to open as many of them for placement to Foundation. At the beginning of the game the left most stack has one card, next one two and so on. Only top card is open and the rest are turned down so we don't see their suit and rank.


Scoring

Standard Scoring

+10 points for card moved from Tableau to Foundation

+5 points for card moved from Stock to Tableau

+5 points for every card turned over in Tableau

-15 points for card moved back from Foundation to Tableau

-20 points for every recycle of Stock when in Draw 3 mode

-150 points for every recycle of Stock when in Draw 1 mode

-2 points every 10 seconds when playing in Timed mode

Las Vegas Scoring

Start with -$52

Every card put to the Foundation wins you $5

There are no time or any other penalties


Difficulty

Difficulty choices of Easy, Medium and Hard affect two areas of game play:

  • Shuffling
  • Stock recycling

Shuffling algorithm

Shuffling algorithm works as follows:

In first step we distribute all cards into starting stacks:

24 cards go to Stock and 28 cards are spread across seven Tableau stacks (1+2+3+4+5+6+7). Initially there is no random distribution but we start with all four Aces and put them to the top of Stock, followed by Two, Threes etc. Once the Stock is full we place next 28 to Tableau.

Next pass does the actual shuffling. It is done by finding random pairs and swapping their positions. Swapping is done by controlling two parameters determined by difficulty of the game:

  • how many swaps are made
  • how far apart can the two positions that are being swapped be

Easy Mode - 5 pairs are swapped, cards can be only 3 positions apart

Medium Mode - 10 pairs are swapped, cards can be only 7 positions apart

Hard Mode - 15 pairs are swapped, cards can 17 positions apart

Stock Recycling

Number of passes allowed when recycling the Stock available is based on Difficulty and number of turned cards as follows:

Easy Mode:

  • Turn 1 - Unlimited passes allowed
  • Turn 3 - Unlimited passes allowed

Medium Mode (default):

  • Turn 1 - 3 passes allowed
  • Turn 3 - 3 passes allowed

Hard Mode:

  • Turn 1 - 1 pass allowed
  • Turn 3 - 3 passes allowed

Ending

For finish the classic cards animation is of course a must. Again challenge was VERA limitation of memory because we can't display so many large sprites in 16 colors, so this was solved by just displaying it tile mode. It is not as smooth as I would want it to be but I think it triggers the same nostalgia effect.



Complete Gameplay


I hope you enjoy the game if you like it and would like me to release more games and write more tutorials consider buying me a coffee.


Download the game here.

Comments

Popular posts from this blog

Commander X16 Premium Keyboard