Đại diện cho một ván bài 5 lá


11

Một cỗ bài là 52. Một tay là 5 lá từ 52 (không thể có một bản sao).

Số bit ít nhất để đại diện cho một tay 5 thẻ là gì và bằng cách nào?
Một bàn tay KHÔNG phụ thuộc vào thứ tự (KQ = QK). 64329 = 96432

Có, có thể sử dụng 52 bit. Điều đó có thể đại diện cho một tay của bất kỳ số lượng thẻ.

Cho một tay là chính xác 5 thẻ có một cách để thể hiện nó với ít hơn 52 bit.

Một thẻ đơn có thể được biểu diễn với 6 bit = 64. Vì vậy, chỉ có thể sử dụng 6 bit * 5 thẻ = 30 bit. Nhưng đó sẽ là phụ thuộc vào thứ tự. Tôi chỉ có thể sắp xếp và điều này sẽ làm việc. Nếu điều đó không làm việc xin vui lòng cho tôi biết.

Có cách nào để lấy khóa từ 32 bit trở xuống và không phải sắp xếp bộ 5 thẻ.

Điều này là dành cho mô phỏng poker và việc sắp xếp sẽ tốn rất nhiều chi phí so với việc chỉ tạo tay. Nếu tôi có một từ điển với giá trị tương đối của mỗi tay thì đó là hai lần tra cứu đơn giản và so sánh để so sánh giá trị của hai tay. Nếu tôi phải sắp xếp các bàn tay lớn trước so với hai lần tra cứu và so sánh. Trong một mô phỏng sẽ so sánh hàng triệu. Tôi sẽ không nhận được bàn tay sắp xếp từ mô phỏng. Cách sắp xếp không đơn giản như 52 51 50 49 48 trước 52 51 50 49 47. Bạn có thể có các góc phẳng thẳng ....

Có 2598960 có thể 5 thẻ tay. Đó là số lượng hàng. Chìa khóa là 5 thẻ. Tôi muốn nhận một khóa có 32 bit hoặc dưới đó các thẻ không cần phải được sắp xếp trước.

Không thể chỉ cần đặt hàng danh sách như nhiều tay buộc. Suit là thuổng, câu lạc bộ, kim cương, và trái tim. 7c 8c 2d 3d 4s = 7s 8s 2c 3c 4h. Có một số lượng lớn các mối quan hệ.

Bước tiếp theo là 64 bit và sẽ thực hiện cú đánh sắp xếp thay vì tăng gấp đôi kích thước của khóa.

Tôi đã thử nghiệm và nhân SortedSet<int> quickSort = new SortedSet<int>() { i, j, k, m, n };đôi thời gian hoạt động nhưng tôi vẫn có thể làm được.

Nó trở nên phức tạp hơn. Tôi cần phải có khả năng đại diện cho một chiếc thuyền như twos trên fives (22255). Vì vậy, sắp xếp chúng phá vỡ điều đó. Tôi biết bạn sẽ nói nhưng đó là nhanh chóng. Vâng, nó nhanh và tầm thường nhưng tôi cần càng nhanh càng tốt.

C # cho câu trả lời được chấp nhận:

private int[] DeckXOR = new int[] {0x00000001,0x00000002,0x00000004,0x00000008,0x00000010,0x00000020,0x00000040,
                                    0x00000080,0x00000100,0x00000200,0x00000400,0x00000800,0x00001000,0x00002000,
                                    0x00004000,0x00008000,0x00010000,0x00020000,0x00040000,0x00080000,0x00100000,
                                    0x00200000,0x00400000,0x00800000,0x01000000,0x02000000,0x04000000,0x07fe0000,
                                    0x07c1f000,0x0639cc00,0x01b5aa00,0x056b5600,0x04ed6900,0x039ad500,0x0717c280,
                                    0x049b9240,0x00dd0cc0,0x06c823c0,0x07a3ef20,0x002a72e0,0x01191f10,0x02c55870,
                                    0x007bbe88,0x05f1b668,0x07a23418,0x0569d998,0x032ade38,0x03cde534,0x060c076a,
                                    0x04878b06,0x069b3c05,0x054089a3};
