Не повторяйте себя в Rock-Paper-Scissors


26

После слухов, что у Codegolf будет турнир Rock-Paper-Scissors, вы заглядываете в тему слов без квадратов . Слово из букв 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не квадратные

правила

  • Это Codegolf, самая короткая программа выигрывает, стандартные лазейки закрыты.
  • Вы можете напечатать слова или создать их в памяти.
  • Ваша программа может быть написана как функция.

Ссылки

Википедия на слова без квадратов

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

Связанный: Произвольные Длина Тернарные Squarefree Слова


4
Было n>3бы неплохо использовать тестовый сценарий, поскольку возникла путаница относительно повторяющихся символов и повторяющихся последовательностей.
Лайкони

Пожалуйста, прокомментируйте запланированное продолжение в песочнице: codegolf.meta.stackexchange.com/a/14133/45211
mschauer

6
Я не думаю, что тег «естественный язык» должен применяться здесь
Лев

1
Ах, «слова» расширились до «естественного языка», я его убрал.
Мшауэр

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соответственно, в каждом из трех экземпляров. Этот процесс останавливается после 1замены всех s.

A`(.+)\1

Наконец, мы просто отбрасываем все строки, содержащие повторение.


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

6

Шелуха , 15 14 байт

-1 байт благодаря Zgarb!

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(...);?
Якоб

@ Якоб Спасибо. И я всегда пользуюсь for(;...;)вне codegolfing-habbit, чтобы быть честным. В худшем случае это тот же счетчик байтов, что while(...)и в лучшем случае, что-то может быть помещено в цикл for для сохранения байтов. Поэтому я стараюсь вообще не использовать whileв кодгольфинге, потому что в любом случае это никогда не помогает подсчету байтов. Он либо увеличивает его, либо остается прежним, так что лично я не беспокоюсь о лучшей читаемости. ;)
Кевин Круйссен

1
Да, я всегда стараюсь сделать мой гольф-код максимально читаемым при заданном количестве байтов. Вероятно, тщетное преследование!
Якоб

Подождите, моя лямбда на самом деле работает здесь? Я был немного небрежен ... Он генерирует строку из n PRS последовательностей, тогда как ваш исходный цикл генерировал последовательность с 2 ^ ( n -2) последовательностями.
Якоб

@Jakob nраз "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,s3 раза, взятые 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
Это не самый компактный из языков, но эй, любой повод использовать его :)
Джейсон Хэндби


1

к, 56 байт

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

Отсутствие нативного регулярного выражения на этот раз оставляет k далеко позади кривой. Я выбрал рекурсивное решение, поскольку символы для его реализации были сохранены с помощью более простой проверки без использования квадратов.

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

является тернарным оператором k, здесь мы делаем интересные вещи для ненулевой длины и возвращаем одну пустую строку, если запрашиваются слова нулевой длины.

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

берёт декартово произведение "RPS" и всех n-1 длинных квадратичных слов. , /: \: соединяет каждый элемент справа налево, давая массив длиной 3 массива n. , / сглаживает это в массив длины 3n.

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

берет первые n букв каждой строки и сравнивает их со вторыми n, а затем сокращает массив до тех мест, где они не совпадают. Поскольку мы знаем, что предыдущий результат не содержит квадратов, необходимо сопоставлять только подстроки, начинающиеся с первого символа - упрощение проверки здесь стоило символов, потраченных на реализацию рекурсии. В заключение,

/1_!x

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

Пожертвовав несколькими символами, мы можем использовать .zs для самостоятельной ссылки, а не полагаться на имя функции, и вместо проверки подстрок длиной до n-1 проверяем только этаж (n / 2) на производительность. Он находит всю длину 49 слов (из них 5207706) примерно за 120 секунд на 7700k, выше того, что я сталкиваюсь с пределом 4GB свободного 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.