Оцените Скат-Хэнд

18

Вступление

Skat - традиционная немецкая карточная игра для 3 игроков. Колода состоит из 32 карт: туз, король, дама, валет, 10, 9, 8, 7 во всех 4 мастях (трефы, пики, червы, алмазы).

В каждом раунде один игрок играет соло, а два других играют против него. В начале раунда каждому игроку раздается по 10 карт, остальные 2 карты называются скатом и кладутся посередине лицевой стороной вниз. Индивидуальный игрок определяется по фазе торгов. Это та часть игры, с которой вам придется столкнуться в этой задаче, подробнее об этом ниже.

Игрок, выигравший фазу торгов, становится сольным игроком. Он поднимает скат, а затем бросает две карты (которые могут быть одинаковыми, другая команда не знает), выбирает козырную масть, и начинается раунд.

Один раунд состоит из десяти трюков. Игрок, выигравший трюк, ведет следующий, пока не будут разыграны все карты. Я не буду объяснять правила здесь, но вы должны знать, что хорошо иметь много козырей. Если вы хотите узнать о правилах, прочитайте статью в Википедии, на которую я ссылался в начале этого поста, но она не нужна для этой задачи.

Соревнование

Вы хотите научить своих двух сыновей играть в скат. Правила не так уж сложны, поэтому они быстро в него входят. Единственное, что доставляет им трудности - это ставки, в частности, подсчет игровой ценности их руки. Итак, вы решили написать небольшую программу, которая выводит максимальную ценность игры, которую они могут предложить, учитывая их текущую руку.

Расчет стоимости игры

Каждая рука имеет определенную игровую ценность. Это определяется количеством последовательных валетов и костюмом, который вы хотите выбрать в качестве козыря. Давайте начнем с первого фактора, домкраты!

Фактор Джека

Валеты всегда козыри, и они бьют все остальные козыри. Порядок силы между четырьмя домкратами:

  1. Джек треф (самый высокий)
  2. Пиковый валет
  3. Валет червей
  4. Бубновый валет (самый низкий)

В дальнейшем объяснении я буду ссылаться на них с номерами, которые я им присвоил здесь.

Вы помните, что есть какой-то фактор, который вы получаете от валетов в руке, который является частью игровой ценности? Большой! Вот как вы это получите:

Этот фактор Джека - это число верхних валетов (см. Порядок выше) в последовательности плюс 1. Таким образом, если у вас есть все 4 домкрата, то это 4 + 1 = 5. Если у вас есть только первые 2 домкрата, это 2 + 1 = 3.

В качестве альтернативы, чтобы сделать вещи немного сложнее, фактор Джека также может быть числом старших валетов в последовательности, которые вы пропустили , плюс 1. Так что, если вы пропустили первый, это 1 + 1 = 2. Если вы отсутствуют первые 3, это 3 + 1 = 4. Вот несколько примеров, используя нумерацию выше:

[1, 4] -> 1 + 1 = 2
[1, 2, 4] -> 2 + 1 = 3
[2, 3, 4] -> 1 + 1 = 2
[1, 2, 3, 4] -> 4 + 1 = 5
[] -> 4 + 1 = 5

Это был первый фактор. Вот как вы получаете 2-й:

Фактор иска Трампа

Этот намного проще. 2-й фактор определяется козырем, который выбирает одиночный игрок, используя следующее отображение:

Clubs    -> 12
Spades   -> 11
Hearts   -> 10
Diamonds ->  9

Это было легко, не так ли?

Значение игры

Значение игры является продуктом двух факторов. Довольно легко, вы думаете? Неправильно! В то время как Джек-фактор зафиксирован, костюм-фактор - нет. Костюм, который вы выберете в качестве козыря, зависит от количества козырей и стоимости ваших не козырных карт в вашей руке. Было бы слишком сложно объяснить, как выглядит хорошая рука, поэтому вы будете использовать следующий алгоритм:

Алгоритм Который-Трамп-до-Я-Пика

