I am teaching myself Java and am hoping the StackOverFlow community would assist me in a 'beginners' code review? I tried to find a Java Users Group in Orlando but the only one listed does not seem active.
I have been a programmer for 12 years, mainly ERP software and C development and am looking to make a career/specialty change to Java. I've read it countless times if you want to learn a new language you need to write code, then write some more code and then finally write more code. So I've written some code!
I love poker, so I have written a small Texas Hold'em program. Here is the overview of what it does:
1) Asks the user for the number of players
2) Create a deck of cards
3) Shuffle
4) Cut the deck
5) Deal players hole cards
6) Burns a card
7) Deals flop
8) Burns a card
9) Deals turn
10) Burns a card
11) Deals river
12) Prints the deck to console to show random deck was used
13) Prints the 'board'
14) Prints burn cards
15) Printers players cards
16) Evaluates the value of each players hand (Royal flush, full house, etc...)
There are 6 .java files (see below for links). I used an interface, created my own comparators, even implemented some try/catch blocks (although Im still learning how to use these properly).
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class TexasHoldEm {
public static void main(String[] args) throws Exception {
// variables
Deck holdemDeck = new Deck();
int numPlayers = 0;
int cardCounter = 0;
int burnCounter = 0;
int boardCounter = 0;
Board board = new Board();
// initializations
numPlayers = getNumberOfPlayers();
Player[] player = new Player[numPlayers];
/* 3 shuffles just like in real life. */
for(int i=0;i<3;i++){
holdemDeck.shuffle();
}
// Cut Deck
holdemDeck.cutDeck();
// Initialize players
for (int i=0;i<numPlayers;i++){
player[i] = new Player();
}
// Main processing
// Deal hole cards to players
for (int i=0;i<2;i++){
for (int j=0;j<numPlayers;j++){
player[j].setCard(holdemDeck.getCard(cardCounter++), i);
}
}
// Start dealing board
// Burn one card before flop
board.setBurnCard(holdemDeck.getCard(cardCounter++), burnCounter++);
// deal flop
for (int i=0; i<3;i++){
board.setBoardCard(holdemDeck.getCard(cardCounter++), boardCounter++);
}
// Burn one card before turn
board.setBurnCard(holdemDeck.getCard(cardCounter++), burnCounter++);
// deal turn
board.setBoardCard(holdemDeck.getCard(cardCounter++), boardCounter++);
// Burn one card before river
board.setBurnCard(holdemDeck.getCard(cardCounter++), burnCounter++);
// deal river
board.setBoardCard(holdemDeck.getCard(cardCounter++), boardCounter++);
//------------------------
// end dealing board
//------------------------
System.out.println("The hand is complete...\n");
// print deck
holdemDeck.printDeck();
//print board
board.printBoard();
// print player cards
System.out.println("The player cards are the following:\n");
for (int i=0;i<numPlayers;i++){
player[i].printPlayerCards(i);
}
// print burn cards
board.printBurnCards();
//------------------------
// Begin hand comparison
//------------------------
for (int i=0;i<numPlayers;i++){
HandEval handToEval = new HandEval();
// populate with player cards
for (int j=0;j<player[i].holeCardsSize();j++){
handToEval.addCard(player[i].getCard(j),j);
}
//populate with board cards
for (int j=player[i].holeCardsSize();j<(player[i].holeCardsSize()+board.boardSize());j++){
handToEval.addCard(board.getBoardCard(j-player[i].holeCardsSize()),j);
}
System.out.println("Player " + (i+1) + " hand value: " + handToEval.evaluateHand());
}
}
protected static int getNumberOfPlayers() throws Exception{
int intPlayers = 0;
String userInput = "";
// Get number of players from user.
System.out.println("Enter number of players (1-9):");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
try {
userInput = br.readLine();
} catch (IOException ioe) {
System.out.println("Error: IO error trying to read input!");
System.exit(1);
}
// convert user input to an integer
try {
intPlayers = Integer.parseInt(userInput);
} catch (NumberFormatException nfe) {
System.out.println("Error: Input provided is not a valid Integer!");
System.exit(1);
}
if ((intPlayers<1) || (intPlayers>9)){
throw new Exception("Error: Number of players must be an integer between 1 and 9");
}
return intPlayers;
}
}
public class Player {
private Card[] holeCards = new Card[2];
//constructor
public Player(){
}
public Player(Card card1, Card card2){
holeCards[0] = card1;
holeCards[1] = card2;
}
//methods
protected void setCard(Card card, int cardNum){
holeCards[cardNum] = card;
}
protected Card getCard(int cardNum){
return holeCards[cardNum];
}
protected int holeCardsSize(){
return holeCards.length;
}
protected void printPlayerCards(int playerNumber){
System.out.println("Player " + (playerNumber+1) + " hole cards:");
for (int i=0;i<2;i++){
System.out.println(holeCards[i].printCard());
}
System.out.println("\n");
}
}
import java.util.Arrays;
public class HandEval {
private Card[] availableCards = new Card[7];
private final static short ONE = 1;
private final static short TWO = 2;
private final static short THREE = 3;
private final static short FOUR = 4;
// Constructor
public HandEval(){
}
//methods
protected void addCard(Card card, int i){
availableCards[i] = card;
}
protected Card getCard(int i){
return availableCards[i];
}
protected int numCards(){
return availableCards.length;
}
protected void sortByRank(){
Arrays.sort(availableCards, new rankComparator());
}
protected void sortBySuit(){
Arrays.sort(availableCards, new suitComparator());
}
protected void sortBySuitThenRank(){
Arrays.sort(availableCards, new suitComparator());
Arrays.sort(availableCards, new rankComparator());
}
protected void sortByRankThenSuit(){
Arrays.sort(availableCards, new rankComparator());
Arrays.sort(availableCards, new suitComparator());
}
protected String evaluateHand(){
String handResult = new String();
short[] rankCounter = new short[13];
short[] suitCounter = new short[4];
// initializations
for (int i=0;i<rankCounter.length;i++){
rankCounter[i] =0;
}
for (int i=4;i<suitCounter.length;i++){
suitCounter[i] = 0;
}
// Loop through sorted cards and total ranks
for(int i=0; i<availableCards.length;i++){
rankCounter[ availableCards[i].getRank() ]++;
suitCounter[ availableCards[i].getSuit() ]++;
}
//sort cards for evaluation
this.sortByRankThenSuit();
// hands are already sorted by rank and suit for royal and straight flush checks.
// check for royal flush
handResult = evaluateRoyal(rankCounter, suitCounter);
// check for straight flush
if (handResult == null || handResult.length() == 0){
handResult = evaluateStraightFlush(rankCounter, suitCounter);
}
// check for four of a kind
if (handResult == null || handResult.length() == 0){
handResult = evaluateFourOfAKind(rankCounter);
}
// check for full house
if (handResult == null || handResult.length() == 0){
handResult = evaluateFullHouse(rankCounter);
}
// check for flush
if (handResult == null || handResult.length() == 0){
handResult = evaluateFlush(rankCounter, suitCounter);
}
// check for straight
if (handResult == null || handResult.length() == 0){
// re-sort by rank, up to this point we had sorted by rank and suit
// but a straight is suit independent.
this.sortByRank();
handResult = evaluateStraight(rankCounter);
}
// check for three of a kind
if (handResult == null || handResult.length() == 0){
handResult = evaluateThreeOfAKind(rankCounter);
}
// check for two pair
if (handResult == null || handResult.length() == 0){
handResult = evaluateTwoPair(rankCounter);
}
// check for one pair
if (handResult == null || handResult.length() == 0){
handResult = evaluateOnePair(rankCounter);
}
// check for highCard
if (handResult == null || handResult.length() == 0){
handResult = evaluateHighCard(rankCounter);
}
return handResult;
}
private String evaluateRoyal(short[] rankCounter, short[] suitCounter){
String result = "";
// Check for Royal Flush (10 - Ace of the same suit).
// check if there are 5 of one suit, if not royal is impossible
if ((rankCounter[9] >= 1 && /* 10 */
rankCounter[10] >= 1 && /* Jack */
rankCounter[11] >= 1 && /* Queen */
rankCounter[12] >= 1 && /* King */
rankCounter[0] >= 1) /* Ace */
&& (suitCounter[0] > 4 || suitCounter[1] > 4 ||
suitCounter[2] > 4 || suitCounter[3] > 4)){
// min. requirements for a royal flush have been met,
// now loop through records for an ace and check subsequent cards.
// Loop through the aces first since they are the first card to
// appear in the sorted array of 7 cards.
royalSearch:
for (int i=0;i<3;i++){
// Check if first card is the ace.
// Ace must be in position 0, 1 or 2
if (availableCards[i].getRank() == 0){
// because the ace could be the first card in the array
// but the remaining 4 cards could start at position 1,
// 2 or 3 loop through checking each possibility.
for (int j=1;j<4-i;j++){
if ((availableCards[i+j].getRank() == 9 &&
availableCards[i+j+1].getRank() == 10 &&
availableCards[i+j+2].getRank() == 11 &&
availableCards[i+j+3].getRank() == 12)
&&
(availableCards[i].getSuit() == availableCards[i+j].getSuit() &&
availableCards[i].getSuit() == availableCards[i+j+1].getSuit() &&
availableCards[i].getSuit() == availableCards[i+j+2].getSuit() &&
availableCards[i].getSuit() == availableCards[i+j+3].getSuit())){
// Found royal flush, break and return.
result = "Royal Flush!! Suit: " + Card.suitAsString(availableCards[i].getSuit());
break royalSearch;
}
}
}
}
}
return result;
}
// Straight flush is 5 consecutive cards of the same suit.
private String evaluateStraightFlush(short[] rankCounter, short[] suitCounter){
String result = "";
if (suitCounter[0] > 4 || suitCounter[1] > 4 ||
suitCounter[2] > 4 || suitCounter[3] > 4){
// min. requirements for a straight flush have been met.
// Loop through available cards looking for 5 consecutive cards of the same suit,
// start in reverse to get the highest value straight flush
for (int i=availableCards.length-1;i>3;i--){
if ((availableCards[i].getRank()-ONE == availableCards[i-ONE].getRank() &&
availableCards[i].getRank()-TWO == availableCards[i-TWO].getRank() &&
availableCards[i].getRank()-THREE == availableCards[i-THREE].getRank() &&
availableCards[i].getRank()-FOUR == availableCards[i-FOUR].getRank())
&&
(availableCards[i].getSuit() == availableCards[i-ONE].getSuit() &&
availableCards[i].getSuit() == availableCards[i-TWO].getSuit() &&
availableCards[i].getSuit() == availableCards[i-THREE].getSuit() &&
availableCards[i].getSuit() == availableCards[i-FOUR].getSuit())){
// Found royal flush, break and return.
result = "Straight Flush!! " + Card.rankAsString(availableCards[i].getRank()) + " high of " + Card.suitAsString(availableCards[i].getSuit());
break;
}
}
}
return result;
}
// Four of a kind is 4 cards with the same rank: 2-2-2-2, 3-3-3-3, etc...
private String evaluateFourOfAKind(short[] rankCounter){
String result = "";
for (int i=0;i<rankCounter.length;i++){
if (rankCounter[i] == FOUR){
result = "Four of a Kind, " + Card.rankAsString(i) +"'s";
break;
}
}
return result;
}
// Full house is having 3 of a kind of one rank, and two of a kind of
// a second rank. EX: J-J-J-3-3
private String evaluateFullHouse(short[] rankCounter){
String result = "";
short threeOfKindRank = -1;
short twoOfKindRank = -1;
for (int i=rankCounter.length;i>0;i--){
if ((threeOfKindRank < (short)0) || (twoOfKindRank < (short)0)){
if ((rankCounter[i-ONE]) > 2){
threeOfKindRank = (short) (i-ONE);
}
else if ((rankCounter[i-ONE]) > 1){
twoOfKindRank = (short)(i-ONE);
}
}
else
{
break;
}
}
if ((threeOfKindRank >= (short)0) && (twoOfKindRank >= (short)0)){
result = "Full House: " + Card.rankAsString(threeOfKindRank) + "'s full of " + Card.rankAsString(twoOfKindRank) + "'s";
}
return result;
}
// Flush is 5 cards of the same suit.
private String evaluateFlush(short[] rankCounter, short[] suitCounter){
String result = "";
// verify at least 1 suit has 5 cards or more.
if (suitCounter[0] > 4 || suitCounter[1] > 4 ||
suitCounter[2] > 4 || suitCounter[3] > 4){
for (int i=availableCards.length-1;i>3;i--){
if (availableCards[i].getSuit() == availableCards[i-ONE].getSuit() &&
availableCards[i].getSuit() == availableCards[i-TWO].getSuit() &&
availableCards[i].getSuit() == availableCards[i-THREE].getSuit() &&
availableCards[i].getSuit() == availableCards[i-FOUR].getSuit()){
// Found royal flush, break and return.
result = "Flush!! " + Card.rankAsString(availableCards[i].getRank()) + " high of " + Card.suitAsString(availableCards[i].getSuit());
break;
}
}
}
return result;
}
// Straight is 5 consecutive cards, regardless of suit.
private String evaluateStraight(short[] rankCounter){
String result = "";
// loop through rank array to check for 5 consecutive
// index with a value greater than zero
for (int i=rankCounter.length;i>4;i--){
if ((rankCounter[i-1] > 0) &&
(rankCounter[i-2] > 0) &&
(rankCounter[i-3] > 0) &&
(rankCounter[i-4] > 0) &&
(rankCounter[i-5] > 0)){
result = "Straight " + Card.rankAsString(i-1) + " high";
break;
}
}
return result;
}
// Three of a kind is 3 cards of the same rank.
private String evaluateThreeOfAKind(short[] rankCounter){
String result = "";
// loop through rank array to check for 5 consecutive
// index with a value greater than zero
for (int i=rankCounter.length;i>0;i--){
if (rankCounter[i-1] > 2){
result = "Three of a Kind " + Card.rankAsString(i-1) + "'s";
break;
}
}
return result;
}
// Two pair is having 2 cards of the same rank, and two
// different cards of the same rank. EX: 3-3-7-7-A
private String evaluateTwoPair(short[] rankCounter){
String result = "";
short firstPairRank = -1;
short secondPairRank = -1;
for (int i=rankCounter.length;i>0;i--){
if ((firstPairRank < (short)0) || (secondPairRank < (short)0)){
if (((rankCounter[i-ONE]) > 1) && (firstPairRank < (short)0)){
firstPairRank = (short) (i-ONE);
}
else if ((rankCounter[i-ONE]) > 1){
secondPairRank = (short)(i-ONE);
}
}
else
{
// two pair found, break loop.
break;
}
}
// populate output
if ((firstPairRank >= (short)0) && (secondPairRank >= (short)0)){
if (secondPairRank == (short)0){
// Aces serve as top rank but are at the bottom of the rank array
// swap places so aces show first as highest pair
result = "Two Pair: " + Card.rankAsString(secondPairRank) + "'s and " + Card.rankAsString(firstPairRank) + "'s";
}
else
{
result = "Two Pair: " + Card.rankAsString(firstPairRank) + "'s and " + Card.rankAsString(secondPairRank) + "'s";
}
}
return result;
}
// One is is two cards of the same rank.
private String evaluateOnePair(short[] rankCounter){
String result = "";
for (int i=rankCounter.length;i>0;i--){
if((rankCounter[i-ONE]) > 1){
result = "One Pair: " + Card.rankAsString(i-ONE) + "'s";
break;
}
}
return result;
}
// high card is the highest card out of the 7 possible cards to be used.
private String evaluateHighCard(short[] rankCounter){
String result = "";
for (int i=rankCounter.length;i>0;i--){
if((rankCounter[i-ONE]) > 0){
result = "High Card: " + Card.rankAsString(i-ONE);
break;
}
}
return result;
}
}
import java.util.Random;
public class Deck{
private Card[] cards = new Card[52];
//Constructor
public Deck(){
int i = 0;
for (short j=0; j<4; j++){
for (short k=0; k<13;k++){
cards[i++] = new Card(k, j);
}
}
}
// Print entire deck in order
protected void printDeck(){
for(int i=0; i<cards.length;i++){
System.out.println(i+1 + ": " + cards[i].printCard());
}
System.out.println("\n");
}
// Find card in deck in a linear fashion
// Use this method if deck is shuffled/random
protected int findCard(Card card){
for (int i=0;i<52;i++){
if (Card.sameCard(cards[i], card)){
return i;
}
}
return -1;
}
//return specified card from deck
protected Card getCard(int cardNum){
return cards[cardNum];
}
protected void shuffle(){
int length = cards.length;
Random random = new Random();
//random.nextInt();
for (int i=0;i<length;i++){
int change = i + random.nextInt(length-i);
swapCards(i, change);
}
}
protected void cutDeck(){
Deck tempDeck = new Deck();
Random random = new Random();
int cutNum = random.nextInt(52);
for (int i=0;i<cutNum;i++){
tempDeck.cards[i] = this.cards[52-cutNum+i];
}
for (int j=0;j<52-cutNum;j++){
tempDeck.cards[j+cutNum] = this.cards[j];
}
this.cards = tempDeck.cards;
}
// Swap cards in array to 'shuffle' the deck.
private void swapCards(int i, int change){
Card temp = cards[i];
cards[i] = cards[change];
cards[change] = temp;
}
}
import java.util.*;
public class Card{
private short rank, suit;
private static String[] ranks = {"Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"};
private static String[] suits = {"Diamonds", "Clubs", "Hearts", "Spades"};
//Constructor
public Card(short rank, short suit){
this.rank = rank;
this.suit = suit;
}
// Getter and Setters
public short getSuit(){
return suit;
}
public short getRank(){
return rank;
}
protected void setSuit(short suit){
this.suit = suit;
}
protected void setRank(short rank){
this.rank = rank;
}
// methods
public static String rankAsString(int __rank){
return ranks[__rank];
}
public static String suitAsString(int __suit){
return suits[__suit];
}
public @Override String toString(){
return rank + " of " + suit;
}
// Print card to string
protected String printCard(){
return ranks[rank] + " of " + suits[suit];
}
// Determine if two cards are the same (Ace of Diamonds == Ace of Diamonds)
public static boolean sameCard(Card card1, Card card2){
return (card1.rank == card2.rank && card1.suit == card2.suit);
}
}
class rankComparator implements Comparator<Object>{
public int compare(Object card1, Object card2) throws ClassCastException{
// verify two Card objects are passed in
if (!((card1 instanceof Card) && (card2 instanceof Card))){
throw new ClassCastException("A Card object was expeected. Parameter 1 class: " + card1.getClass()
+ " Parameter 2 class: " + card2.getClass());
}
short rank1 = ((Card)card1).getRank();
short rank2 = ((Card)card2).getRank();
return rank1 - rank2;
}
}
class suitComparator implements Comparator<Object>{
public int compare(Object card1, Object card2) throws ClassCastException{
// verify two Card objects are passed in
if (!((card1 instanceof Card) && (card2 instanceof Card))){
throw new ClassCastException("A Card object was expeected. Parameter 1 class: " + card1.getClass()
+ " Parameter 2 class: " + card2.getClass());
}
short suit1 = ((Card)card1).getSuit();
short suit2 = ((Card)card2).getSuit();
return suit1 - suit2;
}
}
public class Board {
private Card[] board = new Card[5];
private Card[] burnCards = new Card[3];
//constructor
public Board(){
}
//methods
protected void setBoardCard(Card card, int cardNum){
this.board[cardNum] = card;
}
protected Card getBoardCard(int cardNum){
return this.board[cardNum];
}
protected void setBurnCard(Card card, int cardNum){
this.burnCards[cardNum] = card;
}
protected Card getBurnCard(int cardNum){
return this.burnCards[cardNum];
}
protected int boardSize(){
return board.length;
}
protected void printBoard(){
System.out.println("The board contains the following cards:");
for(int i =0; i<board.length;i++){
System.out.println(i+1 + ": " + getBoardCard(i).printCard());
}
System.out.println("\n");
}
protected void printBurnCards(){
System.out.println("The burn cards are:");
for(int i =0; i<burnCards.length;i++){
System.out.println(i+1 + ": " + getBurnCard(i).printCard());
}
System.out.println("\n");
}
}