Não se repita em Pedra-Papel-Tesoura

26

Com o boato de que Codegolf terá um torneio de Pedra, Papel e Tesoura, você analisa o tema das palavras sem quadrados . A palavra feita das letras R, P, Sé square-livre , se ele não contém uma sequência que se repete duas vezes. Ou seja, a palavra não pode ser escrita como

a x x b

onde ae bsão as palavras de qualquer comprimento e xé uma palavra de comprimento pelo menos um, todos feitos das letras R, P, S.

Tarefa

Escreva um programa que gera os free-quadrados palavras das letras R, P, Sde comprimento n, onde o número 1 <= n <= 10é tomada como entrada.

Exemplo

Por exemplo, as palavras sem quadrado do comprimento 3 são

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

e os de comprimento 4 são

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

e observe que, por exemplo, SPSPou PRPRnão são quadrados

Regras

  • Este é o codegolf, o programa mais curto vence, as brechas padrão estão fechadas.
  • Você pode imprimir as palavras ou criá-las na memória.
  • Seu programa pode ser escrito como uma função.

Referências

Entrada da Wikipedia em palavras sem quadrados

O número de palavras ternárias sem quadrados e de comprimento determinado está em https://oeis.org/A006156

Relacionados: arbitrária de comprimento ternário Squarefree Words

mschauer
fonte
4
Um caso de teste n>3seria uma boa idéia, porque houve alguma confusão sobre caracteres repetidos versus sequências repetidas.
Laikoni 30/10
Por favor, comente sobre o acompanhamento planejado na caixa de areia: codegolf.meta.stackexchange.com/a/14133/45211
mschauer
6
Eu não acho que a tag "natural-language" deva se aplicar aqui
Leo
1
Ah, "palavras" foram expandidas em "linguagem natural", eu a removi.
mschauer
1
Não, ele contém o quadrado SP SP
mschauer

Respostas:

20

Ruby, 39 bytes

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

Essa função hilariamente ineficiente gera todas as seqüências de comprimento N que estão em ordem alfabética entre N Ps e N Ss e, em seguida, filtra a grande maioria que contém caracteres não RPS. A verificação squarefree real apenas usa um backreference Regexp: (.+)\1.

65 bytes mais idiomáticos que terminam em um período de tempo razoável para N = 10:

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

Editar: salvou um byte graças a G B.

histocrata
fonte
Você não precisa de parênteses em grep_v, apenas um espaço entre ele ea barra (save 1 byte)
GB
6
" hilariamente ineficiente " provavelmente descreve algumas respostas neste site.
Fund Monica's Lawsuit
10

Geléia , 15 14 bytes

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

Experimente online!

Como 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
fonte
7

Retina , 28 bytes

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

Experimente online!

Recebe entrada em unário .

Explicação

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

Isso gera todas as strings compostas RPSde comprimento n. A maneira como fazemos isso é que substituímos repetidamente o primeiro 1de cada linha. Vamos pensar sobre a linha como <1>, onde <é tudo na frente do jogo e >é tudo após o jogo (eles são $`e $', respectivamente, em regex substituição de sintaxe, mas aqueles olhar menos intuitivo). Substituímos 1por R>¶<P>¶<S, onde estão os feeds de linha. Assim, o resultado completo desta substituição é, na verdade <R>¶<P>¶<S>, que é três cópias da linha, com a 1substituição com R, P, S, respectivamente, em cada uma das três cópias. Esse processo para quando todos os 1s são substituídos.

A`(.+)\1

Finalmente, simplesmente descartamos todas as linhas que contêm uma repetição.

Martin Ender
fonte
Eu teria substituído repetidamente 1(.*)por, $1R¶$1P¶$1Smas a contagem de bytes é a mesma.
Neil
6

Casca , 15 14 bytes

-1 byte graças ao Zgarb!

fȯεfoE½QΠR"RPS

Experimente online!

Constrói todas as sequências possíveis do comprimento correto e mantém apenas aquelas cujas subseqüências (exceto a vazia) são compostas por duas metades diferentes.

Porra, eu realmente queria vencer Jelly aqui.

Leo
fonte
3
14 bytes para amarrar com Jelly.
Zgarb 31/10/19
5

Mathematica, 61 bytes

""<>#&/@{"R","P","S"}~Tuples~#~DeleteCases~{___,x__,x__,___}&

Experimente online!

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

Embora o Java seja quase sempre detalhado, nesse caso, definitivamente não é a linguagem certa para um desafio como esse. Gerar permutações com substrings é ruim para o desempenho e ineficiente.

Definitivamente pode ser jogado um pouco mais, no entanto.

-8 bytes graças a @Jakob .

Explicação:

Experimente aqui. (O desempenho é muito ruim para casos de teste acima de 3, mas 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
fonte
1
Como sobre este lambda: n->p("",((1<<3*n)+"").replaceAll(".","PRS"),n). Além disso, por que não refatorar for(;i<1;p(...));para while(i<l)p(...);?
Jakob
@Jakob Obrigado. E eu sempre uso for(;...;)fora do codegolfing-habbit para ser honesto. Na pior das hipóteses, é a mesma contagem de bytes que while(...), na melhor das hipóteses, algo pode ser colocado dentro do loop for para salvar bytes. Portanto, tento simplesmente não usá while-lo no codegolfing, porque ele nunca beneficia a contagem de bytes de qualquer maneira. Ou aumenta, ou permanece o mesmo, então eu pessoalmente não me importo com a melhor legibilidade. ;)
Kevin Cruijssen
1
Sim, eu sempre tento tornar meu código de golfe o mais legível possível em uma determinada contagem de bytes. Provavelmente uma busca fútil!
Jakob
Espere, meu lambda realmente funciona aqui? Fui um pouco descuidado ... Ele gera uma sequência de n PRS seqüências, enquanto o loop original gera uma com 2 ^ ( n -2).
Jakob
@Jakob ntimes "PRS" está correto. O meu estava gerando mais porque economizava bytes (e diminuía o desempenho, mas quem se importa com isso com o 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))}

