Saturday, September 17, 2011

The Game of Video Poker

Prerequisites
This is a continuation of previous works.
You would need to read "Console Poker" first.

Quick Start
If you just want to play the game, go to the Source Code section below.


Game Flow
There would be a deal button in the screen. Once it is pressed, five cards would be dealt to you.

If the initial deal forms a winning pattern, you would hold all the cards and press the deal button again. Otherwise, you may hold any number of cards, hoping that the second deal would improve the chance of winning.

The cards are actually buttons and therefore are clickable objects. Clicking on them would change the hold status.

Image Buttons
We can apply a image to the JButton component. But first of all, we must have the card image on hand.
Drawing a playing card is not difficult, and this is already demonstrated in a previous article. For details, read :

We will reuse the file CardPanel.java in the above article. Actually, all we need is the createImage() method, which would be called during initialization in VideoPoker.java

Note that VideoPoker.java will be the only source file created in this article, all other source files come from previous works. This is one of the important software design principle :

Don't reinvent the wheel

Poker Patterns
The table of winning patterns and payouts are shown in the previous article "Console Poker" The game flow logic are inside the source file ConsolePoker.java in the above article. This file will be reused here.


Design
Ideally, the GUI should be separated from the game logic, this is not 100% true in this sample, but it is getting close.

  • ConsolePoker.java - game flow logic
  • VideoPoker.java - GUI components
Auxiliary files :
  • Poker.java - the pattern matcher
  • Pattern.java - define pattern constants
  • CardPanel.java - create card images

Source Code
You will need all the five java files in the same folder.

  • VideoPoker.java - GUI components
  • ConsolePoker.java - game flow logic
  • Poker.java - the pattern matcher
  • Pattern.java - define pattern constants
  • CardPanel.java - create card images

To compile :
javac *.java
To run :
javac VideoPoker
Only VideoPoker.java is new in this article, all other source files are from previous works. Anyway, all of them will be listed here for your convenience.



ConsolePoker.java
Originally defined in : Console Poker




Poker.java
Originally defined in : Console Poker




Pattern.java
Originally defined in : Console Poker




CardPanel.java
Originally defined in : How to display a deck of playing card in a panel ?


Friday, September 9, 2011

Console Poker

Introduction
We are going to write a game of video poker. Typically, it should have a graphical interface. However, to make thing simple, we will start coding the game with a console interface first. The graphical interface will be presented in the next article.

Game Flow
This will be a text mode game and the user will be required to input the command with the keyboard. The only commands are "deal" and "hold". The user will input "D" for "deal", and input a sequences of digit for holding cards. For example, entering "124" will hold the first, second and the forth card.

Sample Run
In the following, the user entered 'D' to draw five cards at random, he then enter "245" to hold the second, forth and the fifth card, and replace the remaining cards with other randomly picked cards. Finally he got "three of a kind" which is a winning pattern.

java ConsolePoker
Credit : 50     Enter 'D' to deal : D
C7 C3 H4 S3 H3
Hold : 245
C6 C3 DK S3 H3
Three of a kind
You win 15
Credit : 60     Enter 'D' to deal :
Example 2 : In the following case, the user entered 'D' to get five cards from deck, which already formed a pair. He held the second and the third card by entering '23' at the command line. He was lucky enough to draw another Jack and two Queens to get a "Full House" winning pattern. Then he played again, held the first and the third card, but this time he was unable to improve the pattern and he lost 5 credits. The game will continue until the credit goes below zero.
java ConsolePoker
Credit : 50     Enter 'D' to deal : D
DK CJ SJ S4 H8
Hold : 23
HJ CJ SJ HQ DQ
Full house
You win 45
Credit : 90     Enter 'D' to deal : D
H3 DQ C3 SK H2
Hold : 13
H3 S7 C3 S4 C2
Nothing
You lose
Credit : 85     Enter 'D' to deal :



