Poker-AI.org

Poker AI and Botting Discussion Forum
It is currently Mon Nov 13, 2023 5:26 pm

All times are UTC




Post new topic Reply to topic  [ 8 posts ] 
Author Message
PostPosted: Sun Sep 04, 2016 5:21 pm 
Offline
Junior Member

Joined: Sat Mar 12, 2016 10:17 am
Posts: 11
Hey guys, Im trying to make a simple push fold bot to calculate a NE, using Outcome Sampling with Monte Carlo Counterfactual Regret Minimization.

The problem is that, I will be using the Meerkat Open Testbed (which I modified for HU, you can find it here: https://github.com/npolychr/Heads-Up-No-Limit-Testbed) where each game has a strictly defined lifecycle, meaning that I cannot call a recursive function and I can only sample just one action at the time.

I'm really confused about this, is it doable? I mean do we need to calculate regrets for both actions (Push, Fold) at each iteration or we can simply calculate for one action each time? Will it mess the algorithm? (I have been reading papers for months now, still can't wrap my head around it)

The paper I'm reading is http://www.jair.org/media/3402/live-3402-5992-jair.pdf and the algorithm is at page 589.


Top
 Profile  
 
PostPosted: Mon Sep 05, 2016 10:00 am 
Offline
Site Admin
User avatar

Joined: Sun Feb 24, 2013 9:39 pm
Posts: 642
I long ago lost track of the different sampling schemes that had been tried.

amax posted some code at https://poker-ai.org/archive/www.pokera ... 335#p40335 which contained outcome sampling and some psuedo code at https://poker-ai.org/archive/www.pokera ... 942#p31942.

Maybe you are making things difficult for yourself by trying to use the testbed.


Top
 Profile  
 
PostPosted: Mon Sep 05, 2016 12:17 pm 
Offline
Junior Member

Joined: Sat Mar 12, 2016 10:17 am
Posts: 11
spears wrote:
I long ago lost track of the different sampling schemes that had been tried.

amax posted some code at https://poker-ai.org/archive/www.pokera ... 335#p40335 which contained outcome sampling and some psuedo code at https://poker-ai.org/archive/www.pokera ... 942#p31942.


Thanks for the reply Spears, you have been extremely helpful on my quest with your numerous posts.

spears wrote:
Maybe you are making things difficult for yourself by trying to use the testbed.


I probably am but, the testbed already has so many things built-in which should make our lives so much easier.

It just amazes me that nobody has tried to apply these algorithms with no recursivity, only one action being sampled at a time etc, eg. as close to how a real hand of poker is being played.

The real question is indifferent to which sampling scheme is being used and here it is; Can we implement CFR (and more specifically perform regret match) while sampling just one action at a time and thus being oblivious to the utilities of the other actions (at least in the first iterations)?


Top
 Profile  
 
PostPosted: Mon Sep 05, 2016 2:44 pm 
Offline
Site Admin
User avatar

Joined: Sun Feb 24, 2013 9:39 pm
Posts: 642
I think I've figured out what the question means. You want to choose a single action at a node instead of considering all of them.

So I looked at amaxs code that I linked before for a few minutes. Decision::TrainOutcomeSampling seems to do just that. So I tentatively say the answer to your question is yes.


Top
 Profile  
 
PostPosted: Mon Sep 05, 2016 2:58 pm 
Offline
Site Admin
User avatar

Joined: Sun Feb 24, 2013 9:39 pm
Posts: 642
Have you seen https://poker-ai.org/archive/www.pokera ... 687#p40687


Top
 Profile  
 
PostPosted: Thu Sep 22, 2016 9:12 am 
Offline
Junior Member

Joined: Sat Mar 12, 2016 10:17 am
Posts: 11
Hey Spears, thanks for everything! I think im really close to finishing my MCCFR OS bot to conclude to an equilibrium.

Would anyone like to review my code? Because most of the results are reasonable but I still get a few that look wrong. It is basically two same bots, one that is always on SB and one that is always BB with no seat permutation and no button moving. It runs on the Open Meerkat testbed (which in general is not suitable for heads-up because there are numerous miscalculations but I have already modified it to almost perfection, will reupload it as soon as I am done with this), so the function that gets called first is getAction().

I would like to know if I made some grave mistake.

So, this is how it goes. For every hand we create a node. If it is the first time we encounter it, we will shove the hand to find what is the utility of shove so we can regret match (we already know the utility of folding the SB). If we encounter the hand again, we will choose a random action with probability e (=0.6 currently) or choose an action based on the current regret strategy with probability (1-e). At the end of every hand gameOverEvent() gets called. The rest are pretty self explanatory (I tried to add comments on most lines).

Thanks everybody!

Code:
Code:
package bots.SuperNova;

import java.util.Arrays;
import java.util.Random;
import java.util.TreeMap;
import javax.swing.JPanel;
import com.biotools.meerkat.Action;
import com.biotools.meerkat.Card;
import com.biotools.meerkat.GameInfo;
import com.biotools.meerkat.Player;
import com.biotools.meerkat.util.Preferences;

public class SuperNova_MCCFR_OS_SB_Verbose implements Player {
   
        private Card c1, c2; // our hole cards
        private int ourSeat; // our seat for the current hand
   private GameInfo gi; // general game information
   private Preferences prefs;
        private Node node;
        int iterations = 1; // the number of iterations so we know when to show the node.
        private String cardsForSwitch; // stores the cards to use on switch statement.
        private char[] cardsForSwitchArray; // Converts cardsForSwitch which is a string to a character array.
        private double startingBankroll = 0.0D; // Stores the initial bankroll.
        private final int max = 1, min = 0, diff = max - min; // Max, min and difference values for 0-1 action choosing, to choose action FOLD or SHOVE.
        int a = 0, tempa = 0; // Variable to store if the action is 0 or 1, FOLD or SHOVE.
        private Action cfrAction; // Variable to store the action chosen by cfr to return to preFlopAction and then return in to getAction
        double[] util = new double[NUM_ACTIONS]; // Store the utilities.
        double e = 0.6; // ε-greedy
        boolean newEntry = false; // Boolean to show if it's the first entry of the hand to choose shove as first action.
        double randomForP = 0.0D; // Variable to store a random number.
        boolean choosingFromP = false; // Boolean to distinguish if we are choosing from random or current strategy.
        double evFoldSB; // Variable to store the EV of folding the SB.

