Не повторіть себе в ножицях-паперах


26

По чутках, що у Кодегольфа відбудеться турнір "Рок-папір-ножиці", ви заглянете в тему слів без квадратних слів . Слово з букв R, P, Sє бесквадратним , якщо вона не містить послідовність , яка повторюється двічі. Тобто слово не можна писати як

a x x b

де aі bслово будь-якої довжини і xслово довжини принаймні один, все з букв R, P, S.

Завдання

Написати програму , яка генерує бесквадратние слова з букв R, P, Sдовжини , nде число 1 <= n <= 10береться в якості вхідних даних.

Приклад

Наприклад, слова без квадрата довжиною 3 є

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

і довжини 4 є

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

і зверніть увагу , що, наприклад , SPSPабо PRPRНЕ бесквадратние

Правила

  • Це кодовий гольф, найкоротші виграші програми, стандартні лазівки закриті.
  • Ви можете надрукувати слова або створити їх у пам'яті.
  • Ваша програма може бути записана як функція.

Список літератури

Запис у Вікіпедії на квадратних словах

Кількість безквадратичних потрійних слів заданої довжини наведено на https://oeis.org/A006156

Пов’язані: Слова довільної довжини «Потрійні квадратні вільні слова»


4
Тестовий випадок n>3було б хорошою ідеєю, оскільки була певна плутанина щодо повторних символів проти повторних послідовностей.
Лайконі

Будь ласка, прокоментуйте заплановані подальші дії у пісочній
mschauer

6
Я не думаю, що тут слід застосувати тег "природні мови"
Лев,

1
Ах, "слова" розширилися в "природній мові", я її видалив.
mschauer

1
Ні, він містить квадрат SP SP
mschauer

Відповіді:


20

Рубін, 39 байт

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

Ця весело неефективна функція генерує всі рядки довжиною N, які лежать в алфавітному порядку між N Ps і N Ss, а потім фільтрує переважну більшість, що містить символи, що не належать до RPS. Фактична перевірка бесквадратной просто використовує зворотне посилання РегВира: (.+)\1.

Більш ідіоматичні 65 байт, які закінчуються за розумну кількість часу за N = 10:

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

Редагувати: Збережено байт завдяки G B.


Не потрібні дужки в grep_v, просто пробіл між ним і косою рисою (зберегти 1 байт)
GB

6
" Весело неефективний ", ймовірно, описує досить багато відповідей на цьому сайті.
Фонд позову Моніки

10

Желе , 15 14 байт

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

Спробуйте в Інтернеті!

Як це працює

“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

Сітківка , 28 байт

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

Спробуйте в Інтернеті!

Здійснює введення в одинаковому режимі .

Пояснення

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

Це створює всі рядки, що складаються RPSз довжини n. Як ми це робимо, це те, що ми неодноразово замінюємо перший 1у кожному рядку. Давайте подумаємо про рядок як <1>, де <все перед матчем і >чи все після матчу (вони $`і $'відповідно у синтаксисі заміщення регулярних виразів, але вони виглядають менш інтуїтивно). Замінимо 1з R>¶<P>¶<S, де знаходяться символи перекладу рядка. Таким чином, повний результат цієї заміни насправді <R>¶<P>¶<S>, що три копії цієї лінії, з 1замінити R, P, Sвідповідно, в кожному з трьох примірників. Цей процес припиняється, коли всі 1s заміняться.

A`(.+)\1

Нарешті, ми просто відкидаємо всі рядки, які містять повторення.


Я неодноразово замінений 1(.*)з , $1R¶$1P¶$1Sале байт-лічильник те ж саме.
Ніл

6

Лушпиння , 15 14 байт

-1 байт дякую Згарбу!

fȯεfoE½QΠR"RPS

Спробуйте в Інтернеті!

Побудує всі можливі послідовності правильної довжини і зберігає лише ті, всі підряди (крім порожнього) складаються з двох різних половинок.

Чорт, я дуже хотів бити тут Желі.


3
14 байт зв’язати з желе.
Згарб


5

Java 8, 285 277 байт

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

Хоча Java майже завжди є багатослівним, у цьому випадку це точно не є правильною мовою для подібного виклику. Генерація перестановок з підрядками погана для продуктивності та неефективна.

Але, безумовно, можна пограти ще трохи.

-8 байт завдяки @Jakob .

Пояснення:

Спробуйте тут. (Продуктивність занадто погана для тестових випадків вище 3, але вона працює локально.)

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
Як про це лямбда: n->p("",((1<<3*n)+"").replaceAll(".","PRS"),n). Крім того , чому б не реорганізувати , for(;i<1;p(...));щоб while(i<l)p(...);?
Якоб

@Jakob Дякую І я завжди використовую for(;...;)кодекси гольфінгу, щоб бути чесним. Найгірший випадок - це той самий підрахунок байтів, що і в while(...)кращому випадку щось можна розмістити всередині циклу for-циклу для збереження байтів. Тому я намагаюся просто не використовувати whileвзагалі кодовий гольф, тому що це ніколи не приносить користі байтовому рахунку. Це або збільшує його, або залишається колишнім, тому я особисто не переймаюся кращою читабельністю. ;)
Кевін Круїссен

1
Так, я завжди намагаюся зробити свій код для гольфу максимально читаним при заданому підрахунку байтів. Напевно, марне слідування!
Якоб

Зачекайте, чи справді тут працює моя лямбда? Я був трохи недбалий ... Він генерує рядок з n PRS послідовностей, тоді як ваш оригінальний цикл генерував один із 2 ^ ( n -2) послідовностей.
Якоб

@Jakob ntimes "PRS" є правильним. Шахта генерувала більше, тому що вона економила байти (і знижувала продуктивність, але хто про це піклується з codegolf). ;)
Кевін Кройсейсен



4

Perl 5 , 37 байт

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

Спробуйте в Інтернеті!

Функція повертає масив квадратних вільних рядків.

Пояснили:

globГенерує всі комбінації R, S, P & з довжиною , рівній до входу. У grepзаяві відфільтровує ті, які не квадратні безкоштовно.


Велике використання розширення брекетів!
Дом Гастінгс

3

R , 97 байт

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

Спробуйте в Інтернеті!

combn(rep(c('p','r','s'),n),n,paste,collapse='')обчислює всі n-character струнах p, r, s, але , до жаль , дублює багато (*), тому ми uniquify, і прийняти ті , які відповідають регулярному виразу (.+)\1, з допомогою зіставлення Perl-стиль, то ми виводимо з отриманого списку.

(*) технічно він генерує всі комбінації 3nбукв у p,r,sповторенні 3 рази, взяті nодночасно, потім застосовується paste(..., collapse='')до кожної комбінації, а не обчислюючи 3^nрядки безпосередньо, але це гольф, ніж expand.grid(справжній декартовий продукт).


3

JavaScript (Firefox 30-57), 69 байт

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

Оскільки всі підрядки слів без квадратних слів також є квадратними, перевірку можна зробити рекурсивно.



2

JavaScript (ES6), 93 байти

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

Перетворює всі цілі числа від 0 до 3ⁿ до базової 3 (з оберненою підкладкою), використовуючи RPSяк цифри, і фільтрує їх для квадратних слів.


2

Юлія, 88

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

Нічого фантазійного.


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

Має бути кращий спосіб зробити це :)


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


1
Це не най компактніші мови, але ей, будь-який привід використовувати його :)
Jason Handby


1

k, 56 байт

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

Відсутність власного регулярного вираження на один раз замикає криву. Я пішов з рекурсивним рішенням, оскільки символи для його реалізації були врятовані простішою квадратною вільністю перевірки.

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

- потрійний оператор k, тут ми робимо цікаві речі для ненульової довжини, і повертаємо один порожній рядок, якщо його запитують слова нульової довжини.

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

бере декартовий твір "RPS" і всі n-1 довжини без квадратних слів. , /: \: приєднується до кожного елемента праворуч зліва, надаючи довжину 3 масиву довжиною n масивів. , / згладжує це в масив довжиною 3n.

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

бере перші п літер кожного рядка і порівнює його з другим n, а потім зменшує масив лише там, де вони не збігаються. Оскільки ми знаємо, що попередній результат є без квадратних значень, потрібні лише відповідні підряди, що починаються з першого символу - спрощення перевірки тут коштувало символів, проведених на рекурсію. Нарешті,

/1_!x

застосовує лямбда до початкового результату, встановленого зліва, повторюючи по кожній довжині підрядка від 1 до (довжина слова) -1. ! x створює список від 0 до x-1, тоді 1_ видаляє перший елемент (оскільки підрядки 0 довжини завжди будуть відповідати)

Приносячи в жертву кілька символів, ми можемо використовувати .zs для самостійного посилання, а не покладатися на ім’я функції, а замість того, щоб перевіряти підрядки до довжини n-1, лише перевіряти рівень (n / 2) на продуктивність. Він знаходить всю довжину 49 слів (з них 5207706) приблизно за 120 секунд на 7700k, що вище, ніж я стикаюся з обмеженням 4 Гб вільного 32-бітного k.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.