Package net.sf.nebulacards.comm

Source Code of net.sf.nebulacards.comm.GameRunner$MyUIListener

package net.sf.nebulacards.comm;

import java.io.IOException;

import net.sf.nebulacards.main.AskTrumpRules;
import net.sf.nebulacards.main.BiddingRules;
import net.sf.nebulacards.main.ChatListenerRules;
import net.sf.nebulacards.main.Communicator;
import net.sf.nebulacards.main.DirectComRules;
import net.sf.nebulacards.main.GameProcedure;
import net.sf.nebulacards.main.GameResult;
import net.sf.nebulacards.main.HandSummaryRules;
import net.sf.nebulacards.main.PassingRules;
import net.sf.nebulacards.main.PileOfCards;
import net.sf.nebulacards.main.Player;
import net.sf.nebulacards.main.PlayingCard;
import net.sf.nebulacards.main.Rules;
import net.sf.nebulacards.main.Tableau;
import net.sf.nebulacards.main.UIListener;
import net.sf.nebulacards.util.proc.DealProc;

public class GameRunner implements Runnable {
  public static final boolean verbose = true;

  private ComManager cm;

  private Communicator[] coms = new Communicator[4];

  private Communicator broadcaster;

  private Integer[] incomingBids = new Integer[4];

  private PlayingCard[] incomingPlays = new PlayingCard[4];

  private PileOfCards[] incomingPasses = new PileOfCards[4];

  private String[] incomingResponses = new String[4];

  private Thread self;

  // game data
  private Rules m_game = null;

  // Hand-specific information
  private PileOfCards beenPlayed = new PileOfCards();

  private Tableau tableau = new Tableau(4);

  private PileOfCards[] cardsWon = new PileOfCards[4];

  public GameRunner(Rules r, ComManager _cm) {
    m_game = r;
    cm = _cm;
    for (int i = 0; i < 4; i++) {
      m_game.getPlayers()[i] = new Player("");
      m_game.getPlayers()[i].setScoreAndBags(0, 0);
      m_game.getHands()[i] = new PileOfCards();
      cardsWon[i] = new PileOfCards();
      incomingBids[i] = null;
      incomingPasses[i] = null;
      incomingPlays[i] = null;
      incomingResponses[i] = null;
      coms[i] = cm.getCommunicator(i);
      coms[i].setCallbacks(new MyUIListener(i));
    }
    broadcaster = cm.getBroadcastCommunicator();
    self = new Thread(this, "Game Runner");
    self.start();
  }

  /*
   * (non-Javadoc)
   * @see java.lang.Runnable#run()
   */
  public void run() {
    try {
      synchronized (cm) {
        while (cm.howManyActive() < 4)
          cm.wait(20000);
      }
      conductGame();
    } catch (Exception e) {
      System.err.println(e.getMessage());
      e.printStackTrace(System.err);
      return;
    }

    if (verbose) {
      System.out.println("Game finished.");
    }
  }

  public void join() throws InterruptedException {
    self.join();
  }

  public boolean isAlive() {
    return self.isAlive();
  }

  /**
   * Utility method to check if all the elements in an array are null.
   */
  public static boolean allNull(Object[] o) {
    for (int i = 0; i < o.length; i++)
      if (o[i] != null)
        return false;
    return true;
  }

  /**
   * Utility method to safely read and reset an incoming data latch.
   */
  public Object delatch(Object[] latches, int index) {
    Object result;
    synchronized (this) {
      result = latches[index];
      latches[index] = null;
    }
    return result;
  }

  public String getName(int where) {
    return m_game.getPlayers()[where].getName();
  }

  public void setName(int where, String name) {
    m_game.getPlayers()[where].setName(name);
  }

  class MyUIListener implements UIListener {
    int im_slot;

    public MyUIListener(int slot) {
      im_slot = slot;
    }

    /**
     * Clean up after a user quits. Even though other classes are
     * responsible for putting the players into the ComManager, we can take
     * them out.
     */
    public void wantToQuit() {
      System.out.println(getName(im_slot) + " is leaving the game.");
      synchronized (cm) {
        setName(im_slot, "");
        cm.remove(im_slot);
        cm.notifyAll();
      }
      broadcastTable();
    }

    public void submitChat(String msg) {
      String chat = getName(im_slot) + "> " + msg;
      if (!chat.endsWith("\n"))
        chat += "\n";
      // broadcast chat message
      broadcaster.chat(chat);
      if (m_game instanceof ChatListenerRules) {
        ((ChatListenerRules) m_game).receiveChat(msg, im_slot);
      }
    }