        // These are the legal actions that we will allow.
        public static final int FOLD = 0, SHOVE = 1, NUM_ACTIONS = 2;

        /** This is a node that stores the information sets.
        * We store our information sets in a TreeMap called nodeMap,
        * indexed by String representations of all information of the information set.
        */
        public TreeMap<String, Node> nodeMap = new TreeMap<String, Node>();

        /** Each information set is represented by an inner class Node. Each node has fields corresponding to
        * the regret and strategy variable definitions of RPSTrainer with an additional field infoSet containing
        * the string representation of the information set.
        */
        class Node {
                String infoSet;
                double[] regretSum = new double[NUM_ACTIONS],
                         strategy = new double[NUM_ACTIONS],
                         strategySum = new double[NUM_ACTIONS],
                         foldShoveUtility = new double[NUM_ACTIONS];

                // Get current information set mixed strategy through regret-matching.
                private double[] getStrategy() {
                        System.out.println("getStrategy has been called!");
                        double normalizingSum = 0;
                        for (int a = 0; a < NUM_ACTIONS; a++) {
                                strategy[a] = regretSum[a] > 0 ? regretSum[a] : 0;
                                normalizingSum += strategy[a];
                        }
                        for (int a = 0; a < NUM_ACTIONS; a++) {
                                if (normalizingSum > 0) {
                                        strategy[a] /= normalizingSum;
                                }
                                else {
                                        strategy[a] = 1.0 / NUM_ACTIONS;
                                }
                                strategySum[a] += strategy[a];
                                }
                        a = tempa;
                        return strategy;
                }
               
                public double[] getAverageStrategy() {
                        System.out.println("getAverageStrategy has been called!");
                        double[] avgStrategy = new double[NUM_ACTIONS];
                        double normalizingSum = 0;
                        for (int a = 0; a < NUM_ACTIONS; a++) {
                                System.out.println("strategySum: " + strategySum[a]);
                                normalizingSum += strategySum[a];
                        }
                        for (int a = 0; a < NUM_ACTIONS; a++) {
                                if (normalizingSum > 0) {
                                        avgStrategy[a] = strategySum[a] / normalizingSum;
                                }
                                else {
                                        avgStrategy[a] = 1.0 / NUM_ACTIONS;
                                }
                        }
                        a = tempa;
                        return avgStrategy;
                }
               
                public String toString() {
                        System.out.println("toString has been called!");
                        return String.format("%4s: %s", infoSet, Arrays.toString(getAverageStrategy()));
                }
        }
   
        /** The utility of moves to check payoffs.
        * We have to store and retrieve it because when the
        * bot will be call again it will probably be set to zero.
        * Done!
        */
        double myUtil = 0.0D;
        double profit = 0.0D;

        private Action cfr(String cardsForSwitch) {
                // Update infoSet.
                String infoSet = cardsForSwitch;
                // Update node.
                this.node = nodeMap.get(infoSet); // Check if node exists.
                if (this.node != null) { // If it exists then,
                        System.out.println("Node EXISTS!");
                }
                if (this.node == null) { // If not then,
                        System.out.println("Node does not exist for " + infoSet + ", creating it...");
                        this.node = new Node(); // create new node,
                        this.node.infoSet = infoSet; // and set it to the infoset.
                        nodeMap.put(infoSet, this.node);
                        newEntry = true;
                }

                double[] strategy = node.getStrategy();
                System.out.println("node.getStrategy() [0]/FOLD: " + strategy[0]);
                System.out.println("node.getStrategy() [1]/SHOVE: " + strategy[1]);
                System.out.println("node.strategySum() [0]/FOLD: " + node.strategySum[0]);
                System.out.println("node.strategySum() [1]/SHOVE: " + node.strategySum[1]);

                // Get the random number for variable random to choose P or U.
                double randomForP = Math.random();
                System.out.println("The randomForP is: " + randomForP);

                if (randomForP <= (1 - e)) {
                        System.out.println("Choosing from P");
                        choosingFromP = true;
                }
                else {
                        System.out.println("Choosing from U");
                        choosingFromP = false;
                }

                // Get what we have to call. If it's 0 and we are at SB the opponent has checked.
                // If it's 0 and we are in BB, there was no action before us.
                double toCall = gi.getAmountToCall(ourSeat); 

                // If it's the first entry of the hand
                if (newEntry) {
                        System.out.println("This is a new entry of the hand. We will choose SHOVE.");

                        // Return newEntry to false.
                        newEntry = false;

                        a = 1; // Set a back to 1 to update the util[1] properly cause it will still choose a random a even though we are on newEntry.

                        System.out.println("Amount Raisable: " + gi.getPlayer(ourSeat).getAmountRaiseable());
                        // Return the chosen action.
                        return Action.raiseAction(gi, (Math.round(gi.getPlayer(ourSeat).getAmountRaiseable() * 100d) / 100d));
                }
                else { // If it is not the first entry eg. if newEntry == false.
                        if (choosingFromP) {

                                System.out.println("Current strategy [0]/FOLD: " + strategy[0]);
                                System.out.println("Current strategy [1]/SHOVE: " + strategy[1]);
                                                       
                                // Create new random.
                                randomForP = Math.random();
                                System.out.println("The New randomForP is: " + randomForP);

                                if (randomForP <= strategy[0]) {
                                        System.out.println("Chosen action is FOLD.");

                                        // Return the chosen action.
                                        return Action.foldAction(toCall);
                                }
                                else {
                                        System.out.println("Chosen action is SHOVE.");

                                        System.out.println("Amount Raisable: " + gi.getPlayer(ourSeat).getAmountRaiseable());
                                        // Return the chosen action.
                                        return Action.raiseAction(gi, (Math.round(gi.getPlayer(ourSeat).getAmountRaiseable() * 100d) / 100d));
                                }
                        }
                        else { // Choosing from U.
                                // Get the random number for variable a to choose the action.
                                Random rn = new Random();
                                a = rn.nextInt(diff + 1);
                                a += min;
                                System.out.println("The Random Number a is " + a + ".");
                                tempa = a;

                                // If a == 0, eg. if the action is FOLD.
                                switch (a) {
                                        case 0:
                                                System.out.println("Chosen action is FOLD.");

                                                // Return the chosen action.
                                                return Action.foldAction(toCall);
                                        case 1:
                                                System.out.println("Chosen action is SHOVE.");


                                                System.out.println("Amount Raisable: " + gi.getPlayer(ourSeat).getAmountRaiseable());
                                                // Return the chosen action.
                                                return Action.raiseAction(gi, (Math.round(gi.getPlayer(ourSeat).getAmountRaiseable() * 100d) / 100d));
                                        default:
                                                System.out.println("This shouldnt happen");
                                                return Action.callAction(toCall);   
                                }
                        }       
                }
        }

