So che hai detto che vuoi mantenere il footprint della memoria il più piccolo possibile, ma c'è una ottimizzazione della tabella di ricerca abbastanza efficiente per la memoria che ho visto usata in alcuni valutatori di poker e l'ho usata io stesso. Se stai facendo delle pesanti simulazioni di poker e hai bisogno della migliore prestazione possibile, potresti prendere in considerazione questo. Anche se ammetto che in questo caso la differenza non è così grande perché il test per un progetto di scala non è un'operazione molto costosa, ma lo stesso principio può essere utilizzato per praticamente ogni tipo di valutazione della mano nella programmazione del poker.
L'idea è che si crea una sorta di una funzione hash che ha le seguenti proprietà:
1) calcola un valore univoco per ciascuna diversa serie di carta ranghi
2) è simmetrica, nel senso che esso doesn' t dipende dall'ordine delle carte
Lo scopo di questo è di ridurre il numero di elementi necessari nella tabella di ricerca.
Un modo semplice per farlo è assegnare un numero primo a ciascun grado (2-> 2, 3-> 3, 4-> 5, 5-> 7, 6-> 11, 7-> 13, 8-> 17, 9-> 19, T-> 23, J-> 29, Q-> 31, K-> 37, A-> 41), quindi calcolare il prodotto dei numeri primi. Ad esempio se le carte sono 39TJQQ, l'hash è 36536259.
Per creare la tabella di ricerca, è possibile utilizzare tutte le possibili combinazioni di gradi e utilizzare un semplice algoritmo per determinare se formano un progetto di scala. Per ciascuna combinazione si calcola anche il valore hash e quindi si memorizzano i risultati in una mappa in cui Key è l'hash e Value è il risultato del controllo di stiratura. Se il numero massimo di carte è piccolo (4 o meno), allora anche un array lineare potrebbe essere fattibile.
Per utilizzare la tabella di ricerca, è innanzitutto necessario calcolare l'hash per il set di carte specifico e quindi leggere il valore corrispondente dalla mappa.
Ecco un esempio in C++. Non garantisco che funzioni correttamente e potrebbe essere ottimizzato molto usando una matrice ordinata e una ricerca binaria invece di hash_map. hash_map è piuttosto lento per questo scopo.
#include <iostream>
#include <vector>
#include <hash_map>
#include <numeric>
using namespace std;
const int MAXCARDS = 9;
stdext::hash_map<long long, bool> lookup;
//"Hash function" that is unique for a each set of card ranks, and also
//symmetric so that the order of cards doesn't matter.
long long hash(const vector<int>& cards)
{
static const int primes[52] = {
2,3,5,7,11,13,17,19,23,29,31,37,41,
2,3,5,7,11,13,17,19,23,29,31,37,41,
2,3,5,7,11,13,17,19,23,29,31,37,41,
2,3,5,7,11,13,17,19,23,29,31,37,41
};
long long res=1;
for(vector<int>::const_iterator i=cards.begin();i!=cards.end();i++)
res *= primes[*i];
return res;
}
//Tests whether there is a straight draw (assuming there is no
//straight). Only used for filling the lookup table.
bool is_draw_slow(const vector<int>& cards)
{
int ranks[14];
memset(ranks,0,14*sizeof(int));
for(vector<int>::const_iterator i=cards.begin();i!=cards.end();i++)
ranks[ *i % 13 + 1 ] = 1;
ranks[0]=ranks[13]; //ace counts also as 1
int count = ranks[0]+ranks[1]+ranks[2]+ranks[3];
for(int i=0; i<=9; i++) {
count += ranks[i+4];
if(count==4)
return true;
count -= ranks[i];
}
return false;
};
void create_lookup_helper(vector<int>& cards, int idx)
{
for(;cards[idx]<13;cards[idx]++) {
if(idx==cards.size()-1)
lookup[hash(cards)] = is_draw_slow(cards);
else {
cards[idx+1] = cards[idx];
create_lookup_helper(cards,idx+1);
}
}
}
void create_lookup()
{
for(int i=1;i<=MAXCARDS;i++) {
vector<int> cards(i);
create_lookup_helper(cards,0);
}
}
//Test for a draw using the lookup table
bool is_draw(const vector<int>& cards)
{
return lookup[hash(cards)];
};
int main(int argc, char* argv[])
{
create_lookup();
cout<<lookup.size()<<endl; //497419
int cards1[] = {1,2,3,4};
int cards2[] = {0,1,2,7,12};
int cards3[] = {3,16,29,42,4,17,30,43};
cout << is_draw(vector<int>(cards1,cards1+4)) <<endl; //true
cout << is_draw(vector<int>(cards2,cards2+5)) <<endl; //true
cout << is_draw(vector<int>(cards3,cards3+8)) <<endl; //false
}
Solo per noi che non gioca a poker, che cosa si disegna? – Gorgen
@Gorgen Una scala è composta da 5 carte successive (ad esempio A 2 3 4 5 o 9 10 J Q K). Un pareggio è quattro delle 5 carte necessarie in una scala. Un sorteggio "aperto" significa che le 4 carte sono sequenziali e non includono A - ad esempio, 2 3 4 5 o 8 9 10 J. Un sorteggio "interno" significa che le carte non sono sequenziali o includono A - ad es. 2 3 5 6 o A 2 3 4. –