fix infinite check bug
[rofl0r-oopoker.git] / unittest.cpp
blob104ceca638164e121d029964bcd48c24fee9cbff
1 /*
2 OOPoker
4 Copyright (c) 2010-2014 Lode Vandevenne
5 All rights reserved.
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/>.
23 #include "unittest.h"
25 #include <vector>
26 #include <string>
27 #include <algorithm>
28 #include <iostream>
30 #include "ai.h"
31 #include "ai_blindlimp.h"
32 #include "ai_call.h"
33 #include "ai_checkfold.h"
34 #include "ai_raise.h"
35 #include "ai_random.h"
36 #include "ai_smart.h"
37 #include "card.h"
38 #include "combination.h"
39 #include "game.h"
40 #include "io_terminal.h"
41 #include "player.h"
42 #include "pokereval.h"
43 #include "pokermath.h"
44 #include "random.h"
45 #include "table.h"
46 #include "info.h"
48 ////////////////////////////////////////////////////////////////////////////////
50 void fail()
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;
62 fail();
66 void assertTrue(bool value, const std::string& message = "")
68 if(!value)
70 std::cout << "Error: expected true." << std::endl;
71 std::cout << "Message: " << message << std::endl;
72 fail();
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()
101 //junk
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");
108 //high card
109 testWinChanceAtFlop("Ah", "Kd", "8s", "7s", "Jh");
111 //pair
112 testWinChanceAtFlop("6h", "2d", "8s", "Ts", "6d");
114 //two pair
115 testWinChanceAtFlop("6h", "2d", "8s", "6s", "2h");
117 //three of a kind
118 testWinChanceAtFlop("6h", "2d", "6d", "6s", "Jh");
120 //high straight
121 testWinChanceAtFlop("Ah", "Td", "Js", "Ks", "Qh");
122 testWinChanceAtFlop("Js", "Ks", "Qh", "Ah", "Td");
124 //flush draw
125 testWinChanceAtFlop("6d", "2d", "8d", "Td", "Jh");
127 //flush
128 testWinChanceAtFlop("6d", "2d", "8d", "Td", "Jd");
130 //full house
131 testWinChanceAtFlop("6h", "2d", "2s", "6s", "6d");
133 //four of a kind
134 testWinChanceAtFlop("6h", "2d", "6s", "6d", "6c");
136 //straight flush
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()
178 //junk
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");
185 //high card
186 testWinChanceAtFlopAgainst9("Ah", "Kd", "8s", "7s", "Jh");
188 //pair
189 testWinChanceAtFlopAgainst9("6h", "2d", "8s", "Ts", "6d");
191 //two pair
192 testWinChanceAtFlopAgainst9("6h", "2d", "8s", "6s", "2h");
194 //three of a kind
195 testWinChanceAtFlopAgainst9("6h", "2d", "6d", "6s", "Jh");
197 //high straight
198 testWinChanceAtFlopAgainst9("Ah", "Td", "Js", "Ks", "Qh");
199 testWinChanceAtFlopAgainst9("Js", "Ks", "Qh", "Ah", "Td");
201 //flush draw
202 testWinChanceAtFlopAgainst9("6d", "2d", "8d", "Td", "Jh");
204 //flush
205 testWinChanceAtFlopAgainst9("6d", "2d", "8d", "Td", "Jd");
207 //full house
208 testWinChanceAtFlopAgainst9("6h", "2d", "2s", "6s", "6d");
210 //four of a kind
211 testWinChanceAtFlopAgainst9("6h", "2d", "6s", "6d", "6c");
213 //straight flush
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;
233 void testEval5()
235 //worse possible
236 testEval5("2h", "3d", "4s", "5s", "7h");
238 //junk
239 testEval5("6h", "2d", "8s", "Ts", "Jh");
240 testEval5("2h", "7d", "5s", "Js", "8h");
242 //high card
243 testEval5("Ah", "Kd", "8s", "7s", "Jh");
245 //pair
246 testEval5("6h", "2d", "8s", "Ts", "6d");
248 //two pair
249 testEval5("6h", "2d", "8s", "6s", "2h");
251 //three of a kind
252 testEval5("6h", "2d", "6d", "6s", "Jh");
254 //high straight
255 testEval5("Ah", "Td", "Js", "Ks", "Qh");
256 testEval5("Js", "Ks", "Qh", "Ah", "Td");
258 //flush draw
259 testEval5("6d", "2d", "8d", "Td", "Jh");
261 //flush
262 testEval5("6d", "2d", "8d", "Td", "Jd");
264 //full house
265 testEval5("6h", "2d", "2s", "6s", "6d");
267 //four of a kind
268 testEval5("6h", "2d", "6s", "6d", "6c");
270 //straight flush
271 testEval5("6h", "2h", "3h", "4h", "5h");
273 //royal flushes
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]);
305 void testDividePot()
307 testDividePot(200,200,200,200,200
308 ,200,200,200,200,200
309 ,0,0,0,0,0
310 ,0,0,0,0,0);
311 testDividePot(0,0,1000,0,0
312 ,200,200,200,200,200
313 ,100,101,200,50,80
314 ,0,0,0,0,0);
315 testDividePot(0,0,0,0,0
316 ,0,0,0,0,0
317 ,0,0,0,0,0
318 ,0,0,0,0,0);
319 testDividePot(0,225,0,0,0
320 ,100,100,5,10,10
321 ,200,300,0,1,100
322 ,0,0,1,1,1);
323 testDividePot(113,112,0,0,0
324 ,100,100,5,10,10
325 ,300,300,0,1,100
326 ,0,0,1,1,1);
327 testDividePot(0,315,0,0,0
328 ,100,100,5,100,10
329 ,200,300,0,1,100
330 ,0,0,1,0,1);
331 testDividePot(0,0,45,0,990
332 ,10,10,10,5,1000
333 ,0,0,100,0,50
334 ,1,1,0,1,0);
335 testDividePot(5,4,6,8,8
336 ,1,2,4,8,16
337 ,16,8,4,2,1
338 ,0,0,0,0,0);
339 testDividePot(0,0,0,0,50
340 ,10,10,10,10,10
341 ,100,101,102,103,1
342 ,1,1,1,1,0);
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
393 , 3, 1, 0
394 , 0,0,0,1,0
395 , 1,0,1,0,1);
396 testBetsSettled(true
397 , 3, 1, 0
398 , 0,1,0,1,0
399 , 1,0,1,0,1);
400 testBetsSettled(true
401 , 2, 3, 1
402 , 0,0,2,0,0
403 , 0,0,0,0,0);
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)
415 Combination combo;
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());
425 void testCombos()
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]));
449 } else {
450 for(size_t i = 0; i < result.size(); i++) result[i] = eval7_index(Card(result[i]));
452 return result;
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;
460 Combination w;
461 getCombo(w, winning);
462 Combination l;
463 getCombo(l, losing);
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));
470 if(cw.size() == 5) {
471 //std::cout << "Eval: " << eval5(&cw[0]) << ", " << eval5(&cl[0]) << std::endl;
472 ASSERT_TRUE(eval5(&cw[0]) > eval5(&cl[0]));
473 } else {
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");
488 void testRandom()
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()
511 int cards[52];
512 for(int i = 0; i < 52; i++)
514 int v = eval7_index(Card(i));
515 cards[i] = v;
518 static const int numSamples = 10000000;
520 std::cout << "Starting benchmark with " << numSamples << " evaluations " << std::endl;
521 std::cout << "Start time: " << getDateString() << std::endl;
523 int test = 0;
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;
546 void doUnitTest()
548 std::cout << "Performing Unit Test" << std::endl << std::endl;
550 testRandom();
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();
560 testEval5();
562 testDividePot();
564 testBetsSettled();
566 testCombos();
567 testCombosCompare();
569 benchmarkEval7();