Wiederholen Sie sich nicht mit einer Stein-Papier-Schere

26

Bei dem Gerücht, dass Codegolf ein Rock-Paper-Scissors-Turnier veranstalten wird, beschäftigen Sie sich mit dem Thema der quadratfreien Wörter . Ein Wort der Buchstaben gemacht R, P, Sist Platz frei , wenn es eine Sequenz, die wiederholt nicht zweimal enthalten. Das heißt, das Wort kann nicht als geschrieben werden

a x x b

wo aund bsind Wörter beliebiger Länge und xist ein Wort mit einer Länge von mindestens einem, alle Buchstaben gemacht R, P, S.

Aufgabe

Ein Programm schreiben, das die erzeugt quadratfreie Wörter aus den Buchstaben R, P, Sder Länge , nwo die Zahl 1 <= n <= 10wird als Eingabe genommen.

Beispiel

Zum Beispiel sind die quadratfreien Wörter der Länge 3

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

und die der Länge 4 sind

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

und beachten Sie, dass zum Beispiel SPSPoder PRPRnicht quadratfrei sind

Regeln

  • Dies ist Codegolf, kürzeste Programmgewinne, Standardlücken sind geschlossen.
  • Sie können die Wörter drucken oder im Speicher erstellen.
  • Ihr Programm kann als eine Funktion geschrieben werden.

Verweise

Wikipedia-Eintrag zu quadratfreien Wörtern

Die Anzahl der quadratfreien ternären Wörter der angegebenen Länge ist in https://oeis.org/A006156 angegeben

Verwandt: Ternäre Rechteckwörter beliebiger Länge

mschauer
quelle
4
Ein Testfall für n>3wäre eine gute Idee, da es einige Verwirrungen über wiederholte Zeichen gegenüber wiederholten Sequenzen gab.
Laikoni
Bitte kommentieren Sie das geplante Follow-up in der Sandbox
mschauer 30.10.17
6
Ich denke nicht, dass das "natürlichsprachige" Tag hier zutreffen sollte
Leo
1
Ah, "Wörter" wurden in "natürlicher Sprache" erweitert, ich habe es entfernt.
mschauer
1
Nein, es enthält das Quadrat SP SP
mschauer

Antworten:

20

Ruby, 39 Bytes

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

Diese unglaublich ineffiziente Funktion generiert alle Zeichenfolgen der Länge N, die alphabetisch zwischen N Ps und N Ss liegen, und filtert dann die überwiegende Mehrheit heraus, die Nicht-RPS-Zeichen enthält. Die tatsächliche quadratPrüfung verwendet nur eine Regexp Rückreferenzierung: (.+)\1.

Weitere idiomatische 65 Bytes , die in angemessener Zeit für N = 10 enden:

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

Edit: Speichert ein Byte dank G B.

Histokrat
quelle
Sie brauchen keine Klammern für grep_v, nur ein Leerzeichen zwischen dem Schrägstrich (1 Byte speichern)
GB
6
" unglaublich ineffizient " beschreibt wahrscheinlich einige Antworten auf dieser Website.
Fund Monica's Lawsuit
10

Jelly , 15 bis 14 Bytes

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

Probieren Sie es online!

Wie es funktioniert

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

Retina , 28 Bytes

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

Probieren Sie es online!

Nimmt unäre Eingaben auf .

Erläuterung

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

