andrewprock / pokerstove

poker evaluation and enumeration software
BSD 3-Clause "New" or "Revised" License
806 stars 350 forks source link

NaN comparison between two cards + board #35

Closed neilconway closed 6 years ago

neilconway commented 7 years ago

The test program below reports:

The whole deck has 52 cards
There are 1 two card combinations
There are 1 two card combinations
The board has 3 cards
The hand As6s has nan % equity (0 0 0 0)
The hand 9c9s has nan % equity (0 0 0 0)

Please let me know if the test program is using the APIs incorrectly.

#include <iostream>
#include <vector>

#include <pokerstove/peval/Card.h>
#include <pokerstove/penum/ShowdownEnumerator.h>

int main() {

using namespace pokerstove;
using namespace std;

CardSet completeDeck;
completeDeck.fill();
cout << "The whole deck has " << completeDeck.size() << " cards" << endl;

CardDistribution hand1;
hand1.parse("As6s");
cout << "There are " << hand1.size() << " two card combinations"  << endl;

CardDistribution hand2;
hand2.parse("9c9s");
cout << "There are " << hand2.size() << " two card combinations"  << endl;

CardSet board;
board.insert(Card(Rank('9'), Suit('d')));
board.insert(Card(Rank('7'), Suit('d')));
board.insert(Card(Rank('2'), Suit('c')));

cout << "The board has " << board.size() << " cards" << endl;

ShowdownEnumerator showdown;
vector<EquityResult> result = showdown.calculateEquity(
    vector<CardDistribution>{hand1, hand2},
    board,
    PokerHandEvaluator::alloc("h")
);

double share1 = result.at(0).winShares + result.at(0).tieShares;
double share2 = result.at(1).winShares + result.at(1).tieShares;
double total = share1 + share2;

cout << "The hand As6s has "  << share1 / total * 100  << " % equity (" << result.at(0).str() << ")" << endl;
cout << "The hand 9c9s has "  << share2 / total * 100  << " % equity (" << result.at(1).str() << ")" << endl;
}
jdoerrie commented 7 years ago

The problem here is a mismatch between the behaviors of the Rank and Suit constructor. Creating Ranks from characters works as expected, but creating Suits does not. In your particular case you obtain a board of 3h Ad 9c instead of the expected 9d 7d 2c (this you can see by printing board.str()). Since both the unexpected board and hand2 contain the card 9c you get the NaNs when you evaluate it. The most simple fix for you is to replace calls to Suit('d') and Suit('c') by Suit("d") and Suit("c"). This works, because the string constructor works as expected. I also created a pull request (#36) that will fix this unexpected behavior in the future.