Non ripetere te stesso in Rock-Paper-Scissors


26

Quando si dice che Codegolf avrà un torneo Rock-Paper-Scissors, si esamina l'argomento delle parole senza quadrati . Una parola fatta di lettere R, P, Sè quadrata gratuita se non contiene una sequenza che si ripete due volte. Vale a dire, la parola non può essere scritta come

a x x b

dove ae bsono parole di qualsiasi lunghezza ed xè una parola di lunghezza almeno uno, tutti realizzati in lettere R, P, S.

Compito

Scrivere un programma che genera i liberi quadrati parole delle lettere R, P, Sdella lunghezza nin cui il numero 1 <= n <= 10è presa come input.

Esempio

Ad esempio, le parole senza quadrati della lunghezza 3 sono

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

e quelli di lunghezza 4 sono

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

e nota che per esempio SPSPo PRPRnon sono quadrati liberi

Regole

  • Questo è codegolf, il programma più corto vince, le scappatoie standard sono chiuse.
  • È possibile stampare le parole o crearle in memoria.
  • Il tuo programma può essere scritto come una funzione.

Riferimenti

Voce di Wikipedia su parole senza quadrati

Il numero di parole ternarie senza quadrato di una determinata lunghezza sono in https://oeis.org/A006156

Correlati: Parole quadrate ternarie di lunghezza arbitraria


4
Un caso di prova n>3sarebbe una buona idea, perché c'è stata una certa confusione su personaggi ripetuti rispetto a sequenze ripetute.
Laikoni,

Si prega di commentare il seguito previsto nella sand-box: codegolf.meta.stackexchange.com/a/14133/45211
mschauer

6
Non credo che il tag "linguaggio naturale" dovrebbe applicarsi qui
Leo

1
Ah, "parole" si sono espanse in "linguaggio naturale", l'ho rimosso.
mschauer,

1
No, contiene il quadrato SP SP
mschauer

Risposte:


20

Rubino, 39 byte

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

Questa funzione esilarante inefficiente genera tutte le stringhe di lunghezza N che si trovano alfabeticamente tra N Ps e N Ss, quindi filtra la stragrande maggioranza che contiene caratteri non RPS. Il controllo di quadrati attuale utilizza solo un backreference Regexp: (.+)\1.

65 byte più idiomatici che terminano in un tempo ragionevole per N = 10:

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

Modifica: salvato un byte grazie a G B.


Non hai bisogno di parentesi su grep_v, solo uno spazio tra esso e la barra (salva 1 byte)
GB

6
" esilarantemente inefficiente " probabilmente descrive alcune risposte su questo sito.
Finanzia la causa di Monica il

10

Gelatina , 15 14 byte

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

Provalo online!

Come funziona

“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.

7

Retina , 28 byte

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

Provalo online!

Riceve input in unario .

Spiegazione

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

Questo genera tutte le stringhe composte da RPSlunghezza n. Il modo in cui lo facciamo è che sostituiamo ripetutamente il primo 1in ogni riga. Pensiamo alla linea come <1>, dove <è tutto davanti alla partita ed >è tutto dopo la partita (sono $`e $'rispettivamente nella sintassi di sostituzione regex, ma quelli sembrano meno intuitivi). Sostituiamo 1con R>¶<P>¶<S, dove sono gli avanzamenti di riga. Così il risultato pieno di questa sostituzione è in realtà <R>¶<P>¶<S>, che è tre copie della linea, con la 1sostituzione con R, P, S, rispettivamente, in ciascuna delle tre copie. Questo processo si interrompe dopo 1aver sostituito tutti i messaggi.

A`(.+)\1

Infine, scartiamo semplicemente tutte le righe che contengono una ripetizione.


Avrei ripetutamente sostituito 1(.*)con $1R¶$1P¶$1Sma il conteggio dei byte è lo stesso.
Neil,

6

Buccia , 15 14 byte

-1 byte grazie a Zgarb!

fȯεfoE½QΠR"RPS

Provalo online!

Costruisce tutte le possibili sequenze della lunghezza corretta e mantiene solo quelle le cui sottostringhe (tranne quella vuota) sono composte da due metà differenti.

Accidenti, volevo davvero battere Jelly qui.


3
14 byte da legare con Jelly.
Zgarb,


5

Java 8, 285 277 byte

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

Sebbene Java sia quasi sempre prolisso, in questo caso non è sicuramente la lingua giusta per una sfida come questa. La generazione di permutazioni con sottostringhe è dannosa per le prestazioni e inefficiente.

Si può sicuramente giocare ancora un po 'a golf.

-8 byte grazie a @Jakob .

Spiegazione:

Provalo qui. (Le prestazioni sono troppo basse per i casi di test superiori a 3, ma funzionano 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

1
Che ne dite di questo lambda: n->p("",((1<<3*n)+"").replaceAll(".","PRS"),n). Inoltre, perché non refactoring for(;i<1;p(...));a while(i<l)p(...);?
Jakob,

@Jakob Grazie. E io uso sempre for(;...;)di codegolfing-habbit per essere onesti. Nel peggiore dei casi è lo stesso conteggio dei byte while(...), nel migliore dei casi qualcosa può essere inserito nel for-loop per salvare i byte. Quindi provo a non usare whileaffatto nel codegolfing, perché comunque non avvantaggia mai il conteggio dei byte. O lo aumenta, o rimane lo stesso, quindi personalmente non mi preoccupo della migliore leggibilità. ;)
Kevin Cruijssen,

1
Sì, cerco sempre di rendere il mio codice golf il più leggibile possibile a un dato conteggio di byte. Probabilmente un inseguimento inutile!
Jakob,

Aspetta, la mia lambda funziona davvero qui? Ero un po 'distratto ... Genera una serie di n PRS sequenze, mentre il tuo loop originale ne ha generato una con 2 ^ ( n -2) sequenze.
Jakob,

@Jakob nvolte "PRS" è corretto. Il mio stava generando di più perché risparmiava byte (e riduceva le prestazioni, ma a chi importa di quello con codegolf). ;)
Kevin Cruijssen,

