Saturday, September 12, 2009

I'm gonna make my own FreeCell in Flash.

It probably sounds stupid, because it's likely to have been done hundreds of times before already. But I was trying out a Facebook app version of Freecell that had omitted some important key features of this game that has been a staple item of every Microsoft Windows PC since version 3.1 or so. So in my opinion, that Facebook app is broken. Thus if I can make a version of Freecell that works correctly, then I know other people can. And since there's been versions of it since DOS and Win3.1 days, it's not like it's impossible to implement all the rules correctly.

The tricky part of this game is deducting the rules from a programmatic logic standpoint. The problem is that I'm normally not a programmer. So this is a simple logic puzzle and a break from my normal routine. Let's try to think of how the thing works...

First is the layout:
You have four free cells, and you have four open dump cells (Officially its called a foundation, but since I consider it dumping cards out of the game, that's what I've called it.), then you have the cards that get laid out on the table, and you count any empty spaces on the table as an extra free cell. You have eight columns of cards laid out on the table in a random cascade, face up. And generally it's the cards from the bottom (but not only the bottom - important!) of a cascade that are put into play or dumped into the foundation squares.

The actual rules can be found at Wikipedia. So it's known what we have to work with.

Now the first thing to do is initially randomize the cards. This will involve a loop that populates an array. We know we have 52 cards in a standard deck. So we know we need a list that's 52 values long, and contains non-repeating values between 1 and 52. (Non-repeating is important, because there is only one of each card of a given suit and value.) So we use a loop that populates the array. The loop generates a random number between 1 and 52. Then it checks the array to see if the random number matches any already on the array. If there is a match, it goes and generates a new random number and tries again. If there is no match, then it adds the new number to the array. And it keeps doing this until all 52 positions of the array are filled. Easy peasy, right?

Next thing we do... Lay out the cards on the table. This is trickier. I'm thinking of using setting depths (if I recall actionscript correctly) and placing each row across. Since we have the cards in a nice random order from the previous routine, we just populate the table (in more than one way) by drawing from the array. Going across 8 columns, and then down to the next row (and a higher depth), until all 52 cards are used.

Since this is done programmatically, we also need some rules for the suits of the cards. Basically since a simple index number between 1 and 52 is the easiest and most obvious way to identify a card, that's what was done already if you haven't figured it out. But we also need to associate the card's index value with it's suit and it's color. Since I went with diamonds, spades, hearts, clubs as the order of suits, this is how associated variable values are figured out. Index numbers 1-13, diamonds. Index 14-26, spades. Index 27-39, hearts. Index 40-52, clubs. Likewise red-black, red-black. So by pulling up any index number, the function automagically lets you know what the card is. And some simple if-greater than statements and some math routines gives the value from the index number. So now we get the traditional cards suits, colors, and values based upon the index number. And again index numbers are what we use to pick and label any of the cards program-wise.

The easiest rule is for the free cells, thus the name of this solitaire card game. Any card may be placed upon an unoccupied free cell. And no other cards may move on an occupied cell. And any card in the "free" cell, may be put back into play on the table or into the dump (foundation) cells.

What's next? We have the four "dump" foundation places. The rules for dumping cards into the foundation is why we needed that variable that "knows" the suit. So we got to make some if-then statements as some rules. If foundation is empty, an ace (1, 14, 27, and 40 from the index) of any suit may go there. If a card of any suit is in the slot, then check that the suits match. If not, disallow the move. Next check to see if the value of the card being placed is that of the lower card +1. If not, then also disallow the move. Once a card is placed into a foundation position, it's no longer allowed in play.