Вам не нужно участвовать в торгах. Если вы решите, что ваша рука слишком плоха, чтобы играть в одиночку, вы можете просто пройти. Ваша рука должна соответствовать следующим критериям для игры:

  • Имейте не менее 6 козырей (карты козырной масти, которые вы выбираете + количество валетов). Если это возможно для более чем одной масти, выберите ту, которая даст больше козырей. Если еще есть галстук, выберите костюм с наивысшим рейтингом, указанным выше.

  • Из не козырных карт есть как минимум 1 туз.

Если ваша рука не соответствует обоим этим критериям, вы пройдете. Если это произойдет, вы выведете рассчитанное игровое значение и выбранную козырную масть.

Краткое примечание: Конечно, это очень упрощенный алгоритм. Существует слишком много стратегии и опыта, чтобы судить руку, которую мы когда-либо могли бы покрыть в такой задаче.

вход

Каждая карточка имеет уникальный идентификатор. Первая часть - это костюм ( C lubs, S pades, H earts, D iamonds), вторая часть - это значение, которое задается этим отображением:

Ace -> A
King -> K
Queen -> Q
Jack -> J
10 -> 0
9 -> 9
8 -> 8
7 -> 7

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

Выход

Если на руке можно играть, выведите значение игры и выбранный козырь (порядок не имеет значения). Если это не так, выведите «pass».

правила

  • Как уже упоминалось, вы можете принять вход в наиболее удобном для вас формате. Примеры см. Ниже в тестовых случаях.
  • Входные данные могут быть предоставлены аргументами командной строки, пользовательским вводом или аргументами функции.
  • Вывод может быть предоставлен как возвращаемое значение или может быть просто напечатан на экране.
  • Карты на входе нельзя заказывать никаким образом. Ваша программа должна иметь возможность обрабатывать любой случайный заказ карты.
  • Побеждает самый низкий счетчик байтов!

Testcases

Ввод в тестовых примерах будет список 2-символьных строк.

1. ["JC", "JS", "JD", "AC", "KC", "9C", "AS", "7H", "QD", "8D"] -> 36 Clubs
2. ["JD", "AS", "0S", "KS", "QS", "9S", "8S", "AD", "8C", "9C"] -> 44 Spades
3. ["JH", "JD", "0S", "KS", "9C", "8C", "QH", "KH", "AD", "9D"] -> pass
4. ["JD", "AS", "KS", "QS", "0S", "9S", "8D", "7D", "0C", "QH"] -> pass

Объяснение:

  1. Два валета подряд с клюшками в роли козыря. Таким образом, значение игры составляет 3 х 12 = 36
  2. Три валета подряд пропали с пиками в качестве козыря. Таким образом, значение игры составляет 4 х 11 = 44
  3. Только максимум 4 козыри возможно, так что вы пройдете.
  4. Шесть козырей с пиками, но без козырного туза, так что вы пройдете.

Если некоторые правила неясны, продолжайте и комментируйте. Я вырос с этой игрой, поэтому мне сложно судить, достаточно ли подробно я описал все.

А теперь ... Удачного кодирования!

редактировать: как указано мне в комментариях (спасибо isaacg), есть правило, которое подсчитывает следующие главные козыри после 4-х валетов в «фактор-джек», так что оно может доходить до 11. Чтобы сделать этот вызов простым и чтобы не запутывать людей, правила, которые я предложил изначально, останутся такими, какие они есть. Таким образом, максимальный коэффициент остается на уровне 5.

Denker
источник
6
Добро пожаловать в Программирование головоломок и Code Golf - отличный первый вызов! :)
Ручка двери
1
Должно ли число прямых или отсутствующих валков включать в себя козыри топ масти по порядку? Это то, что википедия говорит здесь
isaacg
@isaacg Я должен признать, что я не знал об этом правиле до сих пор. Спасибо что подметил это. Я провел некоторое исследование, и вы действительно правы. В моей семье мы не играем с этим правилом, и я не встречал никого, кто бы играл с ним. Он не имеет такой высокой значимости, потому что, когда у вас есть такая рука, вы в большинстве случаев играете в Гранд, который в любом случае считается другим. Таким образом, для этого испытания мы просто будем придерживаться правил, которые я предложил. Я буду редактировать свой пост, чтобы он был понятен всем.
Денкер
1
@DenkerAffe, я много лет играл в Skat в одном из немецких клубов, и, поверьте мне, правило важно, и есть случаи, когда оно чрезвычайно важно (и да, оно неизвестно большинству несерьезных игроков). Особенно с отсутствующей стороной - представьте, что у вас есть козыри K, D, 9, 8, 7 и три A и два 10 в других цветах. Ваш Гранд умирает наверняка, но вы можете сыграть в «6» (собрать немного контра) и побить их, предполагая, что у вас есть представление о том, как Б сидит на торгах. И вы можете делать ставки, пока солнце не взойдет с этой картой.
Аганью
@Aganju Я уже предполагал, что это правило не известно большинству хобби-игроков. Спасибо за подтверждение. Я не сомневаюсь, что это важно, но из моего опыта такие руки довольно редки, поэтому правило не входит в игру так часто.
Денкер