4

Python 3 , 97 96 byte

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

Restituisce un set di stringhe.

Provalo online!



4

Perl 5 , 37 byte

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

Provalo online!

La funzione restituisce un array di stringhe quadrate libere.

Ha spiegato:

Il globgenera tutte le combinazioni di R, S, P e con lunghezza uguale all'ingresso. L' grepistruzione filtra quelli che non sono quadrati liberi.


Grande uso dell'espansione del tutore!
Dom Hastings,

3

R , 97 byte

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

Provalo online!

combn(rep(c('p','r','s'),n),n,paste,collapse='')calcola tutte nle stringhe -CHARACTER con p, r, s, ma duplica purtroppo molti (*), quindi abbiamo uniquify, e prendiamo quelli che corrispondono alla regex (.+)\1, utilizzando corrispondenza perl-stile, poi abbiamo stampare la lista risultante.

(*) tecnicamente, genera tutte le combinazioni di 3nlettere p,r,sripetute 3 volte nalla volta, quindi si applica paste(..., collapse='')a ciascuna combinazione anziché calcolare 3^ndirettamente le stringhe, ma questo è più golfoso di un expand.grid(il vero prodotto cartesiano).


3

JavaScript (Firefox 30-57), 69 byte

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

Poiché tutte le sottostringhe di parole senza quadrati sono anche senza quadrati, il controllo può essere eseguito in modo ricorsivo.



2

JavaScript (ES6), 93 byte

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 tutti i numeri interi da 0 a 3ⁿ in (inversione inversa) in base 3 usando RPScome cifre e li filtra per parole senza quadrati.


2

Julia, 88

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

Nulla di bello.


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

Ci deve essere un modo migliore per farlo :)



1

k, 56 byte

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

La mancanza di regex nativo mette k dietro la curva per una volta. Ho optato per una soluzione ricorsiva, poiché i personaggi per implementarla sono stati salvati da un controllo squarefree più semplice.

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

è l'operatore ternario di k, qui facciamo cose interessanti per una lunghezza diversa da zero e restituiamo una singola stringa vuota se vengono richieste parole di lunghezza zero.

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

prende il prodotto cartesiano di "RPS" e tutte le parole quadrate n-1 di lunghezza libera. , /: \: unisce ogni elemento di destra a sinistra, dando una lunghezza di 3 array di lunghezza n array. , / appiattisce questo in un array di lunghezza 3n.

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

prende le prime n lettere di ogni stringa e la confronta con la seconda n, quindi riduce l'array solo dove non corrispondono. Poiché sappiamo che il risultato precedente è senza quadrati, solo le sottostringhe che iniziano con il primo carattere devono essere abbinate: semplificare il controllo qui valeva la pena spendere i personaggi per implementare la ricorsione. Finalmente,

/1_!x

applica la lambda al set di risultati iniziale alla sua sinistra, ripetendo ogni lunghezza della sottostringa da 1 a (lunghezza della parola) -1. ! x genera un elenco da 0 a x-1, quindi 1_ rimuove il primo elemento (poiché le sottostringhe di lunghezza 0 corrisponderanno sempre)

Sacrificando alcuni caratteri possiamo usare .zs per autoreferenziare piuttosto che fare affidamento sul nome della funzione, e invece di controllare sottostringhe fino alla lunghezza n-1 controlla solo il pavimento (n / 2) per le prestazioni. Trova tutte le 49 parole (di cui ce ne sono 5207706) in circa 120 secondi su un 7700k, al di sopra del quale ho incontrato il limite di 4 GB di k libero a 32 bit.

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

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.