Dies erzeugt alle Zeichenfolgen, die aus RPSder Länge bestehen n. Auf diese Weise ersetzen wir 1in jeder Zeile wiederholt die erste . Denken sie über die Linie wie <1>, wo <alles vor dem Spiel ist und >alles ist nach dem Spiel (sie sind $`und $'jeweils in regex Substitution Syntax, aber die Optik weniger intuitiv). Wir ersetzen die 1mit R>¶<P>¶<S, wo Zeilenvorschübe sind. So ist das vollständige Ergebnis dieser Substitution ist eigentlich <R>¶<P>¶<S>, die drei Kopien der Linie sind, mit dem 1ersetzen R, P, Sjeweils in jedem der drei Kopien. Dieser Vorgang stoppt, sobald alle 1s ersetzt wurden.

A`(.+)\1

Schließlich verwerfen wir einfach alle Zeilen, die eine Wiederholung enthalten.

Martin Ender
quelle
Ich würde immer wieder ersetzt 1(.*)mit , $1R¶$1P¶$1Saber die Byte-Anzahl ist das gleiche.
Neil
6

Schale , 15 bis 14 Bytes

-1 Byte danke an Zgarb!

fȯεfoE½QΠR"RPS

Probieren Sie es online!

Erstellt alle möglichen Sequenzen mit der richtigen Länge und behält nur die bei, deren alle Teilzeichenfolgen (außer der leeren) aus zwei verschiedenen Hälften bestehen.

Verdammt, ich wollte Jelly hier unbedingt schlagen.

Löwe
quelle
3
14 Bytes zum Binden mit 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));}

Obwohl Java fast immer ausführlich ist, ist es in diesem Fall definitiv nicht die richtige Sprache für eine solche Herausforderung. Das Generieren von Permutationen mit Teilzeichenfolgen ist für die Leistung schlecht und ineffizient.

Kann aber definitiv noch mehr golfen werden.

-8 Bytes dank @Jakob .

Erläuterung:

Probieren Sie es hier aus. (Die Leistung ist für Testfälle über 3 zu schlecht, funktioniert jedoch lokal.)

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
quelle
1
Wie über dieses lambda: n->p("",((1<<3*n)+"").replaceAll(".","PRS"),n). Auch, warum nicht Refactoring for(;i<1;p(...));zu while(i<l)p(...);?
Jakob
@ Jakob Danke. Und ich benutze immer for(;...;)aus Codegolf-Habbit um ehrlich zu sein. Im schlimmsten Fall ist es die gleiche Anzahl von Bytes wie while(...)im besten Fall kann etwas in die for-Schleife gestellt werden, um Bytes zu sparen. Deshalb versuche ich, überhaupt kein whileCodegolfing zu verwenden, weil es sowieso nie der Byteanzahl zugute kommt. Entweder wird es vergrößert oder es bleibt gleich, sodass ich mich persönlich nicht um die bessere Lesbarkeit kümmere. ;)
Kevin Cruijssen
1
Ja, ich versuche immer, meinen Code so lesbar wie möglich zu machen. Wahrscheinlich eine vergebliche Verfolgung!
Jakob
Warten Sie, arbeitet mein Lambda tatsächlich hier? Ich war ein bisschen nachlässig ... Es wird eine Folge von n PRS Sequenzen generiert , während Ihre ursprüngliche Schleife eine Folge mit 2 ^ ( n -2) Sequenzen generiert hat.
Jakob,
@ Jakob nmal "PRS" ist richtig. Meins hat mehr generiert, weil es Bytes gespart hat (und die Leistung verringert hat, aber wen interessiert das mit 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))}

Gibt eine Reihe von Zeichenfolgen zurück.

Probieren Sie es online!

Dennis
quelle
4

Perl 5 , 37 Bytes

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

Probieren Sie es online!

Die Funktion gibt ein Array der quadratischen freien Zeichenketten zurück.

Erklärt:

Das globerzeugt alle Kombinationen von R, S und P mit der Länge der Eingabe. Die grepAnweisung filtert diejenigen heraus, die nicht quadratfrei sind.

Xcali
quelle
Großartige Verwendung der Klammererweiterung!
Dom Hastings
3

R 97 Bytes

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

Probieren Sie es online!

combn(rep(c('p','r','s'),n),n,paste,collapse='')berechnet alle n-Charakter Saiten mit p, r, s, aber es leider viele (*) dupliziert, so dass wir es, und nehmen diejenigen uniquify, die die Regex (.+)\1, perl-Stil Matching wir die resultierende Liste auszudrucken dann.

