-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathHistoryNodeLeduc.java
More file actions
220 lines (199 loc) · 6.85 KB
/
Copy pathHistoryNodeLeduc.java
File metadata and controls
220 lines (199 loc) · 6.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
import java.util.Random;
public class HistoryNodeLeduc implements History, ChanceNode, DecisionNode, TerminalNode
{
int NUM_PLAYERS ;
int TOTAL_GAME_ACTIONS ;
// memory - we need to save cards and decisions.
int[] cards={0,0,0}; //P1, P2, flop.
String decisions="";
HistoryNodeLeduc(int num_players, int total_game_actions)
{
NUM_PLAYERS= num_players;
TOTAL_GAME_ACTIONS=total_game_actions ;
// memory - we need to save cards and decisions.
int[] cards={0,0,0}; //P1, P2, flop.
String decisions="";
}
@Override
public double get_utility(int player) // Terminal node // this actually means "get_payoff", since it doesn't include probabilities (algorithm part)
{
if (this.is_terminal())
{
double[] player_bets = {1.0,1.0}; //both players start the game with a bet of 1
int betting_player;
double pay_off=0.0;
boolean is_player_card_higher= cards[player]>cards[1-player]; //for two players
boolean is_player_card_match_flop= cards[player]==cards[2]; //for two players
char curr_char=' ';
for (int i=0; i<decisions.length(); i++)
{
if ((i>=3) && (decisions.charAt(2)=='C')) // the indices run from 0 to l-1.
betting_player = 1-(i%2);
else
betting_player = i%2 ;
curr_char= decisions.charAt(i);
switch (curr_char)
{
case 'b': player_bets[betting_player] +=1.0; break;
case 'C': player_bets[betting_player] +=1.0; break;
case 'R': player_bets[betting_player] +=2.0; break;
default : break;
}
}
if (decisions.endsWith("F"))
{
int finishing_player = 1-get_player(); //get_player() returns the player whose turn is now, so invert it to get the player who played the last turn
pay_off = (player==finishing_player) ? -player_bets[player] : player_bets[1-player]; //the folding player loses his bets
return pay_off;
}
if (cards[player] == cards[1-player]) { //there's a tie, players split the pot so no one profits
return 0.0;
}
if ( (cards[player]==cards[2]) || (cards[1-player]==cards[2]) ) //one of the players matches the flop
{
pay_off = is_player_card_match_flop ? player_bets[1-player] : -player_bets[player] ;
return pay_off;
}
pay_off = is_player_card_higher ? player_bets[1-player] : -player_bets[player] ; //the player with the higher card wins
return pay_off;
}
return 0.0;
}
@Override
public int num_valid_actions() //Decision node
{
if (decisions=="") return 2;
if (decisions.endsWith("b")) return 3;
return 2; // either bet/check or fold/call after raise.
}
@Override
public int total_game_actions() //Decision node
{
return TOTAL_GAME_ACTIONS;
}
@Override
public boolean action_valid(int action) //Decision node
{
if ( (decisions=="") && (action<=1) ) return true; // first check/ bet
if ( (decisions.endsWith("C")) && (action<=1)) return true; // second check/ bet - after call (flop)
if ( (decisions.endsWith("R")) && (action>=2) && (action<=3) ) return true; //fold/ call after raise
if ( (decisions.endsWith("b")) && (action>=2) ) return true; // fold/ call/ raise after bet
if ( (decisions.endsWith("c")) && (action<=1) ) return true; // check/ bet after second check
return false;
}
@Override
public Outcome get_decision_outcome(int outcome_num) //Decision node
{
Outcome_Class outcome=new Outcome_Class();
switch (outcome_num)
{
case 0: outcome.setOutcome('c'); break;
case 1: outcome.setOutcome('b'); break;
case 2: outcome.setOutcome('F'); break;
case 3: outcome.setOutcome('C'); break;
case 4: outcome.setOutcome('R'); break;
}
return outcome;
}
@Override
public Outcome sample_outcome() // Chance node
{// if we want chance sampling.
int player=this.get_player();
if (decisions=="") // the cards are dealt once - before the first turn of player 0.
{ int[] allCards={1,1,2,2,3,3};
Random random = new Random();
for (int c1 = allCards.length - 1; c1 > 0; c1--) //shuffling
{
int c2 = random.nextInt(c1 + 1);
int tmp = allCards[c1];
allCards[c1] = allCards[c2];
allCards[c2] = tmp;
}
cards[0]=allCards[0];
cards[1]=allCards[1];
cards[2]=allCards[2]; //flop
}
Outcome_Class outcome= new Outcome_Class();
outcome.setOutcome(cards[player]);
return outcome;
}
@Override
public int num_chance_outcomes()
{
return 24;
}
public Outcome get_chance_outcome(int outcome_num)
{
int[][] cards_combination = {{1,1,2},{1,2,1},{2,1,1},{1,1,3},{1,3,1},{3,1,1},{2,2,1},{2,1,2},{1,2,2},{2,2,3},{2,3,2},{3,2,2},{3,3,1},{3,1,3},{1,3,3},{3,3,2},{3,2,3},{2,3,3},{1,2,3},{1,3,2},{2,1,3},{2,3,1},{3,1,2},{3,2,1}};
int player=this.get_player();
if (player==0) // the cards are dealt once.
cards = cards_combination[outcome_num];
Outcome_Class outcome = new Outcome_Class();
outcome.setOutcome(cards[player]);
return outcome;
}
public double get_chance_outcome_probability(int outcome_num)
{
assert(outcome_num >= 0 && outcome_num < 24);
if (outcome_num < 18)
return 1.0/30.0;
else
return 1.0/15.0;
}
@Override
public boolean is_terminal() //History
{
if (decisions=="") return false;
if (decisions.endsWith("F")) return true;
if (decisions.endsWith("cc") && decisions.length()>= 4) return true; // "cc" is terminal in the 2nd round only
if (decisions.endsWith("RC") && decisions.length()> 4) return true; // C is terminal in the 2nd round only (length>4 because cbRC is not terminal)
if (decisions.endsWith("bC") && decisions.length()>= 4) return true; // C is terminal in the 2nd round only (length>=4 because bCbC is terminal)
return false;
}
@Override
public boolean is_chance() //History
{
if (cards[0] == 0) return true;
return false;
}
@Override
public History append(Outcome a) //History
{
HistoryNodeLeduc new_history= new HistoryNodeLeduc(NUM_PLAYERS, TOTAL_GAME_ACTIONS);
new_history.cards=cards;
new_history.decisions=decisions;
if (!Character.isDigit(((Outcome_Class)a).getOutcome()))
new_history.decisions+=((Outcome_Class)a).getOutcome();
return new_history;
}
@Override
public String get_information_set() //History
{
int player= this.get_player();
String infoset="";
if (post_flop()) // post flop
infoset= String.valueOf(cards[player])+ String.valueOf(cards[2])+ decisions;
else
infoset= String.valueOf(cards[player])+ decisions;
return infoset;
}
@Override
public int get_player() //History
{
if (decisions=="") return 0;
int l=decisions.length();
if ((l>=3) && (decisions.charAt(2)=='C')) // the indices run from 0 to l-1.
return 1-(l%2);
else
return l%2 ;
}
public boolean post_flop()
{
if ( decisions.contains("C") || (decisions.lastIndexOf('c')>=1) ) {
return true;
}
else {
return false;
}
}
}