Jouons au Rummikub!

11

Remarque: Ceci est lié à une variante du jeu Rummikub


Contexte et règles

Rummikub est un jeu basé sur des tuiles. Il existe quatre couleurs: rouge, orange, bleu et noir. Pour chaque couleur, il y a 13 tuiles (étiquetées de 1 à 13), et il y a aussi 2 Jokers qui sont indépendants de la couleur, donc il y a 54 pièces au total. Dans cette variante de Rummikub, chaque joueur reçoit 14 tuiles et doit obtenir une tuile de plus et en déposer une autre à chaque tour, de sorte que le nombre de tuiles soit constant. Les joueurs ne se voient pas. L'objectif est de regrouper les tuiles, de sorte que toutes les pièces appartiennent à au moins un groupe (voir ci-dessous). Lorsqu'un joueur a regroupé toutes les pièces, il laisse tomber son panneau de tuiles et révèle ses pièces. Les autres vérifient ensuite si toutes les combinaisons sont valides et si elles le sont, le joueur gagne la manche.

Comment regrouper les tuiles?

Il n'y a que deux types de groupes:

  • Groupes multicolores :

    • Ils se composent de 3 ou 4 tuiles.
    • Ils ne contiennent que des tuiles portant le même numéro.
    • Toutes les tuiles sont de couleurs différentes.
    • Exemple: RED 9, BLUE 9, BLACK 9.
  • Couleur Mono groupes:

    • Ils se composent d'au moins 3 tuiles.
    • Ils ne peuvent pas contenir plus de 13 tuiles.
    • Ils ne contiennent que des tuiles portant des numéros différents et consécutifs, dans l'ordre croissant.
    • Toutes les tuiles ont la même couleur.
    • Les carreaux étiquetés avec 1 ne peuvent pas être placés après les carreaux étiquetés 13.
    • Exemple: RED 5, RED 6, RED 7.

Attendez, que font les Jokers?

Les jokers peuvent remplacer n'importe quelle pièce du jeu. Par exemple, notre premier exemple peut devenir JOKER, BLUE 9, BLACK 9, RED 9, JOKER, BLACK 9ou RED 9, BLUE 9, JOKER. La même chose s'applique à notre autre exemple. Cependant, on ne peut pas placer deux Jokers dans le même groupe, donc des choses comme JOKER, ORANGE 8, JOKERsont interdites.


Tâche

