4 Copyright (c) 2010-2014 Lode Vandevenne
7 This file is part of OOPoker.
9 OOPoker is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 OOPoker is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with OOPoker. If not, see <http://www.gnu.org/licenses/>.
31 #include "ai_blindlimp.h"
33 #include "ai_checkfold.h"
35 #include "ai_random.h"
38 #include "combination.h"
40 #include "io_terminal.h"
42 #include "pokereval.h"
43 #include "pokermath.h"
48 ////////////////////////////////////////////////////////////////////////////////
52 throw 1; //that's how to let a unittest fail
55 template<typename T
, typename U
>
56 void assertEquals(const T
& expected
, const U
& actual
, const std::string
& message
= "")
58 if(expected
!= (T
)actual
)
60 std::cout
<< "Error: Not equal! Expected " << expected
<< " got " << (T
)actual
<< "." << std::endl
;
61 std::cout
<< "Message: " << message
<< std::endl
;
66 void assertTrue(bool value
, const std::string
& message
= "")
70 std::cout
<< "Error: expected true." << std::endl
;
71 std::cout
<< "Message: " << message
<< std::endl
;
76 #define STR_EXPAND(s) #s
77 #define STR(s) STR_EXPAND(s)
78 #define ASSERT_EQUALS(e, v) \
80 assertEquals(e, v, std::string() + "line " + STR(__LINE__) + ": " + STR(v));\
82 #define ASSERT_TRUE(v) \
84 assertTrue(v, std::string() + "line " + STR(__LINE__) + ": " + STR(v));\
87 ////////////////////////////////////////////////////////////////////////////////
89 void testWinChanceAtFlop(const std::string
& hcard1
, const std::string
& hcard2
, const std::string
& card1
, const std::string
& card2
, const std::string
& card3
)
91 std::cout
<< "testing win chance at flop (" << hcard1
<< " " << hcard2
<< " | " << card1
<< " " << card2
<< " " << card3
<< ")" << std::endl
;
92 double win
, tie
, lose
;
93 getWinChanceAgainst1AtFlop(win
, tie
, lose
, Card(hcard1
), Card(hcard2
), Card(card1
), Card(card2
), Card(card3
));
94 std::cout
<< "win: " << win
<< " tie: " << tie
<< " lose: " << lose
<< std::endl
;
95 std::cout
<< std::endl
;
99 void testWinChanceAtFlop()
102 testWinChanceAtFlop("6h", "2d", "8s", "Ts", "Jh");
103 testWinChanceAtFlop("2h", "7d", "5s", "Js", "8h");
105 //junk in your hand, good cards on table
106 testWinChanceAtFlop("6h", "2d", "As", "Ac", "Jh");
109 testWinChanceAtFlop("Ah", "Kd", "8s", "7s", "Jh");
112 testWinChanceAtFlop("6h", "2d", "8s", "Ts", "6d");
115 testWinChanceAtFlop("6h", "2d", "8s", "6s", "2h");
118 testWinChanceAtFlop("6h", "2d", "6d", "6s", "Jh");
121 testWinChanceAtFlop("Ah", "Td", "Js", "Ks", "Qh");
122 testWinChanceAtFlop("Js", "Ks", "Qh", "Ah", "Td");
125 testWinChanceAtFlop("6d", "2d", "8d", "Td", "Jh");
128 testWinChanceAtFlop("6d", "2d", "8d", "Td", "Jd");
131 testWinChanceAtFlop("6h", "2d", "2s", "6s", "6d");
134 testWinChanceAtFlop("6h", "2d", "6s", "6d", "6c");
137 testWinChanceAtFlop("6h", "2h", "3h", "4h", "5h");
139 //royal flush (100% win chance)
140 testWinChanceAtFlop("Ad", "Kd", "Qd", "Td", "Jd");
143 void testWinChanceAtRiver(const std::string
& hcard1
, const std::string
& hcard2
, const std::string
& card1
, const std::string
& card2
, const std::string
& card3
, const std::string
& card4
, const std::string
& card5
)
145 std::cout
<< "testing win chance at river (" << hcard1
<< " " << hcard2
<< " | " << card1
<< " " << card2
<< " " << card3
<< " " << card4
<< " " << card5
<< ")" << std::endl
;
146 double win
, tie
, lose
;
147 getWinChanceAgainst1AtRiver(win
, tie
, lose
, Card(hcard1
), Card(hcard2
), Card(card1
), Card(card2
), Card(card3
), Card(card4
), Card(card5
));
148 std::cout
<< "win: " << win
<< " tie: " << tie
<< " lose: " << lose
<< std::endl
;
149 std::cout
<< std::endl
;
152 void testWinChanceAtRiver()
154 //everyone ties due to royal flush on table
155 testWinChanceAtRiver("2d", "7d", "Ad", "Kd", "Qd", "Jd", "Td");
157 //quad aces but with royal flush chance for opponent!
158 testWinChanceAtRiver("Ad", "As", "Ah", "Ac", "Qc", "Jc", "Tc");
166 void testWinChanceAtFlopAgainst9(const std::string
& hcard1
, const std::string
& hcard2
, const std::string
& card1
, const std::string
& card2
, const std::string
& card3
)
168 std::cout
<< "testing win chance at flop against 9 (" << hcard1
<< " " << hcard2
<< " | " << card1
<< " " << card2
<< " " << card3
<< ")" << std::endl
;
169 double win
, tie
, lose
;
170 getWinChanceAgainstNAtFlop(win
, tie
, lose
, Card(hcard1
), Card(hcard2
), Card(card1
), Card(card2
), Card(card3
), 9/*, 10000*/);
171 std::cout
<< "win: " << win
<< " tie: " << tie
<< " lose: " << lose
<< std::endl
;
172 std::cout
<< std::endl
;
176 void testWinChanceAtFlopAgainst9()
179 testWinChanceAtFlopAgainst9("6h", "2d", "8s", "Ts", "Jh");
180 testWinChanceAtFlopAgainst9("2h", "7d", "5s", "Js", "8h");
182 //junk in your hand, good cards on table
183 testWinChanceAtFlopAgainst9("6h", "2d", "As", "Ac", "Jh");
186 testWinChanceAtFlopAgainst9("Ah", "Kd", "8s", "7s", "Jh");
189 testWinChanceAtFlopAgainst9("6h", "2d", "8s", "Ts", "6d");
192 testWinChanceAtFlopAgainst9("6h", "2d", "8s", "6s", "2h");
195 testWinChanceAtFlopAgainst9("6h", "2d", "6d", "6s", "Jh");
198 testWinChanceAtFlopAgainst9("Ah", "Td", "Js", "Ks", "Qh");
199 testWinChanceAtFlopAgainst9("Js", "Ks", "Qh", "Ah", "Td");
202 testWinChanceAtFlopAgainst9("6d", "2d", "8d", "Td", "Jh");
205 testWinChanceAtFlopAgainst9("6d", "2d", "8d", "Td", "Jd");
208 testWinChanceAtFlopAgainst9("6h", "2d", "2s", "6s", "6d");
211 testWinChanceAtFlopAgainst9("6h", "2d", "6s", "6d", "6c");
214 testWinChanceAtFlopAgainst9("6h", "2h", "3h", "4h", "5h");
216 //royal flush (100% win chance)
217 testWinChanceAtFlopAgainst9("Ad", "Kd", "Qd", "Td", "Jd");
224 void testEval5(const std::string
& c1
, const std::string
& c2
, const std::string
& c3
, const std::string
& c4
, const std::string
& c5
)
226 std::cout
<< "testing eval5 (" << c1
<< " " << c2
<< " " << c3
<< " " << c4
<< " " << c5
<< ")" << std::endl
;
227 int cards
[5] = { eval5_index(Card(c1
)), eval5_index(Card(c2
)), eval5_index(Card(c3
)), eval5_index(Card(c4
)), eval5_index(Card(c5
)) };
228 int v
= eval5(cards
);
230 std::cout
<< v
<< " original: " << PokerEval::eval_5hand(cards
) << std::endl
<< std::endl
;
236 testEval5("2h", "3d", "4s", "5s", "7h");
239 testEval5("6h", "2d", "8s", "Ts", "Jh");
240 testEval5("2h", "7d", "5s", "Js", "8h");
243 testEval5("Ah", "Kd", "8s", "7s", "Jh");
246 testEval5("6h", "2d", "8s", "Ts", "6d");
249 testEval5("6h", "2d", "8s", "6s", "2h");
252 testEval5("6h", "2d", "6d", "6s", "Jh");
255 testEval5("Ah", "Td", "Js", "Ks", "Qh");
256 testEval5("Js", "Ks", "Qh", "Ah", "Td");
259 testEval5("6d", "2d", "8d", "Td", "Jh");
262 testEval5("6d", "2d", "8d", "Td", "Jd");
265 testEval5("6h", "2d", "2s", "6s", "6d");
268 testEval5("6h", "2d", "6s", "6d", "6c");
271 testEval5("6h", "2h", "3h", "4h", "5h");
274 testEval5("Ad", "Kd", "Qd", "Jd", "Td");
275 testEval5("Ah", "Kh", "Qh", "Jh", "Th");
276 testEval5("As", "Ks", "Qs", "Js", "Ts");
277 testEval5("Ac", "Kc", "Qc", "Jc", "Tc");
280 void testDividePot(int wins0
, int wins1
, int wins2
, int wins3
, int wins4
//expected wins
281 ,int wager0
, int wager1
, int wager2
, int wager3
, int wager4
282 ,int score0
, int score1
, int score2
, int score3
, int score4
283 ,bool fold0
, bool fold1
, bool fold2
, bool fold3
, bool fold4
)
285 std::vector
<int> wins
;
287 std::vector
<int> wager
; wager
.push_back(wager0
); wager
.push_back(wager1
); wager
.push_back(wager2
); wager
.push_back(wager3
); wager
.push_back(wager4
);
288 std::vector
<int> score
; score
.push_back(score0
); score
.push_back(score1
); score
.push_back(score2
); score
.push_back(score3
); score
.push_back(score4
);
289 std::vector
<bool> fold
; fold
.push_back(fold0
); fold
.push_back(fold1
); fold
.push_back(fold2
); fold
.push_back(fold3
); fold
.push_back(fold4
);
291 dividePot(wins
, wager
, score
, fold
);
293 std::cout
<< "Testing Pot Division" << std::endl
;
294 std::cout
<< "wins: " << wins
[0] << " " << wins
[1] << " " << wins
[2] << " " << wins
[3] << " " << wins
[4] << std::endl
;
295 std::cout
<< "expt: " << wins0
<< " " << wins1
<< " " << wins2
<< " " << wins3
<< " " << wins4
<< std::endl
;
296 std::cout
<< std::endl
;
298 ASSERT_EQUALS(wins0
, wins
[0]);
299 ASSERT_EQUALS(wins1
, wins
[1]);
300 ASSERT_EQUALS(wins2
, wins
[2]);
301 ASSERT_EQUALS(wins3
, wins
[3]);
302 ASSERT_EQUALS(wins4
, wins
[4]);
307 testDividePot(200,200,200,200,200
311 testDividePot(0,0,1000,0,0
315 testDividePot(0,0,0,0,0
319 testDividePot(0,225,0,0,0
323 testDividePot(113,112,0,0,0
327 testDividePot(0,315,0,0,0
331 testDividePot(0,0,45,0,990
335 testDividePot(5,4,6,8,8
339 testDividePot(0,0,0,0,50
347 void testBetsSettled(bool expected
348 , int lastRaiseIndex
, int current
, int prev_current
349 , bool a0
, bool a1
, bool a2
, bool a3
, bool a4
//is this player all-in?
350 , bool f0
, bool f1
, bool f2
, bool f3
, bool f4
) //is this player folded?
352 std::vector
<Player
> players
;
353 for(size_t i
= 0; i
< 5; i
++) players
.push_back(Player(0, ""));
354 for(size_t i
= 0; i
< 5; i
++) players
[i
].wager
= 1;
355 players
[0].folded
= f0
;
356 players
[1].folded
= f1
;
357 players
[2].folded
= f2
;
358 players
[3].folded
= f3
;
359 players
[4].folded
= f4
;
360 players
[0].stack
= a0
? 0 : 1;
361 players
[1].stack
= a1
? 0 : 1;
362 players
[2].stack
= a2
? 0 : 1;
363 players
[3].stack
= a3
? 0 : 1;
364 players
[4].stack
= a4
? 0 : 1;
366 bool result
= betsSettled(lastRaiseIndex
, current
, prev_current
, players
);
368 std::cout
<< "testing bets settled" << std::endl
;
369 std::cout
<< "result: " << result
<< std::endl
;
370 std::cout
<< "expect: " << expected
<< std::endl
;
371 std::cout
<< std::endl
;
374 void testBetsSettled()
377 the current problem with bets settled is:
378 there are two players still not folded. One just went all in. The other has to decide. But it stops!
379 Because of the check "if(getNumActivePlayers(players) < 2) return true;".
383 This check is also in getNextActivePlayer so fix it there too!!!
392 testBetsSettled(false
406 void testCombo(const std::string
& expected
407 , const std::string
& card1
408 , const std::string
& card2
409 , const std::string
& card3
410 , const std::string
& card4
411 , const std::string
& card5
412 , const std::string
& card6
413 , const std::string
& card7
)
416 getCombo(combo
, card1
, card2
, card3
, card4
, card5
, card6
, card7
);
417 std::cout
<< "Testing Combination" << std::endl
;
418 std::cout
<< card1
<< " " << card2
<< " " << card3
<< " " << card4
<< " " << card5
<< " " << card6
<< " " << card7
<< std::endl
;
419 std::cout
<< "got: " << combo
.getNameWithAllCards() << std::endl
;
420 std::cout
<< "exp: " << expected
<< std::endl
;
421 std::cout
<< std::endl
;
422 ASSERT_EQUALS(expected
, combo
.getNameWithAllCards());
427 testCombo("High Card ( 9h 8d 7h 5d 4d )", "5d", "4d", "3s", "2s", "7h", "8d", "9h"); //high card
428 testCombo("Pair ( Th Td Qd Js 9s )", "Th", "5c", "3s", "Td", "9s", "Qd", "Js"); //pair
429 testCombo("Two Pair ( Th Td 9c 9s Qd )", "Th", "9c", "3s", "Td", "9s", "Qd", "Js"); //two pair
430 testCombo("Three Of A Kind ( 4h 4c 4d As Qd )", "4h", "4c", "As", "4d", "9s", "Qd", "Js"); //three of a kind
431 testCombo("Straight ( Kc Qd Js Th 9s )", "Th", "Kc", "3s", "Td", "9s", "Qd", "Js"); //straight
432 testCombo("Straight ( 8c 7d 6h 5d 4s )", "2s", "3h", "4s", "5d", "6h", "7d", "8c"); //straight of 7 cards long (should take highest part)
433 testCombo("Straight ( 5h 4c 3h 2s Ah )", "3h", "8d", "4c", "3c", "Ah", "2s", "5h"); //straight
434 testCombo("Straight ( Ah Ks Qc Jd Th )", "Th", "Jd", "Qc", "Ks", "Ah", "2s", "5h"); //straight
435 testCombo("Flush ( Qh Th Th 9h 3h )", "Th", "Kc", "3h", "Th", "9h", "Qh", "Js"); //flush
436 testCombo("Full House ( 2h 2c 2s 3s 3d )", "2h", "2c", "As", "4d", "3s", "3d", "2s"); //full house
437 testCombo("Four Of A Kind ( Ah Ac As Ad Qd )", "Ah", "Ac", "As", "Ad", "9s", "Qd", "Js"); //four of a kind
438 testCombo("Straight Flush ( Kh Qh Jh Th 9h )", "Th", "Kh", "3s", "Td", "9h", "Qh", "Jh"); //straight flush
439 testCombo("Straight Flush ( 5h 4h 3h 2h Ah )", "3h", "8d", "4h", "3c", "Ah", "2h", "5h"); //straight flush
440 testCombo("Royal Flush ( Ah Kh Qh Jh Th )", "Th", "Kh", "3s", "Td", "Ah", "Qh", "Jh"); //royal flush
443 // Supports 5 or 7 indices
444 std::vector
<int> indicesToEvalIndices(const std::vector
<int>& indices
)
446 std::vector
<int> result
= indices
;
447 if(result
.size() == 5) {
448 for(size_t i
= 0; i
< result
.size(); i
++) result
[i
] = eval5_index(Card(result
[i
]));
450 for(size_t i
= 0; i
< result
.size(); i
++) result
[i
] = eval7_index(Card(result
[i
]));
455 // Check that the winning cards win from the losing set
456 // Supports either both strings 5 cards or both strings 7 cards
457 void testCombosCompare(const std::string
& winning
, const std::string
& losing
)
459 std::cout
<< "Testing " << winning
<< " > " << losing
<< std::endl
;
461 getCombo(w
, winning
);
464 //std::cout << "Combos: " << w.getNameWithAllCards() << ", " << l.getNameWithAllCards() << std::endl;
465 ASSERT_EQUALS(1, compare(w
, l
));
467 std::vector
<int> cw
= indicesToEvalIndices(cardNamesToIndices(winning
));
468 std::vector
<int> cl
= indicesToEvalIndices(cardNamesToIndices(losing
));
471 //std::cout << "Eval: " << eval5(&cw[0]) << ", " << eval5(&cl[0]) << std::endl;
472 ASSERT_TRUE(eval5(&cw
[0]) > eval5(&cl
[0]));
474 //std::cout << "Eval: " << eval7(&cw[0]) << ", " << eval7(&cl[0]) << std::endl;
475 ASSERT_TRUE(eval7(&cw
[0]) > eval7(&cl
[0]));
479 // Each time, the first should be larger than the second
480 void testCombosCompare()
482 testCombosCompare("AhAcAdAsKh", "7h9d3s2d5h");
483 testCombosCompare("6s5h4c3c2s", "5h4c3c2sAh"); // The ace counts as 1 so first straight is better
484 testCombosCompare("2h3h4h5h6h", "Ah2h3h4h5h"); // The ace counts as 1 so first straight is better
485 testCombosCompare("6s5h4c3c2sKdTd", "5h4c3c2sAh9sTd");
490 for(size_t i
= 0; i
< 50; i
++) std::cout
<< getRandom() << " ";
491 std::cout
<< std::endl
;
492 std::cout
<< std::endl
;
493 for(size_t i
= 0; i
< 50; i
++) std::cout
<< getRandom(0, 1) << " ";
494 std::cout
<< std::endl
;
495 std::cout
<< std::endl
;
496 for(size_t i
= 0; i
< 50; i
++) std::cout
<< getRandom(0, 4) << " ";
497 std::cout
<< std::endl
;
500 static void shuffleN(int* values
, int size
, int amount
)
502 for(int i
= 0; i
< amount
; i
++)
504 int r
= getRandomFast(0, size
- 1);
505 std::swap(values
[i
], values
[r
]);
509 void benchmarkEval7()
512 for(int i
= 0; i
< 52; i
++)
514 int v
= eval7_index(Card(i
));
518 static const int numSamples
= 10000000;
520 std::cout
<< "Starting benchmark with " << numSamples
<< " evaluations " << std::endl
;
521 std::cout
<< "Start time: " << getDateString() << std::endl
;
525 for(int i
= 0; i
< numSamples
; i
++)
527 shuffleN(cards
, 52, 7);
528 test
+= eval7(&cards
[0]);
531 std::cout
<< "End time: " << getDateString() << std::endl
;
532 std::cout
<< "Test value: " << test
<< std::endl
; //ensure every calculation performed has some influence on this output to make sure nothing will be optimized away for the benchmark.
534 std::cout
<< std::endl
;
536 //std::cout << "now testing only the shuffling of cards, subtract this time from the above benchmark" << std::endl;
537 //std::cout << "start time: " << getDateString() << std::endl;
538 //for(int i = 0; i < numSamples; i++)
540 //shuffleN(cards, 52, 7);
542 //std::cout << "done shuffling." << std::endl;
543 //std::cout << "end time: " << getDateString() << std::endl;
548 std::cout
<< "Performing Unit Test" << std::endl
<< std::endl
;
552 int dummy
[7] = {1,1,1,1,1,1,1};
553 eval7(dummy
); //show its initialization messages before the unit test starts...
555 testWinChanceAtFlop();
556 testWinChanceAtRiver();
558 testWinChanceAtFlopAgainst9();