        public SuperNova_MCCFR_OS_SB_Verbose() {
        }

        /**
         * Requests an Action from the player
         * Called when it is the Player's turn to act.
         * It's the one function that gets called constantly,
         * so anything that happens must go here.
         * Everything has to happen before the return statement because
         * else it will get ignored.
         */
        @Override
        public Action getAction() {
                if (gi.isPreFlop()) { // If we are preflop
                        return preFlopAction();
                } else if (gi.isPostFlop()){ // If we are postflop
                        return postFlopAction();
                }
                else    throw new IllegalArgumentException("It is neither pre neither post flop.");
        }

        public Action preFlopAction() {

                System.out.println("Iteration: " + iterations);

                System.out.println("e-greedy: " + e);

                // Show starting bankroll
                startingBankroll = (gi.getPlayer(ourSeat).getBankRollAtStartOfHand());
                System.out.println("Bankroll at START of the hand: " + startingBankroll);

                // Show SB to show it's working
                evFoldSB = -(gi.getSmallBlindSize());
                System.out.println("evFoldSB: " + evFoldSB);

                // show card info for debugging purposes
                debug(gi.getPlayerName(ourSeat) + " Hand: [" + c1.toString() + "-" + c2.toString() + "] ");
                cardsForSwitch = c1.toString() + c2.toString();

                //System.out.println("Cards Preview:" + cardsForSwitch);
                cardsForSwitchArray = cardsForSwitch.toCharArray();

                // Variable to store the rank of the card, so we can
                // distinguish which card is higher.
                int firstCardRank = 0, secondCardRank = 0;

                // Switch statement to assign rank to first card.
                switch(String.valueOf(cardsForSwitchArray[0])){
                        case"A":
                                firstCardRank = 13;
                                break;
                        case"K":
                                firstCardRank = 12;
                                break;
                        case"Q":
                                firstCardRank = 11;
                                break;
                        case"J":
                                firstCardRank = 10;
                                break;
                        case"T":
                                firstCardRank = 9;
                                break;
                        case"9":
                                firstCardRank = 8;
                                break;
                        case"8":
                                firstCardRank = 7;
                                break;
                        case"7":
                                firstCardRank = 6;
                                break;
                        case"6":
                                firstCardRank = 5;
                                break;
                        case"5":
                                firstCardRank = 4;
                                break;
                        case"4":
                                firstCardRank = 3;
                                break;
                        case"3":
                                firstCardRank = 2;
                                break;
                        case"2":
                                firstCardRank = 1;
                                break; 
                }

                // Switch statement to assign ranks to second card.
                switch(String.valueOf(cardsForSwitchArray[2])){
                        case"A":
                                secondCardRank = 13;
                                break;
                        case"K":
                                secondCardRank = 12;
                                break;
                        case"Q":
                                secondCardRank = 11;
                                break;
                        case"J":
                                secondCardRank = 10;
                                break;
                        case"T":
                                secondCardRank = 9;
                                break;
                        case"9":
                                secondCardRank = 8;
                                break;
                        case"8":
                                secondCardRank = 7;
                                break;
                        case"7":
                                secondCardRank = 6;
                                break;
                        case"6":
                                secondCardRank = 5;
                                break;
                        case"5":
                                secondCardRank = 4;
                                break;
                        case"4":
                                secondCardRank = 3;
                                break;
                        case"3":
                                secondCardRank = 2;
                                break;
                        case"2":
                                secondCardRank = 1;
                                break; 
                }

                // If pair
                if (cardsForSwitchArray[0] == cardsForSwitchArray[2]){
                        cardsForSwitch = String.valueOf(cardsForSwitchArray[0]) + String.valueOf(cardsForSwitchArray[2]);
                        System.out.println("Hand: " + cardsForSwitch);
                }

                // Else if unpaired ofsuit
                else if ((cardsForSwitchArray[0] != cardsForSwitchArray[2]) && (cardsForSwitchArray[1] != cardsForSwitchArray[3])){
                        if (firstCardRank > secondCardRank){
                                cardsForSwitch = String.valueOf(cardsForSwitchArray[0]) + String.valueOf(cardsForSwitchArray[2]) + "o";
                        }
                        else    cardsForSwitch = String.valueOf(cardsForSwitchArray[2]) + String.valueOf(cardsForSwitchArray[0]) + "o";
                        System.out.println("Hand: " + cardsForSwitch);
                }

                // Else if unpaired suited
                else if ((cardsForSwitchArray[0] != cardsForSwitchArray[2]) && (cardsForSwitchArray[1] == cardsForSwitchArray[3])){
                        if (firstCardRank > secondCardRank){
                                cardsForSwitch = String.valueOf(cardsForSwitchArray[0]) + String.valueOf(cardsForSwitchArray[2] + "s");
                        }
                        else    cardsForSwitch = String.valueOf(cardsForSwitchArray[2]) + String.valueOf(cardsForSwitchArray[0] + "s");
                        System.out.println("Hand: " + cardsForSwitch);
                }

                // Show starting utility
                showUtil();

                cfrAction = cfr(cardsForSwitch);

                return cfrAction;
        }