Ответы:

1

Python 2, пример реализации

Поскольку пока нет ни одного представления, я записал пример реализации на Python. Формат ввода такой же, как в тестовых примерах в задании.

Может быть, это мотивирует вас, ребята, начать, это не так сложно :)

def gameValue(hand):
    jacks = ""
    suits = {"C" : 0, "S" : 0, "H" : 0, "D" : 0}
    # Loop through the hand, find all jacks and count the cards of each suit
    for card in hand:
        jacks += card[1] if "J" in card else ""
        suits[card[1]] += 1 if card[0] != "J" else 0

    # Map the Jacks to numbers while 1 is the highest (Clubs) then sort them ascending
    jacks =  sorted(map(lambda j: {"C" : 1, "S" : 2, "H" : 3, "D" : 4}[j], list(jacks)))

    # Sort the suits by amount. Highest amount and value is first after that
    suits = sorted(suits.items(), key = lambda suit: suit[1], reverse = True)
    trumpSuit = suits[0][0];
    # Amount of trumps is jack-count plus trumpsuit-count
    trumpCount = len(jacks) + suits[0][1];

    # Check for at least one ace that is no trump
    hasAce  = len(filter(lambda c: c[0] == "A" and c[1] != trumpSuit, hand)) >= 1

    # If the hand  is playable, calculate jack-factor and output the result, otherwise pass
    if trumpCount >= 6 and hasAce:
        # If there no jacks the factor is 5. If there are, find the first gap
        if len(jacks) > 0:
            lastJack = 0
            for jack in jacks:
                if jack - lastJack >= 2:
                    break
                lastJack = jack

            jackFactor = jacks[0] if lastJack == 0 else lastJack + 1
        else:
            jackFactor = 5

        trumpFactor = {"C" : 12, "S" : 11, "H" : 10, "D" : 9}[suits[0][0]]
        print str(trumpFactor * jackFactor) + " " + {12 : "Clubs", 11 : "Spades", 10 : "Hearts", 9 : "Diamonds"}[trumpFactor]
    else:
        print "pass"
Denker
источник
0

Java, 256 байт

h->{int i,j=1,m=0,t,n=0,a[]=new int[8];for(var c:h){t=c[1]-48;if(c[0]==74){j+=1<<t;n++;}else{m+=i=c[0]==65?1:0;a[--t+4]+=i;a[t]++;}}for(i=t=0;i<4;i++)t=a[i]<a[t]?t:i;return a[t]+n<6|m-a[t+4]<1?"p":(t+++9)*(5-(int)(Math.log(j>7?~j&7:j)/Math.log(2)))+" "+t;}

Принимает входные данные как массив символьных массивов в формате A4, где 4есть клубы , 3является Пики , 2это сердце и 1является Diamonds . Выход 36 4за ставку 36 с козырной мастью булавы , pдля прохождения.

Попробуйте это онлайн здесь .

Безголовая версия:

h -> { // lambda taking a char[][] as argument and returning a String
    int i,                // used as a loop variable and as a temporary variable
        j = 1,            // variable storing the jacks present in the hand in its four last-to-least significant bits
        m = 0,            // number of aces in the hand
        t,                // used as a temporary variable at first, later stores the trump suit
        n = 0,            // number of jacks in the hand
        a[] = new int[8]; // in the lower 4 indices, stores the number of non-jack cards present in the hand for each suit; in the higher 4 indices, stores the number of aces present in the hand for each suit (0 or 1)

    for(var c : h) {   // loop over all the cards in the hand
        t = c[1] - 48; // determine the suit of the current card; 48 is the ASCII code for '0'
        if(c[0] == 74) { // if it's a jack; 74 is the ASCII code for 'J'
            j += 1 << t; // set the corresponding bit
            n++;         // and increment the total number of jacks
        } else {                             // if it's not a jack
            m += (i = (c[0] == 65 ? 1 : 0)); // increment the total number of aces if it's an ace (65 is the ASCII code for 'A')
            a[ --t + 4] += i;                // increment the number of aces for this suit if it's an ace
            a[t]++;                          // increment the number of non-jack cards for this suit
        }
    }

    for(i = t = 0; i < 4; i++)     // loop over the suits ...
        t = (a[i] < a[t]) ? t : i; // ... and find the one with the most cards, giving priority to higher-valued suits in case of a tie

    return (a[t] + n < 6) |                                             // if there are less than 6 trump cards
           (m - a[t + 4] < 1) ?                                         // or less than 1 non-trump ace
           "p"                                                          // return "p" to pass on the hand
           :                                                            // else return
           ((t++ + 9) *                                                 // the value of the trump suit (and increment the trump suit for output later)
           (5 - (int) (Math.log((j > 7) ? (~j & 7) : j) / Math.log(2))) // times the jack factor
           + " " + t);                                                  // followed by the trump suit
}
OOBalance
источник
0

C 235 байт

f(char*h){int i,j=1,m=0,t,n=0,a[8]={0};for(;*h;h+=2){t=h[1]-48;if(*h-74){m+=i=*h==65;a[--t+4]+=i;a[t]++;}else{j+=1<<t;n++;}}for(i=t=0;i<4;i++)t=a[i]<a[t]?t:i;printf(a[t]+n<6|m-a[t+4]<1?"p":"%d %d",(t+9)*(5-(int)log2(j>7?~j&7:j)),t+1);}

Порт моего Java ответа .

Попробуйте это онлайн здесь .

Принимает входные данные как массив символов в формате A4, где 4есть клубы , 3является Пики , 2это сердце и 1является Diamonds . Выход 36 4за ставку 36 с козырной мастью булавы , pдля прохождения.

Безголовая версия:

f(char* h) { // function taking an array of characters as argument (and implicitly returning an unused int)
    int i,          // used as a loop variable and as a temporary variable
        j = 1,      // variable storing the jacks present in the hand in its four last-to-least significant bits
        m = 0,      // number of aces in the hand
        t,          // used as a temporary variable at first, later stores the trump suit
        n = 0,      // number of jacks in the hand
        a[8] = {0}; // in the lower 4 indices, stores the number of non-jack cards present in the hand for each suit; in the higher 4 indices, stores the number of aces present in the hand for each suit (0 or 1); partially initialized to zero, the compiler will do the rest

    for(; *h; h += 2) { // loop over all the cards in the hand
        t = h[1] - 48;  // determine the suit of the current card; 48 is the ASCII code for '0'
        if(*h - 74) {              // if it's not a jack; 74 is the ASCII code for 'J'
            m += (i = (*h == 65)); // increment the total number of aces if it's an ace (65 is the ASCII code for 'A')
            a[ --t + 4] += i;      // increment the number of aces for this suit if it's an ace
            a[t]++;                // increment the number of non-jack cards for this suit
        } else {         // if it's a jack
            j += 1 << t; // set the corresponding bit
            n++;         // and increment the total number of jacks
        }
    }

    for(i = t = 0; i < 4; i++)   // loop over the suits ...
        t = a[i] < a[t] ? t : i; // ... and find the one with the most cards, giving priority to higher-valued suits in case of a tie

    printf( (a[t] + n) < 6 |                             // if there are less than 6 trump cards
            (m - a[t + 4] < 1) ?                         // or less than 1 non-trump ace
            "p" : "%d %d",                               // print "p" to pass on the hand, else print two numbers
            (t + 9) *                                    // first the value of the trump suit ...
            (5 - (int) log2((j > 7) ? (~j & 7) : j)),    // ... times the jack factor,
            t + 1                                     ); // followed by the trump suit
}
OOBalance
источник
226 байт
floorcat