public void PokerProB()
{
    Stopwatch sw = new Stopwatch();
    sw.Start();
    HashSet<int> cardsXOR = new HashSet<int>();
    int cardXOR;
    int counter = 0;
    for (int i = 51; i >= 4; i--)
    {
        for (int j = i - 1; j >= 3; j--)
        {
            for (int k = j - 1; k >= 2; k--)
            {
                for (int m = k - 1; m >= 1; m--)
                {
                    for (int n = m - 1; n >= 0; n--)
                    {
                        counter++;
                        cardXOR = DeckXOR[i] ^ DeckXOR[j] ^ DeckXOR[k] ^ DeckXOR[m] ^ DeckXOR[n];
                        if (!cardsXOR.Add(cardXOR))
                            Debug.WriteLine("problem");
                    }
                }
            }
        }
    }
    sw.Stop();
    Debug.WriteLine("Count {0} millisec {1} ", counter.ToString("N0"), sw.ElapsedMilliseconds.ToString("N0"));
    Debug.WriteLine("");
}

4
Sử dụng thuật toán sắp xếp được mã hóa bằng tay, hoạt động để sắp xếp danh sách có độ dài 5. Điều này có thể nhanh hơn chức năng thư viện mà bạn hiện đang sử dụng.
Yuval Filmus

1
Tôi không hiểu tại sao bạn nói "Việc sắp xếp không đơn giản" . Cách sắp xếp rất đơn giản - chuyển đổi mỗi thẻ thành một số từ 1 đến 52, sao cho bàn tay được thể hiện bằng một danh sách (có độ dài 5) của thẻ. Sắp xếp danh sách đó. Đó chỉ là vấn đề sắp xếp danh sách 5 số nguyên, có thể được thực hiện rất nhanh, như Yuval đề cập. Tôi đề nghị bạn nên đo trước khi cho rằng nó quá chậm, nhưng tôi đoán là việc sắp xếp một danh sách như vậy sẽ rất nhanh và thậm chí có thể nhanh hơn cả bộ nhớ truy cập ngẫu nhiên không đọc được trong bộ đệm.
DW

@dw Có sắp xếp đơn giản nhưng những gì tôi đang làm (hàng triệu lần) thì đơn giản. Tôi đã thử nghiệm và sắp xếp gấp đôi thời gian.
paparazzo

1
@Paparazzi Không, Yuval đang bảo bạn viết thói quen sắp xếp của riêng bạn, được điều chỉnh cụ thể để sắp xếp năm số từ 1 đến 52. Bạn đã thử sử dụng một thói quen thư viện, chậm vì nó chung chung hơn nhiều so với tính chất đệ quy quicksort làm cho nó rất không hiệu quả trong danh sách ngắn.
David Richerby

Trong thực tế, hầu hết các mục không <= 16 bit cũng có thể là 32 bit. Vì vậy, vì bạn cần ít nhất 23 bit, bất kỳ mã hóa nào sử dụng <= 32 bit có thể khả thi. 6 bit tầm thường trên mỗi thẻ * Mã hóa 5 thẻ hoạt động đủ tốt. Có một cảnh báo: chỉ số mảng 23 bit tốt hơn nhiều so với chỉ số mảng 32 bit.
MSalters

Câu trả lời:


10

Đặt là mã . Ma trận kiểm tra chẵn lẻ của là ma trận bit sao cho số lượng cột tối thiểu có XOR biến mất là . Suy ra cột theo . Chúng ta có thể xác định mỗi là số nhị phân có độ dài bit. Lời hứa là XOR của bất kỳ đến số nào trong số này không bao giờ là . Sử dụng cái này, bạn có thể mã hóa tay dưới dạng , trong đóC[52,25,11]C27×521152A1,,A52Ai271100a,b,c,d,eAaAbAcAdAelà XOR. Thật vậy, rõ ràng điều này không phụ thuộc vào thứ tự và nếu hai tay va chạm, thì XOR hai giá trị băm sẽ cho số có XOR bằng 0.H1,H2102|H1H2|10

