No te repitas en piedra, papel o tijera

26

Ante el rumor de que Codegolf tendrá un torneo Rock-Paper-Scissors , investigará el tema de las palabras sin cuadrados . Una palabra hecha de las cartas R, P, Ses cuadrada libre si no contiene una secuencia que se repite dos veces. Es decir, la palabra no se puede escribir como

a x x b

donde ay bson palabras de cualquier longitud y xes una palabra de longitud al menos uno, todos hechos de las letras R, P, S.

Tarea

Escribir un programa que genera los libre de cuadrados palabras de las letras R, P, Sde la longitud ndonde el número 1 <= n <= 10se toma como entrada.

Ejemplo

Por ejemplo, las palabras sin cuadrados de longitud 3 son

RPR, RSR, RPS, RSP, SPS, SRS, SRP, SPR, PRP, PSP, PSR,PRS

y los de longitud 4 son

RPRS, RPSR, RPSP, RSRP, RSPR, RSPS, PRPS, PRSR, PRSP, PSRP, PSRS, PSPR, SRPR, SRPS, SRSP, SPRP, SPRS,SPSR

y tenga en cuenta que, por ejemplo, SPSPo PRPRno están libres de cuadrados

Reglas

  • Esto es codegolf, el programa más corto gana, las lagunas estándar están cerradas.
  • Puede imprimir las palabras o crearlas en la memoria.
  • Su programa puede escribirse como una función.

Referencias

Entrada de Wikipedia sobre palabras sin cuadrados

El número de palabras ternarias sin cuadrados de longitud dada se encuentra en https://oeis.org/A006156

Relacionado: palabras arbitrarias ternarias cuadradas libres

mschauer
fuente
44
Un caso de prueba para n>3sería una buena idea, porque ha habido cierta confusión sobre los caracteres repetidos frente a las secuencias repetidas.
Laikoni
Comente sobre el seguimiento planificado en la caja de arena: codegolf.meta.stackexchange.com/a/14133/45211
mschauer
66
No creo que la etiqueta de "lenguaje natural" deba aplicarse aquí
Leo
1
Ah, las "palabras" se expandieron en "lenguaje natural", lo eliminé.
mschauer
1
No, contiene el cuadrado SP SP
mschauer

Respuestas:

20

Ruby, 39 bytes

->n{(?P*n..?S*n).grep_v /[^RPS]|(.+)\1/}

Esta función hilarantemente ineficiente genera todas las cadenas de longitud N que se encuentran alfabéticamente entre N Ps y N Ss, luego filtra la gran mayoría que contiene caracteres que no son RPS. El cheque squarefree real sólo utiliza una referencia inversa Regexp: (.+)\1.

65 bytes más idiomáticos que terminan en una cantidad de tiempo razonable para N = 10:

->n{%w[R P S].repeated_permutation(n).map(&:join).grep_v /(.+)\1/}

Editar: guardado un byte gracias a G B.

histocrat
fuente
No necesita paréntesis en grep_v, solo un espacio entre él y la barra diagonal (ahorre 1 byte)
GB
66
" hilarantemente ineficiente " probablemente describe bastantes respuestas en este sitio.
Financia la demanda de Mónica el
10

Jalea , 15 14 bytes

“RPS”ṗẆ;"f$$Ðḟ

Pruébalo en línea!

Cómo funciona

“RPS”ṗẆ;"f$$Ðḟ  Main link. Argument: n

“RPS”ṗ          Cartesian power; yield all strings of length n over this alphabet.
            Ðḟ  Filterfalse; keep only strings for which the quicklink to the left 
                returns a falsy result.
           $      Monadic chain. Argument: s (string)
      Ẇ             Window; yield the array A of all substrings of s.
          $         Monadic chain. Argument: A
       ;"             Concatenate all strings in A with themselves.
         f            Filter; yield all results that belong to A as well.
Dennis
fuente
7

Retina , 28 bytes

+%1`1
R$'¶$`P$'¶$`S
A`(.+)\1

Pruébalo en línea!

Toma entrada en unario .

Explicación

+%1`1
R$'¶$`P$'¶$`S

Esto genera todas las cadenas compuestas RPSde longitud n. La forma en que hacemos esto es que reemplazamos repetidamente el primero 1en cada línea. Pensemos en la línea como <1>, donde <está todo delante del partido y >es todo después del partido (están $`y $'respectivamente en sintaxis de sustitución de expresiones regulares, pero parecen menos intuitivas). Reemplazamos 1con R>¶<P>¶<S, donde están los avances de línea. Así, el resultado completo de esta sustitución es en realidad <R>¶<P>¶<S>, que es tres copias de la línea, con la 1sustitución con R, P, S, respectivamente, en cada una de las tres copias. Este proceso se detiene una vez que todos los 1s hayan sido sustituidos.

A`(.+)\1

Finalmente, simplemente descartamos todas las líneas que contienen una repetición.

Martin Ender
fuente
Me habría reemplazado repetidamente 1(.*)con, $1R¶$1P¶$1Spero el conteo de bytes es el mismo.
Neil
6

Casco , 15 14 bytes

-1 byte gracias a Zgarb!

fȯεfoE½QΠR"RPS

Pruébalo en línea!

Construye todas las secuencias posibles de la longitud correcta y mantiene solo aquellas cuyas subcadenas (excepto la vacía) están compuestas por dos mitades diferentes.

Maldición, realmente quería vencer a Jelly aquí.

León
fuente
3
14 bytes para empatar con Jelly.
Zgarb
5

Java 8, 285 277 bytes

import java.util.*;Set r=new HashSet();n->p("",((1<<3*n)+"").replaceAll(".","PRS"),n)void p(String p,String s,int n){int l=s.length(),i=0;if(l<1&&(s=p.substring(0,n)).equals(s.replaceAll("(.*)\\1","")))r.add(s);for(;i<l;p(p+s.charAt(i),s.substring(0,i)+s.substring(++i,l),n));}

Aunque Java es casi siempre detallado, en este caso definitivamente no es el lenguaje adecuado para un desafío como este. Generar permutaciones con subcadenas es malo para el rendimiento e ineficiente.

Sin embargo, definitivamente se puede jugar un poco más.

-8 bytes gracias a @Jakob .

Explicación:

Pruébalo aquí (El rendimiento es demasiado malo para los casos de prueba superiores a 3, pero funciona localmente ..)

import java.util.*;   // Required import for Set and HashSet

Set r=new HashSet();  // Result-Set on class-level

n->                   // Method with integer parameter and no return-type
  p("",((1<<3*n)+"").replaceAll(".","PRS"),n)
                      //  Get all permutations and save them in the Set
                      // End of method (implicit / single-line return-statement)

void p(String p,String s,int n){
                      // Separated method with 2 String & int parameters and no return-type
  int l=s.length(),   //  The length of the second input-String
      i=0;            //  Index-integer, starting at 0
  if(l<1              //  If the length is 0,
     &&(s=p.substring(0,n)).equals(s.replaceAll("(.*)\\1","")))
                      //  and it doesn't contain a repeated part:
    r.add(s);         //   Add it to the result-Set
  for(;i<l;           //  Loop (2) from 0 to `l`
    p(                //   Recursive-call with:
      p+s.charAt(i),  //    Prefix-input + the character of the second input at index `i`
      s.substring(0,i)+s.substring(++i,l),
                      //    and the second input except for this character
      n)              //    and `n`
  );                  //  End of loop (2)
}                     // End of separated method
Kevin Cruijssen
fuente
1
¿Qué tal esto lambda: n->p("",((1<<3*n)+"").replaceAll(".","PRS"),n). También, por qué no refactorizar for(;i<1;p(...));a while(i<l)p(...);?
Jakob
@ Jakob Gracias. Y siempre uso for(;...;)el codegolfing-habbit para ser honesto. En el peor de los casos, es el mismo recuento de bytes que while(...), en el mejor de los casos, se puede colocar algo dentro del ciclo for para guardar bytes. Así que trato de no usar whilenada en codegolfing, porque de todos modos nunca beneficia al conteo de bytes. Lo aumenta o permanece igual, por lo que personalmente no me molesto con la mejor legibilidad. ;)
Kevin Cruijssen
1
Sí, siempre trato de hacer que mi código de golf sea lo más legible posible en un recuento de bytes determinado. ¡Probablemente una búsqueda inútil!
Jakob
Espera, ¿mi lambda realmente funciona aquí? Fui un poco descuidado ... Genera una cadena de n PRS secuencias, mientras que su ciclo original generó una con 2 ^ ( n -2) secuencias.
Jakob
@Jakob nveces "PRS" es correcto. El mío generaba más porque ahorraba bytes (y disminuía el rendimiento, pero a quién le importa eso con codegolf). ;)
Kevin Cruijssen
4

Python 3 , 97 96 bytes

f=lambda n:{c+s for c in'RPS'*n for s in f(n-1)or{''}if all(k-s.find(c+s[:k])for k in range(n))}

Devuelve un conjunto de cadenas.

Pruébalo en línea!

Dennis
fuente
4

Perl 5 , 37 bytes

sub r{grep!/(.+)\1/,glob"{R,S,P}"x<>}

Pruébalo en línea!

La función devuelve una matriz de cadenas libres cuadradas.

Explicado:

El globgenera todas las combinaciones de R, S y P con una longitud igual a la entrada. La grepdeclaración filtra los que no están libres de cuadrados.

Xcali
fuente
¡Gran uso de la expansión de llaves!
Dom Hastings
3

R , 97 bytes

cat((x=unique(combn(rep(c('p','r','s'),n),n<-scan(),paste,collapse='')))[!grepl("(.+)\\1",x,,T)])

Pruébalo en línea!

combn(rep(c('p','r','s'),n),n,paste,collapse='')computa todas las ncadenas con -character p, r,s , pero por desgracia duplica muchos (*), por lo que uniquify, y tomamos los que coinciden con la expresión regular (.+)\1, mediante la comparación de estilo Perl, entonces imprimir la lista resultante.

(*) técnicamente, genera todas las combinaciones de las 3nletras p,r,srepetidas 3 veces npor vez, luego se aplica paste(..., collapse='')a cada combinación en lugar de calcular las 3^ncadenas directamente, pero esto es más golf que un expand.grid(el verdadero producto cartesiano).

Giuseppe
fuente
3

JavaScript (Firefox 30-57), 69 bytes

f=n=>n?[for(x of f(n-1))for(y of'RPS')if(!/(.+)\1/.test(y+=x))y]:['']

Como todas las subcadenas de palabras sin cuadrados también son sin cuadrados, la verificación se puede hacer de forma recursiva.

Neil
fuente
2

JavaScript (ES6), 93 bytes

n=>[...Array(3**n)].map(g=(d=n,i)=>d?'RPS'[i%3]+g(d-1,i/3|0):'').filter(s=>!/(.+)\1/.test(s))

Convierte todos los enteros de 0 a 3ⁿ a (base invertida) 3 usando RPScomo dígitos y los filtra por palabras sin cuadrados.

Neil
fuente
2

Julia, 88

f(n)=[filter(A->!ismatch.(r"(.+)\1",join(A)),Iterators.product(repeated("RPS",n)...))...]

Nada sofisticado.

mschauer
fuente
1

C # / LINQ, 169

Enumerable.Range(0,(int)Math.Pow(3,n)).Select(i=>string.Concat(Enumerable.Range(1,n).Select(p=>"PRS"[(i/(int)Math.Pow(3,n-p))%3]))).Where(s=>!Regex.IsMatch(s,@"(.+)\1"))

Tiene que haber una mejor manera de hacer esto :)

Jason Handby
fuente
1

F #, 143

let f n=[1..n]|>List.fold(fun l _->List.collect(fun s->["R";"P";"S";]|>List.map((+)s))l)[""]|>Seq.filter(fun x->not(Regex.IsMatch(x,"(.+)\1")))
Jason Handby
fuente
Agradable una respuesta F #!
aloisdg dice Reinstate Monica el
1
No es el más compacto de los idiomas, pero oye, cualquier excusa para usarlo :)
Jason Handby
1
Siento que . Este lenguaje es muy agradable.
aloisdg dice Reinstate Monica
1

k, 56 bytes

f:{$[x;(,/"RPS",/:\:f x-1){x@&~~/'(2,y)#/:x}/1_!x;,""]}

La falta de expresiones regulares nativas pone a k muy por detrás de la curva por una vez. Fui con una solución recursiva, ya que los caracteres para implementarlo se guardaron con un simple cheque sin cuadrados.

$[ test ; if-true ; if-false ]

es el operador ternario de k, aquí hacemos cosas interesantes para longitudes distintas de cero, y devolvemos una sola cadena vacía si se solicitan palabras de longitud cero.

(,/"RPS",/:\:f x-1)

toma el producto cartesiano de "RPS" y todas las palabras n-1 de longitud cuadrada libre. , /: \: une cada elemento de la derecha a la izquierda, dando una longitud de 3 matrices de longitud n matrices. , / aplana esto en una matriz de longitud 3n.

{x@&~~/'(2,y)#/:x}

toma las primeras n letras de cada cadena y la compara con la segunda n, luego reduce la matriz a solo donde no coinciden. Debido a que sabemos que el resultado anterior no tiene cuadrados, solo las subcadenas que comienzan en el primer carácter deben coincidir; simplificando la comprobación aquí valió la pena los caracteres gastados en implementar la recursión. Finalmente,

/1_!x

aplica la lambda al conjunto de resultados inicial a su izquierda, iterando sobre cada longitud de subcadena de 1 a (longitud de palabra) -1. ! x genera una lista de 0 a x-1, luego 1_ elimina el primer elemento (ya que las subcadenas de longitud 0 siempre coincidirán)

Sacrificando algunos caracteres, podemos usar .zs para auto-referenciar en lugar de confiar en el nombre de la función, y en lugar de verificar las subcadenas de hasta n-1, solo verifique el rendimiento (n / 2). Encuentra todas las palabras de longitud 49 (de las cuales hay 5207706) en aproximadamente 120 segundos en un 7700k, por encima de eso me encuentro con el límite de 4 GB de k libre de 32 bits.

{$[x;(,/"RPS",/:\:.z.s x-1){x@&~~/'(2,y)#/:x}/1+!_x%2;,""]}
ostewart
fuente