Tuesday, January 14, 2020

Video Poker, Part 2

Selecting the Cards


Now the player is in a position to select cards to use. We need a way of letting the player know that the card is selected which is why we have the draw movies. This movie is a single frame movie which contains the word “DRAW” in bold red letters. It is placed over each of the cards and is set to be hidden until made visible. These movie clips were placed in the “Info” layer on the first frame and, if you recall, were hidden in the game initialization method. The movie clips are labeled, “draw1_movie,” “draw2_movie,” “draw3_movie,” “draw4_movie,” and “draw5_movie.”

The logic to handle selecting and unselecting code was already written above but before the game can actually let the player select or unselect a card the game needs to tell the program that selections are allowed. We also need a way for the player to tell the game that it is finished selecting cards so the game can continue. This is the select button on the bottom right of the screen which we add in frame 50 and name “draw\_btn”.  On frame 50 we tell the global video poker game class to activate card selection and the select button using the following two lines of code.

this.stop();
videoPokerGame.activateSelectButton();

The activateSelectButton method is a function that we need to write in the global script. It simply sets the global variable “selecting” to true and then activates the draw button to enable the player to start the game. Clicking on the draw button calls a handleSelect event which simply removes the listener from the button and continues playing the video poker movie.

VideoPokerGame.prototype.activateSelectButton = function()
{
this.selecting = true;
this.drawHandler = this.handleSelect.bind(this);
this.vpMovie.draw_btn.addEventListener("click", this.drawHandler);
}
VideoPokerGame.prototype.handleSelect = function()
{
this.selecting = false;
this.vpMovie.draw_btn.removeEventListener("click", this.drawHandler);
this.vpMovie.play();
}

The movie from frame 51 to frame 155 handles the drawing of the cards which we will cover next.


Drawing the Cards


The drawing of new cards to replace selected cards is done on a per card basis so that Adobe Animate CC can animate the cards being replaced. The code to handle the drawing of the cards is similar for all the cards so we can create a simple utility function to handle the drawing. As this function needs to be accessed by code in different frames, we will make this utility function part of the VideoPokerGame class so the code is in the global script. As you can see, this function simply removes the draw state, hides the draw movie, and then sets the card’s value to the next card in the deck.

VideoPokerGame.prototype.drawCard = function(slot)
{
this.drawMovie[slot].visible = false;
this.hand[slot].setCard(this.myDeck.draw());
}

The draw animation consists of the card being removed followed by the new card being moved into place. This is simply a motion tween going from the full sized card to the small card hidden at the bottom of the screen. This is followed by a small card at the top of the screen motion tweened to a full size card. For the “FLCard” layer the removal tween is on frames 56 to 65 and the drawing tween is on frames 66 to 74. The “Lcard” layer has the removal tween on frames 76 to 85 and the drawing tween is on frames 86 to 94. For the “CCard” layer the removal tween is on frames 96 to 105 and the drawing tween is on frames 106 to 114. The “Rcard” layer has the removal tween on frames 116 to 125 and the drawing tween is on frames 126 to 134. Finally, the “FRCard” layer has the removal tween on frames 136 to 144 and the drawing tween on frames 146 to 154. The Figure \below shows the second half of the video poker timeline where drawing happens.



Right now all the cards are being drawn, and the value of the drawn card is the same value that the card already was. To fix these problems we are going to need to add some java script as well as a few more labels. Let us start by adding some code to the “Code” layer of  frame 55 which was labelled “Draw_1.” This code simply checks to see if the card is one of the cards that was selected to be replaced and if it is not skips over the replacement animation for this card. 

if (this.draw1_movie.visible == false)
this.gotoAndPlay("Draw_2");

If the card is not being drawn, we are done. If the replacement animation plays, however then we need to draw a card to replace the draw card. Once the card has been removed from the screen, we can then draw a card. This is done by calling the function we created earlier in this section. Notice that we use the array index of the card in the function, which is one less than the card that we are on. This is one area where API design can bite you in a project. If this was a team project where non-programmers were calling our API then using the semantics that the artist was expecting would make sense. In this case, we could have had the draw card function assume that the caller was referring to the human number and deduct 1 from the passed number. Ideally you would want to document decisions within the API documentation, but surprisingly this rarely happens and has bitten me a number of times when working with third-party libraries. 

