Valuta una mano skat


18

introduzione

Skat è un tradizionale gioco di carte tedesco per 3 giocatori. Il mazzo è composto da 32 carte: Asso, Re, Regina, Jack, 10, 9, 8, 7 in tutti e 4 i semi (fiori, picche, cuori, quadri).

In ogni round un giocatore gioca da solo mentre gli altri due giocano contro di lui. All'inizio di un round a ciascun giocatore vengono distribuite 10 carte, le restanti 2 carte vengono chiamate skat e vengono messe coperte nel mezzo. Il giocatore solista è determinato da una fase di offerta. Questa è la parte del gioco che dovrai affrontare in questa sfida, maggiori dettagli su questo sotto.

Il giocatore che vince la fase di offerta diventa il giocatore solista. Prende lo skat e poi lascia due carte (che possono essere le stesse, l'altra squadra non lo sa), prende il seme di briscola e inizia il round.

Un round è composto da dieci prese. Il giocatore che vince una presa conduce la successiva fino a quando non vengono giocate tutte le carte. Non spiegherò qui le regole, ma dovresti sapere che avere molte carte vincenti è buono. Se vuoi conoscere le regole controlla l'articolo di Wikipedia che ho collegato all'inizio di questo post, ma non è necessario per questa sfida.

La sfida

Vuoi insegnare ai tuoi due figli a giocare a skat. Le regole non sono così difficili, quindi entrano rapidamente in gioco. L'unica cosa che li rende difficili è l'offerta, in particolare calcolando il valore di gioco della loro mano. Quindi decidi di scrivere un piccolo programma che produca il massimo valore di gioco che possono offrire in base alla loro mano attuale.

Calcolo del valore del gioco

Ogni mano ha un certo valore di gioco. È determinato dalla quantità di Jack sequenziali che hai e dal seme che vuoi scegliere come briscola. Cominciamo con il primo fattore, i jack!

Il fattore Jack

I jack sono sempre carte vincenti e battono ogni altra carta vincente. L'ordine di forza tra i quattro jack è:

  1. Jack of Clubs (il più alto)
  2. Jack di picche
  3. Jack di cuori
  4. Jack of Diamonds (il più basso)

Nell'ulteriore spiegazione farò riferimento a loro con i numeri che ho assegnato loro qui.

Ricordi che c'è un qualche tipo di fattore che ottieni dai Jack in mano che fa parte del valore del gioco? Grande! Ecco come lo ottieni:

Questo fattore Jack è il numero di Jack migliori (vedi ordine sopra) in sequenza, più 1. Quindi se hai tutti i 4 Jack è 4 + 1 = 5. Se hai solo i primi 2 Jack, è 2 + 1 = 3.

In alternativa, per rendere le cose un po 'più complicate, il fattore Jack può anche essere il numero di jack migliori in sequenza che ti mancano , più 1. Quindi se ti manca il primo, è 1 + 1 = 2. Se tu mancano i primi 3, è 3 + 1 = 4. Ecco alcuni esempi, usando la numerazione sopra:

[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

Questo è stato il primo fattore. Ecco come ottieni il 2 °:

Il fattore di seme di Trump

Questo è molto più semplice. Il secondo fattore è determinato dal seme di briscola che il giocatore solista sceglie usando la seguente mappatura:

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

È stato facile, no?

Il valore del gioco

Il valore del gioco è il prodotto di due fattori. Abbastanza facile pensi? Sbagliato! Mentre il fattore Jack è fisso, il fattore tuta non lo è. Il seme che scegli come briscola dipende dalla quantità di briscole e dal valore delle tue carte non-briscola nella tua mano. Sarebbe troppo complicato spiegare come appare una buona mano, quindi utilizzerai il seguente algoritmo:

L'algoritmo Which-Trump-do-I-Pick

Non devi partecipare all'offerta. Se decidi che la tua mano è troppo brutta per giocare da solo, puoi semplicemente passare. La tua mano deve soddisfare i seguenti criteri per essere giocabile:

  • Hai almeno 6 carte vincenti (le carte del seme di briscola che scegli + il numero di Jack). Se questo è possibile per più di un seme, scegli quello che si tradurrebbe in più carte vincenti. Se c'è ancora un pareggio, scegli il seme con il punteggio più alto indicato sopra.

  • Delle carte non vincenti, hai almeno 1 asso.

Se la tua mano non soddisfa entrambi questi criteri, passerai. In tal caso, otterrai il valore di gioco calcolato e il seme di briscola scelto.

Breve nota: ovviamente questo è un algoritmo molto semplificato. Nel giudicare una mano ci sono troppe strategie ed esperienze di quante potremmo mai affrontare in una sfida come questa.

Ingresso

Ogni carta ha un identificativo univoco. La prima parte è la tuta ( C lubs, S pad, H earts, D iamonds), la seconda parte è il valore che viene dato da questa mappatura:

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

Entrambe le parti combinate formano una carta. Il valore viene prima, poi arriva il seme. Puoi prendere le carte in qualsiasi formato desideri.

Produzione

Se la mano è giocabile, ottieni il valore del gioco e il seme di briscola scelto (l'ordine non ha importanza). In caso contrario, l'output "passa".

Regole

  • Come accennato, puoi prendere l'input nel formato più conveniente per te. Esempi vedi sotto nei casi di test.
  • L'input può essere fornito da argomenti della riga di comando, input dell'utente o argomenti della funzione.
  • L'output può essere fornito come valore di ritorno o può essere semplicemente stampato sullo schermo.
  • Le carte nell'input non possono essere ordinate in alcun modo. Il tuo programma deve essere in grado di gestire qualsiasi ordine di carta casuale.
  • Il conteggio dei byte più basso vince!

Casi test

L'input nei casi di test sarà un elenco di stringhe a 2 caratteri.

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

Spiegazione:

  1. Due Jack di fila con i Club come briscola. Quindi il valore del gioco è 3 x 12 = 36
  2. Tre Jack di fila mancano con Spades come briscola. Quindi il valore del gioco è 4 x 11 = 44
  3. Sono consentite solo un massimo di 4 carte vincenti, quindi passerai.
  4. Sei carte vincenti con picche ma nessun asso non-briscola, quindi passerai.

Se alcune regole non sono chiare, vai avanti e commenta. Sono cresciuto con questo gioco, quindi per me è difficile giudicare se ho descritto tutto in modo sufficientemente dettagliato.

E ora ... Buona programmazione!

modifica: Come mi è stato sottolineato nei commenti (grazie a isaacg), esiste una regola che conta i seguenti trionfi successivi dopo i 4 Jack nel "fattore Jack" in modo che possa arrivare fino a 11. Per mantenere semplice questa sfida e per non confondere le persone, le regole che ho proposto inizialmente rimarranno come sono. Quindi il fattore massimo rimane a 5.


6
Benvenuti in Programming Puzzles & Code Golf: un'ottima prima sfida! :)
Maniglia della porta

1
Il numero di prese dritte / prese mancanti dovrebbe includere anche i briscole della tuta superiore in sequenza? Questo è quello che dice Wikipedia qui
isaacg,

@isaacg Devo ammettere che finora non sapevo di questa regola. Grazie per la segnalazione. Ho fatto delle ricerche e hai davvero ragione. Nella mia famiglia non giochiamo con questa regola e non ho incontrato nessuno che ci giochi. Tuttavia, non ha un'alta rilevanza, perché quando hai una mano del genere, la maggior parte delle volte giocherai a Grand che viene comunque contato in modo diverso. Quindi per questa sfida rimarremo solo con le regole che ho proposto. Modificherò il mio post in modo che sia chiaro a tutti.
Denker,

1
@DenkerAffe, ho giocato a Skat per molti anni in un club in Germania, e fidati di me, la regola è importante e ci sono casi in cui è estremamente rilevante (e sì, è sconosciuto nella maggior parte dei giocatori non seri). Soprattutto con il lato mancante : immagina di avere la briscola K, D, 9, 8, 7 e tre A e due 10 negli altri colori. Tuo Grand muore di sicuro, ma puoi giocare 'ohne 6' (colleziona alcuni contra) e batterli, supponendo che tu abbia un'idea di come i B siano seduti dall'offerta. E puoi fare offerte fino a quando il sole non arriva con quella carta.
Aganju,

@Aganju Ho già ipotizzato che questa regola non fosse nota alla maggior parte dei giocatori di hobby. Grazie per la conferma. Non dubito che sia importante, ma per esperienza personale mani come questa sono piuttosto rare, quindi la regola non entra in gioco così spesso.
Denker,

Risposte:


1

Python 2, esempio di implementazione

Dato che non ci sono ancora invii, ho scritto un esempio di implementazione in Python. Il formato di input è lo stesso delle prove nella sfida.

Forse questo ti motiva ad andare avanti, non è così difficile :)

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 byte

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

Accetta input come una matrice di array di caratteri nel formato A4, dove 4è Clubs , 3è Spades , 2è Hearts ed 1è Diamonds . L'output è 36 4per un'offerta di 36 con seme di briscola club di , pper il passaggio.

Provalo online qui .

Versione non golfata:

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 byte

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 della mia risposta Java .

Provalo online qui .

Prende input come un array di caratteri nel formato A4, in cui 4è Clubs , 3è Picche , 2è Cuori e 1è Diamanti . L'output è 36 4per un'offerta di 36 con club di briscola , pper il passaggio.

Versione non golfata:

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
}

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.