/** * Copyright (C) 2017 Jan Schäfer (jansch@users.sourceforge.net) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jskat.ai.algorithmic; import org.apache.log4j.Logger; import org.jskat.player.ImmutablePlayerKnowledge; import org.jskat.util.Card; import org.jskat.util.CardList; import org.jskat.util.Player; import org.jskat.util.Rank; import org.jskat.util.Suit; /** * @author Markus J. Luzius <br> * created: 15.06.2011 19:13:50 * */ public class AlgorithmicSinglePlayer implements IAlgorithmicAIPlayer { private static final Logger log = Logger .getLogger(AlgorithmicSinglePlayer.class); private final AlgorithmicAIPlayer myPlayer; private final ImmutablePlayerKnowledge knowledge; /** * */ AlgorithmicSinglePlayer(final AlgorithmicAIPlayer p) { myPlayer = p; knowledge = p.getKnowledge(); log.debug("Defining player <" + myPlayer.getPlayerName() + "> as " + this.getClass().getName()); } /* * (non-Javadoc) * * @see * org.jskat.ai.algorithmic.IAlgorithmicAIPlayer#discardSkat(org.jskat.ai * .algorithmic.BidEvaluator) */ @Override public CardList discardSkat(final BidEvaluator bid) { CardList cards = new CardList(knowledge.getOwnCards()); cards.sort(bid.getSuggestedGameType()); CardList toDiscard = new CardList(); toDiscard.add(cards.remove(10)); toDiscard.add(cards.remove(10)); return toDiscard; } /* * (non-Javadoc) * * @see org.jskat.ai.IJSkatPlayer#playCard() */ @Override public Card playCard() { if (knowledge.getTrickCards() == null || knowledge.getTrickCards().isEmpty()) { if (knowledge.getNoOfTricks() < 1) { return openGame(); } return openTrick(); } if (knowledge.getTrickCards().size() == 1) { return playMiddlehandCard(); } return playRearhandCard(); } private Card openGame() { // at present, game is always opened with trump - using a jack, if // possible // TODO (markus 15.07.11) open single player game with none-trump CardList cards = knowledge.getOwnCards(); if (cards.get(0).getRank() != Rank.JACK) { Card c = cards.get(cards.getLastIndexOfSuit( knowledge.getTrumpSuit(), true)); if (c == null) { // should not happen - if there is no jack, there should be at // least one trump suit card // just to make sure that a card is played c = cards.get(0); } return c; } // from here onwards: first card must be a jack if (cards.get(0).getSuit() == Suit.CLUBS) { if (cards.get(1).getSuit() != Suit.SPADES || cards.get(1).getRank() != Rank.JACK) { return cards.get(0); } if (cards.get(2).getSuit() != Suit.HEARTS || cards.get(2).getRank() != Rank.JACK) { return cards.get(1); } if (cards.get(3).getSuit() != Suit.DIAMONDS || cards.get(3).getRank() != Rank.JACK) { return cards.get(2); } return cards.get(3); } if (cards.get(0).getSuit() == Suit.SPADES) { if (cards.get(1).getSuit() != Suit.HEARTS || cards.get(1).getRank() != Rank.JACK) { return cards.get(0); } if (cards.get(2).getSuit() != Suit.HEARTS || cards.get(2).getRank() != Rank.JACK) { return cards.get(0); } } return cards.get(0); } private Card openTrick() { CardList cards = knowledge.getOwnCards(); // 1: check, if there are still trump cards out if (knowledge.couldOpponentsHaveTrump()) { if (openGame().getRank() == Rank.JACK) { return openGame(); } Card c = cards.get(cards.getLastIndexOfSuit( knowledge.getTrumpSuit(), true)); if (c != null) { return c; } } // if both opponent player don't have a suit, but single player has: // play it! suitLoop: for (Suit s : Suit.values()) { if (!cards.hasSuit(knowledge.getGameType(), s)) { continue; } playerLoop: for (Player p : Player.values()) { if (p == knowledge.getDeclarer()) { continue playerLoop; } if (knowledge.couldHaveSuit(p, s)) { continue suitLoop; } } return cards.get(cards.getLastIndexOfSuit(s)); } // do i have any aces? for (Card c : cards) { if (c.getRank() == Rank.ACE && c.getSuit() != knowledge.getTrumpSuit()) { return c; } if (c.getRank() == Rank.TEN && knowledge.isCardPlayed(Card.getCard(c.getSuit(), Rank.ACE))) { return c; } if (c.getRank() == Rank.KING && knowledge.isCardPlayed(Card.getCard(c.getSuit(), Rank.ACE)) && knowledge.isCardPlayed(Card.getCard(c.getSuit(), Rank.TEN))) { return c; } } // do i have a ten and a lower card of the same suit? int[] myCards = cards.toBinary(); for (Suit s : Suit.values()) { if (s == knowledge.getTrumpSuit()) { continue; } int i = myCards[s.ordinal()]; if ((i & 63) > 32) { return cards.get(cards.getLastIndexOfSuit(s)); } } // fallback: just play the first card return cards.get(0); } private Card playMiddlehandCard() { log.debug("Single player is in middlehand"); // TODO (mjl 23.08.2011) single player middlehand card // fallback: take the first valid card (which is a trump, if there still // is one) CardList cards = knowledge.getOwnCards(); for (Card c : cards) { if (c.isAllowed(knowledge.getGameType(), knowledge.getTrickCards() .isEmpty() ? null : knowledge.getTrickCards().get(0), cards)) { return c; } } log.warn("no possible card found in card list [" + cards + "] with " + knowledge.getGameType() + " / " + knowledge.getTrickCards().get(0)); return cards.get(0); } private Card playRearhandCard() { log.debug("Single player is in rearhand"); // TODO (mjl 23.08.2011) single player rearhand card // fallback: take the first valid card (which is a trump, if there still // is one) CardList cards = knowledge.getOwnCards(); for (Card c : cards) { if (c.isAllowed(knowledge.getGameType(), knowledge.getTrickCards() .isEmpty() ? null : knowledge.getTrickCards().get(0), cards)) { return c; } } log.warn("no possible card found in card list [" + cards + "] with " + knowledge.getGameType() + " / " + knowledge.getTrickCards().get(0)); return cards.get(0); } }