Avalie uma mão skat

18

Introdução

Skat é um jogo de cartas tradicional alemão para 3 jogadores. O baralho é composto por 32 cartas: Ás, Rei, Rainha, Valete, 10, 9, 8, 7 em todos os 4 naipes (Paus, Espadas, Copas, Diamantes).

Em cada rodada, um jogador joga sozinho, enquanto os outros dois jogam contra ele. No início de uma rodada, cada jogador recebe 10 cartas, as 2 cartas restantes são chamadas de skat e colocadas de bruços no meio. O jogador solo é determinado por uma fase de licitação. Esta é a parte do jogo com a qual você terá que lidar neste desafio, mais detalhes sobre isso abaixo.

O jogador que vence a fase de licitação se torna o jogador solo. Ele pega o skat e depois derruba duas cartas (que podem ser iguais, a outra equipe não sabe), escolhe o naipe de trunfo e a rodada começa.

Uma rodada consiste em dez truques. O jogador que vencer um truque lidera o próximo até que todas as cartas sejam jogadas. Não vou explicar as regras aqui, mas você deve saber que ter muitos trunfos é bom. Se você quiser aprender sobre as regras, consulte o artigo da Wikipedia que vinculei no início deste post, mas ele não é necessário para esse desafio.

O desafio

Você quer ensinar seus dois filhos a jogar skat. As regras não são tão difíceis, então elas rapidamente entram nela. A única coisa que lhes causa dificuldades é a licitação, calculando especificamente o valor do jogo na mão. Então você decide escrever um pequeno programa que gera o valor máximo do jogo que eles podem oferecer, dada a mão atual.

Calculando o valor do jogo

Toda mão tem um certo valor de jogo. É determinado pela quantidade de Valetes sequenciais que você possui e pelo naipe que deseja escolher como trunfo. Vamos começar com o primeiro fator, as tomadas!

O fator Jack

Os valetes são sempre trunfos e vencem todos os outros trunfos. A ordem de força entre os quatro valetes é:

  1. Valete de paus (mais alto)
  2. Valete de espadas
  3. Valete de Copas
  4. Valete de ouros (mais baixo)

Na explicação adicional, vou me referir a eles com os números que eu lhes atribuí aqui.

Você se lembra que existe algum tipo de fator que você recebe dos valetes na sua mão que faz parte do valor do jogo? Ótimo! Aqui está como você o obtém:

Esse fator Jack é o número dos principais Jacks (veja a ordem acima) em sequência, mais 1. Portanto, se você tiver todos os 4 Jacks, será 4 + 1 = 5. Se você tiver apenas os 2 primeiros Jacks, será 2 + 1 = 3)

Como alternativa, para tornar as coisas um pouco mais complicadas, o Fator Jack também pode ser o número dos melhores Jacks na sequência que você está perdendo , mais 1. Portanto, se você está perdendo o primeiro, é 1 + 1 = 2. Se você estão faltando ele primeiro 3, é 3 + 1 = 4. Aqui estão alguns exemplos, usando a numeração acima:

