/* POKER SERVERName: GameServer.java Purpose: Act as the server for a poker game Date: 10/11/2000 Written By: Jason Hertzog & Mike Dise Written For: Dr. R. Webster */ import java.io.*; import java.net.*;import java.util.*; public class GameServer { public final static int MAX_PLAYERS = 5; public final static boolean VERBOSE = true; public final static boolean PRINT_ERRORS = true; public final static int ANTE = 5; public final static int PLAYER_START_BANKROLL = 500; private Vector players = new Vector(5,1); private int player_money_start = 100; private int pot = 0; private int bet_call = 0; private int dealer_id = 0; private int gameId = 0; private String gameName = ""; private ServerManager serverManager; private CardDeck deck; private boolean pwdReq = false; private String pwd; private boolean game_started = false; private boolean bet_second = false; private Poker pokerGame = new Poker(); //CONSTRUCTOR public GameServer(int id, ServerManager s, String gn, String pwd1) { if (VERBOSE) System.out.println("GameServer: Starting up new game: Game " + id); gameId = id; serverManager = s; gameName = gn; pwd = pwd1; pwdReq = (pwd.length() > 1 || !pwd.equals(" ")); deck = new CardDeck(); } //Checks if the Game has Started public boolean isGameStarted() { return game_started; } //Checks if the Game is full public boolean isGameFull() { return !(players.size() < 5); } //Returns int game id public int getGameId() { return gameId; } //Returns game name public String getGameName() { return gameName; } //Returns if pwd is req public boolean getPwdReq() { return pwdReq; } //Returns if pwd public String getPwd() { return pwd; } //Returns a comma delimited list of player names public String getPlayerNames() { String names = ""; for (int j=0; j < players.size(); j++) { playerManager temp = (playerManager)players.elementAt(j); if (!temp.isDead) { if (j == players.size()-1){ names = names.concat(temp.name); }else { names = names.concat(temp.name + ","); } } } return names; } //Adds a player to the game //if the game has started or is full then returns false public synchronized boolean addPlayer(Socket s, BufferedReader i, PrintWriter o, String n, String avp) { if (players.size() < MAX_PLAYERS) { if (!this.game_started) { //Check Password if (VERBOSE) System.out.println("GameServer: Adding player " + n + " to Game " + gameId); playerManager temp = new playerManager(s,i,o,n, avp); players.addElement(temp); //Tell everyone about the new player if (temp.player_number == dealer_id) { broadcast("NEW_PLAYER|" + temp.player_number + "|" + temp.name + "|" + temp.bankroll + "|" + temp.avatarPicPath + "|1"); } else { broadcast("NEW_PLAYER|" + temp.player_number + "|" + temp.name + "|" + temp.bankroll + "|" + temp.avatarPicPath + "|0"); } return true; } else { if (VERBOSE) System.out.println("GameServer: Can't add player " + n + " to Game " + gameId + ": Game Started"); return false; } } else { if (VERBOSE) System.out.println("GameServer: Can't add player " + n + " to Game " + gameId + ": Game Full"); return false; } } public static void fail(Exception e, String msg) { if (PRINT_ERRORS) System.err.println(msg + ": " + e); System.exit(1); } class playerManager extends Thread { public Socket clientSocket; public BufferedReader reader; public PrintWriter writer; public PokerHand playerHand; public String name = "user"; public String avatarPicPath = ""; public int bankroll; public int player_number; public int totalBet = 0; public boolean isTurn2Bet = false; public boolean isTurn2Draw = false; public boolean betThisTurn = false; public boolean foldedThisRound = false; public boolean isDead = false; public playerManager(Socket s, BufferedReader i, PrintWriter o, String n, String avp) { clientSocket = s; reader = i; writer = o; name = n; bankroll = PLAYER_START_BANKROLL; avatarPicPath = avp; player_number = players.size(); //Tell Player Connection is Successfull writeSocket(writer,"CHAT|Game " + gameId + ": Connection Successful"); //Tell Applet the player ID - equals element index in vector writeSocket(writer,"YOUR_ID|" + player_number); //Tell applet the player ID of the dealer writeSocket(writer,"DEALER_ID|" + dealer_id); //Tell applet the value of the pot writeSocket(writer,"POT_VALUE|0"); //Tell applet about everyone else already in the game for (int j=0; j < players.size(); j++) { playerManager temp = (playerManager)players.elementAt(j); if (j == dealer_id) { //Tell applet about player|name|cash|picpath|1 if dealer, 0 if not writeSocket(writer,"NEW_PLAYER|" + j + "|" + temp.name + "|" + temp.bankroll + "|" + temp.avatarPicPath + "|1"); } else { writeSocket(writer,"NEW_PLAYER|" + j + "|" + temp.name + "|" + temp.bankroll + "|" + temp.avatarPicPath + "|0"); } } //Start the listener thread this.start(); } public void run() { //Text from Applet String line; StringTokenizer st; String protocolKey; boolean continueLoop = true; int len; try { while(continueLoop) { //Get or wait for next message from the applet line = reader.readLine(); //if null, line broken exit if (line == null) break; st = new StringTokenizer(line, "|"); if (VERBOSE) System.out.println("GameServer: Game " + gameId + " Recieved " + line); protocolKey = st.nextToken().toString(); if (protocolKey.equals("CHAT")){ //Simply a chat message - send it to everyone broadcast("CHAT|" + this.name + ": " + st.nextToken().toString()); }else if(protocolKey.equals("NOTIFY_EXIT")){ //If Game Window closed //Stop the loop continueLoop = false; //Attempt to readd the close to the Server Manager writeSocket(this.writer,"READD_CLIENT"); serverManager.addClient(this.clientSocket,this.reader,this.writer); //Disable the player in the player vector this.isDead = true; //Notify the world broadcast("PLAYER_EXIT|" + this.player_number); }else if(protocolKey.equals("START_ROUND")){ //Player must be dealer to start the round if (player_number == dealer_id) { //Reset pot and misc variables pot = 0; bet_second = false; game_started = true; foldedThisRound = false; bet_call = ANTE; //Total amount needed to meet the bet //New Deck deck.newShuffledDeck(); //Scroll Through All Players for (int j=0; j < players.size(); j++) { playerManager temp = (playerManager)players.elementAt(j); //Deal Player Hand temp.playerHand = new PokerHand(deck.dealTopCard(),deck.dealTopCard(),deck.dealTopCard(),deck.dealTopCard(),deck.dealTopCard()); //Reset player info temp.betThisTurn = false; temp.foldedThisRound = false; //Put in ANTE temp.bankroll = temp.bankroll - ANTE; temp.totalBet = ANTE; pot += ANTE; //Send hand to player writeSocket(temp.writer,"HAND|" + temp.playerHand.toParsableString("|")); //Send World player bankroll broadcast("BANKROLL_UPDATE|"+ j + "|" + temp.bankroll); } //Tell everyone the new pot value since the ante were put in broadcast("POT_VALUE|" + pot); //Tell everyone what they need to call sendAmountToCall(); //Set turn to Dealer ((playerManager)players.elementAt(dealer_id)).setTurnToBet(); } }else if(protocolKey.equals("RAISE_AMT")){ //Make Sure it's this person's Turn if (this.isTurn2Bet) { //Set flag that this person did bet this turn this.betThisTurn = true; this.isTurn2Bet = false; //Get Bet Amount int b = 0; try { //This amount is the amount above the amount to call //i.e. call: b = 0, raise 5: b = 5 b = Integer.parseInt(st.nextToken().toString()); } catch (NumberFormatException iex) {if (PRINT_ERRORS) System.out.println(iex);} // Get "real bet" b += bet_call - this.totalBet; //Decrease players bankroll this.bankroll = this.bankroll - b; //Tell everyone this player's new bankroll amount broadcast("BANKROLL_UPDATE|"+ this.player_number + "|" + this.bankroll); //Increase this person's total bet this.totalBet += b; //The new bet_call must be this persons total bet (though might be equal if called) bet_call = this.totalBet; //Increase the pot pot += b; //Tell Everyone the new pot total broadcast("POT_VALUE|" + pot); //If all bets are equal, then we are done betting if (checkBetsEqual()) { //If seocnd round of betting then end the round if (bet_second) { //Tell eveyone the bets are equal broadcast("BETS_EQUAL"); //Determine the winner determineWinner(); } else { //Tell eveyone the bets are equal broadcast("BETS_EQUAL"); //Get the next person to draw cards getNextDrawCardsTurn(-1).setTurnToDraw(); } } else { //Get the next person to bet getNextBetTurn(this.player_number).setTurnToBet(); } //Tell everyone what they need to call sendAmountToCall(); } else { writeSocket(this.writer,"CHAT| Not Your Turn!"); } }else if(protocolKey.equals("TRADE_CARDS")){ if (this.isTurn2Draw) { this.isTurn2Draw = false; //Get Number of Cards trading int b = 0; try { b = Integer.parseInt(st.nextToken().toString()); } catch (NumberFormatException iex) {if (PRINT_ERRORS) System.out.println(iex);} //Tell everyone the number of cards this person traded broadcast("TRADED|" + this.player_number + "|" + b); //Replace all of the cards for (int i = 0; i < b; i++) { playerHand.replaceCard(new Card(st.nextToken().toCharArray()[0],Integer.parseInt(st.nextToken().toString())),deck.dealTopCard()); } //Tell the person their complete new hand writeSocket(this.writer,"HAND|" + this.playerHand.toParsableString("|")); playerManager nextDrawer = getNextDrawCardsTurn(this.player_number); //If the next drawer would be the dealer if (nextDrawer.player_number == dealer_id){ //On to the second round of betting bet_second = true; //Reset everyone's bet this turn back to false for (int j=0; j < players.size(); j++) { playerManager temp = (playerManager)players.elementAt(j); temp.betThisTurn = false; } //Set the betting turn to the dealer getNextBetTurn(-1).setTurnToBet(); } else { //Set the person to be the next drawer nextDrawer.setTurnToDraw(); } } else { writeSocket(this.writer,"CHAT| Not Your Turn!"); } }else if(protocolKey.equals("FOLD")){ if (this.isTurn2Bet) { //Set this player's turn to bet to false this.isTurn2Bet = false; this.betThisTurn = true; this.foldedThisRound = true; //Tell everyone that this guy is a wimp broadcast("FOLD|"+ this.player_number); //If only one person not folded then quit round System.out.println(numNotFolded()); if (numNotFolded() == 1) { determineWinner(); } else { //If all bets are equal, then we are done betting if (checkBetsEqual()) { //If second round of betting then end the round if (bet_second) { //Tell eveyone the bets are equal broadcast("BETS_EQUAL"); //Determine the winner determineWinner(); } else { //Tell eveyone the bets are equal broadcast("BETS_EQUAL"); //Get the next person to draw cards getNextDrawCardsTurn(-1).setTurnToDraw(); } } else { //Get the next person to bet getNextBetTurn(this.player_number).setTurnToBet(); } //Tell everyone what they need to call sendAmountToCall(); } } else { writeSocket(this.writer,"CHAT| Not Your Turn!"); } } } } catch (IOException e) { //Socket died if (PRINT_ERRORS) System.out.println(e.toString()); //Set dead flag this.isDead = true; if (VERBOSE) System.out.println("Game " + gameId + ":" + name + " disconnected from the server"); //Tell everyone broadcast("PLAYER_EXIT|" + this.player_number); } catch (Exception ex2) {if (PRINT_ERRORS) System.out.println(ex2);} } public void setTurnToBet() { broadcast("TURN2BET|" + this.player_number); this.isTurn2Bet = true; } public void setTurnToDraw() { broadcast("TURN2DRAW|" + this.player_number); this.isTurn2Draw = true; } } private void determineWinner () { Vector hands = new Vector(5,1); //Put valid hands in a vector for (int r = 0; r < players.size(); r++) { playerManager temp = (playerManager)players.elementAt(r); if (!temp.isDead && !temp.foldedThisRound) hands.addElement(temp.playerHand); } //Send to determine winner function int winner = pokerGame.determineWinner(hands, dealer_id); for (int r = 0; r < players.size(); r++) { playerManager temp = (playerManager)players.elementAt(r); if (((PokerHand)hands.elementAt(winner)) == temp.playerHand) winner = temp.player_number; } //Tell everyone the winner broadcast("ROUND_WINNER|" + winner + "|" + PokerWin.toString(pokerGame.getReasonWin())); //Tell everyone Winner's hand and new bankroll playerManager temp = (playerManager)players.elementAt(winner); broadcast("PLAYER_HAND|" + temp.player_number + "|" + temp.playerHand.toParsableString("|")); temp.bankroll += pot; broadcast("BANKROLL_UPDATE|"+ winner + "|" + temp.bankroll); //Reset pot pot = 0; broadcast("ROUND_END"); temp = (playerManager)players.elementAt(((dealer_id+1) % players.size())); while (temp.isDead) temp = (playerManager)players.elementAt(((temp.player_number+1) % players.size())); dealer_id = temp.player_number; //Tell everyone the new dealer broadcast("DEALER_ID|" + dealer_id); //Tell everyone the new pot value broadcast("POT_VALUE|0"); } //Send the amount needed for a person to call private void sendAmountToCall() { for (int j=0; j < players.size(); j++) { playerManager temp = (playerManager)players.elementAt(j); writeSocket(temp.writer,"AMT2CALL|" + (bet_call - temp.totalBet)); } } //Check of all bets are equal private boolean checkBetsEqual() { boolean bets_equal = true; playerManager temp = (playerManager)players.elementAt(0); int bt = temp.totalBet; for (int j=1; j < players.size(); j++) { temp = (playerManager)players.elementAt(j); if (!temp.foldedThisRound && !temp.isDead) { if (bt != temp.totalBet) bets_equal = false; if (!temp.betThisTurn && !temp.isDead && !temp.foldedThisRound) bets_equal = false; } } return bets_equal; } //Gets the next person to draw cards private playerManager getNextDrawCardsTurn(int last) { if (last == -1) { return (playerManager)players.elementAt(dealer_id); } else { playerManager temp = (playerManager)players.elementAt(((last+1) % players.size())); while (temp.foldedThisRound || temp.isDead) temp = (playerManager)players.elementAt(((temp.player_number+1) % players.size())); return temp; } } //Gets the next person to bet private playerManager getNextBetTurn(int last) { if (last == -1) { return (playerManager)players.elementAt(dealer_id); } else { playerManager temp = (playerManager)players.elementAt(((last+1) % players.size())); while (temp.foldedThisRound || temp.isDead) temp = (playerManager)players.elementAt(((temp.player_number+1) % players.size())); return temp; } } private int numNotFolded () { int x = 0; for (int j=0; j < players.size(); j++) { playerManager temp = (playerManager)players.elementAt(j); if (!temp.foldedThisRound) { x++; } } return x; } //Sends a message to everyone in the game private void broadcast (String t) { for (int j=0; j < players.size(); j++) writeSocket(((playerManager)players.elementAt(j)).writer,t); } //Send a message to a PrintWrite and flushes it public void writeSocket (PrintWriter p, String t) { p.println(t); p.flush(); } }