Étant donné un groupe de tuiles Rummikub, déterminez s'il est valide. Vous êtes assuré qu'aucune tuile en double n'apparaîtra, à l'exception des 2 jokers et que les tuiles que vous recevez en entrée sont valides (par exemple, des choses comme 60n'apparaîtront pas).

Entrée sortie

Vous pouvez prendre une entrée et fournir la sortie par n'importe quelle méthode standard.

Certains formats d'entrée valides: liste de chaînes, liste de tuples, listes imbriquées, chaînes ou tout autre élément que vous jugez approprié. Les couleurs peuvent être considérées comme des chaînes (par exemple:) "Blue","Red", etc., comme des abréviations de chaînes (veuillez distinguer les tuiles bleues et noires) ou comme des nombres entiers correspondant à une couleur. En ce qui concerne les Jokers, vous devez mentionner la façon dont votre programme les reçoit en entrée. Si vous choisissez des cordes, vous pouvez avoir quelque chose comme RED 9, JOKER, ..., si vous choisissez des tuples que vous pouvez avoir (9,"RED"), ("JOKER")ou quelque chose d'équivalent. Si cela vous aide, vous pouvez recevoir une couleur pour ce Joker (ce qui ne devrait pas affecter la sortie de votre programme). Par exemple, vous pouvez avoir ("JOKER","RED")ou ("JOKER","BLUE"), mais cela ne doit en aucun cas influencer la sortie.

En ce qui concerne la sortie, les règles standard pour un s'appliquent.

Exemples travaillés

Prenons un exemple qui, je l'espère, faciliterait la compréhension. Étant donné un groupe comme suit, où chaque tuple représente une tuile:

[(9, "ROUGE"), (9, "ORANGE"), ("JOKER"), (9, "NOIR")]

Cela devrait renvoyer une valeur véridique, car l'entrée est valide. Dans ce cas, le Joker se substitue (9, "BLUE")et ils forment un groupe multicolore.

Si vous receviez le groupe suivant:

[(9, "BLEU"), (9, "ORANGE"), (9, "ROUGE"), (9, "NOIR"), ("JOKER")]

Ce serait invalide, et donc votre programme devrait retourner une valeur fausse, car il n'y a plus rien à substituer au joker, car le nombre maximum de cartes dans un groupe multicolore est 4.

Cas de test supplémentaires

Ce sont pour une suite de tests étendue qui couvre presque toutes les situations possibles:

Entrée -> Sortie 

[(1, "BLEU"), (2, "BLEU"), (3, "BLEU"), (4, "BLEU"), (5, "BLEU"), (6, "BLEU")] - > véridique

[(6, "BLEU"), (6, "ROUGE"), (6, "NOIR)] -> véridique

[(5, "NOIR"), (6, "NOIR"), (7, "NOIR"), (8, "NOIR"), (9, "NOIR"), (10, "NOIR"), ( "JOKER"), (12, "NOIR")] -> véridique 

[("JOKER"), (3, "BLEU"), (3, "ROUGE")] -> véridique

[(8, "NOIR"), (2, "ROUGE"), (13, "BLEU")] -> falsy

[(4, "RED"), (3, "RED"), (5, "RED")] -> falsy

[(5, "NOIR"), (6, "NOIR)] -> faux

[("JOKER"), (5, "RED"), ("JOKER")] -> falsy

[(4, "RED"), (5, "RED"), (6, BLUE ")] -> falsy

[(4, "RED"), ("JOKER"), (5, "RED")] -> falsy

[(12, "NOIR"), (13, "NOIR), (1," NOIR ")] -> faux

C'est le , donc le code le plus court en octets dans chaque langue gagne!

M. Xcoder
la source
En relation
Peter Taylor
Le vol est la meilleure partie de rummikub. Même sans cela, cela ressemble à un défi amusant.
Josiah
[] Est-il une entrée valide?
V. Courtois
@ V.Courtois Bien sûr.
M. Xcoder
1
@ V.Courtois on ne peut pas placer deux Jokers dans le même groupe , donc deux une entrée contenant 2 Jokers est fausse.
M. Xcoder

Réponses:

6

APL (Dyalog) , 58 octets

Prend la liste des couleurs (1-4) comme argument de droite et la liste des nombres comme argument de gauche. Un numéro de Joker est indiqué, (⍳4)ce qui équivaut (1 2 3 4)à indiquer qu'il pourrait être l'un de ceux-ci. De même, sa couleur est indiquée (⍳13)pour indiquer qu'il pourrait s'agir de l'un des nombres de 1 à 13.

{(3≤≢⍺)∧((s⍵)∧⍺≡∪⍺)∨((s←{1∊≢∘∪¨⊃,¨/⍵})⍺)∧∨/∊(⊃,¨/⍵)⍷¨⊂⍳13}

Essayez-le en ligne!

Algorithme

Il y a trois conditions, dont les deux dernières ont chacune deux conditions:

  1. La piste doit avoir une longueur supérieure ou égale à 3

ET SOIT

    1. un seul numéro ET

    2. couleurs uniques

OU

    1. une seule couleur ET
    2. nombres séquentiels

pour que la course soit valide.

Ordre de lecture

3≤3 est inférieur ou égal au ≢⍺nombre de tuiles

et

   s⍵ tous les chiffres sont les mêmes

   et

   ⍺≡∪⍺ les couleurs sont uniques

ou

   1∊1 parmi ≢∘∪¨le nombre de  couleurs ⊃,¨/expansées uniques

   et

   ∨/il existe au moins un parmi tous les ⊃,¨/⍵numéros étendus en exécute ⍷¨⊂un qui se trouve dans ⍳131 à 13

Explication complète du code

{} Fonction anonyme où est l'argument gauche et l' argument droit

3.2.

⍳13 les chiffres de 1 à 13

()⍷¨Trouvez les positions de départ de chacune des pistes suivantes:

  ,¨/⍵ joindre chaque élément des nombres (crée une course pour chaque valeur Joker)

   divulguer (car /réduit le rang)

  ϵ nlist (aplatir)

∨/ OU réduction (c.-à-d. Est-ce vrai?)

()∧ ET:

3.1

  ()⍺ Le résultat de l'application de la fonction suivante sur la liste des couleurs:

   s←{}S (for s ame) qui est la fonction anonyme suivante ( est son argument):

    ,¨/⍵ joindre chaque élément à travers (crée une course pour chaque valeur Joker)

     divulguer (car /réduit le rang)

    ≢∘∪¨ le nombre d'éléments uniques dans chaque liste

    1∊ est-on membre? (c.-à-d. y a-t-il des listes identiques?)

()∨OU:

2.2.

  ∪⍺ les couleurs uniques

  ⍺≡ sont identiques aux couleurs (c'est-à-dire qu'elles sont uniques)

  ()∧ ET:

2.1.

   s⍵ les chiffres sont les mêmes

  ()∧ET

1.

   ≢⍺ le nombre de couleurs (ie le nombre de tuiles)

   3≤ trois est inférieur ou égal à celui

Adam
la source
1
Wow, il semble que l'APL soit un excellent outil pour ce défi
M. Xcoder
3

Gelée , 41 40 38 36 octets

EȧI=1ȦȯE
0,W€yµZç/ɓQ⁼⁸ȧ
L>2ȧ4p13ðç€Ṁ

Essayez-le en ligne! (livré avec un pied de page de suite de tests)

Prend l'entrée comme un tableau de (color, value)pour les tuiles régulières et 0pour les jokers. Les couleurs sont représentées sous forme d'entiers (même si je ne suis pas sûr que cela soit important pour le code actuel).

Sorties 1(véridiques) ou 0(fausses).

Explication

L>2ȧ4p13ðç€Ṁ    Main link, checks if a sequence is valid. Args: sequence
L                 Get the length of the sequence.
 >2               Check if it's at least 3 tiles.
   ȧ4             And: yield 4 if it is, 0 otherwise.
     p13          Cartesian product: yield all possible tiles if
                  result was 4, empty array otherwise.
        ð         Begin a new dyadic chain with args (tiles, sequence).
         ç€       Call the first helper link for each tile with args (tile, sequence).

0,W€yµZç/ɓQ⁼⁸ȧ    First helper link, checks if a sequence is valid if jokers
                  are substituted for the given tile. Args: tile, sequence
0,                  Make a pair [0, tile].
  W€                Turn that into [[0], [tile]].
    y               Map all 0's (jokers) into tile in the sequence.
     µ              Begin a new monadic chain with args (sequence).
      Z             Transpose to get list [colors, values].
       ç/           Call the second helper link with args (colors, values).
         ɓ          Begin a new dyadic chain with args (sequence, valid).
          Q         Remove duplicate tiles from the sequence.
           ⁼⁸       Check if the sequence is unchanged (i.e. there were no duplicates).
             ȧ      And with the output of the second helper.

EȧI=1ȦȯE    Second helper link, checks if a sequence is valid assuming no duplicates.
            Args: colors, values
E             Check if all the colors are the same.
 ȧ            Logical and with the values array.
              Yields the values if they were, 0 if not.
  I           Find the differences between each value.
              Yields [] if the colors differed.
   =1         See if each difference is equal to 1.
              Yields [] if the colors differed.
     Ȧ        Check if the list was nonempty and all values were truthy.
              Yields 1 for valid mono-colors, 0 otherwise.
      ȯ       Logical or with the values array.
              Yields 1 for valid mono-colors, the values otherwise.
       E      Check if all the values are the same. For valid mono-colors
              this tests if all items of [1] are equal (obviously true).
              Yields 1 for valid sequences, 0 otherwise.
PurkkaKoodari
la source
Je pense que vous devez produire une vérité / fausse cohérente.
Adám
@ Adám Edited, heureusement, n'a pas affecté le nombre d'octets.
PurkkaKoodari
2

Python 2 , 371 370 362 341 329 325 octets

  • @ Mr.Xcoder a sauvé 1 octet: str.split()au lieu delist literal
  • 8 octets enregistrés: raccourci pour len(x)-1
  • 19 octets enregistrés: J O BK B Rpour les Joker, Orange, Black, Blue, Redlittéraux
  • @ Mr.Xcoder a enregistré encore 12 autres octets, merci !!
  • Encore 4 octets grâce à @ Mr.Xcoder
def f(x):
 j=sum("J"in i for i in x);z=len(x)-1
 if j>1or z<2:return False
 if j<1:return(all(i[0]==x[0][0]for i in x)and sum(i[1]==x[0][1]for i in x)<2)or(all(i[1]==x[0][1]for i in x)and sum(int(x[m+1][0])==int(x[m][0])+1for m in range(z))==z)
 return any(f([[k,(i+1,j)]["J"in k]for k in x])for j in'RBbO'for i in range(13))

Essayez-le en ligne!

officialaimm
la source
2
370 octets
M. Xcoder
1
Cela économise en fait beaucoup plus d'octets que je ne le pensais: 329 .
M. Xcoder
1
325 octets . Désolé pour l' amélioration très tardive .
M. Xcoder
1

Javascript (ES6), 286 octets

var testcases = [[{n:1,c:"BLUE"},{n:2,c:"BLUE"},{n:3,c:"BLUE"},{n:4,c:"BLUE"},{n:5,c:"BLUE"}, {n:6,c:"BLUE"}],[{n:6,c:"BLUE"},{n:6,c:"RED"},{n:6,c:"BLACK"}],[{n:5,c:"BLACK"},{n:6,c:"BLACK"},{n:7,c:"BLACK"},{n:8,c:"BLACK"},{n:9,c:"BLACK"},{n:10,c:"BLACK"},{n:0,c:"JOKER"},{n:12,c:"BLACK"}],[{n:0,c:"JOKER"},{n:3,c:"BLUE"},{n:3,c:"RED"}],[{n:8,c:"BLACK"},{n:2,c:"RED"},{n:13,c:"BLUE"}],[{n:4,c:"RED"}, {n:3,c:"RED"}, {n:5,c:"RED"}],[{n:5,c:"BLACK"}, {n:6,c:"BLACK"}],[{n:0,c:"JOKER"},{n:5,c:"RED"},{n:0,c:"JOKER"}],[{n:4,c:"RED"},{n:5,c:"RED"},{n:6,c:"BLUE"}],[{n:4,c:"RED"},{n:0,c:"JOKER"},{n:5,c:"RED"}],[{n:12,c:"BLACK"},{n:13,c:"BLACK"},{n:1,c:"BLACK"}],[{n:11,c:"BLACK"},{n:12,c:"BLACK"},{n:0,c:"JOKER"}],[{n:1,c:"BLACK"},{n:2,c:"BLACK"},{n:3,c:"BLACK"},{n:1,c:"BLUE"},{n:2,c:"BLUE"},{n:3,c:"BLUE"}]];

g=a=>a.length
j=a=>a.n==0
l=(x,y)=>x.c==y.c||j(x)||j(y)
a=s=>g(s)>2&&([q=[0],x=s[0],s.map(y=>q[0]+=x==y||((l(x,y)||x.n==y.n)&&!(j(x)&&j(y)))&&(([n=s.indexOf(y),n<1||([x=s[n-1],!l(x,y)||y.n>0&&x.n<y.n])[1]||(n<g(s)-1&&x.n+1<s[n+1].n)||(n==g(s)-1&&y.n==0&&x.n<13)])[1])?1:0)])[0][0]==g(s)

testcases.forEach(H=>console.log(a(H)));

(Notez que les cas de test ci-dessus contiennent 2 cas de test supplémentaires qui ne sont pas dans la Question: ils sont respectivement vrai et faux: voir la version non golfée pour la lisibilité).

Processus brut:

 Using first tile x:
   For each tile y:
     count for x: can group with y
 return: x matches n tiles, where n is the number of tiles

Les jokers sont indiqués en ayant un 0comme valeur numérique (un nombre négatif fonctionnerait aussi); cela maintient la structure d'entrée cohérente (a à la fois une couleur et une valeur) et ne dépend pas de devoir vérifier sic=="JOKER" , en économisant 7 octets.

Il est possible que certaines parenthèses soient supprimées, il peut être possible de ne pas encadrer en qtant que tableau (je l'ai essayé et la valeur est restée à 0 ou a provoqué des démons nasaux ).

Non golfé:

var testcases = [
[{n:1,c:"BLUE"},{n:2,c:"BLUE"},{n:3,c:"BLUE"},{n:4,c:"BLUE"},{n:5,c:"BLUE"}, {n:6,c:"BLUE"}],//true
[{n:6,c:"BLUE"},{n:6,c:"RED"},{n:6,c:"BLACK"}],//true
[{n:5,c:"BLACK"},{n:6,c:"BLACK"},{n:7,c:"BLACK"},{n:8,c:"BLACK"},{n:9,c:"BLACK"},{n:10,c:"BLACK"},{n:0,c:"JOKER"},{n:12,c:"BLACK"}],//true
[{n:0,c:"JOKER"},{n:3,c:"BLUE"},{n:3,c:"RED"}],//true
[{n:8,c:"BLACK"},{n:2,c:"RED"},{n:13,c:"BLUE"}],//false
[{n:4,c:"RED"}, {n:3,c:"RED"}, {n:5,c:"RED"}],//false
[{n:5,c:"BLACK"}, {n:6,c:"BLACK"}],//false
[{n:0,c:"JOKER"},{n:5,c:"RED"},{n:0,c:"JOKER"}],//false
[{n:4,c:"RED"},{n:5,c:"RED"},{n:6,c:"BLUE"}],//false
[{n:4,c:"RED"},{n:0,c:"JOKER"},{n:5,c:"RED"}],//false
[{n:12,c:"BLACK"},{n:13,c:"BLACK"},{n:1,c:"BLACK"}],//false
[{n:11,c:"BLACK"},{n:12,c:"BLACK"},{n:0,c:"JOKER"}],//true
[{n:1,c:"BLACK"},{n:2,c:"BLACK"},{n:3,c:"BLACK"},{n:1,c:"BLUE"},{n:2,c:"BLUE"},{n:3,c:"BLUE"}]
];

g=a=>a.length
i=(a,v)=>a.indexOf(v)
j=x=>x.n==0
m=(x,y)=>
       (l(x,y)||x.n==y.n)
    &&!(j(x)&&j(y))
l=(x,y)=>x.c==y.c||j(x)||j(y)
c=(a,v)=>([n=i(a,v),
      n<1
    ||([x=a[n-1],!l(x,v)||v.n>0&&x.n<v.n])[1]
    ||(n<g(a)-1&&x.n+1<a[n+1].n)
    ||(n==g(a)-1&&v.n==0&&x.n<13)])[1]
a=s=>g(s)>2&&([q=[0],x=s[0],s.map(y=>q[0]+=x==y||m(x,y)&&c(s,y)?1:0)])[0][0]==g(s)

testcases.forEach(H=>console.log(a(H)));

Version sur laquelle j'ai travaillé pour obtenir la logique correcte. Les lambdas à usage unique se sont alignés; voici leur fonction correspondante:

g() -> string.length
i() -> indexof
j() -> isJoker
m() -> do tiles match
l() -> do colors match
c() -> same-color isConsecutiveOrder
a() -> main lambda
Draco18s ne fait plus confiance à SE
la source
1

C # (.NET Core) , 198 octets

using System.Linq;(C,N)=>{int l=C.Length,j=C.Count(x=>x<1),c=C.Distinct().Count(),n=N.Distinct().Count(),u=N.Min();foreach(var x in N)u*=0<(u&x)?2:0;return l>2&((u>0&n==l&c<2+j)|(n<2+j&c==l&l<5));};

Prend les couleurs des tuiles et les nombres sur eux comme des listes séparées d'entiers. Les spécificités de ce mappage n'ont pas d'importance tant que chaque couleur a un entier différent et que les jokers sont représentés par 0.

Le format de saisie des nombres est cependant assez spécial. Le nombre qui doit être entré pour un nombre nest à la place 2 ^ n, tandis que le nombre utilisé pour représenter un joker doit être (2 ^ 14) -1. Cela permet au bit et u&xd'évaluer à u si la tuile x a une valeur égale à u ou est un joker.

C # (.NET Core) , 200 octets

using System.Linq;(C,N)=>{int l=C.Length,j=N.Count(x=>x<1),c=C.Distinct().Count(),n=N.Distinct().Count(),u=N.Min();foreach(var x in N)u=u==x|x<1?u+1:0;return l>2&((u>0&n==l&c<2+j)|(n<2+j&c==l&l<5));};

Une solution de 2 octets plus longue qui n'est pas éclectique sur l'entrée. Il s'avère que l'utilisation d'un cas spécial pour les jokers dans le seul endroit avec lequel ils étaient difficiles à gérer n'était pas beaucoup plus longue que l'opération intelligente au niveau du bit dont j'étais si fier. Ici, les jokers sont (0,0), les autres nombres sont comme prévu et les couleurs sont représentées par 4 valeurs distinctes les unes des autres par la comparaison par défaut de C # (en particulier, le LinqDistinct() opération doit considérer les valeurs de la même couleur comme `` non distinctes ''). et les valeurs pour différentes couleurs comme «distinctes»).

Quelque chose qui pourrait être utile à d'autres langues, u*=!u++^x*xserait équivalent à u=u==x|x<1?u+1:0dans certaines langues; u ^ x est 0 ssi u == x, et 0 fois n'importe quel entier est 0, donc u ^ x * x serait 0 pour u == x ou x == 0 si C # n'a pas rendu les opérations au niveau du bit de priorité inférieure à mathématiques. C # ne peut pas non plus interpréter les entiers comme des bools sans casting explicite. Une langue qui essaie plus difficile de faire des types de travail peut convertir les valeurs 0et not 0à falseet trueavant d' appliquer !les bien, et puis quand revenir à un int interpréter !falsecomme 1 et !true0. Cela dit, je ne peux pas garantir une autre langue REELLEMENT bénéficier du reste de l'algorithme de sorte qu'il pourrait même ne pas apparaître.

Kamil Drakari
la source
1

Scala, 491 477 caractères, 491 477 octets

Ce défi était amusant; Merci.

var c=Seq("O","B","b","R")
t match{case _ if t.length<3=>false
case _ if t.exists(x=>x._1==0)=>{var b=false
if(t.filter(q=>q._1!=0).exists(q=>q._1==0))b else{for(y<-1 to 13)for(u<-c)b=b|f(t.takeWhile(q=>q._1!=0)++:(y,u)+:t.reverse.takeWhile(q=>q._1!=0).reverse)
b}}
case _::(x,_)::_ if t.forall(_._1==x)=>true
case _ if t.forall(_._2==c(0))|t.forall(_._2==c(1))|t.forall(_._2==c(2))|t.forall(_._2==c(3))=>(t(0)._1 to t(0)._1+t.length-1).toList equals t.map(_._1)
case _=>false}

Donc fà la ligne 4 est un appel récursif où j'essaie de remplacer "JOKER" par toutes les autres tuiles. Voir tio pour une vue plus claire du code. J'ai choisi de prendre en entrée une séquence de 2 tuples (Int, String) - appelée tdans mon code, voir tio - donc "JOKER" est représenté par un 2-tuple (0, "JOKER").

EDIT: 14 octets enregistrés grâce aux commentaires, je prends OB b R pour ORANGE BLACK BLUE RED.

Essayez-le en ligne!

EDIT: -2 ​​octets, supprimés inutiles (autour des conditions du case _ ifs

V. Courtois
la source
Vous ne pouvez pas utiliser O,B,b,Rau lieu de ORANGE,BLUE,BLACK,REDpour enregistrer des octets? Je ne sais pas comment fonctionne Scala, mais je pense que vous le pouvez.
M. Xcoder du
J'ai essayé; en fait, il enregistre les octets de cette façon (une séquence de chaînes). Il le fait var (O,B,b,R)=("ORANGE","BLACK","BLUE","RED")et les appels sont O B b R, pour un total de 49 octets; où var c=Seq("ORANGE","BLACK","BLUE","RED")et les appels c(...)totalisent 58 octets. Mais le premier cas permet for(u<-c)à la place for(u<-Seq(O,B,b,R)), de sorte que le coût n'est pas -9 mais +2. Merci d'avoir essayé.
V. Courtois
@ V.Courtois Je crois que ce que M. Xcoder a suggéré est d'utiliser var c=Seq("O","B","b","R")et de prendre ces caractères comme entrées plutôt que des chaînes complètes pour la couleur. Comme mentionné dans l'article d'origine, "Les couleurs peuvent être considérées comme ... Abréviations de chaînes".
Kamil Drakari
ohh ~ je vois ce que tu veux dire, merci @ vous deux
V. Courtois