2010-10-28 29 views
9

Tôi đang gặp khó khăn khi viết một thư viện đánh giá poker cho vui và đang tìm cách thêm khả năng kiểm tra các bản vẽ (mở kết thúc, gutshot) cho một bộ thẻ nhất định.Thuật toán để kiểm tra một tay bài poker để vẽ thẳng (4 thẳng)?

Chỉ cần tự hỏi "trạng thái của nghệ thuật" dành cho điều này là gì? Tôi đang cố gắng để giữ cho dấu chân bộ nhớ của tôi hợp lý, vì vậy ý ​​tưởng sử dụng một cái nhìn lên bàn không ngồi tốt nhưng có thể là một điều ác cần thiết.

kế hoạch hiện tại của tôi là dọc theo dòng:

  • trừ cấp bậc thấp nhất từ ​​cấp bậc của tất cả các thẻ trong bộ này.
  • xem xét xem chuỗi nhất định có nghĩa là: 0,1,2,3 hoặc 1,2,3,4 (đối với OESD) là tập con của bộ sưu tập đã sửa đổi.

Tôi hy vọng sẽ làm tốt hơn sự khôn ngoan khôn ngoan, vì 7 thẻ hoặc 9 bộ thẻ sẽ xay mọi thứ để ngăn chặn bằng cách sử dụng phương pháp tiếp cận của tôi.

Mọi ý tưởng đầu vào và/hoặc tốt hơn sẽ được đánh giá cao.

+0

Chỉ cần cho chúng tôi không chơi bài xì phé là gì? – Gorgen

+1

@Gorgen Thẳng là 5 thẻ xếp hạng tiếp theo (ví dụ: A 2 3 4 5 hoặc 9 10 J Q K). Một trận hòa là bốn trong số 5 thẻ yêu cầu trong một thẳng. Một bản vẽ 'mở kết thúc' có nghĩa là 4 thẻ được tuần tự và không bao gồm A - ví dụ, 2 3 4 5 hoặc 8 9 10 J. An 'bên trong' vẽ có nghĩa là các thẻ không tuần tự hoặc bao gồm A - ví dụ, 2 3 5 6 hoặc A 2 3 4. –

Trả lời

7

Cách tiếp cận nhanh nhất có thể để gán một mặt nạ bit cho mỗi cấp thẻ (ví dụ deuce = 1, ba = 2, bốn = 4, năm = 8, sáu = 16, bảy = 32, Tám = 64, chín = 128, mười = 256, jack = 512, nữ hoàng = 1024, vua = 2048, ace = 4096) và OR cùng với giá trị mặt nạ của tất cả các thẻ trong tay. Sau đó, sử dụng bảng tra cứu phần tử 8192 để cho biết liệu bàn tay có thẳng, một đầu mở, một đường gờ, hoặc không có ý nghĩa (một cũng có thể bao gồm nhiều loại vẽ thẳng khác nhau mà không ảnh hưởng đến thời gian thực hiện).

Ngẫu nhiên, sử dụng các giá trị bitmask khác nhau, người ta có thể nhanh chóng phát hiện các tay hữu ích khác như hai loại, ba loại, v.v. Nếu có một số nguyên 64 bit, hãy sử dụng khối lập phương của các mặt nạ bit được chỉ định ở trên (vì vậy deuce = 1, ba = 8, vv lên đến ace = 2^36) và cộng các giá trị của các thẻ. Nếu kết quả, và với 04444444444444 (bát phân) không khác, thì tay là loại bốn. Nếu không, nếu cộng thêm 01111111111111, và và với 04444444444444 mang lại giá trị khác 0 thì tay là một loại ba hoặc một ngôi nhà đầy đủ. Nếu không, nếu kết quả, và với 02222222222222 là khác 0, tay là một cặp hoặc hai cặp. Để xem liệu một tay có chứa hai hay nhiều cặp, 'và' giá trị tay bằng 02222222222222 và lưu giá trị đó. Trừ 1, và 'và' kết quả với giá trị đã lưu. Nếu khác không, bàn tay có chứa ít nhất hai cặp (vì vậy nếu nó chứa một ba-of-a-loại, đó là một ngôi nhà đầy đủ, nếu không nó là hai cặp).

