Оцініть скат-руку


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-й фактор визначається козирним костюмом, який сольний гравець вибирає, використовуючи наступне відображення:

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

Це було легко, чи не так?

Значення гри

Значення гри є добутком двох факторів. Дуже легко ви думаєте? Неправильно! Поки Джек-Фактор фіксований, коефіцієнт костюму - ні. Костюм, який ви в кінцевому підсумку вибираєте як козир, залежить від кількості козирів та вартості ваших нетрудових карт у вашій руці. Було б надто складно пояснити, як виглядає хороша рука, тому ви будете використовувати наступний алгоритм:

Алгоритм «Що-Трамп-робити-я-вибираю»

Не потрібно брати участь у торгах. Якщо ви вирішите, що ваша рука занадто погана, щоб грати в соло, ви можете просто пройти. Для відтворення ваша рука повинна відповідати наступним критеріям:

  • Майте щонайменше 6 козирів (картки козирного костюма, який ви вибираєте + кількість валетів). Якщо це можливо для більш ніж одного костюма, виберіть той, який спричинить за собою більше козирів. Якщо краватка все ж є, виберіть костюм з найвищою оцінкою, наведеною вище.

  • З не козирних карт майте принаймні 1 туз.

Якщо ваша рука не відповідає обом цим критеріям, ви пройдете. Якщо це так, ви виведете розраховане значення гри та обраний козир.

Коротка примітка: Звичайно, це дуже спрощений алгоритм. Існує набагато більше стратегії та досвіду в оцінці руки, ніж ми могли коли-небудь покрити у подібному виклику.

Вхідні дані

Кожна картка має унікальний ідентифікатор. Перша частина костюм ( C Lubs, S Падес, H earts, D iamonds), друга частина являє собою значення , яке визначається цим відображенням:

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

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

Вихід

Якщо рука відтворюється, виведіть ігрову вартість та підібраний козирний костюм (порядок не має значення). Якщо ні, виведіть "pass".

Правила

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

Тестові шафи

Вхід у тестові приклади буде переліком 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 x 12 = 36
  2. Три джеки підряд відсутні з піками як козир. Значить, значення гри 4 x 11 = 44
  3. Можливі лише максимум 4 козирні карти, тож ви пройдете.
  4. Шість козирів з піками, але не без козирного туза, тому ви пройдете.

Якщо деякі правила незрозумілі, продовжуйте і коментуйте. Я виріс із цією грою, тому мені важко судити, чи описав я все досить докладно.

А тепер… Щасливе кодування!

редагувати: Як вказувалося мені в коментарях (завдяки isaacg), є правило, яке підраховує наступні головні козирі після 4-х гнізд у "Джек-фактор", щоб воно могло перейти до 11. Щоб зробити цю проблему простою і щоб не бентежити людей, правила, які я запропонував спочатку, залишатимуться такими, якими вони є. Отже максимальний коефіцієнт залишається на рівні 5.


6
Ласкаво просимо до головоломки програмування та коду для гольфу - відмінне перше завдання! :)
Дверна ручка

1
Чи повинно кількість прямих підключень / відсутніх гнізд також включати козирі у верхньому костюмі послідовно? Ось що тут
isaacg

@isaacg Я повинен визнати, що я до цього часу не знав про це правило. Дякуємо, що вказали на це. Я зробив кілька досліджень, і ти справді маєш рацію. У моїй родині ми не граємо з цим правилом, і я не зустрічав нікого, хто з ним грає. Це не має такої високої актуальності, тому що коли ти будеш мати таку руку, ти здебільшого гратимеш у Гранд, який так чи інакше рахується. Тож для цього виклику ми просто будемо дотримуватися запропонованих мною правил. Я відредагую свій пост, щоб це було зрозуміло всім.
Денкер

1
@DenkerAffe, я багато років грав у «Скат» у клубі Німеччини, і, повірте, це правило важливе, і є випадки, коли це надзвичайно актуально (і так, це невідомо у більшості несерйозних гравців). Особливо з боку, що відсутня - уявіть, що у вас є козир K, D, 9, 8, 7 і три A та два 10 в інших кольорах. Ваш Гранд напевно вмирає, але ви можете грати в «охне 6» (зібрати кілька контрастів) і бити їх, припускаючи, що маєте уявлення про те, як B сидять від торгів. І ви можете робити ставки, поки сонце не з’явиться з цією карткою.
серпня 1616 року

@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"

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
}

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
}

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.