[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

Esse foi o primeiro fator. Aqui está como você obtém o segundo:

O fator de fato do Trump

Este é muito mais simples. O segundo fator é determinado pelo naipe de trunfo que o jogador solo escolhe usando o seguinte mapeamento:

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

Isso foi fácil, não foi?

O valor do jogo

O valor do jogo é o produto dos dois fatores. Muito fácil você acha? Errado! Enquanto o fator de Jack estiver fixo, o fator de naipe não é. O naipe que você escolhe como trunfo depende da quantidade de trunfos e do valor dos seus cartões que não são trunfos na sua mão. Seria muito complicado explicar como é uma boa mão, então você usará o seguinte algoritmo:

O algoritmo What-Trump-do-I-Pick

Você não precisa participar da licitação. Se você decidir que sua mão é ruim demais para jogar sozinho, basta passar. Sua mão deve corresponder aos seguintes critérios para ser jogável:

  • Tenha pelo menos 6 trunfos (cartas do naipe de trunfo que você escolhe + o número de Valetes). Se isso for possível para mais de um naipe, escolha aquele que resultaria em mais trunfos. Se ainda houver um empate, escolha o naipe com a classificação mais alta dada acima.

  • Fora das cartas que não são trunfos, tenha pelo menos 1 Ás.

Se sua mão não corresponder a ambos os critérios, você passará. Se isso acontecer, você exibirá o valor calculado do jogo e o naipe de trunfo escolhido.

Nota curta: Claro que este é um algoritmo muito simplificado. Há muita estratégia e experiência em julgar uma mão do que poderíamos cobrir em um desafio como este.

Entrada

Cada cartão tem um identificador único. A primeira parte é o terno ( C Lubs, S PAdES, H earts, D iamonds), a segunda parte é o valor que é determinado por este mapeamento:

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

Ambas as partes combinadas formam um cartão. O valor vem primeiro, depois o naipe. Você pode levar os cartões em qualquer formato que desejar.

Resultado

Se a mão é jogável, mostre o valor do jogo e o naipe escolhido (a ordem não importa). Caso contrário, digite "pass".

Regras

  • Como mencionado, você pode levar a entrada no formato mais conveniente para você. Exemplos veja abaixo nos casos de teste.
  • A entrada pode ser fornecida por argumentos de linha de comando, entrada do usuário ou argumentos de função.
  • A saída pode ser fornecida como valor de retorno ou apenas pode ser impressa na tela.
  • Os cartões na entrada não podem ser pedidos de forma alguma. Seu programa deve ser capaz de lidar com qualquer pedido de cartão aleatório.
  • Menor número de bytes ganhos!

Casos de teste

A entrada nos casos de teste será uma lista de cadeias de caracteres de 2 caracteres.

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

Explicação:

  1. Dois valetes seguidos com tacos como trunfo. Portanto, o valor do jogo é 3 x 12 = 36
  2. Três valetes seguidos com Spades como trunfo. Portanto, o valor do jogo é 4 x 11 = 44
  3. Somente um máximo de 4 trunfos é possível, então você passará.
  4. Seis trunfos com espadas, mas nenhum ás que não seja trunfo, então você passará.

Se algumas regras não forem claras, vá em frente e comente. Eu cresci com este jogo, então é difícil para mim julgar se descrevi tudo com detalhes suficientes.

E agora ... Feliz codificação!

edit: Como apontado nos comentários (graças a isaacg), existe uma regra que conta os seguintes trunfos após os 4 Valetes para o "fator Valete" para que ele possa subir até 11. Para manter esse desafio simples e para não confundir as pessoas, as regras que propus originalmente permanecerão como estão. Portanto, o fator máximo permanece em 5.

Denker
fonte
6
Bem-vindo à Programação de quebra-cabeças e código de golfe - excelente primeiro desafio! :)
Maçaneta da porta
1
O número de macacos retos / macacos perdidos também deve incluir os trunfos do naipe superior em sequência? Isso é o que a wikipedia diz aqui
isaacg
@isaacg Eu tenho que admitir que não conhecia essa regra até agora. Obrigado por apontar isso. Eu fiz algumas pesquisas e você está realmente certo. Na minha família, não brincamos com essa regra e também não conheci ninguém que brinque com ela. Não tem essa alta relevância, porque quando você tem uma mão, na maioria das vezes joga Grand, que é contado de qualquer maneira. Portanto, para este desafio, ficaremos apenas com as regras que propus. Vou editar meu post para que fique claro para todos.
Denker
1
@ DenkerAffe, joguei o Skat por muitos anos em um clube na Alemanha, e confie em mim, a regra é importante e há casos em que é extremamente relevante (e sim, é desconhecido na maioria dos jogadores não sérios). Especialmente com o lado que faltava - imagine que você tem trunfo K, D, 9, 8, 7 e três A e dois 10 nas outras cores. Seu Grand morre com certeza, mas você pode jogar 'ohne 6' (coletar alguns contra) e vencê-los, assumindo que você tenha uma idéia de como o B está sentado na licitação. E você pode fazer lances até o sol nascer com esse cartão.
Aganju
@Gangan Eu já assumi que esta regra não é conhecida pela maioria dos jogadores de hobby. Obrigado pela confirmação. Não duvido que seja importante, mas, pela minha experiência, mãos como essa são muito raras, então a regra não entra em jogo com tanta frequência.
Denker

Respostas:

1

Python 2, exemplo de implementação

Como ainda não há envios, escrevi um exemplo de implementação em Python. O formato de entrada é o mesmo que nos casos de teste do desafio.

Talvez isso motive vocês a seguir em frente, não é tão difícil :)

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
fonte
0

Java, 256 bytes

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;}

Toma de entrada como um array de arrays de caracteres no formato A4, onde 4é Clubs , 3é Spades , 2é corações e 1é Diamonds . A saída é 36 4para uma oferta de 36 com os clubes do trunfo , ppara aprovação.

Experimente online aqui .

Versão não destruída:

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
fonte
0

C, 235 bytes

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

Porta da minha resposta Java .

Experimente online aqui .

Toma entrada como um array de caracteres no formato A4, onde 4é Clubs , 3é Spades , 2é corações e 1é Diamonds . A saída é 36 4para uma oferta de 36 com os clubes do trunfo , ppara aprovação.

Versão não destruída:

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
fonte
226 bytes
ceilingcat