        public Action postFlopAction() { // Shouldn't be called anyways.
                double toCall = gi.getAmountToCall(ourSeat);
                if (toCall == 0.0D) {
                        return Action.checkAction();
                }
                return Action.callAction(toCall);
        }

        /**
         * If you implement the getSettingsPanel() method, your bot will display
         * the panel in the Opponent Settings Dialog.
         * @return a GUI for configuring your bot (optional)
         */
        public JPanel getSettingsPanel() {
                return null;
        }

        /**
        * The game info state has been updated
        * Called after an action event has been fully processed
        */
        public void gameStateChanged() {
        }

        /**
         * Get the current settings for this bot.
         */
        public Preferences getPreferences() {
                return prefs;
        }

        /**
         * Load the current settings for this bot.
         */
        public void init(Preferences playerPrefs) {
                this.prefs = playerPrefs;
        }

        /**
         * A new betting round has started.
         */
        public void stageEvent(int stage) {
        }

        /**
         * A showdown has occurred.
         * @param pos the position of the player showing
         * @param c1 the first hole card shown
         * @param c2 the second hole card shown
         */
        public void showdownEvent(int seat, Card c1, Card c2) {
        }

        /**
         * A new game has been started.
         * @param gi the game stat information
         */
        public void gameStartEvent(GameInfo gInfo) {
                this.gi = gInfo;
        }

        /**
         * An event sent when all players are being dealt their hole cards
         */
        public void dealHoleCardsEvent() {
        }

        /**
         * An action has been observed.
         */
        public void actionEvent(int pos, Action act) {
        }

        @Override
        public void gameOverEvent() {
                System.out.println("The Game is over now: We should get the profit: ");

                // show bankroll at the end of the hand (should be the same as Updated Profit)
                System.out.println("Bankroll at END of the hand: " + gi.getBankRoll(ourSeat));

                // also show bankroll at START of hand to check it.
                System.out.println("Bankroll at START of the hand: " + startingBankroll);

                profit = (gi.getBankRoll(ourSeat) - startingBankroll);
                System.out.println("Profit for this hand: " + profit);
                profit = (Math.round(profit * 100d) / 100d);
                System.out.println("Rounded profit for this hand: " + profit);
                updatedUtil();

                if (iterations % 1000 == 0) {
                        // Printing the node on the end of the iterations.
                        System.out.println("Average game value myUtil: " + myUtil / iterations);
                        System.out.println("SB Strategy");
                        for (Node n : nodeMap.values()) {
                                System.out.println(n);
                        }
                }
                System.out.println("------------------------------------------------");       

                //if (e > 0 ) { // e makes no sense being negative
                        // Reduce ε-greedy to explore less and less
                        //e -= 0.0001;
                //}

                // Update iterations so it can reach the set point.
                iterations++;
        }

        /**
         * A player at pos has won amount with the hand handName
         */
        public void winEvent(int pos, double amount, String handName) {
        }

        /**
         * @return true if debug mode is on.
         */
        public boolean getDebug() {
                return prefs.getBooleanPreference("DEBUG", false);
        }

        /**
         * print a debug statement.
         */
        public void debug(String str) {
                if (getDebug()) {
                        System.out.println(str);
                }
        }

        /**
         * print a debug statement with no end of line character
         */
        public void debugb(String str) {
                if (getDebug()) {
                        System.out.print(str);
                }
        }

                /**
         * An event called to tell us our hole cards and seat number
         * @param c1 your first hole card
         * @param c2 your second hole card
         * @param seat your seat number at the table
         */
        public void holeCards(Card c1, Card c2, int seat) {
                this.c1 = c1;
                this.c2 = c2;
                this.ourSeat = seat;
        }


        public void showUtil() {
                System.out.println("Starting profit for this hand: " + myUtil);
        }

        public void updatedUtil() {
                myUtil = myUtil + profit;
                System.out.println("Updated Profit: " + myUtil);
                myUtil = (Math.round(myUtil * 100d) / 100d);
                System.out.println("Rounded updated Profit: " + myUtil);

                if (a == 1) {
                        System.out.println("SB: Profit before assigning to util[1] " + profit);
                        System.out.println("SB: last encountered shove utility: " + this.node.foldShoveUtility[1]);
                        util[1] = profit; // Assign the profit to the appropriate cfr results. We need to do this before the regret matching.
                        this.node.foldShoveUtility[1] = util[1];
                        System.out.println("SB: the new shove utility: " + this.node.foldShoveUtility[1]);   
                }

                double regret;

                for (int a = 0; a < NUM_ACTIONS; a++) {
                        if (a == 0) {
                                util[0]= evFoldSB;
                                System.out.println("SB: Regret matching for FOLD: ");
                                System.out.println("util FOLD: " + util[0]);
                                System.out.println("util SHOVE: " + this.node.foldShoveUtility[1]);
                                regret = evFoldSB - this.node.foldShoveUtility[1];
                                this.node.regretSum[0] += regret;
                                System.out.println("The regret for NOT folding is: " + this.node.regretSum[0]);
                        }
                        else if (a == 1){
                                System.out.println("SB: Regret matching for SHOVE: ");
                                System.out.println("util FOLD: " + util[0]);
                                System.out.println("util SHOVE: " + this.node.foldShoveUtility[1]);
                                regret = this.node.foldShoveUtility[1] - evFoldSB;
                                this.node.regretSum[1] += regret;
                                System.out.println("The regret for NOT shoving is: " + this.node.regretSum[1]);
                        }
                }
        }
    }




