All Downloads are FREE. Search and download functionalities are using the official Maven repository.

za.co.knowles.pokewhat.domain.RoundBets Maven / Gradle / Ivy

package za.co.knowles.pokewhat.domain;

import za.co.knowles.pokewhat.domain.lookup.EBetResult;
import za.co.knowles.pokewhat.exceptions.ShouldNotHaveHappenedException;

import java.util.*;
import java.util.stream.Collectors;

public class RoundBets {
    private final Map bets;
    private final Map results = new HashMap<>();
    private final List allInPlayers = new ArrayList<>();
    private final List activePlayers;
    private final List foldedPlayers = new ArrayList<>();

    private final String potName;
    private double currentBet;
    private double totalBets;
    private boolean allIn;
    private int currentPlayerIndex;

    public RoundBets(double blind, Player big, Player little, List activePlayers) {
        this.potName = "Main";
        this.bets = new HashMap<>();

        this.activePlayers = activePlayers;
        for (Player activePlayer : activePlayers) {
            results.put(activePlayer, EBetResult.NOT_BETTED);
        }

        double bigBlind = 2 * blind;

        playerBet(big, bigBlind);
        results.put(big, EBetResult.BLIND);
        playerBet(little, blind);
        results.put(little, EBetResult.BLIND);

        totalBets = sumOfCurrentBets();

        this.currentBet = bigBlind;
        this.currentPlayerIndex = activePlayers.indexOf(little);
    }

    /**
     * Constructor used when resolving all in bets
     *
     * @param newBets the list of new bets taken from breaking an existing betting round down into smaller all-in chunks
     * @param potName the description for the results
     */
    public RoundBets(Map newBets, String potName) {
        this.potName = potName;
        this.activePlayers = new ArrayList<>(newBets.keySet());
        this.bets = newBets;
        this.totalBets = sumOfCurrentBets();
    }

    public Map getBets() {
        return bets;
    }

    public RoundBets(List activeAfterRound, Player firstPlayer) {
        this.potName = "Side";
        this.bets = new HashMap<>();

        this.activePlayers = activeAfterRound;
        this.currentPlayerIndex = activeAfterRound.indexOf(firstPlayer);
        for (Player activePlayer : activePlayers) {
            results.put(activePlayer, EBetResult.NOT_BETTED);
        }
    }

    private double sumOfCurrentBets() {
        return bets.values().stream().mapToDouble(Double::doubleValue).sum();
    }


    public EBetResult placeBet(Player player, double bet) {
        if (activePlayers.indexOf(player) != currentPlayerIndex) {
            return EBetResult.OUT_OF_TURN;
        }

        boolean goingAllIn = bet >= player.getMoney();
        bet = Math.min(bet, player.getMoney());

        double playerTotal = bet + getPlayerBet(player);
        if (!goingAllIn && playerTotal < currentBet) {
            fold(player);
            return EBetResult.FOLDED;
        }

        playerBet(player, bet);

        advancePlayerIndex();

        if (playerTotal >= currentBet && bet == 0) {
            return playerResult(EBetResult.CHECKED, player);
        }

        if (playerTotal == currentBet) {
            return playerResult(goingAllIn ? EBetResult.ALL_IN : EBetResult.SAW, player);
        }

        if (playerTotal > currentBet) {
            currentBet = playerTotal;
            return playerResult(goingAllIn ? EBetResult.ALL_IN : EBetResult.RAISED, player);
        }

        throw new ShouldNotHaveHappenedException("Player total was unlike the bet in any way.");
    }

    private void advancePlayerIndex() {
        Player nextPlayer = null;
        int startingIndex = currentPlayerIndex;
        boolean first = true;
        while ((startingIndex != currentPlayerIndex || first) && (nextPlayer == null || (results.get(nextPlayer) != null && results.get(nextPlayer).isOutOfGame()))) {
            first = false;
            currentPlayerIndex = (currentPlayerIndex + 1) % activePlayers.size();
            nextPlayer = activePlayers.get(currentPlayerIndex);
        }
    }

    /**
     * Special fold for special occasions like the player leaving the game
     */
    public void fold(Player player) {
        results.put(player, EBetResult.FOLDED);
        foldedPlayers.add(player);

        if (getCurrentPlayer() == player) {
            advancePlayerIndex();
        }
    }

