@Override
  public Card playCard() {

    int index = -1;

    log.debug('\n' + knowledge.toString());

    // first find all possible cards
    final CardList possibleCards = getPlayableCards(knowledge.getTrickCards());

    log.debug(
        "found "
            + possibleCards.size()
            + " possible cards: "
            + possibleCards); //$NON-NLS-1$//$NON-NLS-2$

    // then choose a random one
    index = random.nextInt(possibleCards.size());

    log.debug("choosing card " + index); // $NON-NLS-1$
    log.debug(
        "as player "
            + knowledge.getPlayerPosition()
            + ": "
            + possibleCards.get(index)); // $NON-NLS-1$//$NON-NLS-2$

    return possibleCards.get(index);
  }
  private static CardList parseHand(final String hand) {

    final StringTokenizer cardTokens = new StringTokenizer(hand, "."); // $NON-NLS-1$
    final CardList result = new CardList();

    while (cardTokens.hasMoreTokens()) {
      result.add(Card.getCardFromString(cardTokens.nextToken()));
    }

    return result;
  }
  private static CardList parseSkatCards(final String move) {

    final StringTokenizer token = new StringTokenizer(move, "."); // $NON-NLS-1$
    final CardList result = new CardList();

    while (token.hasMoreTokens()) {
      result.add(Card.getCardFromString(token.nextToken()));
    }

    return result;
  }
  @Override
  public CardList getCardsToDiscard() {
    final CardList result = new CardList();

    CardList discardableCards = new CardList(knowledge.getOwnCards());

    // just discard two random cards
    result.add(discardableCards.remove(random.nextInt(discardableCards.size())));
    result.add(discardableCards.remove(random.nextInt(discardableCards.size())));

    return result;
  }
  /**
   * <game-type> :: (G | C | S | H | D | N) (type Grand .. Null) [O] (ouvert) [H] (hand, not given
   * if O + trump game) [S] (schneider announced, only in H games, not if O or Z) [Z] (schwarz
   * announced, only in H games)
   */
  private static GameAnnouncement parseGameAnnoucement(
      final MoveInformation info, final String move) {

    final StringTokenizer annToken = new StringTokenizer(move, "."); // $NON-NLS-1$
    final String gameTypeString = annToken.nextToken();

    final GameAnnouncementFactory factory = GameAnnouncement.getFactory();

    // at first the game type
    GameType gameType = null;
    if (gameTypeString.startsWith("G")) { // $NON-NLS-1$

      gameType = GameType.GRAND;

    } else if (gameTypeString.startsWith("C")) { // $NON-NLS-1$

      gameType = GameType.CLUBS;

    } else if (gameTypeString.startsWith("S")) { // $NON-NLS-1$

      gameType = GameType.SPADES;

    } else if (gameTypeString.startsWith("H")) { // $NON-NLS-1$

      gameType = GameType.HEARTS;

    } else if (gameTypeString.startsWith("D")) { // $NON-NLS-1$

      gameType = GameType.DIAMONDS;

    } else if (gameTypeString.startsWith("N")) { // $NON-NLS-1$

      gameType = GameType.NULL;
    }
    factory.setGameType(gameType);

    boolean handGame = false;
    boolean ouvertGame = false;
    boolean schwarzGame = false;
    // parse other game modifiers
    for (int i = 1; i < gameTypeString.length(); i++) {

      final char mod = gameTypeString.charAt(i);

      if (mod == 'O') {

        factory.setOuvert(Boolean.TRUE);
        ouvertGame = true;

      } else if (mod == 'H') {

        factory.setHand(Boolean.TRUE);
        handGame = true;
      } else if (mod == 'S') {

        factory.setSchneider(Boolean.TRUE);
      } else if (mod == 'Z') {

        factory.setSchwarz(Boolean.TRUE);
        schwarzGame = true;
      }
    }

    if (gameType != GameType.NULL && handGame && schwarzGame) {
      factory.setSchneider(true);
    }
    if (gameType != GameType.NULL && ouvertGame) {
      factory.setHand(true);
      handGame = true;
    }
    if (gameType != GameType.NULL && ouvertGame && handGame) {
      factory.setSchneider(true);
      factory.setSchwarz(true);
    }

    if (annToken.hasMoreTokens()) {

      CardList showedCards = new CardList();

      while (annToken.hasMoreTokens()) {
        showedCards.add(Card.getCardFromString(annToken.nextToken()));
      }

      CardList discardedCards = new CardList();
      CardList ouvertCards = new CardList();

      if (handGame) {
        ouvertCards.addAll(showedCards);
      } else if (showedCards.size() == 2) {
        discardedCards.addAll(showedCards);
      } else {
        discardedCards.add(showedCards.get(0));
        discardedCards.add(showedCards.get(1));

        for (int i = 2; i < showedCards.size(); i++) {
          ouvertCards.add(showedCards.get(i));
        }
      }

      info.setOuvertCards(ouvertCards);
      factory.setDiscardedCards(discardedCards);
    }

    final GameAnnouncement ann = factory.getAnnouncement();
    info.setGameAnnouncement(ann);
    return ann;
  }