Top
 Profile  
 
PostPosted: Thu Sep 22, 2016 9:16 am 
Offline
Junior Member

Joined: Sat Mar 12, 2016 10:17 am
Posts: 11
Also, here is the strategy that it came up with at 100bb at 1m iterations with e = 0.6 (which shoves a lot of hands and I really dont know why). Left entry is the probability of Folding, right is the probability of Shoving (or Calling for the BB).

Code:
SB Strategy
  22: [0.9877887788778877, 0.01221122112211221]   
 32o: [0.999504186866461, 4.95813133539004E-4]
 32s: [0.9971390104341973, 0.00286098956580276]
  33: [0.05980756614913624, 0.9401924338508638]
 42o: [0.9999449460471261, 5.505395287381634E-5]
 42s: [0.999488926746167, 5.110732538330494E-4]
 43o: [0.999944885361552, 5.511463844797178E-5]
 43s: [0.9948760330578512, 0.005123966942148761]
  44: [0.01481401384083045, 0.9851859861591695]
 52o: [0.9987435813394515, 0.001256418660548454]
 52s: [0.970840197693575, 0.02915980230642504]
 53o: [0.9987195189845229, 0.0012804810154771183]
 53s: [0.9985346792575708, 0.001465320742429176]
 54o: [0.9998341441839894, 1.6585581601061478E-4]
 54s: [0.9991803278688525, 8.19672131147541E-4]
  55: [3.367003367003367E-4, 0.9996632996632997]
 62o: [0.9999455397015575, 5.446029844243546E-5]
 62s: [0.9656146179401993, 0.034385382059800663]
 63o: [0.9973118279569892, 0.002688172043010753]
 63s: [0.995368782161235, 0.004631217838765009]
 64o: [0.9900043696744593, 0.009995630325540747]
 64s: [0.9891864057672503, 0.010813594232749742]
 65o: [0.9877405167674547, 0.012259483232545354]
 65s: [0.9912164401723567, 0.008783559827643355]
  66: [0.09327284797521576, 0.9067271520247843]
 72o: [0.999836494440811, 1.6350555918901244E-4]
 72s: [0.9819297082228117, 0.01807029177718833]
 73o: [0.9999450307827616, 5.496921723834653E-5]
 73s: [0.9428715874620829, 0.05712841253791709]
 74o: [0.999945085118067, 5.4914881933003843E-5]
 74s: [0.9998344370860928, 1.6556291390728477E-4]
 75o: [0.9998350560809325, 1.6494391906751705E-4]
 75s: [0.9939739413680782, 0.006026058631921824]
 76o: [0.9992788994896827, 7.211005103172842E-4]
 76s: [0.9762606417812705, 0.023739358218729537]
  77: [1.1001100110011001E-4, 0.9998899889988999]
 82o: [0.9978436359615172, 0.002156364038482804]
 82s: [0.9971974942301352, 0.00280250576986482]
 83o: [0.999499944438271, 5.00055561729081E-4]
 83s: [0.9968088679879072, 0.0031911320120927107]
 84o: [0.9947910832306486, 0.005208916769351406]
 84s: [0.9936419954352788, 0.006358004564721226]
 85o: [0.9988599348534202, 0.0011400651465798045]
 85s: [0.8865213082259663, 0.11347869177403369]
 86o: [0.9999450549450549, 5.4945054945054945E-5]
 86s: [0.4031281533804238, 0.5968718466195762]
 87o: [0.9982756702636556, 0.001724329736344421]
 87s: [0.9998379779650033, 1.6202203499675956E-4]
  88: [1.1208249271463797E-4, 0.9998879175072853]
 92o: [0.9942815900510771, 0.00571840994892294]
 92s: [0.9585414585414586, 0.041458541458541456]
 93o: [0.9955831376495583, 0.004416862350441687]
 93s: [0.9654890415439974, 0.03451095845600262]
 94o: [0.9985120687754877, 0.0014879312245122892]
 94s: [0.9256598730370865, 0.07434012696291346]
 95o: [0.9980865952328887, 0.0019134047671113055]
 95s: [0.997120596205962, 0.0028794037940379404]
 96o: [0.9789156626506024, 0.02108433734939759]
 96s: [0.9345497154335454, 0.06545028456645463]
 97o: [0.7562273674969824, 0.24377263250301767]
 97s: [0.9634977287475666, 0.03650227125243349]
 98o: [0.9726693494299128, 0.02733065057008719]
 98s: [0.7461096075778079, 0.25389039242219213]
  99: [1.0969723562966213E-4, 0.9998903027643703]
 A2o: [0.11648240072202166, 0.8835175992779783]
 A2s: [0.03925755584756899, 0.960742444152431]
 A3o: [0.029405200312465126, 0.9705947996875349]
 A3s: [0.123157549950868, 0.876842450049132]
 A4o: [0.035583840619811846, 0.9644161593801882]
 A4s: [0.23975745657161587, 0.7602425434283842]
 A5o: [0.008181418844717769, 0.9918185811552822]
 A5s: [0.0014715500327011119, 0.9985284499672988]
 A6o: [0.07077376405107498, 0.9292262359489251]
 A6s: [0.031515349444807314, 0.9684846505551927]
 A7o: [0.0028418589100635237, 0.9971581410899365]
 A7s: [0.10878867676102699, 0.891211323238973]
 A8o: [0.004081404450408141, 0.9959185955495918]
 A8s: [1.650709805216243E-4, 0.9998349290194783]
 A9o: [0.08012997026104196, 0.919870029738958]
 A9s: [0.0028581035642232682, 0.9971418964357768]
  AA: [0.0018780380026513477, 0.9981219619973487]
 AJo: [0.026239230166722614, 0.9737607698332774]
 AJs: [0.02066798941798942, 0.9793320105820106]
 AKo: [0.008886190528755934, 0.9911138094712441]
 AKs: [0.07747179827471798, 0.922528201725282]
 AQo: [0.037596899224806204, 0.9624031007751938]
 AQs: [1.639344262295082E-4, 0.9998360655737705]
 ATo: [5.506001541680432E-5, 0.9999449399845832]
 ATs: [0.07725947521865889, 0.922740524781341]
 J2o: [0.9988519571397332, 0.0011480428602667833]
 J2s: [0.711839530332681, 0.288160469667319]
 J3o: [0.977102184948135, 0.02289781505186493]
 J3s: [0.8521928356210244, 0.14780716437897556]
 J4o: [0.9940011007154651, 0.005998899284534948]
 J4s: [0.7634496250407564, 0.23655037495924355]
 J5o: [0.9970766685052399, 0.002923331494760066]
 J5s: [0.6375582168995343, 0.3624417831004657]
 J6o: [0.9694296493564136, 0.03057035064358633]
 J6s: [0.7899088761390483, 0.21009112386095175]
 J7o: [0.9219893546240852, 0.07801064537591483]
 J7s: [0.6644759015840916, 0.3355240984159083]
 J8o: [0.729003421255932, 0.27099657874406796]
 J8s: [0.05860267711394058, 0.9413973228860594]
 J9o: [0.65783736647046, 0.34216263352954]
 J9s: [1.6954899966090201E-4, 0.9998304510003391]
  JJ: [1.0853049706967658E-4, 0.9998914695029303]
 JTo: [0.04495674077319023, 0.9550432592268098]
 JTs: [0.1179357021996616, 0.8820642978003385]
 K2o: [0.9951077396657871, 0.00489226033421284]
 K2s: [0.9209200805910007, 0.07907991940899933]
 K3o: [0.4144816904524837, 0.5855183095475163]
 K3s: [0.227491961414791, 0.772508038585209]
 K4o: [0.944971851197704, 0.05502814880229606]
 K4s: [0.1607264086897488, 0.8392735913102511]
 K5o: [0.6552145875027796, 0.3447854124972204]
 K5s: [0.011778367617783676, 0.9882216323822163]
 K6o: [0.47196467991169977, 0.5280353200883002]
 K6s: [0.09614745931584191, 0.9038525406841581]
 K7o: [0.5275139207337045, 0.47248607926629543]
 K7s: [0.08203653585926929, 0.9179634641407307]
 K8o: [0.19379212872363558, 0.8062078712763644]
 K8s: [0.012651988169569504, 0.9873480118304305]
 K9o: [0.001833944648216072, 0.9981660553517839]
 K9s: [1.7035775127768313E-4, 0.9998296422487223]
 KJo: [0.0017083654799955913, 0.9982916345200044]
 KJs: [0.020308828465928165, 0.9796911715340718]
  KK: [1.0955302366345311E-4, 0.9998904469763366]
 KQo: [0.0013014938886373925, 0.9986985061113626]
 KQs: [1.6270745200130165E-4, 0.9998372925479987]
 KTo: [0.010118323565188544, 0.9898816764348115]
 KTs: [0.009915966386554622, 0.9900840336134453]
 Q2o: [0.9968396540252827, 0.003160345974717232]
 Q2s: [0.6047904191616766, 0.39520958083832336]
 Q3o: [0.8908741066520066, 0.1091258933479934]
 Q3s: [0.9166377816291161, 0.08336221837088388]
 Q4o: [0.9613464951197871, 0.038653504880212956]
 Q4s: [1.6561775422325274E-4, 0.9998343822457767]
 Q5o: [0.999388820980109, 6.11179019891099E-4]
 Q5s: [0.4204209141729694, 0.5795790858270305]
 Q6o: [0.9558098784360968, 0.04419012156390319]
 Q6s: [0.07701000968679367, 0.9229899903132063]
 Q7o: [0.15497271411070276, 0.8450272858892972]
 Q7s: [0.010655737704918032, 0.989344262295082]
 Q8o: [0.06891544733608847, 0.9310845526639115]
 Q8s: [0.15625, 0.84375]
 Q9o: [0.3280769230769231, 0.671923076923077]
 Q9s: [1.650709805216243E-4, 0.9998349290194783]
 QJo: [8.313934153641503E-4, 0.9991686065846358]
 QJs: [0.0772938829787234, 0.9227061170212766]
  QQ: [3.331852509995558E-4, 0.9996668147490004]
 QTo: [0.0608056614044638, 0.9391943385955362]
 QTs: [1.6452780519907864E-4, 0.999835472194801]
 T2o: [0.991887417218543, 0.008112582781456953]
 T2s: [0.838671611598112, 0.16132838840188807]
 T3o: [0.9880648384589763, 0.011935161541023647]
 T3s: [0.9833847207947928, 0.01661527920520726]
 T4o: [0.9123694154256502, 0.08763058457434986]
 T4s: [0.9794340243501152, 0.02056597564988483]
 T5o: [0.998508122444469, 0.001491877555530998]
 T5s: [0.997557003257329, 0.0024429967426710096]
 T6o: [0.9532033743730051, 0.046796625626994985]
 T6s: [0.9392092257001647, 0.06079077429983525]
 T7o: [0.9158228552353399, 0.08417714476466007]
 T7s: [0.6691669326524098, 0.33083306734759016]
 T8o: [0.9983791638721217, 0.0016208361278783813]
 T8s: [0.5514681066486669, 0.4485318933513331]
 T9o: [0.0674678591391839, 0.9325321408608161]
 T9s: [0.9845879299156391, 0.015412070084360805]
  TT: [1.1193194537721066E-4, 0.9998880680546228]