Winning Patterns and Payout Table

PatternsPayout
Jacks or better1
Two pair2
Three of a kind3
Straight4
Flush6
Full House9
Four of a kind25
Straight Flush 50
Royal Flush 800


The Pattern class
Since the name and the payout are the two attributes of a pattern, it is natural to define a Pattern class with two attributes :

// Define constants for winning pattern
class Pattern
{
  String name;
  int payout;

  private Pattern(String name, int payout)
  {
    this.name = name;
    this.payout = payout;
  }
}


Private Constructor
The above Pattern class has a private constructor, that means no other class can define new instances of Pattern. So we must declare the Pattern constants inside the pattern class. This technique is useful to represent a predefined set of constants.


Rewriting the Pattern matcher
We are now going to rewrite Poker.java presented in the previous article

We have already defined a method known as getPatternName() Now we are going to define another method known as getPattern() to replace the above one. Now we no longer need getPatternName(). But to maintain compatibility, you may define a new one if you wish :

Game Control
Now we can define the game control of the Console Poker. If you have read the sample run above, it should be easy to understand.


Full Source Code

You will need Pattern.java, Poker.java and ConsolePoker.java in the same folder to run the game.

To compile :

javac *.java
To run :
java ConsolePoker
I will present the full listing of the three files below. You may double click on the source code to make a copy for yourself.



A little hints
Pattern.java is simple.

Poker.java is just a copy from the previous article, see the related article section for details.

ConsolePoker.java is the main game flow and it is not difficult to understand if you try to play the game yourself.



List 1 : Pattern.java


List 2 : ConsolePoker.java


List 3 : Poker.java


Related Articles


Coming next
A graphical interface of the same game will be presented. We will reuse the three source files in this article and just write a graphical interface on top of that.

Saturday, September 3, 2011

Poker Pattern Matching

Related Articles : If you didn't read "Probability by Counting", read it first.

Suppose you have drawn the following five cards from a deck :
C7 S2 S4 D8 H7

Recall that we use two characters to represent a card, the first character represents the suit and the second represents the point. Hence C7 means the Seven of Club, S2 means the Two of Spade, etc.

To recognize whether there is pair, we sort the five cards by points :
S2 S4 C7 H7 D8

Then we may compare consecutive cards to count the number of potential pairs. Note that the number of potential pairs not necessary means actual pairs. For example :

cards :S3 S7 C7 H7 D9
index : 0  1  2  3  4
card[1] and card[2] potentially forms a pair, so does card[2] and card[3]. Hence the number of potential pairs is two. But actually this is not a "two pair" pattern. It is known as a "Triple" pattern.


Pair Recognition
For any five card combination, it is straight forward to recognize whether it is a "pair pattern" in the poker game. Just count the potential pair formed by consecutive cards. If the result is one, then it is a "pair pattern".


Jack or Better
For the game of video poker, a pair is not necessary a winning pattern. You need to get a pair of "jack or better" in order to win. It is easy to modify the method isPair() to recognize a "Jack or Better" pattern.


Two Pairs
A "two pairs" recognizer is similar to a "pair" recognizer, it just counts the number of potential pairs form by consecutive cards, but it must be clever enough to understand that "a potential pair is not necessary an actual pair". The above comment says "In the caller, we must exclude the "triple" pattern". You will see how this is done in subsequent section.


Four of a kind
There are only two possible patterns : XXXXY or XYYYY. Therefore, two "if statements" would be sufficient to do the task.


Triple
It is also known as "Three of a kind". It is very similar to the above recognizer. Just like the "two pairs" recognizer, it is incomplete and expect some checking in the caller. The caller will be provided later. You will see it is much easier than you think.


Full House


Flush
The recognizer just need to make sure all the cards are of the same suit.


Straight
A recognizer for the "straight pattern" should ignore the suit of all cards. The first thing we should do is to remove the suit. For example, if we have the following cards :