Bob Jenkins mô tả một mã như vậy trong trang web của mình và từ đó chúng ta có thể trích xuất mảng

0x00000001,0x00000002,0x00000004,0x00000008,0x00000010,0x00000020,0x00000040,
0x00000080,0x00000100,0x00000200,0x00000400,0x00000800,0x00001000,0x00002000,
0x00004000,0x00008000,0x00010000,0x00020000,0x00040000,0x00080000,0x00100000,
0x00200000,0x00400000,0x00800000,0x01000000,0x02000000,0x04000000,0x07fe0000,
0x07c1f000,0x0639cc00,0x01b5aa00,0x056b5600,0x04ed6900,0x039ad500,0x0717c280,
0x049b9240,0x00dd0cc0,0x06c823c0,0x07a3ef20,0x002a72e0,0x01191f10,0x02c55870,
0x007bbe88,0x05f1b668,0x07a23418,0x0569d998,0x032ade38,0x03cde534,0x060c076a,
0x04878b06,0x069b3c05,0x054089a3

Vì 27 vectơ đầu tiên chỉ là 27 số của Hamming weight 1, để kiểm tra xem cấu trúc này có đúng hay không, nên xem xét tất cả có thể không tầm thường kết hợp 25 số cuối cùng, kiểm tra xem XOR của chúng luôn có trọng số Hamming ít nhất 10. Ví dụ: số đầu tiên 0x07fe0000 có trọng lượng Hamming chính xác là 10.252271=2251


Tôi không theo dõi chính xác. Cần bao nhiêu bit cho một bàn tay?
paparazzo

Nó cần 27 bit. Bạn có thể sử dụng bất kỳ số lượng bit lớn hơn.
Yuval Filmus

Cảm ơn. Tôi đã thử nghiệm và các con số là duy nhất và <= 32 bit. Tôi có thể lấy được 5 thẻ từ số không? Nếu không ổn chỉ cần hỏi.
paparazzo

Vâng, đó là đại số tuyến tính đơn giản. Bạn có thể sử dụng ma trận chính xác để lấy lại một vectơ có độ dài 52 với 5 cái. Tôi sẽ cho bạn biết điều đó.
Yuval Filmus

13

Nếu chúng ta có một tập hợp kích thước , bạn có thể biểu diễn một phần tử của tập hợp bằng các . Bạn nói rằng có 2598960 tay 5 thẻ có thể. Điều đó có nghĩa là một bàn tay 5 thẻ có thể được biểu diễn bằng cách sử dụng chỉ bit. 22 bit ngắn hơn đáng kể so với 30 bit.lg n lg 2598960 = 22nlgnlg2598960=22

Làm thế nào để đại diện làm việc? Có nhiều lựa chọn khác nhau, với sự đánh đổi khác nhau. Tôi liệt kê hai cái dưới đây.

Từ điển mã hóa cứng

Trong trường hợp này, số tay 5 thẻ có thể đủ nhỏ để bạn có thể có một từ điển được mã hóa cứng liệt kê tất cả 2598960 tay và bạn đại diện cho một tay bằng chỉ số của nó trong từ điển (được biểu thị dưới dạng nhị phân).

Nói cách khác, từ điển có thể là một danh sách sắp xếp của bàn tay. Mỗi tay là 5 tuple của các lá bài trong tay, theo thứ tự được sắp xếp. Bạn có thể tra cứu một từ trong từ điển bằng cách sử dụng tìm kiếm nhị phân và tìm chỉ mục tương ứng của nó; và đưa ra một chỉ số, bạn có thể tìm thấy bàn tay tương ứng. Hoặc, bạn có thể lưu trữ từ điển dưới dạng hashmap ánh xạ từ tay đến chỉ mục của nó. Chỉ số là một số nguyên nằm trong khoảng từ 0 đến 2598959, vì vậy nó có thể được biểu diễn bằng 23 bit.

