Evaluar una mano Skat

18

Introducción

Skat es un juego de cartas alemán tradicional para 3 jugadores. El mazo consta de 32 cartas: as, rey, reina, jota, 10, 9, 8, 7 en los 4 palos (palos, picas, corazones, diamantes).

En cada ronda, un jugador juega solo mientras que los otros dos juegan contra él. Al comienzo de una ronda, cada jugador recibe 10 cartas, las 2 cartas restantes se llaman skat y se colocan boca abajo en el medio. El jugador en solitario está determinado por una fase de licitación. Esta es la parte del juego con la que tendrás que lidiar en este desafío, más detalles sobre esto a continuación.

El jugador que gana la fase de licitación se convierte en el jugador solitario. Recoge el skat y luego deja caer dos cartas (que pueden ser iguales, el otro equipo no lo sabe), elige el palo de triunfo y comienza la ronda.

Una ronda consta de diez trucos. El jugador que gana un truco lidera el siguiente hasta que se juegan todas las cartas. No explicaré las reglas aquí, pero debes saber que tener muchas cartas de triunfo es bueno. Si desea conocer las reglas, consulte el artículo de Wikipedia que he vinculado al comienzo de esta publicación, pero no es necesario para este desafío.

El reto

Quieres enseñarles a tus dos hijos a jugar skat. Las reglas no son tan difíciles, por lo que rápidamente entran en juego. Lo único que les hace pasar un mal rato es la puja, que calcula específicamente el valor del juego de su mano. Entonces decides escribir un pequeño programa que genere el valor máximo del juego que pueden ofertar dada su mano actual.

Calcular el valor del juego

Cada mano tiene un cierto valor de juego. Está determinado por la cantidad de Jacks secuenciales que tiene y el palo que desea elegir como triunfo. ¡Comencemos con el primer factor, los gatos!

El factor jack

Las jotas son siempre cartas de triunfo y superan a cualquier otra carta de triunfo. El orden de fuerza entre los cuatro Jacks es:

  1. Jack of Clubs (el más alto)
  2. Jota de espadas
  3. Jota de corazones
  4. Jota de diamantes (el más bajo)

En la explicación adicional, me referiré a ellos con los números que les asigné aquí.

¿Recuerdas que hay algún tipo de factor que obtienes de los Jacks en tu mano que es parte del valor del juego? ¡Excelente! Así es como lo obtienes:

Este factor de Jack es el número de Jacks superiores (vea el orden anterior) en secuencia, más 1. Entonces, si tiene los 4 Jacks, es 4 + 1 = 5. Si tiene solo los primeros 2 Jacks, es 2 + 1 = 3)

Alternativamente, para hacer las cosas un poco más complicadas, el Factor Jack también puede ser el número de Jacks superiores en secuencia que te faltan , más 1. Entonces, si te falta el primero, es 1 + 1 = 2. Si faltan los primeros 3, es 3 + 1 = 4. Aquí algunos ejemplos, usando la numeración anterior:

[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

Ese fue el primer factor. Así es como obtienes el segundo:

El factor del traje de Trump

Este es mucho más simple. El segundo factor está determinado por el palo de triunfo que el jugador solitario elige usando el siguiente mapeo:

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

Eso fue fácil, ¿no?

El valor del juego

El valor del juego es el producto de los dos factores. ¿Bastante fácil crees? ¡Incorrecto! Mientras que el factor Jack es fijo, el factor traje no lo es. El palo que terminas eligiendo como triunfo depende de la cantidad de triunfos y del valor de tus cartas que no son triunfos en tu mano. Sería demasiado complicado explicar cómo se ve una buena mano, por lo que utilizará el siguiente algoritmo:

El algoritmo "Qué-Trump-hago-yo-elijo"

No tiene que participar en la licitación. Si decides que tu mano es demasiado mala para jugar en solitario, puedes pasar. Su mano debe coincidir con los siguientes criterios para ser jugable:

  • Ten al menos 6 cartas de triunfo (cartas del palo de triunfo que elijas + el número de Jotas). Si esto es posible para más de un palo, elija el que resultaría en más cartas de triunfo. Si todavía hay una corbata, elija el traje con la calificación más alta dada anteriormente.

  • Fuera de las cartas sin triunfo, ten al menos 1 As.

Si su mano no coincide con ambos criterios, pasará. Si lo hace, obtendrá el valor del juego calculado y el palo de triunfo elegido.

Nota breve: Por supuesto, este es un algoritmo muy simplificado. Se necesita demasiada estrategia y experiencia para juzgar una mano de lo que podríamos cubrir en un desafío como este.

Entrada

Cada tarjeta tiene un identificador único. La primera parte es el palo ( C lubs, S pades, H earts, D iamonds), la segunda parte es el valor que da este mapeo:

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

Ambas partes combinadas forman una tarjeta. El valor viene primero, luego viene el traje. Puede tomar las tarjetas en cualquier formato que desee.

Salida

Si la mano es jugable, muestra el valor del juego y el palo de triunfo elegido (el orden no importa). Si no es así, salida "pasar".

Reglas

  • Como se mencionó, puede tomar la entrada en el formato más conveniente para usted. Los ejemplos se muestran a continuación en los casos de prueba.
  • La entrada puede ser proporcionada por argumentos de línea de comando, entrada de usuario o argumentos de función.
  • La salida puede proporcionarse como valor de retorno o simplemente imprimirse en la pantalla.
  • Las tarjetas en la entrada no se pueden ordenar de ninguna manera. Su programa tiene que poder manejar cualquier orden de tarjeta al azar.
  • ¡El conteo de bytes más bajo gana!

Casos de prueba

La entrada en los casos de prueba será una lista de cadenas 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

Explicación:

  1. Dos Jacks seguidos con Clubs como triunfo. Entonces el valor del juego es 3 x 12 = 36
  2. Faltan tres gatos seguidos con Picas como triunfo. Entonces el valor del juego es 4 x 11 = 44
  3. Solo es posible un máximo de 4 cartas de triunfo, por lo que pasará.
  4. Seis cartas de triunfo con espadas pero sin as que no sean de triunfo, así que pasarás.

Si algunas reglas no están claras, continúe y comente. He crecido con este juego, por lo que me resulta difícil juzgar si describí todo con suficiente detalle.

Y ahora ... ¡ Feliz codificación!

editar: Como se me señaló en los comentarios (gracias a isaacg), hay una regla que cuenta los siguientes triunfos superiores después de los 4 Jacks en el "factor Jack", por lo que podría llegar hasta 11. Para mantener este desafío simple y para no confundir a las personas, las reglas que propuse originalmente permanecerán como están. Entonces el factor máximo se mantiene en 5.

Denker
fuente
66
Bienvenido a Programming Puzzles & Code Golf: ¡excelente primer desafío! :)
Pomo de la puerta
1
¿Debería la cantidad de tomas rectas / perdidas también incluir los triunfos del palo superior en secuencia? Eso es lo que dice Wikipedia aquí
isaacg
@isaacg Tengo que admitir que no sabía sobre esta regla hasta ahora. Gracias por señalar eso. Investigué un poco y tienes razón. En mi familia no jugamos con esta regla y tampoco he conocido a nadie que juegue con ella. No tiene tanta relevancia, porque cuando tienes una mano así, la mayoría de las veces jugarás Grand, que de todos modos se cuenta diferente. Entonces, para este desafío, nos quedaremos con las reglas que propuse. Editaré mi publicación para que sea clara para todos.
Denker
1
@DenkerAffe, jugué Skat durante muchos años en un club en Alemania, y confía en mí, la regla es importante, y hay casos en los que es extremadamente relevante (y sí, es desconocido en la mayoría de los jugadores no serios). Especialmente con el lado faltante : imagine que tiene triunfo K, D, 9, 8, 7 y tres A y dos 10 en los otros colores. Tu Gran muere seguro, pero puedes jugar 'ohne 6' (recoger algo de contra) y vencerlos, suponiendo que tengas una idea de cómo se sientan los B de la subasta. Y puedes pujar hasta que salga el sol con esa carta.
Aganju
@Aganju Ya supuse que esta regla no es conocida por la mayoría de los jugadores aficionados. Gracias por la confirmación. No dudo que sea importante, pero según mi experiencia, manos como esta son bastante raras, por lo que la regla no entra en juego tan a menudo.
Denker

Respuestas:

1

Python 2, ejemplo de implementación

Como todavía no hay envíos, escribí un ejemplo de implementación en Python. El formato de entrada es el mismo que en los casos de prueba en el desafío.

Tal vez eso los motive a ponerse en marcha, no es tan 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
fuente
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 una serie de matrices de caracteres en el formato A4, donde 4es Clubs , 3es Picas , 2es corazones y 1es diamantes . La salida es 36 4para una oferta de 36 con clubes de palo de triunfo , ppara pasar.

Pruébelo en línea aquí .

Versión sin golf:

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

Puerto de mi respuesta Java .

Pruébelo en línea aquí .

Toma de entrada como una serie de caracteres en el formato A4, donde 4es Clubs , 3es Picas , 2es corazones y 1es diamantes . La salida es 36 4para una oferta de 36 con clubes de palo de triunfo , ppara pasar.

Versión sin golf:

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
fuente
226 bytes
ceilingcat el