After that, we need the rest of the rules. Which is tricker to implement. On the table, an empy position can be used by any card. Then if a card is in a playable spot, only a card of an alternate color and a value lower by -1 may be placed on it. However the tricky thing to implement is the moving of stacks of cards. (And this is where the Facebook app that inspired the idea is broken.) If you have a stack of alternating cards in downward order, then entire stacks of cards are playable based on the value of the topmost card. But the playable topmost card of a stack is determined by number of free cells and open columns on available the table. The number of cards that can be moved as a stack are 1 + open columns + free cells. (There's also some programmatic trick in the MS version that anticipates some other moves and allows even more cards, depending on how many table columns are empty.)

The tricky thing is figuring out how to keep stacks together. I'll probably have to to assign variables that tell which row and column a card is currently placed in on the table. Then it's a matter of doing some routine that swaps the depths for all the cards in play so they layout properly from a visual perspective when moved. Scripting is fun (*half-sarcastic lol*), isn't it?

And once all cards are played from the table and free cells and into the foundation cells, the game is a win. If no moves are possible to clear the table (I've still got to figure out how that works programatically, I think I'll just have a manual button in my first implementation), then the game is a loss.

I think I'll give this a shot. I already did the card graphics. Now it's time to start digging into my books and reviewing the actionscript stuff. Other things to add are some stats. Total plays, wins, losses, and win/loss ratio. Maybe some time stats too, like fastest game and average play time. (If other freecell players are like I am, they could care less about other ways of scoring.) I'm also thinking of throwing some quirky goodies into the game, that spoofs the king icon in the MS version. Maybe even have it talk and say random insults when a move isn't allowed, just to make it unique and a bit more fun.

3 comments:

Anthony said...

Hey Paul. I have saw your Bede 5 mesh and I am looking to use it for a freeware project for Microsoft Flight Simulator X. I searched around for an e-mail adress and the best i could do weas here. But drop me a line on d0ugi3 [At} hotmail . co . uk through e-mail or by messenger if you wish.

The great thing is. I have a low poly external model made which is great. Then your model is a very nice 3-D model with a fully functional cockpit which is exactly what I need to maximise performance with multiple users.

I actually help out with a company called IRIS Simulations irissimulations . com but this project is FREEWARE and has no affiliation to IRIS except for the fact, they help me with coding and such.

Thanks very much. Your work is very nice btw

Harry Davis said...

Hi Paul,
Followed your link from Renderosity forum.

Re Freecell cards, you might think about a pre-loaded string or array for a standard set of cards then pick two random locations and swap their values and in effect shuffle them. Creating random values and comparing them to existing values could start running into time even with todays processors.
Swapping values should be done at least 1.5 times the total (52) to appear random but 2 times the total would be safer.

Like your shopping cart.
Only available through one source?
Sell many?
Curious because I've got a project I'd love to get finished and market, a propeller driven steampunk car.

pauljs75 said...

Ahh... The freecell thing is a somewhat stalled project. There were some other issues I couldn't quite figure out, and then other things come up. But the thing that bugged me about the online versions I could find was the lack of "super-moves" which I believe is a MAJOR aspect of gameplay for that particular version of solitaire. I'm sure the initial randomization could be made more optimal, but since it's only done once at the beginning of a round it's not too bad. I think I borrowed the idea from a quiz randomizer I made that keeps questions from being repeats.

I could probably make the file available as it is now with some of the groundwork stuff done. And open up what Actionscript is done. It's nothing I'm all that attached to, so who knows?

As for the shopping cart... If I recall correctly I also had it on Renderosity at one point, but the demand there wasn't so strong. (Their biggest market is accessories for Poser/Daz studio figures.) Renderoisty pulls stuff that doesn't sell for 2-3 months. Turbosquid doesn't seem to pull stuff that I'm aware of. However I don't have that huge an inventory (thus not too much reputation) at TurboSquid, so my sales there are pretty slow too. (Not that the quality of my items there are bad, mind you.) The advantage there is that my stuff stays up so people can buy if they want. I think the trick with online 3D sales is to either push a lot of products heavily or sell a few things at ridiculously high prices in hopes of even just one purchase. I believe in keeping prices fair, but I likely don't move enough product to make much that way.

Odds are that I have a few good shelved items needing completion, which would sell. My problem is I'm not sure how to judge if there's enough demand in order to take on finishing them and make them available. (With some things - even the free stuff, I don't get enough feedback as it is.)