Như một lưu ý chia tay, việc tính toán được thực hiện để kiểm tra xem bạn cũng sẽ cho phép bạn xác định nhanh bao nhiêu cấp bậc khác nhau của thẻ trong tay. Nếu có N thẻ và N cấp bậc khác nhau, bàn tay không thể chứa bất kỳ cặp hoặc tốt hơn (nhưng có thể chứa một thẳng hoặc tuôn ra, tất nhiên). Nếu có N-1 cấp bậc khác nhau, bàn tay chứa chính xác một cặp. Chỉ khi có ít cấp bậc khác nhau thì người ta phải sử dụng logic phức tạp hơn (nếu có N-2, tay có thể là hai hoặc ba-of-a-loại, nếu N-3 hoặc ít hơn, bàn tay có thể là một " ba cặp "(điểm số là hai cặp), nhà đầy đủ, hoặc bốn-of-a-loại).

Một điều nữa: nếu bạn không thể quản lý bảng tra cứu phần tử 8192, bạn có thể sử dụng bảng tra cứu phần tử 512.Tính toán bitmap như trên, và sau đó thực hiện tra cứu trên mảng [bitmask & 511] và mảng [bitmask >> 4] và OR kết quả. Bất kỳ hợp pháp thẳng hoặc rút ra sẽ đăng ký trên một hoặc tra cứu khác. Lưu ý rằng điều này sẽ không trực tiếp cung cấp cho bạn số lượng các cấp bậc khác nhau (vì thẻ từ sáu đến mười sẽ được tính trong cả hai lần tra cứu) nhưng một lần tra cứu cùng một mảng (sử dụng mảng [bitmask >> 9]) sẽ chỉ đếm qua aces.

+0

Đầu vào tuyệt vời. Không bao giờ nghĩ đến việc sử dụng mặt nạ như thế này. Đã thực sự chỉ được sử dụng chúng để thử nghiệm cho tuôn ra. –

0

Cập nhật: Theo nhận xét của Christian Mann của ... nó có thể là thế này:

giả, A được biểu diễn dưới dạng 1. J như 11, Q 12 vv

loop through 1 to 13 as i 
    if my cards already has this card i, then don't worry about this case, skip to next card 
    for this card i, look to the left for number of consecutive cards there is 
    same as above, but look to the right 
    if count_left_consecutive + count_right_consecutive == 4, then found case 

bạn sẽ cần phải xác định các chức năng để tìm kiếm số lượng thẻ liên tiếp trái và thẻ đúng liên tiếp ... và cũng có thể xử lý các trường hợp khi khi nhìn thẳng liên tiếp , sau K, liên tiếp A.

+1

Điều đó sẽ cho kết quả dương tính giả ở các cạnh (Aces và Twos). Trong -addition, nó không kiểm tra ở tất cả cho gutshots (như 5-6-8-9). –

+0

oops, đó là sự thật ... chỉ nghĩ đến các trường hợp như 3,4,5,6 ... –

+0

ok, cố định ... mặc dù nếu tôi viết chương trình này tôi sẽ thử và gỡ lỗi cho bất kỳ lỗi nào –

3

Đây có thể là một giải pháp ngây thơ, nhưng tôi khá chắc chắn nó sẽ làm việc, mặc dù tôi không chắc chắn về các vấn đề về hiệu suất.

Giả sử một lần nữa thẻ được đại diện bằng các số từ 1 đến 13, sau đó nếu 4 thẻ của bạn có dải số 3 hoặc 4 (từ thứ hạng cao nhất đến thấp nhất) và không có bản sao thì bạn có thể vẽ thẳng .

Phạm vi 3 ngụ ý bạn có một bản vẽ mở, ví dụ 2,3,4,5 có phạm vi 3 và không chứa bản sao.

Phạm vi 4 ngụ ý bạn có một gutshot (như bạn gọi nó) ví dụ: 5,6,8,9 có phạm vi 4 và không chứa bản sao.

+0

Tôi nghĩ rằng điều này hiện nó ... –

+0