In addition to the code for replacing the card, on Frame 66, we add a draw card sound to the Sound layer so that the sound of a card being drawn is played while the card is being animated in.

playSound("drawwav");

The above procedure is used for the other 4 cards with the draw sound being played on frames 86, 106, 126, and 146. The code is probably self explanatory, but for the sake of completeness I will show the code.

Frame 75 which is labelled “Draw_2”:

if (this.draw2_movie.visible == false)
this.gotoAndPlay("Draw_3");

Frame 86:

videoPokerGame.drawCard(1);

Frame 95 which is also labelled “Draw_3”:

if (this.draw3_movie.visible == false)
this.gotoAndPlay("Draw_4");

Frame 106:

videoPokerGame.drawCard(2);

Frame 115 which is also labelled “Draw\_4”:

if (this.draw4_movie.visible == false)
this.gotoAndPlay("Draw_5");

Frame 126:

videoPokerGame.drawCard(3);

Frame 135 which is also labelled “Draw\_5”:

if (this.draw5_movie.visible == false)
this.gotoAndPlay("Results");

Frame 146:
videoPokerGame.drawCard(4);

Finally we extend all layers to frame 155, label this frame “Results”. Calculating the results of the hand is the most complicated part of the game which we will cover in the next section.

Calculating the Win


The results of the hand can now be calculated. While this work is all done in a single function, the work is kind of complicated. For that reason, I will be breaking the function into a series of sections so I can better explain the logic behind the function. It would have been possible to break down the function into a number of smaller and more specialized functions, which may be a good idea as it simplifies the logic but at a cost of a lot of overhead and duplicate code. If I was going to refactor this function, I would turn it into it's own class so duplicate code could be reduced and the steps broken into separate private methods.

The first thing that is done is the cards are sorted by their face values. Face values are calculated by using the modulus (remainder) of dividing the deck by 13. To make this work, the card ID is reduced by 1.

VideoPokerGame.prototype.findResults = function()
{
var sortedCards = new Array(5);
var cntr1, cntr2, temp, low, testA, testB;
for (cntr1 = 0; cntr1 < 5; ++cntr1)
{
sortedCards[cntr1] = this.hand[cntr1].getCard();
}
// sort, by face value
for (cntr1 = 0; cntr1 < 4; ++cntr1)
{
low = cntr1;
for (cntr2 = cntr1 + 1; cntr2 < 5; ++cntr2)
{
testA = (sortedCards[low] - 1) % 13;
testB = (sortedCards[cntr2] - 1) % 13;
if (testB < testA)
low = cntr2;
}
temp = sortedCards[low];
sortedCards[low] = sortedCards[cntr1];
sortedCards[cntr1] = temp;
}

Next, we prepare all the variables that we are going to need to find the results. We use pairFace to track which card we are trying to match for a pair or triple or quad. We assume at the beginning of our testing that we have a straight and a flush until either of these assumptions are proven wrong during our analysis of the hand. The run is the longest number of matching faces so a run of 2 is a pair, a run of 3 is three of a kind, and a run of 4 is four of a kind. The suit of the first card is the suit we are looking for in the other four cards to determine if we have a flush.

var pairFace = 0;
var isStreight = true;
var isFlush = true;
var longestRun = 0;
var numRuns = 0;
var targetSuit = Math.floor((sortedCards[0] - 1) / 13);
var curRun = 1;


To be a flush, all suits must be the same, so we simply check to see that the suit of the current card in the loop is the same as that of the first card. To see if we have a pair or better, we track the run length of the current card by counting how many cards in a row contain the same face value. As it is possible for more than one pair, we also count how many different face cards are matching. Likewise, to handle a full house, we need to know the length of the longest run of matching cards. Straights are simply a test to make sure that the face value of each card in the sorted hand increases by one (taking into account the fact that an ace can be in two possible positions).


for (cntr1 = 1; cntr1 < 5; ++cntr1)
{
if ( Math.floor((sortedCards[cntr1] - 1) / 13) != targetSuit)
isFlush = false;
testA = (sortedCards[cntr1 - 1] - 1) % 13;
testB = (sortedCards[cntr1] - 1) % 13;
if (testA == testB)
{
isStreight = false;
++curRun;
}
else
{
if (curRun > 1)
{
if (curRun > longestRun)
longestRun = curRun;
curRun = 1;
++numRuns;
pairFace = testA; // if only a pair, need to know face value
}
if (((testB-testA) != 1) && ((testA != 0) || (testB != 9)))
isStreight = false;
}
}
if (curRun > 1)
{
if (curRun > longestRun)
longestRun = curRun;
++numRuns;
pairFace = testA; // if only a pair, need to know face value
}

Analysing the results is the last stage of determining what the hand was. This is done by using the various variables that were set in the analysis phase above and going from the highest value hand down to the weakest hand checking at each hand to see if we meet the criteria for the hand continuing until we have met the criteria for a hand or have a high-card.

// Now analyse results
if ((isStreight & isFlush) == true)
{
if (((sortedCards[4] - 1) % 13) == 12)
{
this.message = "ROYAL FLUSH!!!";
this.lastWin = 250 * this.bet;
}
else
{
this.message = "Streight Flush";
this.lastWin = 50 * this.bet;
}
}
else if (longestRun == 4)
{
this.message = "Four of a Kind";
this.lastWin = 25 * this.bet;
}
else if (longestRun == 3)
{
if (numRuns == 2)
{
this.message = "Full House";
this.lastWin = 9 * this.bet;
}
else
{
this.message = "Three of a Kind";
this.lastWin = 3 * this.bet;
}
}
else if (isFlush)
{
this.message = "Flush";
this.lastWin = 5 * this.bet;
}
else if (isStreight)
{
this.message = "Streight";
this.lastWin = 4 * this.bet;
}
else if (numRuns == 2)
{
this.message = "Two Pairs";
this.lastWin = 2 * this.bet;
}
else if ( (numRuns == 1) && ((pairFace == 0) || (pairFace > 9)) )
{
this.message = "Jacks or Better";
this.lastWin = this.bet;
}
else
{
this.message = "Nothing";
this.lastWin = 0;
}
this.cash += this.lastWin;
return (this.lastWin > 0);
}