Average game value myUtil: -0.056953


Code:
BB Strategy
  22: [0.6160337552742616, 0.38396624472573837]
 32o: [0.9998812633578722, 1.1873664212776063E-4]
 32s: [0.9828910614525139, 0.017108938547486033]
  33: [0.0947808961102905, 0.9052191038897095]
 42o: [0.9807033569308061, 0.01929664306919388]
 42s: [0.9996481351161154, 3.518648838845883E-4]
 43o: [0.9927776462230642, 0.007222353776935827]
 43s: [0.9891151685393258, 0.010884831460674158]
  44: [0.9577702702702703, 0.04222972972972973]
 52o: [0.9804696860771627, 0.019530313922837286]
 52s: [0.9512820512820512, 0.04871794871794872]
 53o: [0.9994070208728653, 5.929791271347248E-4]
 53s: [0.9996493688639552, 3.506311360448808E-4]
 54o: [0.952794292508918, 0.04720570749108204]
 54s: [0.9960116026105874, 0.003988397389412618]
  55: [0.005457997152349312, 0.9945420028476507]
 62o: [0.991192084942085, 0.008807915057915058]
 62s: [0.9996374184191443, 3.6258158085569254E-4]
 63o: [0.9923637218045113, 0.007636278195488721]
 63s: [0.9230769230769231, 0.07692307692307693]
 64o: [0.9763083451202264, 0.02369165487977369]
 64s: [0.9996402877697842, 3.5971223021582735E-4]
 65o: [0.9998806967310905, 1.1930326890956812E-4]
 65s: [0.9975404075895994, 0.002459592410400562]
  66: [0.026721232546942707, 0.9732787674530573]
 72o: [0.9954714352066883, 0.004528564793311658]
 72s: [0.8363197794624397, 0.16368022053756032]
 73o: [0.9915856838113297, 0.008414316188670301]
 73s: [0.997523000707714, 0.0024769992922859165]
 74o: [0.9998820198206702, 1.1798017932987259E-4]
 74s: [0.9989285714285714, 0.0010714285714285715]
 75o: [0.9902168788307402, 0.009783121169259784]
 75s: [0.9900953778429934, 0.009904622157006602]
 76o: [0.9960779652959354, 0.003922034704064654]
 76s: [0.99822695035461, 0.0017730496453900709]
  77: [0.09578454332552694, 0.9042154566744731]
 82o: [0.9986608229851474, 0.0013391770148526905]
 82s: [0.9115013774104683, 0.08849862258953169]
 83o: [0.9998822143698469, 1.1778563015312132E-4]
 83s: [0.8588110403397028, 0.14118895966029724]
 84o: [0.999877750611247, 1.2224938875305622E-4]
 84s: [0.888109305760709, 0.11189069423929099]
 85o: [0.9978855721393035, 0.0021144278606965174]
 85s: [0.9946996466431095, 0.00530035335689046]
 86o: [0.9970181297709924, 0.0029818702290076338]
 86s: [0.7844036697247706, 0.21559633027522937]
 87o: [0.9850580390219807, 0.014941960978019263]
 87s: [0.9982614742698191, 0.0017385257301808068]
  88: [2.4295432458697764E-4, 0.999757045675413]
 92o: [0.9984545886828341, 0.0015454113171659534]
 92s: [0.9391210374639769, 0.060878962536023054]
 93o: [0.9986948267679164, 0.0013051732320835312]
 93s: [0.9878048780487805, 0.012195121951219513]
 94o: [0.9945323406235458, 0.005467659376454164]
 94s: [0.9677304964539007, 0.03226950354609929]
 95o: [0.9938980617372577, 0.006101938262742283]
 95s: [0.7240726722180166, 0.27592732778198337]
 96o: [0.9977397097311445, 0.002260290268855579]
 96s: [0.08767424798239179, 0.9123257520176082]
 97o: [0.8381537719932514, 0.1618462280067486]
 97s: [0.0024475524475524478, 0.9975524475524475]
 98o: [0.9032911996184116, 0.09670880038158836]
 98s: [0.9476090014064698, 0.05239099859353024]
  99: [0.001721593703885883, 0.9982784062961141]
 A2o: [0.7142684693384839, 0.2857315306615162]
 A2s: [0.26903735632183906, 0.7309626436781609]
 A3o: [0.6985581622678397, 0.3014418377321603]
 A3s: [0.8519188993482983, 0.14808110065170166]
 A4o: [8.663366336633663E-4, 0.9991336633663367]
 A4s: [0.0032774945375091042, 0.9967225054624909]
 A5o: [0.004525440313111546, 0.9954745596868885]
 A5s: [0.06185944363103953, 0.9381405563689604]
 A6o: [1.2138868657441127E-4, 0.9998786113134256]
 A6s: [0.0184115523465704, 0.9815884476534296]
 A7o: [0.07273809523809524, 0.9272619047619047]
 A7s: [3.654970760233918E-4, 0.9996345029239766]
 A8o: [0.002890173410404624, 0.9971098265895953]
 A8s: [3.748125937031484E-4, 0.9996251874062968]
 A9o: [0.027050395256916996, 0.972949604743083]
 A9s: [3.5612535612535614E-4, 0.9996438746438746]
  AA: [2.469135802469136E-4, 0.9997530864197531]
 AJo: [0.017835767297103185, 0.9821642327028968]
 AJs: [3.700962250185048E-4, 0.9996299037749815]
 AKo: [0.018055555555555554, 0.9819444444444444]
 AKs: [0.03634361233480176, 0.9636563876651982]
 AQo: [0.08398388315285822, 0.9160161168471418]
 AQs: [3.787878787878788E-4, 0.9996212121212121]
 ATo: [0.004848334162108404, 0.9951516658378916]
 ATs: [0.009398496240601503, 0.9906015037593985]
 J2o: [0.9993965725319817, 6.034274680183442E-4]
 J2s: [0.9282592862345229, 0.07174071376547705]
 J3o: [0.8867122964361577, 0.11328770356384234]
 J3s: [0.9653846153846154, 0.03461538461538462]
 J4o: [0.9987077067669173, 0.0012922932330827067]
 J4s: [0.08350803633822501, 0.916491963661775]
 J5o: [0.9196470041802136, 0.08035299581978635]
 J5s: [0.9803571428571428, 0.019642857142857142]
 J6o: [0.9998808104886769, 1.1918951132300358E-4]
 J6s: [0.6974820143884892, 0.3025179856115108]
 J7o: [0.9850911779201578, 0.014908822079842288]
 J7s: [0.9910394265232975, 0.008960573476702509]
 J8o: [0.8632633357470432, 0.1367366642529568]
 J8s: [0.4803008595988539, 0.5196991404011462]
 J9o: [0.004627313656828414, 0.9953726863431716]
 J9s: [0.5840989399293286, 0.4159010600706714]
  JJ: [7.22543352601156E-4, 0.9992774566473989]
 JTo: [0.043503890591841544, 0.9564961094081584]
 JTs: [0.1345307917888563, 0.8654692082111437]
 K2o: [0.9979368932038835, 0.002063106796116505]
 K2s: [0.7427849927849928, 0.25721500721500723]
 K3o: [0.5023295733202551, 0.497670426679745]
 K3s: [0.5623591284748309, 0.43764087152516906]
 K4o: [0.9981558888615687, 0.001844111138431276]
 K4s: [0.9840876944837341, 0.015912305516265914]
 K5o: [0.7435805135589153, 0.2564194864410847]
 K5s: [0.34734848484848485, 0.6526515151515152]
 K6o: [1.2297097884899163E-4, 0.999877029021151]
 K6s: [0.6734913793103449, 0.3265086206896552]
 K7o: [0.10693928128872367, 0.8930607187112763]
 K7s: [0.006629448709002094, 0.9933705512909979]
 K8o: [0.05501578819528783, 0.9449842118047121]
 K8s: [0.38958496476115895, 0.610415035238841]
 K9o: [0.08226624788596279, 0.9177337521140372]
 K9s: [0.17229729729729729, 0.8277027027027027]
 KJo: [0.06561140647655872, 0.9343885935234413]
 KJs: [0.042360608254887765, 0.9576393917451123]
  KK: [2.560163850486431E-4, 0.9997439836149513]
 KQo: [0.16716529543754674, 0.8328347045624532]
 KQs: [0.0011312217194570137, 0.998868778280543]
 KTo: [1.24595066035385E-4, 0.9998754049339647]
 KTs: [0.011498516320474777, 0.9885014836795252]
 Q2o: [0.9947637603507062, 0.005236239649293716]
 Q2s: [0.4762247838616715, 0.5237752161383286]
 Q3o: [0.9066294317629917, 0.09337056823700826]
 Q3s: [0.8469387755102041, 0.15306122448979592]
 Q4o: [0.9313677514069, 0.06863224859310008]
 Q4s: [0.8526354862657758, 0.1473645137342242]
 Q5o: [0.4686351384464592, 0.5313648615535408]
 Q5s: [0.6958798882681564, 0.30412011173184356]
 Q6o: [0.8793517406962785, 0.12064825930372149]
 Q6s: [0.0032444124008651765, 0.9967555875991349]
 Q7o: [0.7577217692117618, 0.2422782307882382]
 Q7s: [0.07570422535211267, 0.9242957746478874]
 Q8o: [0.2218164110056002, 0.7781835889943998]
 Q8s: [0.22048104956268222, 0.7795189504373178]
 Q9o: [0.9852904820766378, 0.014709517923362175]
 Q9s: [0.10843819393042191, 0.8915618060695781]
 QJo: [0.01786594381468704, 0.9821340561853129]
 QJs: [0.026276831976313843, 0.9737231680236862]
  QQ: [0.01774112943528236, 0.9822588705647176]
 QTo: [0.007641921397379912, 0.99235807860262]
 QTs: [0.15043290043290045, 0.8495670995670995]
 T2o: [0.9824330783938815, 0.017566921606118547]
 T2s: [0.9580598103574034, 0.041940189642596645]
 T3o: [0.9948736289938007, 0.005126371006199332]
 T3s: [0.9712562100780695, 0.028743789921930447]
 T4o: [0.9867557715674362, 0.01324422843256379]
 T4s: [0.811231884057971, 0.188768115942029]
 T5o: [0.9720677146311971, 0.027932285368802903]
 T5s: [0.9996448863636364, 3.551136363636364E-4]
 T6o: [0.9147221554005293, 0.08527784459947077]
 T6s: [0.09015804597701149, 0.9098419540229885]
 T7o: [0.9096751577471371, 0.09032484225286282]
 T7s: [0.01850453172205438, 0.9814954682779456]
 T8o: [0.9782557592853784, 0.021744240714621534]
 T8s: [0.982488822652757, 0.01751117734724292]
 T9o: [0.7543922984356197, 0.24560770156438028]
 T9s: [0.29888059701492536, 0.7011194029850746]
  TT: [0.01516610495907559, 0.9848338950409244]


Top
 Profile  
 
PostPosted: Wed Sep 28, 2016 12:47 pm 
Offline
Junior Member

Joined: Sat Mar 12, 2016 10:17 am
Posts: 11
Noone wants to at least comment on it? :(


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 8 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group