Tôi cũng nghĩ thế. Tôi đã nghĩ về phương pháp này ban đầu, nhưng lo lắng về việc phải loại bỏ bản sao (không phải là một thỏa thuận lớn), nhưng nếu chúng tôi có 7 cấp bậc duy nhất, chúng tôi sẽ phải kiểm tra phạm vi cho 7 lựa chọn 4 kết hợp. Có thể có một thủ thuật loại bỏ một số những kết hợp mặc dù, sẽ suy nghĩ về nó nhiều hơn một chút. –

+0

Đây là những gì tôi dự định làm. Tôi nhận ra rằng tôi sẽ không làm một bài kiểm tra đa chiều lớn cho các trận hòa, vì vậy nó không cần phải linh hoạt như mã đánh giá của tôi. Tôi đã bỏ qua để xem xét các mũi tiêm đôi trong bài viết gốc của mình, tôi đã xử lý chúng bằng cách đếm số lượng đường ruột trong một bộ 5 lá. –

7

Tôi biết bạn đã nói rằng bạn muốn giữ chân bộ nhớ càng nhỏ càng tốt, nhưng có một bảng tối ưu hóa bộ nhớ hiệu quả mà tôi từng thấy ở một số người đánh giá bài xì phé và tôi đã sử dụng nó. Nếu bạn đang làm mô phỏng poker nặng và cần hiệu suất tốt nhất có thể, bạn có thể muốn xem xét điều này. Mặc dù tôi thừa nhận trong trường hợp này sự khác biệt không phải là lớn bởi vì thử nghiệm cho một vẽ thẳng không phải là hoạt động rất tốn kém, nhưng nguyên tắc tương tự có thể được sử dụng cho khá nhiều loại đánh giá tay trong lập trình poker.

Ý tưởng là chúng ta tạo ra một loại một hàm băm có các thuộc tính sau:
1) tính toán một giá trị duy nhất cho mỗi bộ khác nhau của thẻ đứng
2) là đối xứng theo nghĩa là nó doesn' t phụ thuộc vào thứ tự của các thẻ
Mục đích của việc này là giảm số lượng thành phần cần thiết trong bảng tra cứu.

Cách gọn gàng để thực hiện việc này là gán một số nguyên tố cho mỗi cấp bậc (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), và sau đó tính toán sản phẩm của số nguyên tố. Ví dụ nếu các thẻ là 39TJQQ, thì băm là 36536259.

Để tạo bảng tra cứu, bạn thực hiện tất cả các kết hợp xếp hạng có thể, và sử dụng một số thuật toán đơn giản để xác định xem chúng có tạo hình thẳng hay không. Đối với mỗi kết hợp, bạn cũng tính toán giá trị băm và sau đó lưu trữ các kết quả trong bản đồ trong đó Khóa là giá trị băm và Giá trị là kết quả của việc kiểm tra vẽ thẳng. Nếu số lượng thẻ tối thiểu nhỏ (4 hoặc ít hơn) thì ngay cả một mảng tuyến tính cũng có thể khả thi.

Để sử dụng bảng tra cứu, trước tiên bạn tính giá trị băm cho tập hợp thẻ cụ thể và sau đó đọc giá trị tương ứng từ bản đồ.

Đây là một ví dụ trong C++. Tôi không đảm bảo rằng nó hoạt động chính xác và nó có thể được tối ưu hóa rất nhiều bằng cách sử dụng một mảng được sắp xếp và tìm kiếm nhị phân thay vì hash_map. hash_map là kinda chậm cho mục đích này.

#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 

} 
+0

Cảm ơn. Tôi thực sự sử dụng phương pháp này (số nguyên tố) cho mã đánh giá của tôi (sử dụng gperf để tạo ra các bảng băm hoàn hảo), tôi chưa thực hiện phép tính để xem có bao nhiêu việc thêm vào bảng sẽ thêm (nếu có), nhưng tôi là một chút antsy để làm điều này, như các bảng băm là khá lớn hiện nay. Cuối cùng tôi hy vọng sẽ chuyển sang thói quen đánh giá thẻ 7 để tăng tốc độ cho một số tính toán, vì vậy tôi có thể tăng gấp đôi và kết hợp nó vào thời điểm này. Đầu vào tốt! –

Các vấn đề liên quan