    private void playerBet(Player player, double bet) {
        player.loseMoney(bet);

        double entireBet = bet + getPlayerBet(player);
        bets.put(player, entireBet);

        totalBets += bet;
    }

    private Double getPlayerBet(Player player) {
        if (!bets.containsKey(player)) {
            return 0d;
        }

        return bets.get(player);
    }

    public boolean isRoundDone() {
        if (allIn) {
            return true;
        }

        List bettingPlayers = activePlayers.stream().filter(a -> results.get(a) != EBetResult.FOLDED).collect(Collectors.toList());
        if (bettingPlayers.size() == 1) {
            return true;
        }

        for (Player bettingPlayer : bettingPlayers) {
            EBetResult playerResult = results.get(bettingPlayer);
            if (playerResult == EBetResult.NOT_BETTED || playerResult == EBetResult.BLIND || (playerResult != EBetResult.ALL_IN && bets.get(bettingPlayer) < currentBet)) {
                return false;
            }
        }

        return true;
    }

    private List getBettingPlayers() {
        return activePlayers.stream().filter(a -> !results.get(a).isOutOfGame()).collect(Collectors.toList());
    }

    public List getInGamePlayers() {
        ArrayList players = new ArrayList<>(activePlayers);
        players.removeAll(foldedPlayers);
        return players;
    }

    private EBetResult playerResult(EBetResult result, Player player) {
        results.put(player, result);
        return result;
    }

    public void next(Player nextPlayer) {
        if (!isRoundDone()) {
            return;
        }

        Set foldedPlayers = new HashSet<>();
        for (Player player : results.keySet()) {
            EBetResult result = results.get(player);

            if (result != EBetResult.FOLDED) {
                if (result == EBetResult.ALL_IN) {
                    allInPlayers.add(player);
                }
            } else {
                foldedPlayers.add(player);
            }
        }

        if (results.containsValue(EBetResult.ALL_IN)) {
            allIn = true;
        }

        List bettingPlayers = getBettingPlayers();

        results.clear();
        currentBet = 0;

        for (Player foldedPlayer : foldedPlayers) {
            results.put(foldedPlayer, EBetResult.FOLDED);
        }

        for (Player foldedPlayer : allInPlayers) {
            results.put(foldedPlayer, EBetResult.ALL_IN);
        }

        for (Player bettingPlayer : bettingPlayers) {
            results.put(bettingPlayer, EBetResult.NOT_BETTED);
        }

        if (nextPlayer != null) {
            currentPlayerIndex = activePlayers.indexOf(nextPlayer);
        }
    }

    public double getTotalBetPool() {
        return totalBets;
    }

    public boolean isAllIn() {
        return allIn;
    }

    public List getActiveAfterRound() {
        return getBettingPlayers();
    }

    public Player getCurrentPlayer() {
        return activePlayers.get(currentPlayerIndex);
    }

    public String getDescription() {
        return potName;
    }

    public List normalize() {
        if (!isRoundDone() || this.allInPlayers.size() <= 1) {
            return Collections.singletonList(this);
        }

        List resultingBets = new ArrayList<>();
        List activePlayers = new ArrayList<>(this.activePlayers);
        Map> collect = this.allInPlayers.stream().collect(Collectors.groupingBy(bets::get));
        ArrayList allInBets = new ArrayList<>(collect.keySet());
        allInBets.sort(Double::compareTo);

        while (allInBets.size() > 1) {
            Map newBets = new HashMap<>();
            Double current = allInBets.remove(0);
            for (Player activePlayer : activePlayers) {
                newBets.put(activePlayer, current);
            }

            resultingBets.add(new RoundBets(newBets, resultingBets.isEmpty() ? "Main" : "Side"));

            for (Player activePlayer : activePlayers) {
                if (collect.get(current).contains(activePlayer)) {
                    bets.remove(activePlayer);
                } else {
                    bets.put(activePlayer, bets.get(activePlayer) - current);
                }
            }
        }

        resultingBets.add(new RoundBets(bets, "Side"));

        return resultingBets;
    }

    public double getCurrentBet() {
        return currentBet;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy