A new week, and more progress on the Solitaire project. Actually a pretty exciting week, this should be a good post. To start things off, the first thing I implemented this week was the ability to deal a game of Solitaire and play. This seemed like a good place to start since to my estimate I had already made all vital game functionality last week. So pretty quickly after starting the week I had a legitimate game of Solitaire going.

DealAndPlayGame.gif

At this point when starting the game the Deck would add all cards to the game, shuffle itself, put the card actors in order on the game board, and then deal out a game. This was great fun, and honestly I wasted a whole lot of time just playing Solitaire after this got accomplished!

WinningGame.png

WonAGame.png

That said, it didn’t take me long to realize that the next feature needed was game reset functionality. Some games of Solitaire are unwinnable, and even amongst the technically winnable games an early bad move can cost you the game later on. I went ahead and implemented a gameReset method. This method queries all CardStructures other than the Deck and determines if they have cards in them. If they do, then it transfers all cards in that CardStructure back to the deck. I implemented a little bit of special functionality here, since I wanted the deal and reset functions to employ animations, so when those cards are reset back into the deck the Sprite position is not set immediately, but rather it is animated towards the decks position. The feature then waits a short period of time for the animations to play out, shuffles the deck, puts all card actors back in order, and then deals out a new game. I’m not really on the polish part of this project just yet, but I think this looks pretty good!

ResetAndReshuffle.gif

The next feature to implement was “undo” functionality. Most every game of Solitaire that I’ve played had an “undo” function which would undo the players last move. Indeed, outside of undoing just the last move, most games I’ve played have allowed you to undo many moves. To me, this “undo” functionality sounded like a Stack data structure. I defined a new class called a CardMovement that was able to describe each kind of card movement made in the game. This boiled down to three types: a card could be individually moved between CardStructures, a group of cards (CardGroup) could be moved between Columns, and the card Stack could be reshuffled into the Deck (if the Deck was empty). Once this class was defined, I defined a Stack data structure of these objects that is retained by the GameMaster, and implemented a method of pushing CardMovements onto the stack. I then went into every drag listener employed by the game, and made creating a CardMovement that defined the movement and pushing it onto the Stack a prerequisite to completing a valid movement. Finally, I built an “undo” method into the CardMovement object, that could undo the defined movement. In it’s current state then, upon pressing ‘U’ the GameMaster will check to see if the stack is populated, and if so it will pop off the first element (last added) in the stack, execute the undo method, and dereference it. I didn’t want an unbounded data structure existing in the game, so I set a Constant (defaulted to 15 for now) that defined the maxiumum size of the stack, and if more than 15 elements are pushed onto the stack I set it up so that they fall out of the bottom.

UndoFunctionality.gif

Most Solitaire games that I’ve played had a “win on board” function, where in if the game detected that you had a “win on board” (ie you haven’t met the win condition of having all cards in the Heaps, but the board is set up so that that is assured), it would go ahead and complete the game for you. I decided that this should be my next feature. I was already checking for win conditions on every move. These win conditions were just: do all four heaps have 13 cards in them. I set about writing “win on board” conditions, and what I came up with was: are all cards in all columns turned face up, is the deck empty, and is there only one card remaining in the stack. I think that this could actually be broadened somewhat, but this seemed like a good place to start. I made a “checkWinOnBoard” method where I check for these conditions, and if they exist I made a “performWinOnBoardActions” method where it goes ahead and completes the game for you.

WinOnBoardCompletion.gif

The last couple of features I completed this week are not super obvious from a pure gameplay perspective. I realized that I wanted the board to be random, but I wanted a way to recreate the board if desired. To accomplish this, I first set up a new Random object that is used to shuffle the deck. The normal way of shuffling the deck is now this: use the singleton Random object to get a new seed integer, apply this integer as the seed for the Deck’s Random object, and then shuffle the deck, with that seeded Random as the source of randomness. This allows me to keep reference to the seed provided to shuffle the deck, if I feel like doing that. Additionally, for debuging, I can comment in some debug code that sets the seed to a known, good board value, so that during debuging the Solitaire board is shuffled/dealt the same way every time.

Finally, obviously this seeded Random object is only useful if we start shuffling from a known state. Since we have the ability to reset games, and since I didn’t want to dereference/reinstantiate objects all the time, I built in a way to sort the deck back to a known order. The deck is then always set to this order prior to shuffling, and since we know the seed of our Random, we can then always arrive at a given game board as long as we know the seed that that game board started with.

SortingFeature.png

That’s about it for the week, and honestly, this game feels pretty “complete” in that it’s a game, it has win conditions, and it’s pretty addicting to just play. However, I am planning on adding a lot more embellishements/polish to this game. Knock on wood, but my plan is to actually release it on the Google PlayStore (as well as itch.io, etc), so while I don’t think I have it in me to “out perform” any of the existing Solitaire games, I do think I have it in me to at least make a game that’s themed differently/monetized diffferently then existing offerings. Anyway, more of that to come next week!