Cách tiếp cận này sẽ hoạt động và rất đơn giản để lập trình, nhưng nó lãng phí trong không gian (kích thước của chương trình thực thi).

Xếp hạng / không xếp hạng

Ngoài ra, nếu bạn quan tâm, có những phương pháp tốt hơn. Xem, ví dụ, bất kỳ tài liệu tham khảo nào sau đây:

Chủ đề chung được gọi là "xếp hạng (và không xếp hạng) của các kết hợp". Đây là một chút phức tạp hơn để thực hiện và hiểu, nhưng tránh sự cần thiết phải bao gồm một từ điển mã hóa cứng trong chương trình.


Tôi sẽ cập nhật câu hỏi. Có có 2598960 tay. Từ điển sẽ có nhiều hàng. Vấn đề của tôi là thế hệ của chìa khóa. Từ 5 thẻ tôi cần tạo một khóa để thực hiện tra cứu từ điển.
paparazzo

@Paparazzi, nếu bạn sử dụng cách tiếp cận từ điển, bàn tay chìa khóa. Nói cách khác, chìa khóa là 5 tuple của các thẻ trong tay (theo thứ tự được sắp xếp). Từ điển có thể được lưu trữ dưới dạng hashtable bằng cách sử dụng đó làm khóa. Nếu bạn không thích chi phí bộ nhớ của từ điển, hãy sử dụng phương pháp thay thế: xếp hạng / không xếp hạng.
DW

Có tôi biết tôi có thể nhận được khóa 30 bit nếu tôi sắp xếp. Tôi tự hỏi liệu có cách nào để lấy khóa 32 bit trở xuống mà không cần sắp xếp bộ 5 thẻ. Tôi sẽ xem xét thứ hạng và xếp hạng.
paparazzo

Tôi không theo dõi thứ hạng / không được cảm ơn nhưng cảm ơn. Tôi sẽ cố gắng và tìm ra nó. Cũng có khả năng quan hệ. Có rất nhiều mối quan hệ.
paparazzo


3

Bạn có thể sắp xếp năm mục và kiểm tra đồng thời các bản sao mà không có sự so sánh nào trên một số bộ xử lý: Giả sử bộ xử lý có lệnh nhanh xác định vị trí của tập bit cao nhất và lệnh nhanh tính toán một số chỉ với tập bit thứ n .

Đặt bit (n) là số có chính xác tập bit thứ n. Đặt high_bit (x) là số bit cao nhất được đặt trong số x, với giá trị không xác định nếu x = 0. Đặt x ^ y là độc quyền hoặc của x và y.

Cho là năm số a, b, c, d và e, mỗi số từ 0 đến 51, đại diện cho năm thẻ trong tay.

Đặt x = bit (a) ^ bit (b) ^ bit (c) ^ bit (d) ^ bit (e).

Đặt A = cao nhất_bit (x), thay đổi x thành x ^ bit (A).

Đặt B = cao_bit (x), thay đổi x thành x ^ bit (B).

Đặt C = cao_bit (x), thay đổi x thành x ^ bit (C).

Đặt D = cao nhất_bit (x), thay đổi x thành x ^ bit (D).

Đặt E = cao_bit (x).

Nếu x = 0 thì có các bản sao ở phần a, b, c, d và e. Mặt khác, sử dụng A * bit (24) + B * bit (18) + C * bit (12) + D * bit (6) + E làm mã hóa của tay, trong đó A, B, C, D và E là định nghĩa như trên. Điều này mã hóa một bàn tay dưới dạng chuỗi 30 bit, trong khi thực hiện sắp xếp theo cách rất hiệu quả.


Cái này có sử dụng 52 bit không?
paparazzo

@Paparazzi, không. Hãy xem lại đoạn cuối. Tôi chỉnh sửa nó để cố gắng cung cấp rõ ràng hơn nữa.
DW

1
Nó đòi hỏi CPU 64 bit, nhưng kết quả cuối cùng chỉ là 30 bit.
Yuval Filmus
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.