-
Notifications
You must be signed in to change notification settings - Fork 1
/
match.cc
227 lines (188 loc) · 6.54 KB
/
match.cc
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
221
222
223
224
225
226
#include <iostream>
#include <string>
#include <vector>
#include <assert.h>
#include "match.h"
#include "trace.h"
// This plays a match between the two players, consisting of a number
// of independent games.
int Match::play(int numGames)
{
std::cout << "Playing match between " << m_p1->name() << " and "
<< m_p2->name() << std::endl;
int sum = 0;
for (int g=0; g<numGames; ++g)
{
sum += playOneGame();
} // end of for
return sum;
} // end of play
// This plays a single game between the two players. Both players are given
// an initial bank credit, and the game continues until one player runs
// out of credit.
int Match::playOneGame()
{
TRACE(std::endl);
TRACE(std::endl);
TRACE("============================" << std::endl);
TRACE("Starting new game" << std::endl);
TRACE("============================" << std::endl);
TRACE(std::endl);
std::vector<Player*> players({m_p1, m_p2});
// The players current bank accounts
std::vector<int> banks({100, 100});
// The current value of the pot
int pot = 0;
// This is the player to make the first action in the next round.
int startingPlayer = 0;
// Keep playing until one player runs out of credit.
while (banks[0] > 0 && banks[1] > 0)
{
TRACE(std::endl << std::endl);
TRACE("Current credis: " << players[0]->name() << "=" << banks[0] <<
", " << players[1]->name() << "=" << banks[1] <<
", pot=" << pot << std::endl);
playOneRound(players, banks, pot, startingPlayer);
startingPlayer = 1 - startingPlayer;
} // end of while (banks[0] > 0 && banks[1] > 0)
// The game is finished.
if (banks[0] <= 0) // Player 0 has lost
{
return -1;
}
if (banks[1] <= 0) // Player 1 has lost
{
return 1;
}
return 0; // Should never happen
} // end of playOneGame
// This plays a single round between the two players.
// See README.md for a description of the rules. See also
// https://en.wikipedia.org/wiki/Betting_in_poker for a description
// of the source of inspiration.
void Match::playOneRound(const std::vector<Player*>& players,
std::vector<int>& banks, int& pot, int startingPlayer)
{
// The players dealt card
std::vector<unsigned> cards({rand()%13U, rand()%13U});
TRACE("+++++++++++++++++++++++++++++++++++++++" << std::endl);
TRACE("" << players[0]->name() << "'s card: " << cards[0] <<
", " << players[1]->name() << "'s card: " <<
cards[1] << std::endl);
// True if the current player has not made any action yet.
std::vector<bool> firstAction({true, true});
// The current amount needed to call
int callCost = 0;
// Both players must pay 'ante' of 1 unit to the pot
banks[0] -= 1;
banks[1] -= 1;
pot += 2;
TRACE("Both players ante" << std::endl);
int curPlayer = startingPlayer;
// The following while loop plays one round
while (true)
{
TRACE(std::endl << players[curPlayer]->name() << "'s turn: callCost=" <<
callCost << ", credits=" << banks[curPlayer] <<
", pot=" << pot << std::endl);
// Get action from player
int bet = players[curPlayer]->bet(cards[curPlayer], callCost,
banks[curPlayer], pot);
if (bet < 0)
{
TRACE("" << players[curPlayer]->name() << " folds." << std::endl);
// Opponent keeps the pot.
banks[1-curPlayer] += pot;
pot = 0;
return; // This round has now ended.
}
else if (bet == 0)
{
TRACE("" << players[curPlayer]->name() << " checks." << std::endl);
// This is only allowed on the first round
if (!firstAction[curPlayer])
{
TRACE("" << players[curPlayer]->name() << " is cheating: " <<
"Checking is only allowed on the first move." << std::endl);
assert(false);
}
if (callCost > 0)
{
TRACE("" << players[curPlayer]->name() << " is cheating: " <<
"Checking is not allowed when there is a bet made already" <<
std::endl);
assert(false);
}
}
else // bet > 0
{
if (callCost == 0)
{
TRACE("" << players[curPlayer]->name() << " bets " << bet <<
"." << std::endl);
}
else if (bet == callCost)
{
TRACE("" << players[curPlayer]->name() << " calls." << std::endl);
}
else if (bet > callCost)
{
TRACE("" << players[curPlayer]->name() << " raises " << bet-callCost <<
"." << std::endl);
}
else
{
TRACE("" << players[curPlayer]->name() << " is cheating: " <<
"Trying to call without paying enough money." << std::endl);
assert(false);
}
if (bet > banks[curPlayer])
{
TRACE("" << players[curPlayer]->name() << " goes all in. " <<
"Pot reduced by " << bet-banks[curPlayer] << std::endl);
// Player is going ALL-IN
// Reduce the pot accordingly
pot -= (bet-banks[curPlayer]);
banks[1-curPlayer] += (bet-banks[curPlayer]);
callCost = banks[curPlayer];
bet = banks[curPlayer];
}
// Player pays to the pot.
banks[curPlayer] -= bet;
pot += bet;
// Calculate the new value to pay for a call.
callCost = bet - callCost;
if (callCost == 0)
{
// Player has CALL'ed.
if (cards[0] > cards[1])
{
// Player 0 earns the pot.
TRACE("" << players[0]->name() << " wins the pot." << std::endl);
banks[0] += pot;
pot = 0;
}
else if (cards[0] < cards[1])
{
// Player 1 earns the pot.
TRACE("" << players[1]->name() << " wins the pot." << std::endl);
banks[1] += pot;
pot = 0;
}
else
{
TRACE("Cards match. Pot remains." << std::endl);
}
// If the cards are the same, just leave the pot.
return; // Play a new round
}
}
firstAction[curPlayer] = false;
curPlayer = 1-curPlayer;
if (!firstAction[0] && !firstAction[1] && callCost == 0)
{
TRACE("Both players checked. Dealing new cards." << std::endl);
return; // Play a new round
}
} // end of while (true)
} // end of playOneRound