    /*
     * (non-Javadoc)
     *
     * @see net.sf.nebulacards.main.UIListener#submitResponse(java.lang.String)
     */
    public void submitResponse(String s) {
      synchronized (GameRunner.this) {
        incomingResponses[im_slot] = s;
        GameRunner.this.notifyAll();
      }
    }

    /*
     * (non-Javadoc)
     *
     * @see net.sf.nebulacards.main.UIListener#submitBid(int)
     */
    public boolean submitBid(int bid) {
      synchronized (GameRunner.this) {
        incomingBids[im_slot] = new Integer(bid);
        GameRunner.this.notifyAll();
      }
      return true;
    }

    /*
     * (non-Javadoc)
     *
     * @see net.sf.nebulacards.main.UIListener#submitPlay(net.sf.nebulacards.main.PlayingCard)
     */
    public boolean submitPlay(PlayingCard p) {
      synchronized (GameRunner.this) {
        incomingPlays[im_slot] = p;
        GameRunner.this.notifyAll();
      }
      return true;
    }

    /*
     * (non-Javadoc)
     *
     * @see net.sf.nebulacards.main.UIListener#submitPass(net.sf.nebulacards.main.PileOfCards)
     */
    public boolean submitPass(PileOfCards p) {
      synchronized (GameRunner.this) {
        incomingPasses[im_slot] = new PileOfCards(p);
        GameRunner.this.notifyAll();
      }
      return true;
    }
  }

  private void conductPassing() throws IOException, InterruptedException {
    int[] howmany = new int[4], where = new int[4];
    PileOfCards[] pass = new PileOfCards[4];
    boolean[] done = new boolean[4];
    PassingRules pm_game = (PassingRules) m_game;
    for (int i = 0; i < 4; i++) {
      if ((howmany[i] = pm_game.numPass(i)) > 0) {
        where[i] = pm_game.wherePass(i);
        done[i] = false;
        delatch(incomingPasses, i); // clean up input area
        synchronized (coms[i]) {
          coms[i].clearResend();
          coms[i].yourTurnToPass(howmany[i], where[i]);
        }
      } else
        done[i] = true;
    }
    while (!(done[0] && done[1] && done[2] && done[3])) {
      synchronized (this) {
        if (allNull(incomingPasses))
          wait(1000);
      }
      for (int i = 0; i < 4; i++) {
        pass[i] = (PileOfCards) delatch(incomingPasses, i);
        if (pass[i] != null) {
          if (pass[i].howManyCardsNotNull() == howmany[i]) {
            done[i] = true;
            for (int j = 0; j < pass[i].size(); j++) {
              if (!m_game.getHands()[i].contains(pass[i].get(j)))
                done[i] = false;
            }
            if (done[i])
              done[i] = pm_game.checkPass(i, pass[i]);
          }
          if (!done[i]) { // illegal pass, have to ask again
            synchronized (coms[i]) {
              coms[i].clearResend();
              coms[i].yourTurnToPass(howmany[i], where[i]);
            }
          }
        } else {
          if (howmany[i] > 0) {
            delatch(incomingPasses, i);
            synchronized (coms[i]) {
              coms[i].resendOnly();
              coms[i].yourTurnToPass(howmany[i], where[i]);
            }
          }
        }
      }
    }
    // All passes are in and contain the right number of cards.
    // Now we move the cards.
    for (int i = 0; i < 4; i++) {
      if (howmany[i] > 0) {
        m_game.getHands()[i].removeAll(pass[i]);
        // cards can be thrown away by specifying where[i] = -1
        if (where[i] >= 0 && where[i] < m_game.getCapacity())
          m_game.getHands()[where[i]].addAll(pass[i]);
      }
    }
    // distribute the new hands
    for (int i = 0; i < 4; i++) {
      m_game.getHands()[i].sort(m_game);
      synchronized (coms[i]) {
        coms[i].dealHand(new PileOfCards(m_game.getHands()[i]));
      }
    }
  }

