Source code: org/pokersource/enum/SAIE.java
1 // $Id: SAIE.java,v 1.7 2002/06/13 03:04:56 mjmaurer Exp $
2
3 package org.pokersource.enum;
4 import org.pokersource.game.Deck;
5 import java.util.Map;
6 import java.util.Iterator;
7 import java.util.Enumeration;
8
9 /** Algorithms for computing subjective all-in equity. SAIE is a player's pot
10 equity given particular beliefs about the possible hands of the
11 opponent(s) and assuming no further betting. Beliefs about an opponent's
12 hand distribution are represented by a BeliefVector object which maps each
13 possible opponent hand to the probability of its occurrence.
14 @author Michael Maurer <mjmaurer@yahoo.com>
15 */
16
17 public class SAIE {
18
19 /** Compute the subjective all-in equity of each player based on a
20 belief distribution for each player's hands. Typical usage is
21 to fix one player's cards and allow the other players' cards to
22 range over a distribution; however, it is valid for all players to
23 have multiple possible hands.
24 @param gameType One of Enumerate.GAME_HOLDEM, etc.
25 @param nmatchups number of matchups to sample (if zero, full enumeration)
26 [Note: matchups are counted before they are tested for feasibility, that
27 is, whether they share cards. So the total number of matchups that
28 contribute to the SAIE estimate may be less than nmatchups.]
29 @param noutcomes number of boards to sample (if zero, full enumeration)
30 @param handDistribs the hand distribution belief vector for each player
31 @param board bitmask of cards already dealt to board (can be zero)
32 @param dead bitmask of cards that cannot appear in any hand or on
33 the board (can be zero)
34 @param ev output: ev[i] player i's all-in pot equity
35 @param matchups output: map of {HandMatchup, MatchupOutcome}
36 pairs, one for each matchup
37 */
38 public static void FlopGameSAIE(int gameType,
39 int nmatchups, int noutcomes,
40 BeliefVector[] handDistribs,
41 long board, long dead,
42 double ev[], Map matchups) {
43 if (matchups != null)
44 matchups.clear();
45 int nplayers = handDistribs.length;
46 long[][] hands = new long[nplayers][];
47 int[] nhands = new int[nplayers];
48 for (int i=0; i<nplayers; i++) {
49 hands[i] = handDistribs[i].getHands();
50 nhands[i] = hands[i].length;
51 ev[i] = 0;
52 }
53 long unavail1 = dead | board;
54 double totalprob = 0;
55 double[] matchev = new double[nplayers];
56 long[] curhands = new long[nplayers];
57 Enumeration enum;
58 if (nmatchups == 0) {
59 enum = new NestedLoopEnumeration(nhands);
60 } else {
61 enum = new NestedLoopSampling(nhands, nmatchups);
62 }
63 mainloop:
64 while (enum.hasMoreElements()) { // loop over all hand matchups
65 int[] indices = (int[]) enum.nextElement();
66 long unavail2 = unavail1;
67 double matchprob = 1; // the probability of this matchup
68 for (int i=0; i<nplayers; i++) {
69 // get a particular hand for each player to use in this matchup
70 curhands[i] = hands[i][indices[i]];
71 if ((curhands[i] & unavail2) != 0) // already used one of these cards?
72 continue mainloop; // if so, this matchup cannot occur
73 unavail2 |= curhands[i];
74 matchprob *= handDistribs[i].getBeliefProb(curhands[i]);
75 if (matchprob == 0)
76 continue mainloop;
77 }
78
79 // heavy lifting for this matchup: enumerate all outcomes
80 Enumerate.PotEquity(gameType, noutcomes, curhands, board, dead, matchev);
81
82 if (matchups != null) { // save to Collection if requested
83 HandMatchup matchup = new HandMatchup(curhands);
84 MatchupOutcome outcome = new MatchupOutcome(matchprob, matchev);
85 MatchupOutcome existing = (MatchupOutcome) matchups.get(matchup);
86 if (existing != null)
87 existing.merge(outcome);
88 else
89 matchups.put(matchup, outcome);
90 }
91
92 // accumulate this matchup into totals
93 for (int i=0; i<nplayers; i++)
94 ev[i] += matchev[i] * matchprob;
95 totalprob += matchprob;
96 }
97 if (totalprob == 0)
98 throw new IllegalArgumentException("no matchups sampled: increase nmatchups?");
99 // Scale by the total probability of all matchups (this factor is less
100 // than one when the hand distributions are not disjoint).
101 for (int i=0; i<nplayers; i++)
102 ev[i] /= totalprob;
103 if (matchups != null) {
104 for (Iterator iter=matchups.values().iterator(); iter.hasNext(); ) {
105 MatchupOutcome outcome = (MatchupOutcome) iter.next();
106 outcome.matchProb /= totalprob;
107 }
108 }
109 }
110
111 public static void main(String[] args) {
112 int nmatchups = Integer.parseInt(args[0]);
113 int noutcomes = Integer.parseInt(args[1]);
114 int nplayers = args.length - 4;
115 System.out.println("nplayers=" + nplayers +
116 ", nmatchups=" + nmatchups +
117 ((nmatchups == 0) ? " (enumerate)" : " (sample)") +
118 ", noutcomes=" + noutcomes +
119 ((noutcomes == 0) ? " (enumerate)" : " (sample)"));
120 HoldemBeliefVector[] beliefs = new HoldemBeliefVector[nplayers];
121 for (int i=0; i<nplayers; i++) {
122 beliefs[i] = new HoldemBeliefVector(args[i+2]);
123 System.out.println("beliefs[" + i + "].toString = " +
124 beliefs[i].toString());
125 System.out.println("beliefs[" + i + "].toStringAtomic = " +
126 beliefs[i].toStringAtomic());
127 }
128 long board = Deck.parseCardMask(args[args.length-2]);
129 long dead = Deck.parseCardMask(args[args.length-1]);
130 System.out.println("board = " + Deck.cardMaskString(board));
131 System.out.println("dead = " + Deck.cardMaskString(dead));
132
133 double[] totalev = new double[nplayers];
134 FlopGameSAIE(Enumerate.GAME_HOLDEM, nmatchups, noutcomes,
135 beliefs, board, dead, totalev, null);
136 for (int i=0; i<nplayers; i++) {
137 System.out.println("FlopGameSAIE: totalev[" + i + "] = " + totalev[i]);
138 }
139 }
140 }