我克隆了这个:https://github.com/dickreuter/PokerEquityCalculator Github Repo并重写了它,以便它也适用于范围。整个代码似乎没有任何问题(因为VS Code没有高亮显示红色)。它唯一做的事情highlite red是下面的代码:
PYBIND11_MODULE(Scoring, m) {
m.def("montecarlo", &montecarlo);
}
特别是.def()。我知道C++,这是我第一次使用pybind 11,所以我不知道它的意思。当用cmake编译代码时,它编译得很好,但它不会创建一个pyd或dll文件,我相信这是由这个错误引起的。
Scoring.cpp(错误为):
//cppimport
/*
<%
setup_pybind11(cfg)
%>
*/
#include "Scoring.h"
#include <array>
#include <vector>
#include <iostream>
#include <tuple>
#include <algorithm>
#include <iostream>
#include <algorithm>
#include <random>
#include <iterator>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/complex.h>
#include <pybind11/functional.h>
#include <pybind11/chrono.h>
namespace py = pybind11;
using namespace pybind11::literals;
PYBIND11_MODULE(Scoring, m) {
m.def("montecarlo", &montecarlo);
}
namespace
{
constexpr auto x = std::array<int, 4>{2, 2, 2, 1};
}
bool eval_best_hand(const std::vector<std::set<std::string>>& all_cards_with_table_combined)
// returns true if first player has best hand
{
std::vector<std::tuple< std::vector<int>, std::vector<int>, std::string>> all_players_score;
std::vector<std::tuple< std::vector<int>, std::vector<int>, std::string>> all_players_score_original;
bool best_hand;
for (const auto& cards_with_table : all_cards_with_table_combined)
{
auto result = calc_score(cards_with_table);
all_players_score.emplace_back(result);
}
all_players_score_original = all_players_score;
std::sort(all_players_score.begin(), all_players_score.end(), std::greater<>());
if (all_players_score[0] == all_players_score_original[0])
best_hand = true; // first player is best hand
else
best_hand = false; // different player is best hand
return best_hand;
}
Score get_rcounts(const std::set<std::string>& all_cards_with_table_combined,
std::vector<std::size_t> available_ranks,
const std::string original_ranks) {
Score rcounts;
for (const auto& card : all_cards_with_table_combined) {
available_ranks.emplace_back(original_ranks.find(card.substr(0, 1)));
}
for (int i = 0; i <= 12; i++) {
int count = std::count(available_ranks.begin(), available_ranks.end(), i);
if (count > 0) {
rcounts.emplace_back(std::make_pair(count, i));
}
}
return rcounts;
}
std::tuple< std::vector<int>, std::vector<int>, std::string> calc_score(const std::set<std::string>& all_cards_with_table_combined) {
const std::string original_ranks = "23456789TJQKA";
const std::vector<std::string> original_suits{ "C","D","H","S" };
std::vector<std::size_t> available_ranks;
std::vector<std::string> available_suits;
std::vector<int> score;
std::vector<int> card_ranks;
std::vector<int> sorted_card_ranks;
std::string hand_type;
bool flush = false;
bool straight = false;
Score rcounts;
std::vector<std::tuple<int, std::string>> rsuits;
rcounts = get_rcounts(all_cards_with_table_combined, available_ranks, original_ranks);
// sort tuple and split into score and card ranks
std::sort(rcounts.begin(), rcounts.end(), std::greater<std::tuple<int, int>>());
for (auto it = std::make_move_iterator(rcounts.begin()),
end = std::make_move_iterator(rcounts.end()); it != end; ++it)
{
score.push_back(std::get<0>(*it)); // amount of occurrences
card_ranks.push_back(std::get<1>(*it)); // ranks of individual cards
}
bool potential_threeofakind = score[0] == 3;
bool potential_twopair = score == std::vector<int> {2, 2, 1, 1, 1};
bool potential_pair = score == std::vector<int> {2, 1, 1, 1, 1, 1};
auto sub_score2 = slice(score, 0, 2);
auto sub_score4 = slice(score, 0, 5);
auto sub_score0 = slice(score, 0, 0);
// # fullhouse(three of a kind and pair, or two three of a kind)
if (sub_score2 == std::vector<int> {3, 2} || sub_score2 == std::vector<int> {3, 3}) {
// make adjustment
card_ranks = slice(card_ranks, 0, 2);
score = { 3,2 };
}
// edge case: convert three pair to two pair
//const auto x = &score[3];
else if (sub_score4 == std::vector<int>{2, 2, 2, 1}) {
score = { 2,2,1 };
int kicker = std::max(card_ranks[2], card_ranks[3]);
card_ranks = { card_ranks[0], card_ranks[1], kicker };
}
else if (score[0] == 4) { // four of a kind
score = { 4, };
// avoid for example 11, 8, 9
sorted_card_ranks = card_ranks;
std::sort(sorted_card_ranks.begin(), sorted_card_ranks.end(), std::greater <>());
card_ranks = { sorted_card_ranks[0], sorted_card_ranks[1] };
}
else if (score.size() >= 5) { // high card, flush, straight and straight flush
// straight
// adjust for 5 high straight
if (std::find(card_ranks.begin(), card_ranks.end(), 12) != card_ranks.end())
card_ranks.push_back(-1);
sorted_card_ranks = card_ranks;
std::sort(sorted_card_ranks.begin(), sorted_card_ranks.end(), std::greater <>()); // sort again
for (int i = 0; i < sorted_card_ranks.size() - 4; ++i) {
straight = sorted_card_ranks[i] - sorted_card_ranks[i + 4] == 4;
if (straight == true) {
card_ranks = {
sorted_card_ranks[i], sorted_card_ranks[i + 1], sorted_card_ranks[i + 2], sorted_card_ranks[i + 3],
sorted_card_ranks[i + 4] };
break;
}
}
//flush
for (std::string card : all_cards_with_table_combined) {
available_suits.emplace_back(card.substr(1, 1));
}
std::vector<int> suit_counts;
std::vector<std::string> suit_cards;
for (const auto& suit : original_suits) { // why can original_suits not be a string and suit a char?
int count = std::count(available_suits.begin(), available_suits.end(), suit);
if (count > 0) {
rsuits.emplace_back(std::make_pair(count, suit));
}
}
std::sort(rsuits.begin(), rsuits.end(), std::greater<std::tuple<int, std::string>>());
flush = std::get<0>(rsuits[0]) >= 5; // the most occurred suit appear at least 5 times
if (flush == true)
{
auto flush_suit = std::get<1>(rsuits[0]);
std::set<std::string> flush_hand;
for (auto card : all_cards_with_table_combined) {
if (card[1] == flush_suit[0]) {
flush_hand.insert(card);
}
}
Score rcounts_flush = get_rcounts(flush_hand, available_ranks, original_ranks);
// sort tuple and split into score and card ranks
std::sort(rcounts_flush.begin(), rcounts_flush.end(), std::greater<std::tuple<int, int>>());
card_ranks.clear();
score.clear();
for (auto it = std::make_move_iterator(rcounts_flush.begin()),
end = std::make_move_iterator(rcounts_flush.end()); it != end; ++it)
{
score.push_back(std::get<0>(*it)); // ranks of individual cards
card_ranks.push_back(std::get<1>(*it)); // amount of occurrences
}
// # check for straight in flush
// if 12 in card_ranks and -1 not in card_ranks : # adjust if 5 high straight
if (std::find(card_ranks.begin(), card_ranks.end(), 12) != card_ranks.end() &&
!(std::find(card_ranks.begin(), card_ranks.end(), -1) != card_ranks.end())) {
card_ranks.push_back(-1);
}
for (int i = 0; i < card_ranks.size() - 4; i++) {
straight = card_ranks[i] - card_ranks[i + 4] == 4;
if (straight == true)
{
break;
}
}
}
// no pair, straight, flush, or straight flush
if (flush == false && straight == false)
score = { 1 };
else if (flush == false && straight == true)
score = { 3, 1, 2 };
else if (flush == true && straight == false)
score = { 3, 1, 3 };
else if (flush == true && straight == true)
score = { 5 };
}
if (score[0] == 1 && potential_threeofakind == true)
score = { 3,1 };
else if (score[0] == 1 && potential_twopair == true)
score = { 2, 2, 1 };
else if (score[0] == 1 && potential_pair == true)
score = { 2, 1, 1 };
if (score[0] == 5)
// # crdRanks=crdRanks[:5] # five card rule makes no difference {:5] would be incorrect
hand_type = "StraightFlush";
else if (score[0] == 4)
hand_type = "FoufOfAKind"; // crdRanks = crdRanks[:2] # already implemented above
else if (slice(score, 0, 2) == std::vector<int> {3, 2})
hand_type = "FullHouse"; // # crdRanks = crdRanks[:2] # already implmeneted above
else if (slice(score, 0, 3) == std::vector<int> {3, 1, 3}) {
hand_type = "Flush";
card_ranks = slice(card_ranks, 0, 5);
}
else if (slice(score, 0, 3) == std::vector<int> {3, 1, 2}) {
hand_type = "Straight";
card_ranks = slice(card_ranks, 0, 5);
}
else if (slice(score, 0, 2) == std::vector<int> {3, 1}) {
hand_type = "ThreeOfAKind";
card_ranks = slice(card_ranks, 0, 3);
}
else if (slice(score, 0, 2) == std::vector<int> {3, 1}) {
hand_type = "ThreeOfAKind";
card_ranks = slice(card_ranks, 0, 3);
}
else if (slice(score, 0, 2) == std::vector<int> {2, 2}) {
hand_type = "TwoPair";
card_ranks = slice(card_ranks, 0, 3);
}
else if (score[0] == 2) {
hand_type = "Pair";
card_ranks = slice(card_ranks, 0, 4);
}
else if (score[0] == 1) {
hand_type = "HighCard";
card_ranks = slice(card_ranks, 0, 5);
}
else
throw std::runtime_error("Card Type error!");
auto res = std::make_tuple(score, card_ranks, hand_type);
return res;
}
double montecarlo(const std::set<std::string>& my_cards, const std::set<std::string>& cards_on_table, const std::vector<std::vector<std::set<std::string>>> ranges, const int number_of_players, const int iterations) {
int wins = 0;
for (int i = 0; i < iterations; i++)
{
Deck deck;
/*
std::vector<int> idx_list;
for (int i=0; i < ranges.size(); i++){
idx_list.push_back(rand() % ranges[i].size());
}
std::set<std::string> opponents_hole;
for (auto i=0; i<ranges.size(); i++){
for (auto it = ranges[i].begin(); it!=ranges[i].end(); it++){
//auto it = next(ranges[i].begin(), idx_list[i]); this was a mistake as this just gives us the card of the set and not the entire set
//auto card_string = *it;
// opponents_hole.push_back(card_string);
std::string choosen_opponent_pair = ranges[i][idx_list[i]];
opponents_hole.insert(std::string(1, choosen_opponent_pair));
}
}
*/
std::vector<int> idx_list;
for (int i=0; i < ranges.size(); i++){
std::random_device random_device;
std::mt19937 engine{random_device()};
std::uniform_int_distribution<int> dist(0, ranges[i].size() - 1);
int k = dist(engine);
idx_list.push_back(k);
}
/*
22 std::set<std::string> opponents_hole;
23 for (auto it = ranges[0][0].begin(); it != ranges[0][0].end(); ++it){
24 std::string k = *it;
25 std::cout << k;
26 //std::string choosen_opponent_pair = ranges[i][idx_list[i]];
27 //opponents_hole.insert(std::string(1, choosen_opponent_pair));
28 }
29 */
std::vector<std::set<std::string>> opponents_hole;
std::set<std::string> cards;
for (int i=0; i<ranges.size(); i++){
for (auto it = ranges[i][idx_list[i]].begin(); it!=ranges[i][idx_list[i]].end(); it++){
//std::string choosen_opponent_pair = ranges[i][idx_list[i]];
//opponents_hole.insert(std::string(1, choosen_opponent_pair));
std::string k = *it;
std::cout << k;
cards.insert(k);
if(cards.size()==2){
opponents_hole.push_back(cards);
cards.clear();
}
//opponents_hole.insert(cards);
}
}
deck.remove_visible_cards(my_cards, cards_on_table);
deck.distribute_cards(number_of_players, opponents_hole);
std::vector<std::set<std::string>> cards_with_table_combined = deck.get_cards_combined();
bool first_player_has_best_hand = eval_best_hand(cards_with_table_combined);
if (first_player_has_best_hand == true)
wins += 1;
}
double equity = (wins / (double)iterations) * 100.0;
std::cout << "Equity: " << equity << "%" << std::endl;
return equity;
}
Deck::Deck() {
std::string combined;
//std::cout << "Constructing deck..." << std::endl;
for (char& r : ranks) {
for (char& s : suits) {
combined = std::string() + r + s;
full_deck.insert(combined);
};
};
//std::cout << "Cards in deck: " << full_deck.size() << std::endl;
}
void Deck::remove_visible_cards(const Hand& my_cards_, const std::set<std::string>& cards_on_table_) {
// remove my_cards and cards_on_table from full_deck
set_difference(full_deck.begin(), full_deck.end(), my_cards_.begin(), my_cards_.end(),
std::inserter(remaining_cards_tmp, remaining_cards_tmp.end()));
// remove visible table cards from deck
set_difference(remaining_cards_tmp.begin(), remaining_cards_tmp.end(), cards_on_table_.begin(),
cards_on_table_.end(),
std::inserter(remaining_cards, remaining_cards.end()));
//std::cout << "Remaining cards: " << remaining_cards.size() << std::endl;
this->my_cards = my_cards_.cards;
this->cards_on_table = cards_on_table_;
//std::cout << "Removed my cards from deck...\n";
}
void Deck::distribute_cards(int number_players, const std::vector<std::set<std::string>>& opponents_hole) { //number_players INLCUDING OURSELF
constexpr size_t cards_in_hand = 2;
std::vector<std::string> shuffled_deck(remaining_cards.begin(), remaining_cards.end());
std::shuffle(shuffled_deck.begin(), shuffled_deck.end(), std::mt19937_64(std::random_device()()));
std::vector<Hand> player_hands(number_players); // empty container
auto hand_it = player_hands.begin();
*hand_it = Hand(my_cards); // set my own cards
hand_it++;
auto card_it = shuffled_deck.begin();
int i = 0;
while (hand_it != player_hands.end() && i<opponents_hole.size()) {
//*hand_it = Hand(std::set<std::string>{*++card_it, * ++card_it});
//auto it = next(opponents_hole.begin(), i);
//std::set<std::string>::iterator it = opponents_hole.begin();
//std::advance(it, i);
//*hand_it = Hand(*it);
//++hand_it;
//i++;
*hand_it = Hand(opponents_hole[i]);
i++;
}
i=0;
while (cards_on_table.size() < 5) {
cards_on_table.emplace(*++card_it);
}
// print out the hands
//for (auto const& player_hand : player_hands) {
// std::cout << "Cards: ";
// for (const auto& card : player_hand.cards)
// std::cout << card << " ";
// std::cout << std::endl;
//}
this->player_hands = player_hands;
//std::cout << "Cards on table: ";
//print_set(cards_on_table);
}
std::vector<std::set<std::string>> Deck::get_cards_combined() {
std::set<std::string> cards_with_table_combined;
std::vector<std::set<std::string>> all_cards_with_table_combined;
for (const auto& player_hand : player_hands) {
cards_with_table_combined = player_hand.cards;
cards_with_table_combined.insert(cards_on_table.begin(), cards_on_table.end());
all_cards_with_table_combined.push_back(cards_with_table_combined);
}
return all_cards_with_table_combined;
}
void Deck::print_set(const std::set<std::string>& set) {
for (const auto& card : set)
std::cout << card << " ";
std::cout << std::endl;
}
CMakeLists.txt
cmake_minimum_required (VERSION 3.27.1)
project (equity_calculator)
enable_language(C)
enable_language(CXX)
set(pybind11_DIR C:/Python39/Lib/site-packages/pybind11/share/cmake/pybind11)
set(PYTHON_EXECUTABLE C:/Python39/python.exe)
set(pybind11_LIBRARIES C:/Python39/libs/python39.lib)
find_package(pybind11 CONFIG REQUIRED)
include_directories(${pybind11_INCLUDE_DIRS})
message([MAIN] "Found pybind11 v${pybind11_VERSION}: ${pybind11_INCLUDE_DIRS}")
MESSAGE( [Main] " pybind11_INCLUDE_DIRS = ${pybind11_INCLUDE_DIRS}")
MESSAGE( [Main] " pybind11_LIBRARIES = ${pybind11_LIBRARIES}")
#
# # Create an extension module
# add_library(mylib MODULE main.cpp)
# target_link_libraries(mylib pybind11::module)
#
# # Or embed the Python interpreter into an executable
# add_executable(myexe main.cpp)
# target_link_libraries(myexe pybind11::embed)
# method (1): generate `examplelib.pyd`
pybind11_add_module(Scoring Scoring.cpp)
# method (2): generate `examplelib.dll` rename to `examplelib.pyd`
#add_library(Scoring MODULE Scoring.cpp)
#target_link_libraries(Scoring pybind11::module)
MESSAGE( [Main] " pybind11_INCLUDE_DIRS = ${pybind11_INCLUDE_DIRS}")
MESSAGE( [Main] " pybind11_LIBRARIES = ${pybind11_LIBRARIES}")
#add_executable(cpp_use_python cpp_use_python.cpp)
#target_link_libraries(cpp_use_python PRIVATE pybind11::embed)
我试着把PYBIND11_MODULE放在最后,但它仍然不起作用。就像我说的,我从来没有使用过Pybind 11,所以我不知道这个错误意味着什么,也不知道为什么cmake不创建pyd文件。我还查看了官方的Pybind 11文档,特别是第一步页面,他们完全是这样做的,所以我不知道哪里出错了。
我会很感激任何帮助!提前感谢!
1条答案
按热度按时间1szpjjfi1#
我现在已经解决了我的问题,改变了Scoring.h文件中以前没有看到的一行,现在我使用cppimport来使用蒙特卡洛函数,一切都很好。不过,当我使用cmake编译它时,它仍然不会创建pyd或dll文件。