part_b_basic_overview - OpenHoldem/openholdembot GitHub Wiki
If you are not following my guide “Compiling the first dll” there might be slight differences in the basic files you use, since i already added some code, which is needed anyway.
#define WHUSER_EXPORTS
#include "OH-DLL.h" #include <windows.h>
/////////////////////////////////////
//card macros
#define RANK(c) ((c>>4)&0x0f)
#define SUIT(c) ((c>>0)&0x0f)
#define ISCARDBACK(c) (c==0xff)
#define ISUNKNOWN(c) (c==0)
/////////////////////////////////////
////////////////////////////////////
//consecutive states
holdem_state m_holdem_state[256];
unsigned char m_ndx;
////////////////////////////////////
////////////////////////////////////
//versus list & prwin
phl1k_t m_phl1k;
pp13 prw1326;
////////////////////////////////////
////////////////////////////////////
//WH symbols pfgws_t m_pget_winholdem_symbol;
////////////////////////////////////
double gws(int chair, const char* name, bool& iserr) {
return (*m_pget_winholdem_symbol)(chair,name,iserr);
}
double gws(const char* name) {
bool iserr;
int mychair = (int)gws(0,"userchair",iserr);
return gws(mychair,name,iserr);
}
bool hlset( int rank0, int rank1, int listnum, bool onoff ) {
return ((*m_phl1k)[listnum][rank0-2][rank1-2] = onoff);
}
bool hlget( int rank0, int rank1, int listnum ) {
return ((*m_phl1k)[listnum][rank0-2][rank1-2]);
}
double process_query(const char* pquery){
if(pquery==NULL)
return 0; //example
if(strcmp(pquery,"dll$test")==0)
return 101;
return 0;
}
double process_state(holdem_state* pstate){
if(pstate!=NULL)
m_holdem_state[ (++m_ndx)&0xff ] = *pstate;
return 0;
}
/////////////////////////////////////////////////////
//WINHOLDEM RUNTIME ENTRY POINT
/////////////////////////////////////////////////////
WHUSER_API double process_message(const char* pmessage, const void* param) {
if(pmessage==NULL){
return 0; }
if(param==NULL)
return 0;
if(strcmp(pmessage,"state")==0)
return process_state( (holdem_state*)param );
if(strcmp(pmessage,"phl1k")==0) {
m_phl1k = (phl1k_t)param;
return 0;
}
if(strcmp(pmessage,"prw1326")==0) {
prw1326 = (pp13)param;
return 0;
}
if(strcmp(pmessage,"query")==0)
return process_query((const char*)param);
if(strcmp(pmessage,"pfgws")==0) {
m_pget_winholdem_symbol = (pfgws_t)param;
return 0;
}
return 0;
}
/////////////////////////////////
//DLLMAIN
/////////////////////////////////
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
switch(ul_reason_for_call) {
case DLL_PROCESS_ATTACH: break;
case DLL_THREAD_ATTACH: break;
case DLL_THREAD_DETACH: break;
case DLL_PROCESS_DETACH: break;
}
return TRUE;
}
double gws(const char* name) {
bool iserr;
int mychair = (int)gws(0,"userchair",iserr);
return gws(mychair,name,iserr);
}
This function you see here, is very important, because you can access all symbols, which are available for Openholdem with it. E.g: gws(userchair) returns the value of the userchair symbol.
bool hlset( int rank0, int rank1, int listnum, bool onoff ) {
return ((*m_phl1k)[listnum][rank0-2][rank1-2] = onoff);
}
bool hlget( int rank0, int rank1, int listnum ) {
return ((*m_phl1k)[listnum][rank0-2][rank1-2]);
}
These functions can be used to access and dynamically modify versus lists during play e.g:
hlset( 14, 13, 5, 1);
this sets AKs on list 5 to true. More details can be found here: http://www.maxinmontreal.com/wiki/index.php5?title=Phl1k.!!!
double process_query(const char* pquery){
if(pquery==NULL)
return 0; //example
if(strcmp(pquery,"dll$test")==0) return 101;
return 0;
}
Inside this scope you can define symbols which you can access with the OH formula editor.
E.g: If you add = dll$test in the OH formula editor in the debug tab, you’ll get the value . You can experiment with it if you want and try some values from the gws function, but remember to recompile each time you change something in the code.
double process_state(holdem_state* pstate){
if(pstate!=NULL) m_holdem_state[ (++m_ndx)&0xff ] = *pstate;
return 0;
}
#ifndef _whuser_h_ #define _whuser_h_
#ifdef WHUSER_EXPORTS #define WHUSER_API __declspec(dllexport)
#else
#define WHUSER_API __declspec(dllimport) #
endif
struct holdem_player{
char m_name[16]; //player name if known
double m_balance; //player balance
double m_currentbet; //player current bet
unsigned char m_cards[2] ; //player cards
unsigned char m_name_known : 1 ; //0=no 1=yes
unsigned char m_balance_known : 1 ; //0=no 1=yes
unsigned char m_fillerbits : 6 ; //filler bits
unsigned char m_fillerbyte ; //filler bytes
};
struct holdem_state{
char m_title[64] ; //table title
double m_pot[10] ; //total in each pot
unsigned char m_cards[5] ; //common cards
unsigned char m_is_playing : 1 ; //0=sitting-out, 1=sitting-in
unsigned char m_is_posting : 1 ; //0=autopost-off, 1=autopost-on
unsigned char m_fillerbits : 6 ; //filler bits
unsigned char m_fillerbyte ; //filler byte
unsigned char m_dealer_chair ; //0-9
holdem_player m_player[10] ; //player records
};
struct sprw1326_chair{
int level; //indicates weighting level for 'always consider'
int limit; //max index into weight array - used for computational efficiency
int ignored; //if non-zero no weighting will be applied to this chair
int rankhi[1326]; //higher ranked card number in pocket cards
int ranklo[1326]; //lower ranked card number in pocket cards
int weight[1326]; //the significance value for this hand
double scratch; //for future reference
};
struct sprw1326{
int useme; //unless set to 1326 the normal OH prwin will be used
int preflop; //unless set to 1326 the normal OH prwin will be used pre-flop
int usecallback; //unless set to 1326 the callback function will not be invoked
double (*prw_callback)(void); //if enabled will be invoked before the prwin calculation
pass
double scratch; //for future reference int bblimp;
//if non-zero no weighting will be applied if a chair has put nothing in the pot
//will be precalculated by OH at startup - convenience values
sprw1326_chair vanilla_chair;
sprw1326_chair chair[10]; //structures for each chair
};
typedef double (*process_message_t)(const char* message, const void* param );
WHUSER_API double process_message( const char* message, const void* param );
typedef double (*pfgws_t)( int c, const char* psym, bool& iserr );
typedef bool hl1k_t[1000][13][13]; // list number, rank0, rank1
// rank0>=rank1 == suited, rank0<rank1 == unsuited
typedef hl1k_t* phl1k_t;
typedef sprw1326* pp13;
#endif
Here you have some definitions of datatypes. The important definitions are the two structs, you can basically compare a struct-datatype to an object with some attributes, these attributes are accessed by using the . operator, look in the examples section below.
struct holdem_state{
char m_title[64] ; //table title
double m_pot[10] ; //total in each pot
unsigned char m_cards[5] ; //common cards
unsigned char m_is_playing : 1 ; //0=sitting-out, 1=sitting-in
unsigned char m_is_posting : 1 ; //0=autopost-off, 1=autopost-on
unsigned char m_fillerbits : 6 ; //filler bits
unsigned char m_fillerbyte ; //filler byte
unsigned char m_dealer_chair ; //0-9
holdem_player m_player[10] ; //player records
};
-
What you basically have here is the information of a OH state which was scraped.
-
You can access information like the tabletitle/potsize/dealerchair etc. Ofcourse that is nothing new, as you have symbols formost of that at the formula level.
-
It also holds information about the players which is saved in the struct holdem_player.
struct holdem_player{
char m_name[16] ; //player name if known
double m_balance ; //player balance
double m_currentbet ; //player current bet
unsigned char m_cards[2] ; //player cards
unsigned char m_name_known : 1 ; //0=no 1=yes
unsigned char m_balance_known : 1 ; //0=no 1=yes
unsigned char m_fillerbits : 6 ; //filler bits
unsigned char m_fillerbyte ; //filler bytes
};
Pretty obvious that this contains information about the players at the table. You can access balances / currentbets /cards (if yours or at showdown) / names.
You can find all information and examples on it in these articles: http://www.maxinmontreal.com/wiki/index.php5?title=Prw1326, http://www.maxinmontreal.com/wiki/index.php5?title=Enhanced_Prwin.!!!
double process_query(const char* pquery){
if(pquery==NULL)
return 0; //example
if(strcmp(pquery,"dll$test")==0)
return 101;
if(strcmp(pquery,"dll$dealerchair")==0)
return m_holdem_state[(m_ndx)&0xff].m_dealer_chair;
if(strcmp(pquery,"dll$currentbet3")==0)
return m_holdem_state[(m_ndx)&0xff].m_player[3].m_currentbet;
return 0;
}
You can see in the code example above, how you have to use the point operator on a struct to access the information stored in the struct of the scraped state.
For convinience we restructure the code, by adding another header file:
-
Click on project -> Add New Item -> select Header File (.h) -> name it OH-general, you can also do it in the solution explorer by clicking on the Header Files folder.
///////////////////////////////////// //card macros #define RANK(c) ((c>>4)&0x0f) #define SUIT(c) ((c>>0)&0x0f) #define ISCARDBACK(c) (c==0xff) #define ISUNKNOWN(c) (c==0) ///////////////////////////////////// //////////////////////////////////// //consecutive states holdem_state m_holdem_state[256]; unsigned char m_ndx; //////////////////////////////////// //////////////////////////////////// //versus list & prwin phl1k_t m_phl1k; pp13 prw1326; //////////////////////////////////// //////////////////////////////////// //WH symbols pfgws_t m_pget_winholdem_symbol; //////////////////////////////////// double gws(int chair, const char* name, bool& iserr) { return (*m_pget_winholdem_symbol)(chair,name,iserr); } double gws(const char* name) { bool iserr; int mychair = (int)gws(0,"userchair",iserr); return gws(mychair,name,iserr); } bool hlset( int rank0, int rank1, int listnum, bool onoff ) { return ((*m_phl1k)[listnum][rank0-2][rank1-2] = onoff); } bool hlget( int rank0, int rank1, int listnum ) { return ((*m_phl1k)[listnum][rank0-2][rank1-2]); }
-
Cut / paste the code above from the OH-DLL.cpp file to the OH-general.h header file.
-
We will also need another include now, its a standart library of c++, wich contains a datatype called bitset.
-
The bitset datatype converts integer values to their binary representation, we will need this because we are going to work with srankbits.
-
You can read more about how rankbit values are obtained in the chapter about OpenHoldem symbols; look at the very bottom of the page.
-
You can find documentation on the C++ library here: http://www.cppreference.com/wiki/stl/bitset/start.
After you’re done with cut-pasting add the bitset include and also using namespace std; this is neccessary line, don’t think much about it, but the include would not work without it. Your OH-DLL.cpp “#includes” section should look like this now:
#define WHUSER_EXPORTS
#include "OH-DLL.h"
#include <windows.h>
#include <bitset>
using namespace std;
#include "OH-general.h"
Now we can begin with the actual coding, in the next step open OH-general.h and add the following code:
int srankhiplayer;
int srankbits;
int flushrank;
int set_flush_rank(){
bitset<16> srb( srankbits );
srb = (~srb ) >>= srankhiplayer;
return (int)srb.count(); }
This function will determine the flush rank via some bitset operations, 1 = nutflush, 2 = 2nd nutflush, etc.
void int_oh_symbols(){
srankbits = (int)gws("srankbits");
srankhiplayer = (int)gws("srankhiplayer");
flushrank = set_flush_rank();
}
This function will update the values each time a new state is scraped.
You also need to modify the OH-DLL.cpp to include this new symbol:
double process_query(const char* pquery) {
if(pquery==NULL)
return 0; //example
if(strcmp(pquery,"dll$test")==0)
return 101;
if(strcmp(pquery,"dll$dealerchair")==0)
return m_holdem_state[(m_ndx)&0xff].m_dealer_chair;
if(strcmp(pquery,"dll$currentbet3")==0)
return m_holdem_state[(m_ndx)&0xff].m_player[3].m_currentbet;
if(strcmp(pquery,"dll$flushrank")==0)
return flushrank;
return 0;
}
double process_state(holdem_state* pstate){
if(pstate!=NULL){m_holdem_state[ (++m_ndx)&0xff ] = *pstate;}
int_oh_symbols();
return 0;
}
If all went well you can access the flush rank with dll$flushrank on formula level now.
The files for this tutorial can be found here: http://www.maxinmontreal.com/wiki/index.php5?title=Image:OH-DLL-B.rar.