简体   繁体   English

存放二十一点手牌的最佳方法?

[英]Best way to store a BlackJack hand?

First off, I'm still new to C, so please let me know about any suggestions you can make (especially about handling arrays). 首先,我还是C语言的新手,所以请让我知道您可以提出的任何建议(尤其是关于处理数组的建议)。

I want to store a BlackJack hand in C. I've come to the conclusion that a hand or card has to be a string, because cards can be both characters: A, J, Q, K or numbers: 1, 2.. 10 , where 10 should actually be a string of two characters. 我想将BlackJack手存储在C中。我得出的结论是,手或卡片必须是字符串,因为卡片可以是两个字符: A, J, Q, K或数字: 1, 2.. 10 ,其中10实际上应该是两个字符的字符串。

Now, I tried storing cards making up a hand into an array like this: 现在,我尝试将组成一手牌的卡片存储到这样的数组中:

char* hand;
hand[1] = "A";
hand[2] = "2";

The problem is the 10 , which takes up two indices of the array instead of one. 问题是10 ,它占用数组的两个索引而不是一个。 A way I could get around this would just be to create a struct with 5 strings (the maximum number of cards in a BlackJack hand), one for each card. 我可以解决的一种方法是,创建一个具有5个字符串的结构(BlackJack牌中的最大牌数),每张牌一个。 However, what if I, for some reason, wanted to have a hand of thousands of cards? 但是,如果由于某种原因我想拿几千张纸牌怎么办? What would be the best way to store a hand then? 那么存储手的最佳方法是什么?

You might find this site interesting. 您可能会发现此站点很有趣。

http://www.computerpokercompetition.org/ http://www.computerpokercompetition.org/

They host an annual AI poker competition. 他们举办年度AI扑克比赛。 Their server is written in C, and you can download the code from the above site. 他们的服务器是用C编写的,您可以从上述站点下载代码。

Basically, they store the cards as integers. 基本上,它们将卡存储为整数。 This is the most efficient way of dealing with the cards. 这是处理卡的最有效方法。 There are only 52 types of cards in the deck. 卡座中只有52种类型的卡。 More if there are jokers present. 如果有小丑的话,更多。 So you can map this into an integer value between 0 and 51. They use the following function to print out what a card is, since an integer card number is not going to tell you much. 因此,您可以将其映射为0到51之间的整数值。它们使用以下函数来打印出一张卡,因为整数卡号不会告诉您太多。 Notice they build the string based on rank and suite. 注意,他们基于等级和套件来构建字符串。

int printCard( const uint8_t card, const int maxLen, char *string  )
{
  if( 3 > maxLen ) {
    return -1;
  }

  string[ 0 ] = rankChars[ rankOfCard( card ) ];
  string[ 1 ] = suitChars[ suitOfCard( card ) ];
  string[ 2 ] = 0;

  return 2;
}

Don't store the cards as strings (eg "9" ), but as chars (eg '9' ). 不要将卡存储为字符串(例如"9" ),而是存储为字符(例如'9' )。 For the value 10 you could use a replacement char like 'T' . 对于值10您可以使用替换字符,例如'T' Example code: 示例代码:

char hand[MAX_HAND_LEN];
int hand_len;

get_hand(hand, hand_len);

for (int i = 0; i < hand_len; i++) { 
    if (hand[i] == 'T') {
        putchar('1');
        putchar('0');
    } else {
        putchar(hand[i]);
    }
    putchar(' ');
}
putchar('\n');

This way you neither waste unnecessary memory (since one card now only requires one byte of storage), nor sacrifice code simplicity or readability. 这样,您既不会浪费不必要的内存(因为一张卡现在只需要一个字节的存储空间),也不会牺牲代码的简单性或可读性。

I wrote an essay on the subject here . 我在这里写了一篇关于这个问题的文章。 Using strings is a really bad idea. 使用字符串是一个非常糟糕的主意。 Integers are better, and the best order to use is to put suit in the low-order bits, ie, use the order 2c, 2d, 2h, 2s, 3c, 3d, ... Ks, Ac, Ad, Ah, As. 整数更好,最好的使用顺序是将低序位放在一起,即使用2c,2d,2h,2s,3c,3d,...,Ks,Ac,Ad,Ah,As 。 That way, you don't even have to separate ranks and suits to do the math. 这样,您甚至不必分开等级和西装就可以进行数学计算。 Hands, then, are just arrays of integers. 那么,手就是整数数组。 I can run billions of hands in minutes with this representation. 通过这种表示,我可以在数分钟内完成数十亿手操作。 The function in my library to calculate the total of a blackjack hand looks like this (the OJ_CARD macro expands to an integer constant, so that compare is fast): 我的库中用于计算二十一点手总数的函数如下所示(OJ_CARD宏扩展为整数常量,因此比较很快):

int ojb_total(const oj_cardlist_t *sp) {
    int i, c, t = 0, ace = 0, soft = 0;

    for (i = 0; i < sp->length; ++i) {
        c = sp->cards[i];
        if (c >= OJ_CARD(OJR_ACE, OJS_CLUB)) {
            ace = 1;
            ++t;
        } else if (c >= OJ_CARD(OJR_TEN, OJS_CLUB)) {
            t += 10;
        } else {
            t += OJ_RANK(c) + 2;
        }
    }
    if (ace && t < 12) {
        t += 10;
        soft = 1;
    }
    return soft ? -t : t;
}

That's from a general-purpose card simulation library and it's quite fast, but if I really wanted balls-to-the-wall speed from a blackjack simulation that did nothing else, I wouldn't represent cards at all, but just have a "deck" of multiple copies of {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10}, and deal from that. 这是来自通用卡片模拟库的,而且速度非常快,但是如果我真的想要二十一点模拟的弹球到墙壁的速度,却什么也没做,我根本就不会代表卡片,只需要一个“ {1,2,3,4,5,6,7,8,9,10,10,10,10}的多个副本”,然后从中进行处理。

I'd say there is no single best way. 我会说没有唯一的最佳方法。 However, char *hand; 但是, char *hand; does not define an array of strings; 没有定义字符串数组; you could use char *hand[5] , and the 10 would not take two indices; 您可以使用char *hand[5] ,而10将不接受两个索引; or you could use char hand[5] , and store the 10 as a single character, eg '0' or 'T'. 或者您可以使用char hand[5]并将10存储为单个字符,例如'0'或'T'。

Store the cards as integers: 将卡存储为整数:

  • 1 = Ace 1 =王牌
  • 2 = 2 2 = 2
  • 3 = 3 3 = 3
  • ... ...
  • 9 = 9 9 = 9
  • 10 = 10 10 = 10
  • 11 = Jack 11 =杰克
  • 12 = Queen 12 =女王
  • 13 = King 13 =国王

For display purposes, translate the integers to their names using a translate function: 出于显示目的,使用转换函数将整数转换为它们的名称:

string GetCardNameFromNumber(int cardNumber)
{
    switch(cardNumber)
    {
        case 1:
            return "A";
        case 11:
            return "J";
        case 12:
            return "Q";
        case 13:
            return "K";
        default:
            return cardNumber.ToString();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM