¡Juguemos a Rummikub!

11

Nota: Esto está relacionado con una variación del juego Rummikub


Antecedentes y reglas

Rummikub es un juego basado en fichas. Hay cuatro colores: rojo, naranja, azul y negro. Para cada color hay 13 fichas (etiquetadas del 1 al 13), y también hay 2 comodines que son independientes del color, por lo tanto, hay 54 piezas en total. En esta variación de Rummikub, cada jugador recibe 14 fichas y debe obtener una ficha más y soltar otra cada ronda, de modo que el recuento de fichas sea constante. Los jugadores no ven las fichas del otro. El objetivo es agrupar las fichas, de modo que todas las piezas pertenezcan al menos a un grupo (ver más abajo). Cuando un jugador tiene todas las piezas agrupadas, sueltan su tablero de fichas y revelan sus piezas. Luego, los demás verifican si todas las combinaciones son válidas, y si lo son, el jugador gana la ronda.

¿Cómo se pueden agrupar los mosaicos?

Solo hay dos tipos de grupos:

  • Grupos multicolores :

    • Se componen de 3 o 4 fichas.
    • Solo contienen fichas con el mismo número.
    • Todos los azulejos son de diferentes colores.
    • Ejemplo: RED 9, BLUE 9, BLACK 9.
  • Grupos monocolor :

    • Se componen de al menos 3 fichas.
    • No pueden contener más de 13 fichas.
    • Solo contienen fichas con diferentes números consecutivos, en orden ascendente.
    • Todos los azulejos tienen el mismo color.
    • Las baldosas etiquetadas con 1 pueden no ser lugares después de las baldosas etiquetadas 13.
    • Ejemplo: RED 5, RED 6, RED 7.

Espera, ¿qué hacen los comodines?

Los comodines pueden sustituir cualquier pieza del juego. Por ejemplo, nuestro primer ejemplo puede ser JOKER, BLUE 9, BLACK 9, RED 9, JOKER, BLACK 9o RED 9, BLUE 9, JOKER. Lo mismo se aplica a nuestro otro ejemplo. Sin embargo, uno no puede colocar dos comodines en el mismo grupo, por lo que cosas como JOKER, ORANGE 8, JOKERestán prohibidas.


Tarea

Dado un grupo de mosaicos Rummikub, determine si es válido. Se le garantiza que no aparecerán mosaicos duplicados, excepto los 2 comodines y que los mosaicos que reciba como entrada son válidos (por ejemplo, cosas como 60no aparecerán).

De entrada y salida

Puede tomar la entrada y proporcionar la salida por cualquier método estándar.

Algunos formatos de entrada válidos: lista de cadenas, lista de tuplas, listas anidadas, cadenas o cualquier otra cosa que considere adecuada. Los colores pueden tomarse como Cadenas (por ejemplo:) "Blue","Red", etc., como abreviaturas de Cadena (haga que las baldosas Azul y Negra sean distinguibles) o como enteros que correspondan a un color. Cuando se trata de comodines, debe mencionar la forma en que su programa los recibe como entrada. Si elige cadenas, puede tener algo como RED 9, JOKER, ..., si elige tuplas que puede tener (9,"RED"), ("JOKER")o algo equivalente. Si ayuda, puede recibir un color para ese Joker (que no debería afectar la salida de su programa). Por ejemplo, puede tener ("JOKER","RED")o ("JOKER","BLUE"), pero eso no debería influir en la salida de ninguna manera.

Con respecto a la salida, se aplican las reglas estándar para un .

Ejemplos trabajados

Tomemos un ejemplo, que con suerte hará que sea más fácil de entender. Dado un grupo de la siguiente manera, donde cada tupla representa un mosaico:

[(9, "ROJO"), (9, "NARANJA"), ("JOKER"), (9, "NEGRO")]

Esto debería devolver un valor verdadero, porque la entrada es válida. En este caso, el Joker sustituye (9, "BLUE"), y forman un grupo multicolor.

Si le dieran el siguiente grupo:

[(9, "AZUL"), (9, "NARANJA"), (9, "ROJO"), (9, "NEGRO"), ("JOKER")]

Sería inválido y, por lo tanto, su programa debería devolver un valor falso, porque no queda nada para que el comodín lo sustituya, porque el número máximo de tarjetas en un grupo multicolor es 4.

Casos de prueba adicionales

Estos son para un conjunto de pruebas extendido que cubre casi todas las situaciones posibles:

Entrada -> Salida 

[(1, "AZUL"), (2, "AZUL"), (3, "AZUL"), (4, "AZUL"), (5, "AZUL"), (6, "AZUL")] - > veraz

