/** * 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.newalgorithm; import org.apache.log4j.Logger; import org.jskat.ai.newalgorithm.exception.IllegalMethodException; import org.jskat.util.Card; import org.jskat.util.CardList; import org.jskat.util.GameType; import org.jskat.util.Player; import org.jskat.util.Rank; import org.jskat.util.Suit; public class AlgorithmOpponentGrand extends AbstractAlgorithmAI { private static final Logger log = Logger .getLogger(AlgorithmOpponentGrand.class); AlgorithmOpponentGrand(final AlgorithmAI p, GameType pGameType) { super(p, pGameType); log.debug("Defining player <" + myPlayer.getPlayerName() + "> as " + this.getClass().getName()); } @Override protected Card startGame() { log.debug("OpponentGrand starts Game: " + knowledge.getPlayerPosition()); return playStartGameCard(knowledge.getOwnCards(), knowledge.getTrickCards(), oPlayedCards, oNotOpponentCards, oSituation, knowledge.getDeclarer()); } @Override protected Card playForehandCard() { log.debug("OpponentGrand plays Forehand-Card: " + knowledge.getPlayerPosition()); return playForehandCard(knowledge.getOwnCards(), knowledge.getTrickCards(), oPlayedCards, oNotOpponentCards, oSituation, knowledge.getDeclarer()); } @Override protected Card playMiddlehandCard() { log.debug("OpponentGrand plays Middlehand-Card: " + knowledge.getPlayerPosition()); return playMiddlehandCard( myPlayer.getPlayableCards(knowledge.getTrickCards()), knowledge.getTrickCards(), oPlayedCards, oNotOpponentCards, oSituation, knowledge.getDeclarer()); } @Override protected Card playRearhandCard() { log.debug("OpponentGrand plays Rearhand-Card: " + knowledge.getPlayerPosition()); return playRearhandCard( myPlayer.getPlayableCards(knowledge.getTrickCards()), knowledge.getTrickCards(), oPlayedCards, oNotOpponentCards, oSituation, knowledge.getPlayerPosition(), knowledge.getDeclarer()); } @Override public CardList discardSkat(BidEvaluator bidEvaluator) { throw new IllegalMethodException( "AlgorithmOpponentGrand has nothing to discard!"); } // static methods for creating JUnit-tests and test cardplaybehavior public static Card playStartGameCard(CardList pCards, CardList pTrickCards, CardList pPlayedCards, CardList pNotOpponentCards, Situation pSituation, Player pDeclarer) { return playForehandCard(pCards, pTrickCards, pPlayedCards, pNotOpponentCards, pSituation, pDeclarer); } public static Card playForehandCard(CardList pCards, CardList pTrickCards, CardList pPlayedCards, CardList pNotOpponentCards, Situation pSituation, Player pDeclarer) { pCards.sort(pSituation.getGameType()); boolean tDeclarerInMiddle = Player.FOREHAND.getLeftNeighbor() == pDeclarer; CardList possibleCards = new CardList(); for (Suit s : Suit.values()) { if (!pCards.hasSuit(GameType.GRAND, s)) { continue; } Card possibleHighCard = pCards.get(pCards.getFirstIndexOfSuit(s, false)); // highest Card Card possibleLowCard = pCards.get(pCards.getLastIndexOfSuit(s, false)); // lowest Card // Wenn hoechste Karte und weniger als 5 Karten bislang gespielt // wurden -> spielen if (Helper.isHighestSuitCard(possibleHighCard, pPlayedCards, pTrickCards) && pPlayedCards.getSuitCount(s, false) < 5) { return possibleHighCard; } // ansonsten nur spielen, wenn Solo-Spieler in der Mitte else if (tDeclarerInMiddle) { // Wenn Mitspieler Blank ist if (pSituation.isRightPlayerBlankOnColor(s)) { return possibleHighCard; } possibleCards.add(possibleLowCard); } else if (!tDeclarerInMiddle && pSituation.isLeftPlayerBlankOnColor(s)) { return possibleHighCard; } } if (!possibleCards.isEmpty()) { return playRandomCard(possibleCards); } possibleCards = getPossibleMaxValueCards(pCards, 0); if (!possibleCards.isEmpty()) { return playRandomCard(possibleCards); } possibleCards = getPossibleMaxValueCards(pCards, 3); if (!possibleCards.isEmpty()) { return playRandomCard(possibleCards); } possibleCards = getPossibleMaxValueCards(pCards, 4); if (!possibleCards.isEmpty()) { return playRandomCard(possibleCards); } return getRandomAllowedCard(pCards, null, pSituation.getGameType()); } public static Card playMiddlehandCard(CardList pCards, CardList pTrickCards, CardList pPlayedCards, CardList pNotOpponentCards, Situation pSituation, Player pDeclarer) { pCards.sort(GameType.CLUBS); boolean tDeclarerInForehand = Player.MIDDLEHAND.getRightNeighbor() == pDeclarer; Card tForehandCard = pTrickCards.get(0); Suit tSuit = tForehandCard.getSuit(); CardList possibleCards = new CardList(); // Solo-Spieler hat die erste Karte gelegt if (tDeclarerInForehand) { // Wenn Bube gespielt if (tForehandCard.getRank() == Rank.JACK) { // Wenn Bube vorhanden if (pCards.get(0).getRank() == Rank.JACK) { // Wenn schlagbar, dann den niedrigsten Buben spielen, der // die Vorhand schlaegt if (pCards.get(0).beats(GameType.GRAND, tForehandCard)) { if (pCards.get(1).beats(GameType.GRAND, tForehandCard)) { if (pCards.get(2).beats(GameType.GRAND, tForehandCard)) { return pCards.get(2); } return pCards.get(1); } return pCards.get(0); } // Sonst niedrigsten Buben spielen return pCards.get(Helper.countJacks(pCards) - 1); } // Wenn der Mitspieler noch einen Buben haben koennte, der // besser ist if (Helper.countJacks(pNotOpponentCards) != 3 && (!pNotOpponentCards.contains(Card.CJ) && tForehandCard != Card.CJ || pNotOpponentCards .contains(Card.CJ) && !pNotOpponentCards.contains(Card.SJ) && tForehandCard != Card.SJ)) { CardList tPossibleCards = new CardList(); // Butter eine hohe Karte in der Farbe in der der // Solo-Spieler blank ist for (Suit s : pSituation.getRightPlayerBlankSuits()) { if (pCards.getSuitCount(s, false) == 0) { continue; } Card lPossibleHighCard = pCards.get(pCards .getFirstIndexOfSuit(s, false)); if (lPossibleHighCard.getPoints() >= 10) { return lPossibleHighCard; } else if (lPossibleHighCard.getPoints() >= 4) { tPossibleCards.add(lPossibleHighCard); } } if (!tPossibleCards.isEmpty()) { return playRandomCard(tPossibleCards); } // Butter eine andere hohe Karte for (Suit s : Suit.values()) { if (pCards.getSuitCount(s, false) == 0) { continue; } Card lPossibleHighCard = pCards.get(pCards .getFirstIndexOfSuit(s, false)); if (lPossibleHighCard.getPoints() >= 10) { return lPossibleHighCard; } else if (lPossibleHighCard.getPoints() >= 4) { tPossibleCards.add(lPossibleHighCard); } } } } // Wenn Farbe gespielt else if (tForehandCard.getRank() != Rank.JACK) { Card possibleHighCard = pCards.get(pCards.getFirstIndexOfSuit( tSuit, false)); // highest Card Card possibleLowCard = pCards.get(pCards.getLastIndexOfSuit( tSuit, false)); // lowest Card // Wenn Karten der Farbe auf der Hand if (pCards.hasSuit(pSituation.getGameType(), tSuit)) { if (pCards.getSuitCount(tSuit, false) == 1) { return possibleHighCard; } // Wenn schlagbar if (possibleHighCard.beats(pSituation.getGameType(), tForehandCard)) { // Wenn die zweithöchste Karte anschliessend // unschlagbar ist if (Helper.isHighestSuitCard(pCards.get(pCards .getFirstIndexOfSuit(tSuit, false) + 1), pSituation.getGameType(), pNotOpponentCards, pTrickCards) || pNotOpponentCards.getSuitCount(tSuit, false) > 2) { return possibleHighCard; } for (int i = pCards.getLastIndexOfSuit(tSuit, false); i >= pCards .getFirstIndexOfSuit(tSuit, false); i--) { if (pCards.get(i).beats(pSituation.getGameType(), tForehandCard)) { return pCards.get(i); } } } if (Helper.getSuitCardsToBinary(pNotOpponentCards, tSuit) + Helper.getSuitCardsToBinary(pTrickCards, tSuit) == 127) { return possibleHighCard; } // Wenn nicht schlagbar return possibleLowCard; } // Spieler hat die Farbe blank // Wenn Bube hat if (pCards.get(0).getRank() == Rank.JACK) { // >=10 Punkte niedrigsten Buben spielen if (tForehandCard.getPoints() >= 10) { pCards.get(Helper.countJacks(pCards) - 1); } } // Wenn die Karte die Hoechste ist || Mitspieler keine Karte der // Farbe hat -> Lusche werfen if (Helper.isHighestSuitCard(tForehandCard, pSituation.getGameType(), pPlayedCards, pTrickCards) || pSituation.isLeftPlayerBlankOnColor(tSuit)) { return getLowValueCard(pCards, pSituation, tForehandCard, pPlayedCards, pTrickCards); } } // Blank Suites vom Solo-Spieler freispielen for (Suit s : pSituation.getRightPlayerBlankSuits()) { Card lPossibleLowCard = pCards.get(pCards.getLastIndexOfSuit(s, false)); if (lPossibleLowCard != null && lPossibleLowCard.getPoints() <= 4) { return lPossibleLowCard; } } if (!possibleCards.isEmpty()) { return playRandomCard(possibleCards); } // Lusche werfen return getLowValueCard(pCards, pSituation, tForehandCard, pPlayedCards, pTrickCards); } // Solo-Spieler sitzt hinter dem Spieler else { // Solo-Spieler ist blank auf der Farbe oder hat eine moegliche // Karte -> wahrscheinlich gedrueckt! if (pSituation.getLeftPlayerBlankSuits().contains(tSuit) || pNotOpponentCards.getSuitCount(tSuit, false) >= 6) { return pCards.get(pCards.getLastIndexOfSuit(tSuit, false)); } // Wenn Spieler bedienen muss if (pCards.getSuitCount(tSuit, false) > 0) { Card possibleHighCard = pCards.get(pCards.getFirstIndexOfSuit( tSuit, false)); // highest Card Card possibleLowCard = pCards.get(pCards.getLastIndexOfSuit( tSuit, false)); // lowest Card // Hat der Spieler die hoechste Karte -> spielen if (Helper.isHighestSuitCard(possibleHighCard, pPlayedCards, pTrickCards)) { return possibleHighCard; } return possibleLowCard; } // Spieler kann nicht bedienen // Vorhandkarte ist die höchste if (Helper.isHighestSuitCard(tForehandCard, pPlayedCards, pTrickCards)) { // Solo-Spieler ist blank auf der Farbe if (pSituation.isLeftPlayerBlankOnColor(tSuit)) { // Solo-Spieler hat keinen Buben mehr -> Buttern if (Helper.countJacks(pPlayedCards) + Helper.countJacks(pCards) == 4 || !pSituation.leftPlayerHasTrump()) { return getHighValueCard(pCards, pSituation, tForehandCard); } else { possibleCards = getPossibleMaxValueCards(pCards, 0); if (!possibleCards.isEmpty()) { return playRandomCard(possibleCards); } possibleCards = getPossibleMaxValueCards(pCards, 3); if (!possibleCards.isEmpty()) { return playRandomCard(possibleCards); } possibleCards = getPossibleMaxValueCards(pCards, 4); if (!possibleCards.isEmpty()) { return playRandomCard(possibleCards); } } } // Solo-Spieler hat moeglicherweise noch eine Karte der Farbe -> // Buttern else { return getHighValueCard(pCards, pSituation, tForehandCard); } } } return getRandomAllowedCard(pCards, tForehandCard, pSituation.getGameType()); } public static Card playRearhandCard(CardList pCards, CardList pTrickCards, CardList pPlayedCards, CardList pNotOpponentCards, Situation pSituation, Player pPlayerPosition, Player pDeclarer) { pCards.sort(pSituation.getGameType()); Card tForehandCard = pTrickCards.get(0); Card tMiddlehandCard = pTrickCards.get(1); Card tCardToBeat = tForehandCard; if (tMiddlehandCard.beats(pSituation.getGameType(), tCardToBeat)) { tCardToBeat = tMiddlehandCard; } // ArrayList<Suit> tDeclarerBlankSuits = // pSituation.getLeftPlayerBlankSuits(); // if(Player.REARHAND.getRightNeighbor() == pDeclarer) // tDeclarerBlankSuits = pSituation.getRightPlayerBlankSuits(); // Grand spiel: Hinterhand karte muss gespielt werden // Erste Karte ist ein Bube if (tForehandCard.getRank() == Rank.JACK) { // Wenn ein Bube vorhanden if (pCards.get(0).getRank() == Rank.JACK) { // Wenn der Stich dem Solo-Spieler gehört -> versuchen zu // stechen if (tMiddlehandCard.beats(pSituation.getGameType(), tForehandCard) == (pPlayerPosition.getRightNeighbor() == pDeclarer)) { if (pCards.get(0).beats(GameType.GRAND, tForehandCard)) { if (pCards.get(1).beats(GameType.GRAND, tForehandCard)) { if (pCards.get(2).beats(GameType.GRAND, tForehandCard)) { return pCards.get(2); } return pCards.get(1); } return pCards.get(0); } // Sonst niedrigsten Buben spielen return pCards.get(Helper.countJacks(pCards) - 1); } } // Kein Buben im eigenen Blatt // Stich gehört dem Solo-Spieler -> Lusche werfen if (tMiddlehandCard.beats(pSituation.getGameType(), tForehandCard) == (pPlayerPosition .getRightNeighbor() == pDeclarer)) { return getLowValueCard(pCards, pSituation, tForehandCard, pPlayedCards, pTrickCards); } // Mitspieler gehört der Stich -> Buttern return getHighValueCard(pCards, pSituation, tForehandCard); } // Farbe gespielt else { // Muss bedienen if (pCards.hasSuit(pSituation.getGameType(), tForehandCard.getSuit())) { Card possibleHighCard = pCards.get(pCards.getFirstIndexOfSuit( tForehandCard.getSuit(), false)); // highest Card Card possibleLowCard = pCards.get(pCards.getLastIndexOfSuit( tForehandCard.getSuit(), false)); // lowest Card // Solo-Spieler hat den Stich if (tMiddlehandCard.beats(pSituation.getGameType(), tForehandCard) == (pPlayerPosition.getRightNeighbor() == pDeclarer)) { // Wenn selbst schlagbar -> Schlagen if (possibleHighCard.beats(pSituation.getGameType(), tCardToBeat)) { return possibleHighCard; } // -> Karte mit niedrigem Wert return possibleLowCard; } // Mitspieler hat den Stich -> Karte mit hohem Wert return possibleHighCard; } // Kann nicht bedienen // Solospieler hat den Stich // Hat Bube && viele Punkte -> Stechen // Lusche werfen if (tMiddlehandCard.beats(pSituation.getGameType(), tForehandCard) == (pPlayerPosition .getRightNeighbor() == pDeclarer)) { if (pCards.get(0).getRank() == Rank.JACK && pTrickCards.getTotalValue() > 9) { return pCards.get(Helper.countJacks(pCards) - 1); } return getLowValueCard(pCards, pSituation, tForehandCard, pPlayedCards, pTrickCards); } // Mitspieler hat den Stich -> Buttern return getHighValueCard(pCards, pSituation, tForehandCard); } } // Buttern public static Card getHighValueCard(CardList pCards, Situation pSituation, Card pInitialCard) { CardList possibleCards = new CardList(); for (Suit s : Suit.values()) { int lSuitCount = pCards.getSuitCount(s, false); if (lSuitCount == 0) { continue; } Card possibleHighCard = pCards.get(pCards.getFirstIndexOfSuit(s, false)); // highest Card if (lSuitCount == 1) { if (possibleHighCard.getPoints() > 4) { return possibleHighCard; } else { possibleCards.add(possibleHighCard); } } if (pSituation.isLeftPlayerBlankOnColor(s)) { possibleCards.add(possibleHighCard); } if (lSuitCount >= 3) { possibleCards.add(possibleHighCard); } } if (!possibleCards.isEmpty()) { return playRandomCard(possibleCards); } else { return getRandomAllowedCard(pCards, pInitialCard, pSituation.getGameType()); } } // Lusche Werfen public static Card getLowValueCard(CardList pCards, Situation pSituation, Card pInitialCard, CardList pPlayedCards, CardList pTrickCards) { CardList possibleCards = new CardList(); for (Suit s : Suit.values()) { int lSuitCount = pCards.getSuitCount(s, false); if (lSuitCount == 0) { continue; } Card possibleHighCard = pCards.get(pCards.getFirstIndexOfSuit(s, false)); // highest Card Card possibleLowCard = pCards.get(pCards.getLastIndexOfSuit(s, false)); // lowest Card if (lSuitCount == 1 && possibleHighCard.getPoints() < 10) { return possibleHighCard; } if (lSuitCount == 2 && Helper.isHighestSuitCard(possibleHighCard, pPlayedCards, pTrickCards)) { return possibleLowCard; } if (lSuitCount >= 3) { possibleCards.add(possibleLowCard); } } if (!possibleCards.isEmpty()) { return playRandomCard(possibleCards); } else { return getRandomAllowedCard(pCards, pInitialCard, pSituation.getGameType()); } } }