Retorna um conjunto de strings.

Experimente online!

Dennis
fonte
4

Julia 0.6 , 65 bytes

!n=n>0?["$c"s for s=!~-n,c="RPS"if~ismatch(r"(.+)\1","$c"s)]:[""]

Experimente online!

Dennis
fonte
4

Perl 5 , 37 bytes

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

Experimente online!

A função retorna uma matriz de cadeias livres quadradas.

Explicado:

O globgera todas as combinações de R, S e P com comprimento igual à entrada. A grepinstrução filtra os que não são livres de quadrados.

Xcali
fonte
Grande uso da expansão da cinta!
Dom Hastings
3

R , 97 bytes

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

Experimente online!

combn(rep(c('p','r','s'),n),n,paste,collapse='')computa todas as ncordas -character com p, r, s, mas infelizmente duplica muitos (*), de modo que uniquify-la e leve aqueles que correspondem a regex (.+)\1, usando a correspondência de estilo perl, então imprimir a lista resultante.

(*) tecnicamente, gera todas as combinações de 3nletras p,r,srepetidas três vezes npor vez, depois se aplica paste(..., collapse='')a cada combinação, em vez de calcular 3^ndiretamente as cordas, mas isso é mais golfista que um expand.grid(o verdadeiro produto cartesiano).

Giuseppe
fonte
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 as substrings de palavras sem quadrados também são sem quadrados, a verificação pode ser feita recursivamente.

Neil
fonte
2

Haskell , 101 98 bytes

f n=[x:r|x:r<-mapM(\_->"RPS")[1..n],[x]#r]
h#t@(x:r)=h/=take(length h)t&&(h++[x])#r&&[x]#r
h#t=1<3

Experimente online!

Laikoni
fonte
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))

Converte todos os números inteiros de 0 a 3ⁿ para (base invertida) 3 usando RPScomo dígitos e os filtra para palavras sem quadrados.

Neil
fonte
2

Julia, 88

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

Nada chique.

mschauer
fonte
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"))

Tem que haver uma maneira melhor de fazer isso :)

Jason Handby
fonte
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
fonte
Boa resposta em F #!
aloisdg diz Reinstate Monica
1
Não é o mais compacto de línguas, mas hey, qualquer desculpa para usá-lo :)
Jason Handby
1
Eu sinto você . Essa linguagem é tão legal.
aloisdg diz Reinstate Monica
1

k, 56 bytes

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

A falta de regex nativo coloca k bem atrás da curva pela primeira vez. Fui com uma solução recursiva, já que os caracteres para implementá-la foram salvos por uma verificação mais simples, sem quadrados.

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

é o operador ternário de k, aqui fazemos coisas interessantes com comprimento diferente de zero e retornamos uma única string vazia, se solicitadas palavras com comprimento zero.

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

pega o produto cartesiano de "RPS" e todas as palavras n-1 de comprimento. , /: \: une cada elemento da direita para a esquerda, fornecendo uma matriz de comprimento 3 de matriz de comprimento n. , / nivela isso em uma matriz de comprimento 3n.

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

pega as primeiras n letras de cada string e a compara com o segundo n, depois reduz a matriz para apenas onde elas não coincidem. Como sabemos que o resultado anterior é livre de quadrados, apenas as subseqüências que começam no primeiro caractere precisam ser correspondidas - simplificando a verificação aqui valia os caracteres gastos implementando a recursão. Finalmente,

/1_!x

aplica o lambda ao resultado inicial definido à sua esquerda, repetindo o comprimento de cada substring de 1 a (comprimento da palavra) -1. ! x gera uma lista de 0 a x-1 e, em seguida, 1_ remove o primeiro elemento (uma vez que as substrings de comprimento 0 sempre correspondem)

Sacrificando alguns caracteres, podemos usar .zs para se auto-referenciar em vez de confiar no nome da função e, em vez de verificar substrings com o comprimento n-1, verifique apenas o piso (n / 2) quanto ao desempenho. Ele encontra todo o comprimento de 49 palavras (das quais existem 5207706) em cerca de 120 segundos em um 7700k, acima do que eu me deparo com o limite de 4 GB de k de 32 bits livre.

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

Python 2 , 99 bytes

import re
f=lambda n:n and[c+s for c in'RPS'for s in f(n-1)if not re.search(r'(.+)(\1)',c+s)]or['']

Experimente online!

Chas Brown
fonte