private void playSeat(int seatIndex) { Seat seat = this.seats.get(seatIndex); for (int i = 0; i < seat.hands.size(); i++) { CardsAndBet hand = seat.hands.get(i); if (i == 0 && HandUtilities.blackjack(hand.cards())) { hand.setResult(Result.PLAYER_BLACKJACK); } else { List<PlayerAction> allowedActions = new ArrayList<PlayerAction>(Arrays.asList(PlayerAction.values())); if (hand.cards().size() == 1) // hand is result of splitting { if (hand.cards().get(0).value() == Value.ACE) // hand is result of splitting aces { allowedActions.remove(PlayerAction.HIT); allowedActions.remove(PlayerAction.DOUBLE); } allowedActions.remove(PlayerAction.SURRENDER); hand.dealCardTo(dealFaceUpCard()); } if (i != 0 || hand.cards().size() != 2) allowedActions.remove(PlayerAction.SURRENDER); if (hand.cards().size() != 2 || seat.hands.size() == 7 || // 7 hands means 4 valid hands (rest are sources of splits) (hand.cards().get(0).value().numericValue() != hand.cards().get(1).value().numericValue())) allowedActions.remove(PlayerAction.SPLIT); // TODO: player should not be asked to make a decision if split hand is 21 // TODO: why does this only happen in the observer, not the basic player when just playing? if (HandUtilities.value(hand.cards()) == HandUtilities.MAX_VALUE) allowedActions.clear(); while (allowedActions.size() >= 2) // player still has at least 1 decision to make { ArrayList<PlayerAction> allowedActionsCopy = new ArrayList<PlayerAction>(allowedActions); PlayerAction action = seat.player.act(hand.cards(), this.dealerHand.get(0), allowedActionsCopy); if (!allowedActions.contains(action)) throw new IllegalActionException( seat.player.id() + " attempted to " + action + " when not allowed."); for (BlackjackObserver observer : this.observers) observer.decision( seatIndex, hand.cards(), this.dealerHand.get(0), allowedActionsCopy, action); allowedActions.clear(); switch (action) { case HIT: hand.dealCardTo(dealFaceUpCard()); if (HandUtilities.value(hand.cards()) < HandUtilities.MAX_VALUE) { allowedActions.add(PlayerAction.HIT); allowedActions.add(PlayerAction.STAND); } break; case DOUBLE: hand.dealCardTo(dealFaceUpCard()); hand.doubleBet(); break; case STAND: break; case SURRENDER: hand.setResult(Result.SURRENDER); break; case SPLIT: List<Card> cards = hand.cards(); hand.setResult(Result.SOURCE_OF_SPLIT); seat.hands.add(i + 1, new CardsAndBet(hand.bet())); seat.hands.get(i + 1).dealCardTo(cards.get(0)); seat.hands.add(i + 2, new CardsAndBet(hand.bet())); seat.hands.get(i + 2).dealCardTo(cards.get(1)); break; } } if (!hand.isDone() && HandUtilities.bust(hand.cards())) hand.setResult(Result.DEALER_WIN); } } }