Jangan ulangi diri Anda dengan Rock-Paper-Gunting


26

Setelah desas-desus bahwa Codegolf akan mengadakan turnamen Rock-Paper-Gunting Anda melihat ke dalam topik kata-kata bebas persegi . Sebuah kata yang terbuat dari huruf R, P, Sadalah persegi bebas jika tidak mengandung urutan yang mengulangi dua kali. Artinya, kata itu tidak bisa ditulis sebagai

a x x b

di mana adan badalah kata-kata dari setiap panjang dan xadalah kata panjang setidaknya satu, semua terbuat dari huruf R, P, S.

Tugas

Menulis sebuah program yang menghasilkan persegi bebas kata-kata dari huruf-huruf R, P, Spanjang ndi mana jumlah 1 <= n <= 10diambil sebagai masukan.

Contoh

Misalnya kata - kata bebas persegi panjang 3 adalah

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

dan yang panjangnya 4 adalah

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

dan perhatikan bahwa misalnya SPSPatau PRPRtidak bebas persegi

Aturan

  • Ini codegolf, kemenangan program terpendek, celah standar ditutup.
  • Anda dapat mencetak kata-kata atau membuatnya dalam memori.
  • Program Anda dapat ditulis sebagai fungsi.

Referensi

Entri Wikipedia pada kata-kata bebas persegi

Jumlah kata terner bebas persegi dengan panjang tertentu ada di https://oeis.org/A006156

Terkait: Kata-kata Ternary Squarefree Sewenang-Wenang-Panjang


4
Sebuah test case n>3akan menjadi ide yang baik, karena telah ada beberapa kebingungan tentang karakter yang berulang vs urutan yang berulang.
Laikoni

Silakan mengomentari rencana tindak lanjut yang direncanakan di kotak pasir: codegolf.meta.stackexchange.com/a/14133/45211
mschauer

6
Saya rasa tag "bahasa alami" tidak berlaku di sini
Leo

1
Ah, "kata-kata" diperluas dalam "bahasa alami", saya menghapusnya.
mschauer

1
Tidak, ini berisi kotak SP SP
mschauer

Jawaban:


20

Ruby, 39 byte

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

Fungsi lucu yang tidak efisien ini menghasilkan semua string dengan panjang N yang terletak secara alfabetis antara N Ps dan N Ss, kemudian menyaring sebagian besar yang berisi karakter non-RPS. Cek squarefree yang sebenarnya hanya menggunakan backreference Regexp: (.+)\1.

Lebih banyak 65 byte idiomatis yang selesai dalam jumlah waktu yang wajar untuk N = 10:

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

Sunting: Menyimpan satu byte berkat G B.


Anda tidak perlu tanda kurung di grep_v, cukup spasi antara itu dan slash (simpan 1 byte)
GB

6
" sangat tidak efisien " mungkin menjelaskan beberapa jawaban di situs ini.
Dana Gugatan Monica

10

Jelly , 15 14 byte

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

Cobalah online!

Bagaimana itu bekerja

“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

Cobalah online!

Mengambil input di unary .

Penjelasan

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

Ini menghasilkan semua string yang terdiri RPSdari panjang n. Cara kami melakukan ini adalah bahwa kami berulang kali mengganti yang pertama 1di setiap baris. Mari kita berpikir tentang garis sebagai <1>, di mana <segala sesuatu di depan pertandingan dan >segalanya setelah pertandingan (mereka $`dan $'masing - masing dalam sintaks substitusi regex, tetapi yang terlihat kurang intuitif). Kami mengganti 1dengan R>¶<P>¶<S, di mana umpan baris. Jadi hasil substitusi penuh ini sebenarnya <R>¶<P>¶<S>, yang merupakan tiga salinan garis, dengan 1mengganti dengan R, P, S, masing-masing, di masing-masing tiga eksemplar. Proses ini berhenti setelah semua 1diganti.

A`(.+)\1

Akhirnya, kami hanya membuang semua baris yang berisi pengulangan.


Saya akan berulang kali diganti 1(.*)dengan $1R¶$1P¶$1Stetapi byte-countnya sama.
Neil

6

Sekam , 15 14 byte

-1 byte terima kasih kepada Zgarb!

fȯεfoE½QΠR"RPS

Cobalah online!

Buat semua urutan yang mungkin dari panjang yang benar dan simpan hanya yang memiliki semua substring (kecuali yang kosong) yang disusun oleh dua bagian yang berbeda.

Sial, aku benar-benar ingin mengalahkan Jelly di sini.


3
14 byte untuk diikat dengan 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));}

Meskipun Java hampir selalu bertele-tele, dalam hal ini jelas bukan bahasa yang tepat untuk tantangan seperti ini. Menghasilkan permutasi dengan substring buruk untuk kinerja dan tidak efisien.

Pasti bisa bermain golf lagi.

-8 byte berkat @Jakob .

Penjelasan:

Coba di sini. (Kinerja terlalu buruk untuk kasus uji di atas 3, tetapi itu berfungsi secara 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

1
Bagaimana lambda ini: n->p("",((1<<3*n)+"").replaceAll(".","PRS"),n). Juga, mengapa tidak refactor for(;i<1;p(...));ke while(i<l)p(...);?
Jakob

@ Jakob Terima kasih. Dan saya selalu menggunakan for(;...;)codegolf-habbit untuk jujur. Kasing terburuk adalah byte-count yang sama dengan while(...), kasing terbaik dapat ditempatkan di dalam for-loop untuk menghemat byte. Jadi saya mencoba untuk tidak menggunakan whilesama sekali dalam codegolfing, karena tidak pernah menguntungkan byte-count. Entah itu meningkatkannya, atau tetap sama, jadi saya pribadi tidak peduli dengan keterbacaan yang lebih baik. ;)
Kevin Cruijssen

1
Ya, saya selalu mencoba membuat kode golf saya dapat dibaca dengan jumlah byte yang ditentukan. Mungkin pengejaran sia-sia!
Jakob

Tunggu, apakah lambda saya benar-benar berfungsi di sini? Saya agak ceroboh ... Ini menghasilkan serangkaian n PRS urutan, sedangkan loop asli Anda menghasilkan satu dengan 2 ^ ( n -2) urutan.
Jakob

@Jakob nkali "PRS" benar. Milik saya menghasilkan lebih banyak karena menghemat byte (dan menurunkan kinerja, tetapi siapa yang peduli dengan 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))}

Mengembalikan serangkaian string.

Cobalah online!



4

Perl 5 , 37 byte

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

Cobalah online!

Function mengembalikan array dari string bebas persegi.

Dijelaskan:

The globmenghasilkan semua kombinasi dari R, S, & P dengan panjang sama untuk input. The greppernyataan filter keluar orang-orang yang tidak persegi gratis.


Penggunaan ekspansi brace yang bagus!
Dom Hastings

3

R , 97 byte

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

Cobalah online!

combn(rep(c('p','r','s'),n),n,paste,collapse='')menghitung semua nstring sepanjang karakter dengan p, r,s , tapi sayangnya duplikat banyak (*), jadi kami uniquify itu, dan mengambil orang-orang yang sesuai regex (.+)\1, menggunakan pencocokan perl-gaya, maka kita mencetak daftar yang dihasilkan.

(*) Secara teknis, ini menghasilkan semua kombinasi 3nhuruf secara p,r,sberulang 3 kali diambil npada satu waktu, kemudian berlaku paste(..., collapse='')untuk setiap kombinasi daripada menghitung 3^nstring secara langsung, tetapi ini lebih golf daripada expand.grid(produk Cartesian yang sebenarnya).


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

Karena semua substring dari kata-kata bebas persegi juga bebas persegi, pemeriksaan dapat dilakukan secara rekursif.



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

Mengonversi semua bilangan bulat dari 0 ke 3ⁿ menjadi (dibalik berlapis) basis 3 menggunakan RPSsebagai digit dan memfilternya untuk kata-kata bebas persegi.


2

Julia, 88

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

Tidak ada yang mewah.


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

Harus ada cara yang lebih baik untuk melakukan ini :)



1

k, 56 byte

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

Kurangnya regex asli menempatkan k jauh di belakang kurva untuk sekali. Saya pergi dengan solusi rekursif, karena karakter untuk mengimplementasikannya disimpan oleh cek squarefree sederhana.

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

adalah operator ternary k, di sini kami melakukan hal-hal menarik tanpa panjang nol, dan mengembalikan string kosong tunggal jika diminta kata-kata panjang nol.

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

mengambil produk cartesian "RPS" dan semua kata bebas persegi n-1. , /: \: bergabung dengan setiap elemen dari kanan ke kiri, memberikan panjang array 3 panjang n array. , / ratakan ini menjadi array 3n panjang.

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

mengambil n huruf pertama dari setiap string dan membandingkannya dengan n kedua, kemudian mengurangi array hanya di mana mereka tidak cocok. Karena kita tahu hasil sebelumnya bebas persegi, hanya substring yang dimulai dari karakter pertama yang perlu dicocokkan - menyederhanakan pemeriksaan di sini sepadan dengan karakter yang dihabiskan untuk mengimplementasikan rekursi. Akhirnya,

/1_!x

menerapkan lambda ke hasil awal yang ditetapkan di sebelah kirinya, iterasi setiap panjang substring dari 1 ke (panjang kata) -1. ! x membuat daftar dari 0 hingga x-1, lalu 1_ menghapus elemen pertama (karena substring panjang 0 akan selalu cocok)

Mengorbankan beberapa karakter dapat kita gunakan .zs untuk referensi-sendiri daripada bergantung pada nama fungsi, dan alih-alih memeriksa substring hingga panjang n-1 hanya lantai periksa (n / 2) untuk kinerja. Ia menemukan semua panjang 49 kata (yang ada 5207706) dalam sekitar 120 detik pada 7700k, di atas itu saya mengalami batas 4GB gratis 32-bit k.

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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.