  private void conductBidding() throws IOException, InterruptedException {
    int stopCount = 0;
    for (int w = 0; stopCount < 4; w = (w + 1) % 4) {
      if (!((BiddingRules) m_game).shouldBid(w)) {
        stopCount++;
        continue;
      }
      stopCount = 0;
      delatch(incomingBids, w);
      synchronized (coms[w]) {
        coms[w].clearResend();
        coms[w].yourTurnToBid();
      }
      for (;;) { // wait for bid
        synchronized (this) {
          while (incomingBids[w] == null) {
            wait(300);
            synchronized (coms[w]) {
              coms[w].resendOnly();
              coms[w].yourTurnToBid();
            }
          }
        }
        Integer bid = (Integer) delatch(incomingBids, w);
        if (bid != null) {
          m_game.getPlayers()[w].setBid(bid.intValue());
          ((BiddingRules) m_game).reportBid(w, bid.intValue());
          break;
        }
      }
      broadcaster.setBid(w, m_game.getPlayers()[w].getBid());
    }
    ((BiddingRules) m_game).doneBidding();
  }

  /**
   * Ask a player to pick trump.
   */
  private void conductTrumpDiscovery() throws IOException,
      InterruptedException {
    AskTrumpRules atm_game = (AskTrumpRules) m_game;
    String response;
    do {
      int who = atm_game.whoPicksTrump();
      delatch(incomingResponses, who);
      synchronized (coms[who]) {
        coms[who].clearResend();
        coms[who].respond("Please choose the trump.");
      }
      synchronized (this) {
        while (incomingResponses[who] == null) {
          synchronized (coms[who]) {
            coms[who].resendOnly();
            coms[who].respond("Please choose the trump.");
          }
          wait(1000);
        }
        response = (String) delatch(incomingResponses, who);
      }
    } while (!atm_game.trumpResponse(response));
    broadcaster.setTrump(m_game.getTrump(), m_game.getTrumpName());
  }

  private void conductGame() throws IOException, InterruptedException {
    for (int handCount = 0;; handCount++) {
      // start a new hand
      // clear old piles
      for (int i = 0; i < 4; i++) {
        cardsWon[i] = new PileOfCards();
        m_game.getHands()[i] = new PileOfCards();
      }
      beenPlayed = new PileOfCards();
      tableau = new Tableau();
      GameProcedure[] order = m_game.getProcedureOrdering();
      for (int i = 0; order != null && i < order.length; i++) {
        switch (order[i].getProcedure()) {
        case GameProcedure.DEALCARDS:
          (new DealProc()).runProcedure(coms, m_game);
          break;
        case GameProcedure.BIDDING:
          if (m_game instanceof BiddingRules)
            conductBidding();
          break;
        case GameProcedure.PASSING:
          if (m_game instanceof PassingRules)
            conductPassing();
          break;
        case GameProcedure.ASKTRUMP:
          if (m_game instanceof AskTrumpRules)
            conductTrumpDiscovery();
          break;
        case GameProcedure.DIRECTCOM:
          if (m_game instanceof DirectComRules) {
            Communicator[] tmp = (Communicator[]) coms.clone();
            ((DirectComRules) m_game).conductDirectCom(tmp);
          }
          break;
        case GameProcedure.CUSTOM:
          order[i]
              .runProcedure((Communicator[]) coms.clone(), m_game);
          break;
        }
      }
      broadcaster.setTrump(m_game.getTrump(), m_game.getTrumpName());

      int lastWinner = -1;
      int lastPlayer = 0;
      // play out the hand
      while (m_game.getHands()[0].howManyCardsNotNull() > 0
          && !m_game.quitHand()) {
        for (int cardsPlayed = 0; cardsPlayed < 4; cardsPlayed++) {
          if (m_game.quitHand()) {
            break;
          }
          int w = m_game.whoPlaysNext((cardsPlayed == 0), lastPlayer,
              lastWinner);
          if (w < 0 || w > 3) {
            if (lastWinner < 0)
              w = handCount % 4;
            else if (cardsPlayed == 0)
              w = lastWinner;
            else
              w = (lastPlayer + 1) % 4;
          }
          lastPlayer = w;
          if (cardsPlayed == 0)
            tableau.setLead(w);
          delatch(incomingPlays, w);
          synchronized (coms[w]) {
            coms[w].clearResend();
            coms[w].yourTurn();
          }
          PlayingCard c = null;
          // loop until we get a valid play
          while (true) {
            // wait for play
            synchronized (this) {
              while (incomingPlays[w] == null) {
                synchronized (coms[w]) {
                  coms[w].resendOnly();
                  coms[w].yourTurn();
                }
                wait(1000);
              }
            }
            c = (PlayingCard) delatch(incomingPlays, w);
            if (!m_game.validPlay(beenPlayed, tableau, m_game
                .getHands()[w], c)
                || !m_game.getHands()[w].contains(c)) {
              synchronized (coms[w]) {
                coms[w].noResend();
                coms[w].rejected();
                // prompt again
                coms[w].clearResend();
                coms[w].yourTurn();
              }
              continue; // go wait for another play
            }
            // signal acceptance
            synchronized (coms[w]) {
              coms[w].noResend();
              coms[w].accepted();
            }
            // remove card from hand
            m_game.getHands()[w].remove(c);
            // make sure a new player gets the correct hand.
            synchronized (coms[w]) {
              coms[w].resendOnly();
              coms[w].dealHand(m_game.getHands()[w]);
            }
            beenPlayed.add(c);
            tableau.set(w, c);
            broadcaster.cardToTableau(w, c);
            break;
          }
        } // now all players have played a card
        int winner = m_game.whoWinsTrick(tableau);
        m_game.trickDone(tableau, winner);
        cardsWon[winner].addAll(tableau);
        tableau.clear();
        broadcaster.clearTableau(winner);
        lastWinner = winner;
      }
      // now all tricks have been played
      m_game.score(cardsWon, m_game.getPlayers());
      broadcastTable();
      broadcaster.endHand();
      try {
        String[] summary = ((HandSummaryRules) m_game).getSummary();
        for (int i = 0; i < summary.length; i++) {
          broadcaster.chat(summary[i]);
        }
      } catch (NullPointerException e) { /* no summary */
      } catch (ClassCastException e) { /* m_game don't summarize */
      }

      GameResult gr = m_game.done(m_game.getPlayers());
      if (gr.done) {
        String res = "*** Game is complete. ***\nWinners are: ";
        if (gr.winners.length > 0)
          res += m_game.getPlayers()[gr.winners[0]].getName();
        for (int i = 1; i < gr.winners.length; i++)
          res += " & " + m_game.getPlayers()[gr.winners[i]].getName();
        res += "\n";
        broadcaster.chat(res);
        broadcaster.endGame(new GameResult(gr));
        break;
      }
      for (int i = 0; i < 4; i++) {
        m_game.getPlayers()[i].clearBid();
      }
    }
    // end of game
    if (verbose) {
      for (int count = 0; count < 4; count++) {
        System.out.print(m_game.getPlayers()[count].getName() + ": ");
        System.out.print(m_game.getPlayers()[count].getScore());
        System.out.print("_");
        System.out.println(m_game.getPlayers()[count].getBags());
      }
    }
  }