Of course, being able to determine the results of a hand is not of much use unless we do something with those results so in the next section we will actually call this method and handle the results of doing so.

Handing the Results


In the results frame we have code that will call the find results method we wrote in the previous section. This code goes to the bet loop immediately if the result of the hand wasn’t a winning hand, otherwise the movie continues playing to give us time to show the results.

var didWin = videoPokerGame.findResults();
videoPokerGame.updateText();
if (didWin == false)
this.gotoAndPlay("BetWait");

To make winning more exciting Video Poker machines have bells and whistles go off when you win anything. This is part of the psychology of gambling and is a reinforcement factor to make the player more excited so they keep playing the game. The bell sound I use is a bit more subtle but still emphasizes that the player has won something so that is placed in frame 156. 

Finally we skip over some frames (so the result message will be shown for a few seconds) and we then place our final “Code” layer key-frame, which simply contains one line of code which goes back to the “betWait” frame.

this.gotoAndPlay("BetWait");

With that we have a complete Video Poker game. For those who want to take this a bit further It is not that difficult to modify the game to support the different types of Video poker such as deuces wild or variants that include a joker. Likewise creating a better deck of cards and running the game at a high-definition resolution would also be simple enough to do.  For the more ambitious people out there, this could be expanded into a full poker game, possibly even a multi-player game.

Have fun and when you are ready come back and explore the world of board games with Pent Up Anger.

Sunday, December 15, 2019

Video Poker Part 1

As I only want to deal with 1 blog, I am posting the first half of chapter 8 of my "Creating HTML5 Games using AnimateCC" eBook at https://homebrewgamejam.blogspot.com/2019/12/video-poker-part-1.html where we cover the creation of my Video Poker game.

Saturday, October 19, 2019

Porting Halloween Liche

My first real post and for some reason it is not showing up on my home page. For those who are interested in learning how I ported Halloween Liche from Flash to HTML5, the link is http://spelchan.ca/?p=10 I will continue fighting with wordpress but if I keep having issues will have to come up with a new plan.

Saturday, October 5, 2019

When Blogs Collide

I have concluded that having two separate blogs is just too big of a pain. I am also thinking that posting chapters one section at a time is not the best approach. If I was to post entire chapters at a time would be more useful to anyone wanting to read my work. This obviously means that I will not be posting the new blog every week but instead will be cutting down to a long post once a month. Chapters from my animate (and possibly create.js) eBook will be posted once every 3 to 4 months, with posts on other subjects in between the chapter posts. The in-between posts will be about Spelchan.com content, game-jam or home-brew content, and articles related to what I am researching with the odd miscellaneous soapbox post appearing related to whatever thing got me angry enough to write a post.

This leads to the next question as to where these posts will appear. While I have nothing against blogger, I would prefer that it was on a site that I control. For that reason I set up WordPress on my Spelchan.ca site so my blog posts will appear on Spelchan.ca while my games appear on Spelchan.com. For the next while, I will probably be posting TLDR summaries on this blog for a while.

The first post will be on Halloween Liche and will be posted in the middle of October.

Saturday, September 21, 2019

Creating the Deck class

Last section we created tests for building our deck class. Now we are ready to create a deck class. Initially we will create the code within the testDeck.html file but once it is functional move the code into the Deck.js file so it can be used by our various card projects. While it is certainly possible to create the code entirely within the Deck.js file and import that file, for prototyping it is often faster to write the code within the test file and iterate over the code before moving it to the appropriate class as during prototyping the structure of the code may change multiple times so keeping it outside of the main code-base until it is stable can make maintaining the project easier.

This class needs to hold 52 cards in a deck, deal out those cards, and shuffle those cards. First, we are going to need to create the constructor function for this class. This will just create an array for itself to hold the deck and fill that array with in-order values. We also set the index for where we are going to grab cards to the top of the deck.

spelchan.Deck = function()
{
this.cardArray = [];//new Array(52);
for (var cntr = 0; cntr < 52; ++cntr)
this.cardArray[cntr] = cntr + 1;
this.nextCardIndex = 0;
}

This means that we now have a deck of cards but running the test will still fail. While the card ids are in the deck, the deal method is not dealing them out! Dealing out a card is simply the matter of returning the card at the nextCardIndex while increasing the index.

spelchan.Deck.prototype.draw = function()
{
var rv = this.cardArray[this.nextCardIndex];
++this.nextCardIndex;
return rv;
}

Running the tests now show us that we are getting there but the shuffling is not sufficiently random enough to pass our test. This is because we are not shuffling the deck yet. We are going to need a way of shuffling the deck. Think about the different ways to shuffle a deck. There are many ways of shuffling, but most of them are inefficient as far as the computer is concerned. What our goal is, simply stated, is to make the cards in the deck appear in a random order. I realized that taking each card and swapping it at random with another card would be a very good way of shuffling as the computer can do this blindingly fast with really good results. While I came up with this algorithm on my own, my Algorithms teacher did tell me that I was not the first person to think of this and that this is like the technique that shuffling machines use.

spelchan.Deck.prototype.shuffle = function()
{
var cntr, temp, rnd;

for (cntr = 0; cntr < 52; ++cntr)
{
rnd = Math.floor(Math.random() * 52);
temp = this.cardArray[cntr];
this.cardArray[cntr] = this.cardArray[rnd];
this.cardArray[rnd] = temp;
}
this.nextCardIndex = 0;
}

Now when we run the test we see that all the tests have passed. We are now ready to start planning the tests we will be needing for a video poker game. There are other things that we could probably add to this class, but I have discovered over my years that it is easy to refactor and to add things later, especially if you have a testing framework to verify your changes don’t break anything. One tenant of Extreme Programming is to only write the code that you need. We have all that we need for video poker, so next chapter we will start working on a video poker game!

Saturday, September 7, 2019

Test Driven Deck

While having a plan for testing your code is important, Test Driven Development (TDD) takes this to another level. The idea here is that you write automated tests before you start writing the code. When it is practical to do this, it is an incredibly good way of creating code. Planning tests gets you thinking about the code you are going to write – hopefully with an idea of the fringe cases that you are going to encounter. Writing the tests give you something to check the code against. All tests should initially fail, with a successful test likely indicating either an error with the test or an error with the test plan.