(*) Technisch gesehen werden alle 3nBuchstabenkombinationen p,r,sdreimal hintereinander wiederholt nund dann paste(..., collapse='')auf jede Kombination 3^nangewendet, anstatt die Zeichenfolgen direkt zu berechnen. Dies ist jedoch Golfspieler als ein expand.grid(echtes kartesisches Produkt).

Giuseppe
quelle
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]:['']

Da alle Teilstrings von quadratfreien Wörtern auch quadratfrei sind, kann die Prüfung rekursiv durchgeführt werden.

Neil
quelle
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

Probieren Sie es online!

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

Wandelt alle Ganzzahlen von 0 auf 3ⁿ in (umgekehrt gepolsterte) Basis 3 um RPSund filtert sie nach quadratfreien Wörtern.

Neil
quelle
2

Julia, 88

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

Nichts Außergewöhnliches.

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

Es muss einen besseren Weg geben, dies zu tun :)

Jason Handby
quelle
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
quelle
Schön eine F # Antwort!
Aloisdg sagt Reinstate Monica
1
Es ist nicht die kompakteste Sprache, aber hey, jede Ausrede, um es zu benutzen :)
Jason Handby
1
Ich fühle dich . Diese Sprache ist so schön.
aloisdg sagt Reinstate Monica
1

k, 56 Bytes

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

Der Mangel an nativem Regex lässt k ausnahmsweise einmal hinter der Kurve liegen. Ich entschied mich für eine rekursive Lösung, da die zu implementierenden Zeichen durch eine einfachere Überprüfung ohne Rechtecke gespeichert wurden.

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

ist ks ternärer Operator. Hier machen wir interessante Sachen für die Länge ungleich Null und geben eine einzelne leere Zeichenkette zurück, wenn wir nach Wörtern der Länge Null gefragt werden.

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

Nimmt das kartesische Produkt von "RPS" und allen n-1 längenquadratfreien Wörtern. , /: \: verbindet jedes Element von rechts nach links und ergibt ein Array der Länge 3 mit einer Länge von n Arrays. , / reduziert dies auf ein 3n-Array.

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

Nimmt die ersten n Buchstaben jeder Zeichenfolge und vergleicht sie mit den zweiten n. Reduziert dann das Array auf nur diejenigen, bei denen sie nicht übereinstimmen. Da wir wissen, dass das vorherige Ergebnis keine Quadrate enthält, müssen nur die Teilzeichenfolgen ab dem ersten Zeichen abgeglichen werden. Die Vereinfachung der Prüfung hat sich für die Zeichen gelohnt, die für die Implementierung der Rekursion aufgewendet wurden. Endlich,

/1_!x

Wendet das Lambda auf die erste Ergebnismenge auf der linken Seite an und iteriert über jede Teilzeichenfolgenlänge von 1 bis (Wortlänge) -1. ! x generiert eine Liste von 0 bis x-1, dann entfernt 1_ das erste Element (da Teilzeichenfolgen mit der Länge 0 immer übereinstimmen).

Wenn wir ein paar Zeichen opfern, können wir .zs verwenden, um auf sich selbst zu verweisen, anstatt uns auf den Funktionsnamen zu verlassen, und anstatt Teilzeichenfolgen bis zur Länge n-1 zu überprüfen, überprüfen Sie nur Floor (n / 2) auf Leistung. Es findet alle Länge 49 Wörter (von denen es 5207706 gibt) in ungefähr 120 Sekunden auf einem 7700k, darüber laufe ich in die 4 GB-Grenze von freiem 32-Bit-k.

{$[x;(,/"RPS",/:\:.z.s x-1){x@&~~/'(2,y)#/:x}/1+!_x%2;,""]}
ostewart
quelle
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['']

Probieren Sie es online!

Chas Brown
quelle