/** * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ package bots.mctsbot.ai.bots.bot.gametree.search; import java.util.Set; import org.apache.log4j.Logger; import bots.mctsbot.ai.bots.bot.gametree.action.DefaultWinnerException; import bots.mctsbot.ai.bots.bot.gametree.action.GameEndedException; import bots.mctsbot.ai.bots.bot.gametree.action.ProbabilityAction; import bots.mctsbot.ai.bots.bot.gametree.search.nodevisitor.NodeVisitor; import bots.mctsbot.ai.opponentmodels.OpponentModel; import bots.mctsbot.client.common.gamestate.GameState; import bots.mctsbot.client.common.playerstate.PlayerState; import bots.mctsbot.common.elements.player.PlayerId; import bots.mctsbot.common.util.Pair; import bots.mctsbot.common.util.Triple; public abstract class ActionNode implements InnerGameTreeNode { @SuppressWarnings("unused") private final static Logger logger = Logger.getLogger(ActionNode.class); protected final GameState gameState; protected final PlayerId playerId; protected final PlayerId botId; protected final NodeVisitor[] visitors; protected final SearchConfiguration config; protected final int searchId; public ActionNode(PlayerId playerId, PlayerId botId, GameState gameState, SearchConfiguration config, int searchId, NodeVisitor... visitors) { this.gameState = gameState; this.playerId = playerId; this.visitors = visitors; this.botId = botId; this.config = config; this.searchId = searchId; } @Override public GameTreeNode getChildAfter(ProbabilityAction action, int tokens) { if (action.getAction().endsInvolvementOf(botId)) { // bot folded return new ConstantLeafNode(gameState, gameState.getPlayer(botId).getStack(), 0, tokens); } else { try { GameState nextState = action.getAction().getStateAfterAction(); // expand further PlayerId nextToAct = nextState.getNextToAct(); if (nextToAct.equals(botId)) { // go to next player node return new BotActionNode(botId, nextState, config, config.getSampler(), tokens, searchId, visitors); } else { return new OpponentActionNode(nextToAct, botId, nextState, config, config.getSampler(), tokens, searchId, visitors); } } catch (GameEndedException e) { // no active players left // go to showdown return config.getShowdownNodeFactory().create(botId, e.lastState, tokens, config, searchId, visitors); } catch (DefaultWinnerException e) { assert e.winner.getPlayerId().equals(botId) : "Bot should have folded earlier, winner can't be " + e.winner; // bot wins int stack = e.winner.getStack(); int pots = e.foldState.getGamePotSize(); double rakeFactor = 1 - gameState.getTableConfiguration().getRake(); return new ConstantLeafNode(gameState, stack + rakeFactor * pots, 0, tokens); } } } public double getUpperWinBound() { PlayerState bot = gameState.getPlayer(botId); int botStack = bot.getStack(); //TODO check what if bot allin and 2 other players? int stealable = 0; Set<PlayerState> players = gameState.getAllSeatedPlayers(); double rakeFactor = 1 - gameState.getTableConfiguration().getRake(); for (PlayerState p : players) { PlayerId opponent = p.getPlayerId(); if (p.isActivelyPlaying() && !opponent.equals(botId)) { int callValue = gameState.getCallValue(opponent); stealable += rakeFactor * (Math.min(botStack, p.getStack() - callValue) + callValue); } } return botStack + stealable + rakeFactor * gameState.getGamePotSize(); } @Override public Triple<Double, Double, Double> getFoldCallRaiseProbabilities() { for (NodeVisitor visitor : visitors) { visitor.callOpponentModel(); } return config.getOpponentModel().getFoldCallRaiseProbabilities(gameState, playerId); } @Override public Pair<Double, Double> getCheckBetProbabilities() { for (NodeVisitor visitor : visitors) { visitor.callOpponentModel(); } return config.getOpponentModel().getCheckBetProbabilities(gameState, playerId); } public PlayerId getPlayerId() { return playerId; } @Override public PlayerId getBotId() { return botId; } @Override public OpponentModel getOpponentModel() { return config.getOpponentModel(); } @Override public GameState getGameState() { return gameState; } @Override public String toString() { return "Action Node"; } }