2

首先,我还是 C 的新手,所以请让我知道您可以提出的任何建议(尤其是关于处理数组的建议)。

我想在 C 中存储 BlackJack 手牌。我得出的结论是手牌或卡片必须是字符串,因为卡片可以同时是字符:A, J, Q, K或数字:1, 2.. 10,其中 10 实际上应该是两个字符的字符串。

现在,我尝试将组成手的卡片存储到这样的数组中:

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

问题是10,它占用了数组的两个索引而不是一个。我可以解决这个问题的一种方法就是创建一个包含 5 个字符串(21 点手牌中的最大牌数)的结构,每张牌一个。但是,如果我出于某种原因想要拥有数千张牌怎么办?那么存放手的最佳方式是什么?

4

5 回答 5

2

你可能会觉得这个网站很有趣。

http://www.computerpokercompetition.org/

他们每年举办一次人工智能扑克比赛。他们的服务器是用 C 语言编写的,你可以从上面的站点下载代码。

基本上,他们将卡片存储为整数。这是处理卡片最有效的方法。牌组中只有 52 种卡片。如果有小丑在场,那就更多了。因此,您可以将其映射为 0 到 51 之间的整数值。他们使用以下函数来打印卡是什么,因为整数卡号不会告诉您太多信息。请注意,他们根据等级和套件构建字符串。

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;
}
于 2013-06-06T07:01:07.977 回答
1

Don't store the cards as strings (e.g. "9"), but as chars (e.g. '9'). For the value 10 you could use a replacement char like '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.

于 2013-06-06T06:57:33.643 回答
1

我在这里写了一篇关于这个主题的文章。使用字符串是一个非常糟糕的主意。整数更好,最好的使用顺序是把花色放在低位,即使用顺序 2c, 2d, 2h, 2s, 3c, 3d, ... Ks, Ac, Ad, Ah, As . 这样,您甚至不必分开军衔和西装来进行数学计算。那么,手只是整数数组。有了这种表示,我可以在几分钟内完成数十亿手牌。我的库中计算二十一点手牌总数的函数如下所示(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;
}

那来自一个通用的纸牌模拟库,它非常快,但如果我真的想要从没有其他任何作用的二十一点模拟中获得球到墙上的速度,我根本不会代表纸牌,而只是有一个“一副{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10}的多个副本,并从中处理。

于 2013-06-06T07:26:11.097 回答
0

我想说没有单一的最佳方法。但是,char *hand;没有定义字符串数组;您可以使用char *hand[5],并且 10 不会占用两个索引;或者您可以使用char hand[5], 并将 10 存储为单个字符,例如“0”或“T”。

于 2013-06-06T06:52:42.903 回答
0

将卡片存储为整数:

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

出于显示目的,使用 translate 函数将整数转换为其名称:

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();
    }
}
于 2013-06-06T06:53:34.267 回答