You then write the code and run it against the tests trying to pass one test at a time. Once you have passed all the tests and no missing tests have been discovered, you are finished the code and can start planning the tests for the next piece of code that you need to write. Having automated tests also means that it is easy to have the tests running frequently while you do other things and if something breaks then you know right away and as it is likely what you (or someone on your team) is currently working on, it will be trivial to fix the bug! Remember that in general the quicker you can find a bug, the less it will cost to fix it. This cost is in time, but can also be in money if the bug is in a production version and you have marketing and patching costs in addition to the cost of finding and fixing a bug.

We have a card class that can display any card, so what we need next is a deck of cards. This deck needs to be able to be shuffled and we need to be able to deal cards from the deck. So, how would we test such a beast?

In a sorted deck, the cards should be from 1 to 52 so simply drawing cards from a sorted deck and making sure they are in sequence would solve this problem. A shuffled deck, however, has two issues that we need to check for. First, we want to make sure that all the cards are in the shuffle (that we haven’t duplicated cards losing some cards or other similar problem). Next we want tom make sure the cards are not in order. Simply checking to see the card is different from its position in the deck will not work as we would expect that at least some of the time a randomly shuffled card would end up in the proper deck position. A good shuffle would have at least half the cards in a different position so simply counting how many cards don’t match would suffice most of the time.

As the deck class can be written without the card class, as it uses card IDs and not instances of cards, it is possible to write the deck class in its own html file which I called deckTest. This starts off with your typical html5 boilerplate followed by a simple version of the Deck class with none of the necessary methods implemented.



Deck JavaScript Test


test results go here





Now some of you may have noticed that there is a lot of test code here. This is the downside to test driven development. You will often end up with test code that is the same size as the code that you are testing, and sometimes even larger. The plus side is that you know your code works within the testing parameters and if you refactor or change code you will be able to check to make sure that nothing you have done is broken. Manual testing could have been done with a lot less code. As always there is a trade-off that must be made. In a solo environment, and possibly a small team, manual testing may be adequate and may be productive enough. As you start to get to larger teams, people inadvertently mucking up other people’s code happens a lot more often than you would expect.

Saturday, August 24, 2019

The Importance of Testing

Before you write any code you should have a way in your mind to test the code in order to make sure that the code does what you want. There are many types of tests but when you get right down to it, all tests are either manual or automated. Manual tests tend to be the easiest to implement as they just require some code that can be observed to be doing the correct thing. As games tend to be dynamic in nature, manual testing is very common in game development as coming up with automated tests is not always practical. Automated tests, however, are always preferable when possible to do so due to the simple fact that people do not have the time to go through hours of manual testing just to make a minor change. This means that most manual tests will only be run on rare occasions so that something may be broken for months before it is discovered making finding out why it broke difficult.

Due to the visual nature of the cards, automatic testing is not really that practical so we will resort to manual testing. More to the point, as the cards are poignant to the game, any problems with the card class will be detected immediately so manually testing them is not much of a risk. A very simple test program can be created to make sure that the card class works the way it is supposed to.

Create a new “CardTest” movie for holding the test. Copy the Card movie clip into this movie. This can be done by having a file with that movie open in another tab then in the library tab selecting that file and dragging the Card movie onto the stage. Make sure that the layer holding the card extends to the second frame. Add a layer for holding code and in the second frame create a blank keyframe in the code layer. Right-click and chose add actions to bring up the code editor for editing JavaScript on that frame. Here is the test code:

var firstCard = new spelchan.Card(this.firstCardMovie);
firstCard.setCard(1);
this.firstCardMovie.addEventListener("click", nextCard);
this.stop();

function nextCard(e) {
if (firstCard.faceShowing)
firstCard.setCard(firstCard.cardID + 1);
else
firstCard.showFace();
console.log("face: " + firstCard.getFaceValue() +
" suit: " + firstCard.getSuit());
}

While in the actions editor, make sure to add the Deck.js file to the includes by expanding the global list of scripts then selecting the include option and clicking on the + to add a script. Browse to find the script.

You can now simply click on the card to show the first card in the deck and keep clicking on the cards to loop through all the cards that make up a deck. This is a very simple test but one that confirms that the Card class is working as expected. Proponents of the technique known as test driven development would start with the test code and then write the actual code as we will see when creating the deck class that deals with handling a deck of cards.