[(6, "AZUL"), (6, "ROJO"), (6, "NEGRO)] -> verdad

[(5, "NEGRO"), (6, "NEGRO"), (7, "NEGRO"), (8, "NEGRO"), (9, "NEGRO"), (10, "NEGRO"), ( "JOKER"), (12, "BLACK")] -> verdad 

[("JOKER"), (3, "AZUL"), (3, "ROJO")] -> verdad

[(8, "NEGRO"), (2, "ROJO"), (13, "AZUL")] -> falso

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

[(5, "NEGRO"), (6, "NEGRO)] -> falsedad

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

[(4, "ROJO"), (5, "ROJO"), (6, AZUL ")] -> falsedad

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

[(12, "NEGRO"), (13, "NEGRO), (1," NEGRO ")] -> falsedad

Este es el , por lo que gana el código más corto en bytes en cada idioma.

Sr. Xcoder
fuente
Relacionado
Peter Taylor
Robar es la mejor parte de rummikub. Incluso sin eso, esto parece un desafío divertido.
Josiah
¿Es [] una entrada válida?
V. Courtois
@ V.Courtois Por supuesto.
Sr. Xcoder
1
@ V.Courtois no se pueden colocar dos comodines en el mismo grupo , por lo que dos entradas que contengan 2 comodines son falsas.
Sr. Xcoder

Respuestas:

6

APL (Dyalog) , 58 bytes

Toma la lista de colores (1-4) como argumento derecho y la lista de números como argumento izquierdo. El número de un Joker se denota, lo (⍳4)que equivale (1 2 3 4)a indicar que podría ser cualquiera de esos. Del mismo modo, su color se denota (⍳13)para indicar que podría ser cualquiera de los números del 1 al 13.

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

Pruébalo en línea!

Algoritmo

Hay tres condiciones, de las cuales las dos últimas tienen dos condiciones cada una:

  1. La carrera debe tener una longitud mayor o igual a 3

Y TAMBIÉN

    1. un solo número Y

    2. colores únicos

O

    1. un solo color Y
    2. números secuenciales

para que la carrera sea válida.

Orden de lectura

3≤3 es menor o igual que el ≢⍺número de fichas

y

   s⍵ todos los numeros son iguales

   y

   ⍺≡∪⍺ los colores son únicos

o

   1∊1 está entre ≢∘∪¨la cantidad de  colores ⊃,¨/expandidos únicos

   y

   ∨/existe al menos uno entre todos los ⊃,¨/⍵números expandidos ⍷¨⊂que se encuentran en ⍳131 a 13

Explicación completa del código

{... } función anónima donde se deja argumento y es argumento correcto

3.2.

⍳13 los números del 1 al 13

()⍷¨Encuentre las posiciones iniciales de cada una de las siguientes carreras:

  ,¨/⍵ une cada elemento de los números (crea una carrera para cada valor de Joker)

   revelar (porque /reduce el rango)

  ϵ nlist (aplanar)

∨/ O reducción (es decir, ¿hay alguna verdad?)

(... )∧ Y:

3.1

  (... )⍺ el resultado de aplicar la siguiente función en la lista de colores:

   s←{... }s (por s AME), que es la siguiente función anónima ( es su argumento):

    ,¨/⍵ une cada elemento (crea una carrera para cada valor Joker)

     revelar (porque /reduce el rango)

    ≢∘∪¨ el número de elementos únicos en cada lista

    1∊ es uno un miembro? (es decir, ¿hay listas todas iguales?)

(... )∨O:

2.2.

  ∪⍺ los colores únicos

  ⍺≡ son idénticos a los colores (es decir, son únicos)

  (... )∧ Y:

2.1.

   s⍵ los números son todos iguales

  (... )∧Y

1)

   ≢⍺ la cantidad de colores (es decir, la cantidad de mosaicos)

   3≤ tres es menor o igual a eso

Adán
fuente
1
Wow, parece que APL es una gran herramienta para este desafío
Sr. Xcoder
3

Gelatina , 41 40 38 36 bytes

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

Pruébalo en línea! (viene con un pie de página de la suite de prueba)

Toma datos como una matriz de (color, value)mosaicos regulares y 0comodines. Los colores se representan como enteros (aunque no estoy seguro de si eso es importante para el código actual).

Salidas 1(verdad) o 0(falsedad).

Explicación

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
fuente
Creo que debe emitir una verdad / falsedad consistente.
Adám
@ Adám Editado, afortunadamente no afectó el conteo de bytes.
PurkkaKoodari
2

Python 2 , 371 370 362 341 329 325 bytes

  • @ Mr.Xcoder guardó 1 byte: en str.split()lugar delist literal
  • 8 bytes guardados: taquigrafía para len(x)-1
  • 19 bytes guardados: J O BK B Rpara Joker, Orange, Black, Blue, Redliterales
  • @ Mr.Xcoder guardó otros 12 bytes, ¡Gracias!
  • Otros 4 bytes gracias a @ 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))

Pruébalo en línea!

officialaimm
fuente
2
370 bytes
Sr. Xcoder
1
Esto realmente ahorra muchos más bytes de lo que pensaba: 329 .
Sr. Xcoder
1
325 bytes . Perdón por la mejora muy tardía .
Sr. Xcoder
1

Javascript (ES6), 286 bytes

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

(Tenga en cuenta que los casos de prueba anteriores contienen 2 casos de prueba adicionales que no están en la Pregunta: son verdaderos y falsos, respectivamente: consulte la versión no protegida para facilitar la lectura).

Proceso áspero:

 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

Los comodines se indican teniendo a 0como su valor numérico (un número negativo también funcionaría); Esto mantiene la estructura de entrada consistente (tiene un color y un valor) y no depende de tener que verificar si c=="JOKER", ahorrando 7 bytes.

Es posible que se eliminen algunos paréntesis, podría ser posible no encajonar qcomo una matriz (lo probé y el valor simplemente permaneció 0 o causó demonios nasales ).

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

Versión en la que trabajé para obtener la lógica correcta. Las lambdas de un solo uso se alinearon; Aquí está su función correspondiente:

g() -> string.length
i() -> indexof
j() -> isJoker
m() -> do tiles match
l() -> do colors match
c() -> same-color isConsecutiveOrder
a() -> main lambda
Draco18s ya no confía en SE
fuente
1

C # (.NET Core) , 198 bytes

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

Toma los colores de los mosaicos y los números en ellos como listas separadas de enteros. Los detalles de ese mapeo no importan siempre que cada color tenga un número entero diferente y los comodines se representen como 0.

Sin embargo, el formato para ingresar números es bastante especial. El número que debe ingresarse para un número nes, en cambio, 2 ^ n, mientras que el número utilizado para representar un comodín debe ser (2 ^ 14) -1. Esto habilita el bit u&xa bit y para evaluar si el mosaico x tiene un valor igual a u o es un comodín.

C # (.NET Core) , 200 bytes

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

Una solución más larga de 2 bytes que no es ecléctica con respecto a la entrada. Resulta que solo usé un caso especial para bromistas en el único lugar con el que eran difíciles de tratar no fue mucho más que la inteligente operación bit a bit de la que estaba tan orgulloso. Aquí los comodines son (0,0), otros números son los esperados y los colores se representan con 4 valores que son distintos entre sí por la comparación predeterminada de C # (específicamente, el LinqDistinct() operación debe considerar valores para el mismo color como 'no distinto' y valores para diferentes colores como 'distintos').

Algo que podría ser útil para otros idiomas, u*=!u++^x*xsería equivalente a u=u==x|x<1?u+1:0en algunos idiomas; u ^ x es 0 si u == x, y 0 veces cualquier int es 0, entonces u ^ x * x sería 0 para u == x o x == 0 si C # no hizo que las operaciones bit a bit tuvieran una precedencia menor que los matemáticos C # tampoco puede interpretar ints como bools sin conversión explícita. Un lenguaje que se esfuerza más para hacer que los tipos de trabajo podría convertir los valores 0y not 0a falsey trueantes de aplicar !a ellos, sin embargo, y luego cuando se va de nuevo a un int interpretar !falsecomo 1 y !truecomo 0. Dicho todo esto, no puedo garantizar otro idioma en realidad beneficiarse del resto del algoritmo, por lo que es posible que ni siquiera aparezca.

Kamil Drakari
fuente
1

Scala, 491 477 caracteres, 491 477 bytes

Este desafío fue divertido; Gracias.

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}

Entonces, fen la línea 4 hay una llamada recursiva donde trato de reemplazar "JOKER" por cada otro mosaico. Ver tio para una visión más clara del código. Elegí tomar como entrada una secuencia de 2 tuplas (Int, String), llamada ten mi código, ver tio , por lo que "JOKER" está representado por una 2-tupla (0, "JOKER").

EDITAR: 14 bytes guardados gracias a los comentarios, tomo OB b R para NARANJA NEGRO AZUL ROJO.

¡Pruébelo en línea!

EDITAR: -2 bytes, borrado inútil (alrededor de las condiciones del case _ ifs

V. Courtois
fuente
¿No puedes usar en O,B,b,Rlugar de ORANGE,BLUE,BLACK,REDguardar bytes? No tengo idea de cómo funciona Scala, pero creo que puedes.
Sr. Xcoder
Lo intenté; de hecho, ahorra bytes de esta manera (una secuencia de cadenas). Lo hace var (O,B,b,R)=("ORANGE","BLACK","BLUE","RED")y las llamadas son O B b R, para un total de 49 bytes; donde var c=Seq("ORANGE","BLACK","BLUE","RED")y las llamadas c(...)totalizan 58 bytes. PERO el primer caso lo permite for(u<-c)en lugar de for(u<-Seq(O,B,b,R)), por lo que el costo no es -9 sino +2. Gracias por intentarlo sin embargo.
V. Courtois
@ V.Courtois Creo que lo que sugirió el Sr. Xcoder es usar var c=Seq("O","B","b","R")y tomar esos caracteres como entradas en lugar de cadenas completas para el color. Como se menciona en la publicación original, "Los colores se pueden tomar como ... Abreviaturas de cadena".
Kamil Drakari
ohh ~ ya veo lo que quieres decir, gracias @ ambos
V. Courtois