Build a Poker Game in Corona: Game Logic

In the first part of this tutorial, we set up the project and created the game's interface. We also created and implemented a function to create a deck of cards. In this second tutorial, we will create the game logic.


Sample Application

If you want to run the sample application of this tutorial, make sure to include images for the cars as I explained in the previous tutorial. Don't forget to include and update the dataSaver library mentioned in this tutorial.


1. enableDealButton

Update the implementation of the enableDealButton function as shown below.

We first call disableDealButton, which removes any previously added listeners, and add a tap listener, which invokes doDeal. The addEventListener method accepts an event and a callback. There are a number of events you can listen for, depending on the context in which you are calling it.


2. disableDealButton

As I mentioned in the previous section, in disableButton we remove any previously added listeners.


3. enableBetButtons

In enableBetButtons, we add tap listeners to betMaxButton and betButton, and give the player some instructions on how to place their bet.


4. disableBetButtons

As in disableDealButton, we remove any previously added listeners in disableBetButtons.


5. enableHoldButtons

In enableHoldButtons, we loop through the holdButtons table and add a tap listener to each button.


6. disableHoldButtons

In the disableHoldButtons function, we also loop through the holdButtons table, but we remove previously added listeners instead of adding new listeners.


7. generateCard

The implementation of generateCard requires a bit more explanation. We first generate a random number from 1 to the length of the deck table. We then create a temporary card using deck["randIndex]..".png" and store a reference in tempCard. What deck["randIndex]..".png" does, is grab a random element from the deck table, which would be something like c1 or h5 and adds .png to it. Because Lua is a dynamic language, we can add new properties to the objects. In this example, we add a isHolding property, which tells us whether the player is holding the card, a cardNumber property by getting a substring of the chosen deck element, and we do the same for the cardSuit property. Finally, we remove the chosen element from the deck table and return the array.


8. getCard

In getCard, we set the cardPosition, which is the x coordinate of the first card in the game's interface. We generate a card, add it to the playerHand table, and pass in a cardIndex variable, which will be a number between 1 and 5, representing one of the five cards. This enables us to position the cards in the proper order in the playerHand table. We set the position of each card by using an offset of (93 * (cardIndex - 1)). This means that the cards are 93 pixels apart from one another.


9. holdCard

In holdCard, we first obtain a reference to the button that was pressed by using its buttonNumber property. This enables us to check whether the card is in the playerHand table. If it is, we set isHolding to false and update the card's y coordinate. If the card isn't in the playerHand table, we set isHolding to true and update the card's y coordinate. If the player chooses to hold the card, it's y coordinate is decreased, which means the card is moved up slightly.


10. resetCardsYPosition

In resetCardsYPosition, we loop through the playerHand table and see if any of the cards are being held. The ones that are, are moved back to their original position using the Transition library. The Transition library makes it very easy to move objects around and tween their properties.


11. Persisting Data Across Sessions

We want our game to be able to persist values or data across sessions. We can build a solution ourselves using Corona's io library, but in this tutorial we are going to use a third party solution. Arturs Sosins has made a handy little module for persisting data across game sessions.

Download the library and add the two files it contains to your project. To make use of the library, add the following line at the top of main.lua.

To make the library work in our project, we need to make a few minor changes to dataSaver.lua. Open this file and change require "json" to local json = require "json".

Change:

To:

The second change we need to make is change all the occurrences of system.ResourceDirectory to system.DocumentsDirectory as shown below.

Change:

To:


12. createDataFile

To set up a data store, insert the following code snippet below the setupTextFields function. Make sure to include the function definition as we didn't stub this function in the previous tutorial.

In createDataFile, we first attempt to load the gameData key from the saver into the gameData variable. The loadValue method returns nil if the key doesn't exist. If it doesn't exist, we initialize the gameData table, add numberOfCredits and numberOfGames properties, update the respective text fields, and save the gameData table by invoking saveValue on saver. If the key does exist, then we've already done this and we can populate the text fields with the correct values.

In the next step, we invoke the createDataFile function in the setup function as shown below.


13. betMax

In betMax, we start by loading our data into gameData. If the number of credits is greater than or equal to 15, we go ahead and call doDeal. Otherwise, the player does not have enough credits to bet the maximum of 15 credits and we show the player an alert.


14. bet

In the bet function, we enable the deal button and remove the listener from betMaxButton. Since the player is doing a regular bet, she cannot play a maximum bet at the same time. We need to check if the number of credits is greater than or equal to 5 to make sure that the player isn't trying to bet more credits than they have left. If betAmount is equal to 15, we call doDeal as they've bet the maximum amount.


15. doDeal

The doDeal function coordinates the dealing of the cards. If it's a new game, we deal the initial hand. Otherwise, we deal the player new cards.


16. dealInitialHand

We disable the bet buttons in dealInitialHand and enable the hold buttons. We invoke getCard five times, which generates the initial five cards. We then load gameData, update currentCredits, calculate newCredits, update credit text field, and save gameData.


17. dealNewCards

In dealNewCards, we check whether the player is holding a card. If they are, then we get a reference to the current card, call removeSelf, set it to nil, and get a new card by invoking getCard(i).

Whenever you remove something from the screen, you should always set it to nil to make sure it is setup for garbage collection properly.

18. getHand

The getHand function determines the player's hand. As you can see below, the function is pretty involved. Let's break if down to see what's going on. Start by implementing the getHand function as shown below.

We start by calling table.sort on the playerHand table. The sort method does an in-place sort, it uses the operator to determine whether an element of the table should come before or after another element. We can pass a comparison function as the second argument. In our example, we check whether the cardNumber property is less than the previous one. If it is, then it swaps the two elements.

We then create a frequencies table, populate it with thirteen zeros (0), loop through the playerHand table, and increment each index's number if the playerHand contains that number. For example, if you had two three's and three fives, then the frequencies table would be 0, 0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0.

In the next step we declare and set a number of local variables that we need in a few moments. We then loop through the frequencies table and check the numbers to see if the index contains a 2, which means we have a pair, a 3, which means we have three of a kind, or a 4, which means we have four of a kind. Next, we check the number of pairs, three of a kind, and four of a kind, and update the winningHand and cashAward values accordingly.

To check for a Royal Straight, we need to check if the first card is equal to an ace and the remaining cards would be ten, Jack, Queen, and King. To check for a regular Straight we loop through the playerHand and check if each subsequent cardNumber is one greater than the previous. To check for a Flush, we check if all the cards cardSuit keys were equal to the first card's cardSuit key.

At the end of getHand, we invoke awardWinnings.


19. awardWinnings

In awardWinnings, we show the player what hand they have in their hand and update the gameData settings. We save gameData and invoke newGame with a delay of three seconds.


20. newGame

In newGame, we go through and reset all the variables, create a new deck of cards, and check if gameData.numberOfCredits is equal to zero. If it is, then the player has expended all their credits so we award them 100 more credits. Finally, we update the text fields.


21. Testing the Game

Update the setup function by invoking the createDeck function as shown below and test the final result.


Conclusion

In this tutorial, we created a fun and interesting Poker game. We did not implement the button to cash out yet, but you are free to do so in your game. I hope you learned something useful in this tutorial. Leave your feedback in the comments below.

Tags:

Comments

Related Articles