  /**
   * Handle the connection of a new player in a previously used slot.
   *
   * @param where
   *            The position where the new player is sitting.
   */
  public void reconnect(int where) {
    synchronized (coms[where]) {
      if (!m_game.getHands()[where].isEmpty())
        coms[where].dealHand(new PileOfCards(m_game.getHands()[where]));
      coms[where].setTrump(m_game.getTrump(), m_game.getTrumpName());
      PileOfCards tmp = new PileOfCards(beenPlayed);
      tmp.removeAll(tableau);
      coms[where].playedSoFar(tmp);
      // resend tableau
      for (int i = 0; i < 4; i++) {
        PlayingCard c = tableau.get(i);
        if (!c.isNull())
          coms[where].cardToTableau(i, c);
      }
      // resend bids
      for (int i = 0; i < m_game.getPlayers().length; i++) {
        if (m_game.getPlayers()[i].hasBid())
          coms[where].setBid(i, m_game.getPlayers()[i].getBid());
      }
      if (m_game != null && m_game instanceof DirectComRules)
        ((DirectComRules) m_game).reconnect(where);
    }
  }

  public void broadcastTable() {
    Player[] bt = new Player[4];
    for (int i = 0; i < 4; i++) {
      if (m_game.getPlayers()[i] != null)
        bt[i] = m_game.getPlayers()[i];
      else
        bt[i] = new Player("");
    }
    broadcaster.setPlayers(bt);
    broadcaster.setGameName(m_game.getName());
  }

  // returns how many players are connected
  public int howMany() {
    return cm.howManyActive();
  }

  public String[] getNames() {
    String[] names = new String[m_game.getPlayers().length];
    for (int i = 0; i < names.length; i++)
      names[i] = m_game.getPlayers()[i].getName();
    return names;
  }
}
TOP

Related Classes of net.sf.nebulacards.comm.GameRunner$MyUIListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.