Лучший способ сохранить руку в блэкджеке?

Во-первых, я все еще новичок в C, поэтому, пожалуйста, дайте мне знать о любых предложениях, которые вы можете сделать (особенно о работе с массивами).

Я хочу сохранить раздачу блэкджека в C. Я пришел к выводу, что рука или карта должны быть строкой, потому что карты могут быть как символами: A, J, Q, K, так и числами: 1, 2.. 10, где 10 на самом деле должно быть строкой из двух символы.

Теперь я попытался сохранить карты, составляющие руку, в такой массив:

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

Проблема в том, что 10 занимает два индекса массива вместо одного. Чтобы обойти это, я мог бы просто создать структуру с 5 строками (максимальное количество карт в руке Блэкджек), по одной для каждой карты. Однако что, если я по какой-то причине захотел иметь на руках тысячи карт? Как тогда лучше хранить руку?


person dtgee    schedule 06.06.2013    source источник
comment
Вы можете использовать "T" для представления 10. Что касается руки из тысяч карт, вы можете использовать число для представления карт вместо строки из одной буквы.   -  person jxh    schedule 06.06.2013
comment
Думаю, я недостаточно четко изложил свои намерения, но я пытаюсь распечатать свою руку на ЖК-дисплее для проекта встроенных систем. Мой ЖК-экран довольно ограничен, поэтому было бы лучше, если бы я печатал J, Q или K вместо 11, 12, 13.   -  person dtgee    schedule 06.06.2013
comment
Печать и хранение — разные задачи. Очевидно, что они не являются независимыми, но при выборе формата хранения необходимо указать свои требования и ограничения. Вы можете сохранить руку как изображение того, что вы хотите отобразить на экране, но это может быть непросто прочитать и интерпретировать в другой части вашего приложения.   -  person CB Bailey    schedule 06.06.2013
comment
Первое, что нужно узнать о C: НИКОГДА не используйте строки ни для чего, кроме случаев, когда это действительно необходимо.   -  person Lee Daniel Crocker    schedule 06.06.2013


Ответы (5)


Вы можете найти этот сайт интересным.

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;
}
person JeffHeaton    schedule 06.06.2013

Не храните карты в виде строк (например, "9"), а в виде символов (например, '9'). Для значения 10 вы можете использовать заменяющий символ, например 'T'. Пример кода:

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');

Таким образом, вы не тратите ненужную память (поскольку для одной карты теперь требуется только один байт памяти), а также не жертвуете простотой или читабельностью кода.

person Will    schedule 06.06.2013
comment
ИТИМ putchar(). putc() дополнительно требует аргумента потока. - person Jens; 06.06.2013
comment
Да, я перепутал их в своей голове. Фиксированный. - person Will; 06.06.2013
comment
Лучше, чем строки, но все же хуже, чем простые целые числа. - person Lee Daniel Crocker; 06.06.2013
comment
@LeeDanielCrocker В C символы являются целыми числами. При этом самый маленький вид. - person Will; 06.06.2013
comment
Да, но если вы используете такие символы, как T, J и т. д., то вам нужно что-то вроде переключателя, чтобы получить значения для добавления к итогу. Я имею в виду целочисленное представление в порядке, с которым можно напрямую вычислить. И нет, я не говорю о сжатии рук в одно значение — я говорю об использовании массивов целых чисел для рук. - person Lee Daniel Crocker; 06.06.2013
comment
Хорошо, в обстоятельствах, когда эта единственная условная ветвь действительно имеет значение, вы можете быть правы. - person Will; 06.06.2013
comment
Начинающим программистам также важно понимать, что внутреннее вычислительное представление чего-либо и читаемое текстовое представление того же самого объекта имеют очень разные цели, и обычно рекомендуется рассматривать их по отдельности. - person Lee Daniel Crocker; 06.06.2013

Я написал эссе на эту тему здесь. Использование строк - действительно плохая идея. Целые лучше, и лучший порядок использования состоит в том, чтобы поместить костюм в младшие биты, т. е. использовать порядок 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} и рассчитывайте исходя из этого.

person Lee Daniel Crocker    schedule 06.06.2013
comment
Ваш ответ технически лучший, так как хранение карт в минимально возможном количестве бит, очевидно, даст вам наилучшую производительность, когда вы имеете дело с большими объемами, поэтому +1. Тем не менее, я чувствую, что этот ответ может быть излишним для кого-то все еще плохо знакомого с C... - person Will; 06.06.2013
comment
Использование всей библиотеки может быть излишним, но целочисленное представление максимально простое. Если вы пытаетесь изучить C, первое, что вы должны усвоить, это никогда не использовать строки, если в этом нет особой необходимости. - person Lee Daniel Crocker; 06.06.2013

Сохраните карты как целые числа:

  • 1 = туз
  • 2 = 2
  • 3 = 3
  • ...
  • 9 = 9
  • 10 = 10
  • 11 = Джек
  • 12 = Королева
  • 13 = король

В целях отображения переведите целые числа в их имена, используя функцию перевода:

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();
    }
}
person STLDev    schedule 06.06.2013
comment
Мне нравится идея @Amali использовать букву «T» или «0» для обозначения 10. Я думаю, что лучше всего внутренне представлять значения карты как целые числа и преобразовывать их в символы для вывода. - person STLDev; 06.06.2013
comment
Это помечено C, а не Java :-) Никаких строк, никаких классов. - person Jens; 06.06.2013
comment
Для большей удобочитаемости вы можете объявить перечисление, чтобы дать имена внутренним целым числам. - person mouviciel; 06.06.2013
comment
Неправильный выбор порядка для целых чисел. Требуется разделить на 13, чтобы получить ранг. См. моё эссе на эту тему. - person Lee Daniel Crocker; 06.06.2013
comment
Вообще-то, я только что заметил, что вы не имеете дело с костюмами, так что заказ на самом деле хорош. Однако функция возврата символа сложнее, чем нужно: почему бы не просто "XA23456789TJQK"[rank]? - person Lee Daniel Crocker; 06.06.2013

Я бы сказал, что нет единого лучшего способа. Однако char *hand; не определяет массив строк; вы можете использовать char *hand[5], и 10 не будет занимать два индекса; или вы можете использовать char hand[5] и сохранить 10 как один символ, например. г. «0» или «Т».

person Armali    schedule 06.06.2013