{ "S2","S4","C7","H7","D8" }
The above cards are already sorted by points. Removing all the suit would become :
 "2","4","7","7","8" 
We can define a string to hold the point pattern.
String pointPattern="24778";
Of course it should not be hard coded and it should be built from the card list. Once we have the pointPattern on hand, we can compare it against a predefined list of "Straight patterns". See the following code segment for details.


The caller
We have seen several comments about what the caller must do. For example, in the implementation of isTwoPair(), the comment says "the caller must exclude the triple" pattern. Actually, if we implement the caller with a priority, we don't need extra checking at all.

If a pattern is a full house, then it is not a triple.
If a pattern is a triple, then it is not a "two pairs".
We just check the pattern in the priority order, and the result would be correct. See the code below and you will understand.


Demonstration
We are going to write a program that draws five card from a shuffled deck, then display the name of the pattern. A sample run follows :

java Poker
D8 S7 C7 H3 C3
Two pairs

java Poker
S6 C5 SA H3 HT
Nothing

java Poker
D6 S2 H2 D5 H6
Two pairs

java Poker
SA S7 H4 D4 HT
Nothing

java Poker
H5 CA ST H9 HT
Nothing

java Poker
S9 D3 SJ H5 CJ
Jack or better

Saturday, August 27, 2011

Probability by Counting

Related Articles


Poker Probability

Suppose you draw five cards from a shuffled deck, what is the probability of getting a pair ?

Card Representation

Let's represent the five drawn cards in an array of String. For example :
String[] cards = {"S5,"SA","D6","H7","CT"};
Which means the five of Spade, the ace of Spade, the six of Diamond, the seven of Heart and the ten of Club. In the related article section, you may see some practical use of this representation in shuffling and displaying the cards.

Sorting the Cards

if we sort the card array, then it is easy to determined whether it contains a pair. All we have to do is just to compare consecutive cards.
boolean pair=false;
if (samePoint(cards[0],cards[1])) pair=true;
if (samePoint(cards[1],cards[2])) pair=true;
if (samePoint(cards[2],cards[3])) pair=true;
if (samePoint(cards[3],cards[4])) pair=true;

Array sorting is easy and you may see the series of "Sorting in Java" in the related articles section.

You may write four compare statements as above, or you may write a for loop as follows :

boolean pair=false;
for (int i=0;i<cards.length-1;i++)
  if (samePoint(cards[i],cards[i+1])) pair=true;

Strict Definition of a "Pair Pattern"


In the game of poker, typically we don't consider a triple as a pair. We don't consider full house as a pair. We don't consider "two pairs" as a pair. Therefore we must refine the above implementation to handle the following patterns :
PatternsRemarks
AAABCThis is known as a triple and is not considered as a pair
AAABBThis is known as a "full house" and is not considered as a pair
AAAABThis is known as "four of a kind" and is not considered as a pair
AABBCThis is known as "two pairs" and is not considered as a pair
AABCDThis is known as "a pair" and is what we want

Fortunately, it is easier than we think. All we have to do is to ensure there is one and only one pair.


Counting the probability


Just generate all five card combinations out of a deck of 52 cards. If it is pair, increase the counter by one. Then the probability is calculated by :
pair_count / total_combination

Combination generation can be found in the related article section. You should read that article first. A modified version that handles String array is provided as follows :




Testing the combination program


javac Combination.java
java Combination

Result

S2 S3 S4
S2 S3 S5
S2 S3 S6
S2 S4 S5
S2 S4 S6
S2 S5 S6
S3 S4 S5
S3 S4 S6
S3 S5 S6
S4 S5 S6

The Probability Counting Program

We are now going to write a probability counting program with the following output :
javac *.java
java ProbabilityCount

Probability of getting a pair = 1098240/2598960 = 0.4225690276
Probability of getting two pairs = 123552/2598960 = 0.0475390156
Probability of getting three of a kind = 54912/2598960 = 0.0211284514
Probability of getting four of a kind = 624/2598960 = 0.0002400960
Probability of getting full house = 3744/2598960 = 0.0014405762

Source Code


Saturday, August 13, 2011

Screen Capture

Related Articles


Introduction

In this article, you will see a simple program that captures the screen and saves the image to a jpeg file. It consists of only a few lines of Java code and yet it is doing something meaningful.

Getting the Screen Dimension




Save it as A.java and run it, a sample run is shown below :
javac A.java
java A
screen dimension = 1280x800

Screen Capture


Once we get the screen dimension and save it in a Rectangle structure, we can define a capture() method that takes the rectangle as a parameter. Compile and run the following program, a jpeg file screen.jpg would be created.

Monday, August 8, 2011

Popup menu in Java

Popup menu

It is also known as context menu. It is typically triggered by the right mouse button. For system with only one mouse button, it is triggered by pressing and holding the primary mouse button.

Mouse Event

In Java, the MouseListener interface is used for capturing and handling the mouse event. The mousePressed() and the mouseReleased() methods must be implemented in order to trigger a popup menu.



To implement a full MouseListener, we must also implements the following method :
  public void mouseEntered(java.awt.event.MouseEvent e)
  public void mouseExited(java.awt.event.MouseEvent e)
  public void mouseClicked(java.awt.event.MouseEvent e)

Since we are not interested in the above events, we will implement the above with empty methods.

Adding popup menu

We will need to use these two classes.
javax.swing.JPopupMenu
javax.swing.JMenuItem
A single popup menu may contain multpile menu items, the following method create a simple popup menu with 3 menu items.




ActionEvent


Whenever a menu item is clicked, an action event is triggered. We need to implement an ActionListener in order to capture the action event. For the ActionListener interface, the only method that required to be implemented is actionPerformed.



Demonstration


The following program will create a panel with a text field inside it. Type anything into it.
Right click the text field, click "select all", click "copy", then click "paste" several times.


Friday, August 5, 2011

Text Processing - html to text

Two days ago, I was asked to write a method htmlToText(). The method would take an html filename as parameter. It would simply copy the content of the html file to a text file, with all the html tags removed.

For example, consider the following html file :


With all the tags removed, the output would be :
Hello, there

I wrote this method with pen and paper. Yes, I was actually "WRITING" program with pen, not "TYPING" program in front of a computer. Here is the version I wrote :



Drawback

The above program read the input file line by line, remove the tags for each line, and then append the line to the output file.

There is a major drawback of the above implementation. Since the removeTag() method is applied on a line by line basis, it doesn't work if the open tag and the close tag are on separated lines, such as :


Alternative : Reading the whole file into a content buffer

When I finally arrived home and got access to a computer, I rewrote the method.


This method consumes more memory. However, it is a completely feasible method. Most html files are not very big. You won't find a html with a file size of 100 megabytes.

Regular Expression

Finally, I simplified the method further with the help of regular expression.



Lesson Learned

Nowadays, good programmers are not necessary good at "writing" program, the are good at "typing" program in front of a computer, with google as their friends.

Thursday, August 4, 2011

Set Operations in Java

What is a Set


Mathematically, a set is just a collection of objects, for example
let set=["apple","orange","banana"]

For a simple set, the order of the element is not important.

You can add element to a set.
set.add("strawberry") is ["apple","orange","banana". "strawberry"]

You can remove element from a set
set.remove("orange") is ["apple","banana","strawberry"]

You can ask whether a set contains a certain element.
set.contains("banana") is true

The following is a simple example.



Compile and run :
javac SetDemo.java
java SetDemo

[banana, orange, apple]
[banana, orange, apple, strawberry]
[banana, apple, strawberry]
apple in the set=true
orange in the set=false

Set Operations : union, intersection, difference, subset

  • Union: set1.addAll(set2);
  • Intersection: set1.retainAll(set2);
  • Difference: set1.removeAll(set2);
  • subset test: set1.containsAll(set2);

Sample :
Suppose a person has three friends :
friends = ["Helen","Mary","John"];

Suppose he has three classmates :
classmates = ["John","Peter","Mary"];

"Peter" belongs to classmates but not friends, because he treats "Peter" as enemy.

Then,
intersection = set of people who is a friend as well as a classmate
             = ["John","Mary"];

union = set of people who is either a friend or a classmate
      = ["John", "Mary", "Peter", "Helen"];


subset test :
  friends.containAll(classmates) would return false, 
  because not all classmates are friends.
  That is, classmates is not a subset of friends

The following is the program that demonstrated the above operations.


Result

javac SetOperation.java
java SetOperation

friends=[Mary, John, Helen]
classmates=[Mary, Peter, John]
intersection=[Mary, John]
union=[Mary, Peter, John, Helen]
'classmates' is a subset of 'friends' : false

Friday, July 22, 2011

Java Console Programming - Master Mind

Related article


The Game Of Master Mind


I found the following "functional spec" in programmingforums.org.

We will implement this game with a top down design approach.



Mastermind Game

You are to write a program that generates a secret code at random and let the human player guess this code. Each time the player inputs his guess, the program responds with a score that reflects how close or far the player's guess is from the secret code.

To make the game interesting, this secret code is made up of animals. There are 12 animals to choose from, namely: Ant, Bear, Cat, Dog, Emu, Goat, Lizard, Monkey, Parrot, Rabbit, Snake, and Tiger.

Upon start, the program chooses a code, which is 4 randomly selected animals. The program cannot select the same animal more than once in the code. So the 4 animals are all different from each other.

Examples of valid codes:
[ Tiger, Snake, Monkey, Rabbit ]
[ Monkey, Parrot, Snake, Ant ]

Examples of invalid codes:
Reason
[ Ant, Cat, Monkey, Ant ] Ant selected twice
[ Rabbit, Monkey, Snake ] Code must be 4 animals

Scoring:
The objective of the game is for the player to guess the 4 animals, with the least number of attempts. The program has two levels of difficulty. In the low difficulty setting, the player has to guess the 4 animals but not necessarily in the same order.

For example, if the secret code is [Cat, Dog, Ant, Tiger] and the player
guesses [Dog, Tiger, Ant, Cat], the guess will be considered correct.

In the low difficulty setting, the program takes the input guess and finds out which animals in the input matches with those on the code. The score is the number of correct animals. Obviously, if the score is 4, the player wins and the program ends. Here are some examples:

Secret Code: [ Cat, Dog, Ant, Tiger ]
Guess: [ Ant, Rabbit, Monkey, Snake ] Score is 1 (Ant matches)
Guess: [ Rabbit, Ant, Dog, Snake ] Score is 2 (Ant and Dog)
Guess: [ Dog, Tiger, Ant, Cat ] Score is 4 (Player wins)

In the high difficulty setting, the player has to guess the 4 animals and also the positions of each animal. In the third guess above, notice that only "Ant" is guessed correctly at the right position (i.e., third position). In this level, the program outputs two numbers for the score: (a) number of correct animals; and (b) number of
correct animals in the correct position. Study the examples below. Note the computer-generated scores for (a) and (b) are shown on the right side.

Secret Code: [ Cat, Dog, Ant, Tiger ]
Computer Outputs Score
Guess: [ Rabbit, Ant, Dog, Snake ] (a) is 2 (b) is 0
Guess: [ Cat, Ant, Dog, Snake ] (a) is 3 (b) is 1
Guess: [ Cat, Dog, Ant, Snake ] (a) is 3 (b) is 3
Guess: [ Cat, Dog, Ant, Tiger ] (a) is 4 (b) is 4

Obviously, the required score to win is 4 for both (a) and (b). Only then does the program terminate.

Below is a list of specific requirements that your program must satisfy.
1. Your program should use the time() function to seed the random number generator. This will make the program select different codes each time it is executed. Study how to use this with srandom() function.
2. The required input format for each guess is 4 characters. Notice that the 12 animals have different starting characters. Use the first character of each animal as a means to identify it. For example, an input
of "CDAT" means [Cat, Dog, Ant, Tiger]. This makes it unnecessary to use "Ant", "Tiger", etc. for input.
3. Your program must also validate the input. Here are some examples of invalid inputs:
Input Reason Error Message
CDAA A is repeated "Repeated Animal"
SADQ Q is not a valid animal "Invalid Animal"
Use the error messages above when an invalid user input is encountered.


Design

This is a good example of console programming that implements something interesting.

We will use System.in for reading input, System.out for printing output.

There is a java.io.Console class which is available after JDK 1.5, but we won't use this class anyway.

Top down Approach


We will implement the game using the top-down approach. First of all, let's define the flow in the main() method.



Now we are going to fill the above methods one by one. A good starting point is to define the game flow first. Hence the first method I choose to fill is game(). Since the function names used below are self-documentary, the game flow should be easy to understand.






Quick Prototyping

Now we are going to create a first version that doesn't have compilation error. We will create empty functions if necessary.





Now we have a completed prototype, compile it, and run it. It doesn't do anything meaningful right now. But it is a good starting point. Once all the empty functions are filled, we have a fully working game.

Shuffle()


There are quite a few empty methods to be implemented. What should be next ?. There are many reasonable choices. I would choose shuffle() to generate a secret code. Before writing the method, we need to define data structure to hold the animal names and the animal codes(the first letter).






Once we have the data structure ready, we can generate the secretCode, which stands for the 4 randomly picked animals. We are going to use the Knuth Shuffling algorithm to randomize the permutation array. Then use the first 4 index in the permutation to pick 4 animals.





displaySolution()

Now we want to check our shuffe() method, therefore the next reasonable method to implement is displaySolution()



Now it is time to recompile and run MasterMind.java. It will display 4 randomly picked animals every time you run the program.


getPlayeGuess() - getting input from user

Up to now the program is not interactive. We are going to enable the input function right now.



The above method call two auxiliary methods,getInputLine() and validateInput().

getInputLine() - reading from System.in

It simply reads a line from System.in. Implementation follows :





validateInput()

When the user enter a guess, we must validate it.




The above method introduces another auxiliary method, getAnimalIndex(), which would return -1 if the character is not a valid animal, otherwise it would return a index to the array of animals. This function is very simple, it is just a single line method.



Now you may compile and run the program again. You may test the program with the following input. The blue part is input by player. The program will quit whenever a valid input is read.


Animal Code : ABCDEGLMPRST
Enter your guess : abcde
Must enter 4 letters
Animal Code : ABCDEGLMPRST
Enter your guess : abcx
Invalid Animal
Animal Code : ABCDEGLMPRST
Enter your guess : abcc
Repeated Animal.
Animal Code : ABCDEGLMPRST
Enter your guess : abcd
Congratulations ! The solution is :
[Snake, Bear, Ant, Emu]


setDifficulty()

At this point, we have the input validation method ready. The next reasonable step is to calculate and display the score for each guess. However, since the game provides two difficulty settings, which would affect the score calculation method, we must first implement the setDifficulty() method.



calculateScore()

We may now implement calculateScore().




And of course we must display the calculated score, hence the next method would be displayScore()

displayScore()





At this point we have already completed the whole game flow. You may compile and play the game now. We are still missing the replay() method, which asks the player to play another game or not after a successful guess. But it doesn't affect the whole game flow. The method replay() will be implemented in the full source anyway.

Full Source




Conclusion

This article demonstrated how to convert a functional specification into a running program, using a top down design approach. To see example of bottom-up design, read this article :Tetris from Scratch