Код Гольф: последовательность Морриса
Соревнование
Самый короткий код за счет количества символов, который выведет последовательность чисел Морриса. Числовая последовательность Морриса, также известная как последовательность " посмотри и скажи", представляет собой последовательность чисел, которая начинается следующим образом:
1, 11, 21, 1211, 111221, 312211, ...
Вы можете генерировать последовательность бесконечно (т. Е. Вам не нужно генерировать конкретное число).
Ожидания ввода / вывода
Программа не должна принимать какие-либо входные данные (но бонусные баллы за принятие входных данных и, тем самым, дают возможность начать с любой произвольной начальной точки или числа). По крайней мере, ваша программа должна начинаться с 1
,
Выход, как минимум, должен быть последовательностью:
1
11
21
1211
111221
312211
...
Дополнительный кредит
Если вы собираетесь получить дополнительный кредит, вам нужно сделать что-то вроде этого:
$ morris 1
1
11
21
1211
111221
312211
...
$ morris 3
3
13
1113
3113
132113
...
41 ответ
GolfScript - 41 (дополнительный кредит: 40)
1{.p`n+0:c:P;{:|P=c{c`P|:P!}if):c;}%~1}do
{~.p`n+0:c:P;{:|P=c{c`P|:P!}if):c;}%1}do
Какие?
Процедура получения следующего числа в последовательности: преобразование текущего числа в строку, добавление новой строки и зацикливание символов. Для каждой цифры, если предыдущая цифра P
то же самое, увеличить счетчик c
, В противном случае добавьте c
а также P
к тому, что будет следующим числом, затем обновите эти переменные. Добавляемая нами новая строка позволяет добавить последнюю группу цифр к следующему номеру.
Точные детали можно получить, изучив документацию по GolfScript. (Обратите внимание, что |
используется в качестве переменной.)
Haskell: 115 88 85
import List
m x=do a:b<-group x;show(length b+1)++[a]
main=mapM putStrLn$iterate m"1"
Это бесконечная последовательность. Я знаю, что это можно значительно улучшить - я довольно новичок в Haskell.
Немного короче, вставляя mapM и повторяя:
import List
m(a:b)=show(length b+1)++[a]
f x=putStrLn x>>f(group x>>=m)
main=f"1"
Perl (46 символов)
$_="1$/";s/(.)\1*/length($&).$1/eg while print
Дополнительный кредит (52 символа)
$_=(pop||1).$/;s/(.)\1*/length($&).$1/eg while print
Perl, 46 символов
$_=1;s/(.)\1*/$&=~y!!!c.$1/ge while print$_,$/
Дополнительный кредит, 51 символ:
$_=pop||1;s/(.)\1*/$&=~y!!!c.$1/ge while print$_,$/
Javascript 100 97
for(x=prompt();confirm(y=x);)for(x="";y;){for(c=0;y[c++]&&y[c]==y[0];);x+=c+y[0];y=y.substr(c--)}
Позволяет прерывать последовательность (нажав "Отмена"), чтобы мы не блокировали пользовательский агент и не привязывали процессор. Это также позволяет начинать с любого положительного целого числа (дополнительный кредит).
Живой пример: http://jsbin.com/izeqo/2
Mathematica - 62 53 50 символов - дополнительный кредит включен
Изменить: 40 символов... но справа налево:(
Любопытно, что если мы читаем последовательность справа налево (т.е. 1,11,12,1121, ..), 40 символов достаточно
NestList[Flatten[Tally /@ Split@#] &, #2, #] &
Это потому, что Талли генерирует список {elem,counter}!
Изменить: 50 символов
NestList[Flatten@Reverse[Tally /@ Split@#, 3] &, #2, #] &
Рассечение: (читать комментарии вверх)
NestList[ // 5-Recursively get the first N iterations
Flatten@ // 4-Convert to one big list
Reverse // 3-Reverse to get {counter,element}
[Tally /@ // 2-Count each run (generates {element,counter})
Split@#, // 1-Split list in runs of equal elements
3] &,
#2,// Input param: Starting Number
#] // Input param: Number of iterations
Изменить: рефакторинг
NestList[Flatten[{Length@#, #[[1]]} & /@ Split@#, 1] &, #2, #1] &
Конец редактирования ///
NestList[Flatten@Riffle[Length /@ (c = Split@#), First /@ c] &, #2, #1] &
Пробелы не нужны / добавлены для ясности
Вызвать с
%[NumberOfRuns,{Seed}]
Мой первый раз, когда я использовал Riffle, чтобы объединить {1,2,3} и {a,b,c} в {1,a,2,b,3,c}:)
Питон, 97 102 115
Пробелами должны быть вкладки:
x='1'
while 1:
print x;y=d=''
for c in x+'_':
if c!=d:
if d:y+=`n`+d
n,d=0,c
n+=1
x=y
Например:
$ python morris.py | head
1
11
21
1211
111221
312211
13112221
1113213211
31131211131221
13211311123113112211
Вот моя попытка C# с использованием LINQ и первая попытка Code Golf:
C# - 205 194 211 198 байт с дополнительным кредитом (включая шаблон C#)
using System.Linq;class C{static void Main(string[]a){var v=a[0];for(;;){var r="";while(v!=""){int i=v.TakeWhile(d=>d==v[0]).Count();r+=i;r+=v[0];v=v.Remove(0,i);}System.Console.WriteLine(r);v=r;}}}
Читаемая версия:
static void Main(string[] args)
{
string value = args[0];
for (;;)
{
string result = "";
while (value != "")
{
int i = value.TakeWhile(d => d == value[0]).Count();
result += i;
result += value[0];
value = value.Remove(0, i);
}
Console.WriteLine(result);
value = result;
}
}
Образец вывода:
11
21
1211
111221
312211
13112221
1113213211
...
Рубин - 52
s=?1;loop{puts s;s.gsub!(/(.)\1*/){"#{$&.size}"+$1}}
Задача слишком проста и слишком безрассудна...
Вот моя реализация (в Прологе):
Пролог с DCG (174 символа):
m(D):-write(D),nl,m(1,write(D),T,[nl|T],_).
m(C,D,T)-->[D],{succ(C,N)},!,m(N,D,T).
m(C,D,[G,D|T])-->[N],{G=write(C),G,D,(N=nl->(M-T-O=0-[N|R]-_,N);M-T-O=1-R-N)},!,m(M,O,R).
Простой ванильный пролог, код гораздо более читабельный (225 символов):
m(D):-
((D=1->write(D),nl);true),
m([], [1,D]).
m([], [C,D|M]):-
write(C), write(D),nl,
reverse([D,C|M],[N|X]),
!,
m([N|X],[0,N]).
m([D|T], [C,D|M]):-
succ(C,N),
!,
m(T,[N,D|M]).
m([Y|T],[C,D|M]):-
write(C), write(D),
!,
m(T,[1,Y,D,C|M]).
Чтобы вывести последовательность Морриса: m(D). где D - начальная цифра.
Perl, 67 символов
в том числе -l
флаг.
sub f{$_=pop;print;my$n;$n.=$+[0].$1while(s/(.)\1*//);f($n)}f(1)
Perl, 72 символа с дополнительным кредитом
sub f{$_=pop;print;my$n;$n.=$+[0].$1while(s/(.)\1*//);f($n)}f(pop||1)
C, 128 символов
использует статический буфер, гарантированно вызывающий ошибку сегментации
main(){char*c,v[4096],*o,*b,d[4096]="1";for(;o=v,puts(d);strcpy(d,v))for(c=d;*c;o+=sprintf(o,"%d%c",c-b,*b))for(b=c;*++c==*b;);}
Perl (дополнительный кредит), 47 символов
$_=pop.$/;{print;s/(.)\1*/$&=~y|||c.$1/ge;redo}
Назовите строку "Morris-ish", если она не содержит ничего, кроме цифр 1-3, и не содержит ни одной последовательности больше трех цифр. Если исходной строкой является Morris-ish, все строки, итеративно сгенерированные из нее, также будут Morris-ish. Аналогично, если исходная строка не является Morris-ish, то ни одна сгенерированная строка не будет Morris-ish, если числа больше десяти не рассматриваются как комбинации цифр (например, если 11111111111 рассматривается как свертывание в три, а не как "одиннадцать" и один).
Учитывая это наблюдение, каждая итерация, начинающаяся с начального числа Морриса, может быть выполнена в виде следующей последовательности операций поиска / замены:
111 -> CA 11 -> BA 1 -> AA 222 -> CB 22 -> BB 2 -> AB 333 -> УК 33 -> до н.э 3 -> AC A -> 1 B -> 2 C -> 3
Обратите внимание, что последовательность является префиксом Морриса перед вышеупомянутой заменой, второй символ каждой сгенерированной пары будет отличаться от второго символа предыдущей и последующих пар; таким образом, невозможно иметь более трех одинаковых символов в последовательности.
Интересно, сколько существует непересекающихся последовательностей Морриса?
Джава
Моя первая попытка "Code-Golf", которую я только что бросил, во время части моего класса IB CS:
238 конденсированных
Сгущенное:
String a="1",b="1",z;int i,c;while(true){System.out.println(b);for(c=0,i=0,b="",z=a.substring(0,1);i<a.length();i++){if(z.equals(a.substring(i,i+1)))c++;else{b+=Integer.toString(c)+z;z=a.substring(i,i+1);c=1;}}b+=Integer.toString(c)+z;a=b;}
Правильно отформатированный:
String a = "1", b = "1", z;
int i, c;
while (true) {
System.out.println(b);
for (c = 0, i = 0, b = "", z = a.substring(0, 1); i < a.length(); i++) {
if (z.equals(a.substring(i, i + 1))) c++;
else {
b += Integer.toString(c) + z;
z = a.substring(i, i + 1);
c = 1;
}
}
b += Integer.toString(c) + z;
a = b;
}
J, 44 символа с дополнительным кредитом
(([:,#;.1@{:,.{:#{.)@(,:0<1,[:|2-/\]))^:(<9)
К сожалению, это генерирует только 9 итераций, но количество итераций <9
можно настроить, чтобы быть чем угодно. Установка его в a:
генерирует бесконечную последовательность, но, очевидно, это не может быть напечатано.
Использование:
(([:,#;.1@{:,.{:#{.)@(,:0<1,[:|2-/\]))^:(<9) 1
1 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 0 0 0 0 0 0 0 0 0 0 0 0
2 1 0 0 0 0 0 0 0 0 0 0 0 0
1 2 1 1 0 0 0 0 0 0 0 0 0 0
1 1 1 2 2 1 0 0 0 0 0 0 0 0
3 1 2 2 1 1 0 0 0 0 0 0 0 0
1 3 1 1 2 2 2 1 0 0 0 0 0 0
1 1 1 3 2 1 3 2 1 1 0 0 0 0
3 1 1 3 1 2 1 1 1 3 1 2 2 1
(([:,#;.1@{:,.{:#{.)@(,:0<1,[:|2-/\]))^:(<11) 4
4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
3 1 1 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 3 2 1 1 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 3 1 2 2 1 1 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
3 1 1 3 1 1 2 2 2 1 1 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 3 2 1 1 3 2 1 3 2 2 1 1 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 3 1 2 2 1 1 3 1 2 1 1 1 3 2 2 2 1 1 4 0 0 0 0 0 0 0 0
3 1 1 3 1 1 2 2 2 1 1 3 1 1 1 2 3 1 1 3 3 2 2 1 1 4 0 0 0 0
1 3 2 1 1 3 2 1 3 2 2 1 1 3 3 1 1 2 1 3 2 1 2 3 2 2 2 1 1 4
Java - 167 символов (с учетом)
(122 без класса / основной шаблон)
class M{public static void main(String[]a){for(String i=a[0],o="";;System.out.println(i=o),o="")for(String p:i.split("(?<=(.)(?!\\1))"))o+=p.length()+""+p.charAt(0);}}
С символами новой строки:
class M{
public static void main(String[]a){
for(String i=a[0],o="";;System.out.println(i=o),o="")
for(String p:i.split("(?<=(.)(?!\\1))"))
o+=p.length()+""+p.charAt(0);
}
}
Вот моя самая первая попытка в код-гольфе, поэтому, пожалуйста, не будьте слишком строги ко мне!
PHP, 128 122 112 байт с открывающим тегом
122 116 106 байт без открывающего тега и начальных пробелов.
<?php for($a="1";!$c="";print"$a\n",$a=$c)for($j=0,$x=1;$a[$j];++$j)$a[$j]==$a[$j+1]?$x++:($c.=$x.$a[$j])&&$x=1;
(Жаль, я должен инициализировать $a
как строка, хотя, стоит мне 2 дополнительных байта, в противном случае я не могу использовать индексную нотацию на нем.)
Выход
$ php morris.php
1
11
21
1211
111221
312211
...
PHP (дополнительный кредит), 133 127 117 байт с открывающим тегом
127 121 111 байт без открытия <?php
тег и ведущий пробел.
<?php for($a=$argv[1];!$c="";print"$a\n",$a=$c)for($j=0,$x=1;$a[$j];++$j)$a[$j]==$a[$j+1]?$x++:($c.=$x.$a[$j])&&$x=1;
Выход
$ php morris.php 3
3
13
1113
3113
132113
1113122113
...
^C
$ php morris.php 614
614
161114
11163114
3116132114
1321161113122114
1113122116311311222114
...
PHP (дополнительный кредит), не зацикленный на открытии и закрытии тегов
<?php
for ($a = $argv[1]; !$c = ""; print "$a\n", $a = $c)
{
for ($j = 0, $x = 1; $a[$j]; ++$j)
{
// NB: this was golfed using ternary and logical AND operators:
// $a[$j] == $a[$j + 1] ? $x++ : ($c .= $x . $a[$j]) && $x = 1;
if ($a[$j] == $a[$j + 1])
{
$x++;
}
else
{
$c .= $x . $a[$j];
$x = 1;
}
}
}
?>
Delphi
Delphi - ужасный язык игры в гольф, но все же:
var i,n:Int32;s,t,k:string;u:char;label l;begin s:='1';l:writeln(s);t:='';u:=s[1
];n:=1;for i:=2to length(s)do if s[i]=u then inc(n)else begin str(n,k);t:=t+k+u;
u:=s[i];n:=1;end;str(n,k);t:=t+k+u;s:=t;goto l;end.
Это 211 байт (и он компилируется, как есть).
PHP: 111
Моя первая попытка поиграть в гольф, довольная результатом.
for($x=1;;){echo$y=$x,"\n";for($x="";$y;){for($c=0;$y[$c++]&&$y[$c]==$y[0];);$x.=$c.$y[0];$y=substr($y,$c--);}}
дает:
> php htdocs/golf.php
1
11
21
... (endless loop)
PHP с дополнительным кредитом: 118
for($x=$argv[1];;){echo$y=$x,"\n";for($x="";$y;){for($c=0;$y[$c++]&&$y[$c]==$y[0];);$x.=$c.$y[0];$y=substr($y,$c--);}}
дает:
> php htdocs/golf.php 4
4
14
1114
3114
... (to infinity and beyond)
Питон - 98 символов
from itertools import *
L='1'
while 1:print L;L=''.join('%s'%len(list(y))+x for x,y in groupby(L))
106 символов для бонуса
from itertools import *
L=raw_input()
while 1:print L;L=''.join('%s'%len(list(y))+x for x,y in groupby(L))
C++, 310 символов.
#include <iostream>
#include <list>
using namespace std;
int main(){list<int> l(1,1);cout<<1<<endl;while(1){list<int> t;for(list<int>::iterator i=l.begin();i!=l.end();){list<int>::iterator p=i;++i;while((i!=l.end())&&(*i==*p)){++i;}int c=distance(p,i);cout<<c<<*p;t.push_back(c);t.push_back(*p);}cout<<'\n';l=t;}}
Правильно отступ:
#include <iostream>
#include <list>
using namespace std;
int main() {
list <int> l(1,1);
cout << 1 << endl;
while(1) {
list <int> t;
for (list <int>::iterator i = l.begin(); i != l.end();) {
const list <int>::iterator p = i;
++i;
while ((i != l.end()) && (*i == *p)) {
++i;
}
int c = distance(p, i);
cout << c << *p;
t.push_back(c);
t.push_back(*p);
}
cout << '\n';
l = t;
}
}
C#, 204 байта (256 с дополнительным кредитом)
Моя первая попытка кода в гольф
static void Main(){var v="1";for(;;){Console.Write(v + "\n");var r=v.Aggregate("", (x, y) => x.LastOrDefault()==y?x.Remove(0, x.Length-2)+(int.Parse(x[x.Length-2].ToString())+1).ToString()+y:x+="1"+y);v=r;}}
Читаемая версия, отличие от других в том, что я использую функцию агрегирования Linq
static void Main(){
var value="1";
for(;;)
{
Console.Write(value + "\n");
var result = value.Aggregate("", (seed, character) =>
seed.LastOrDefault() == character ?
seed.Remove(seed.Length-2) + (int.Parse(seed[seed.Length-2].ToString())+1).ToString() + character
: seed += "1" + character
);
value = result;
}
}
F# - 135
let rec m l=Seq.iter(printf "%i")l;printfn"";m(List.foldBack(fun x s->match s with|c::v::t when x=v->(c+1)::v::t|_->1::x::s)l [])
m[1]
Форматированный код
let rec m l=
Seq.iter(printf "%i")l;printfn"";
m (List.foldBack(fun x s->
match s with
|c::v::t when x=v->(c+1)::v::t
|_->1::x::s) l [])
m[1]
Все еще надеюсь, что смогу найти лучший способ напечатать список или использовать вместо него строку /bigint.
Питон - 117
Мой питон-фу не силен, поэтому я много гуглил для этого.:)
a='1'
while 1:
print a
a=''.join([`len(s)`+s[0]for s in''.join([x+' '*(x!=y)for x,y in zip(a,(2*a)[1:])]).split()])
Идея состоит в том, чтобы использовать zip для генерации списка пар (a[i],a[i+1]), использовать внутреннее понимание, чтобы вставить пробел, когда a[i]!= A [i+1], присоединиться к Получив список из строки и разделив его на пробелы, используйте другое понимание в этом списке, чтобы заменить каждый элемент длиной элемента и первым символом, и, наконец, соединиться, чтобы получить следующее значение в последовательности.
Common Lisp - 124 122 115 символов
(do((l'(1)(do(a r)((not l)r)(setf a(1+(mismatch(cdr l)l))r(,@r,a,(car l))l(nthcdr a l)))))((format t"~{~s~}~%"l)))
С форматированием:
(do ((l '(1) (do (a r) ((not l) r) (setf a (1+ (mismatch (cdr l) l))
r `(,@r ,a ,(car l)) l (nthcdr a l)))))
((format t "~{~s~}~%" l)))
PHP 72 байта
<?for(;;)echo$a=preg_filter('#(.)\1*#e','strlen("$0"). $1',$a)?:5554,~õ;
Этот сценарий может быть дополнительно оптимизирован. Но поскольку у нас в PHPGolf ({http://www.phpgolf.org/?p=challenges&challenge_id=28}) точно такая же последовательность, я продолжаю придерживаться этого.
C - 120 символов
129 с дополнительным кредитом
main(){char*p,*s,*r,x[99]="1",t[99];for(;r=t,puts(p=x);strcpy(x,t))
for(;*p;*r++=p-s+48,*r++=*s,*r=0)for(s=p;*++p==*s;);}
Новая строка существует только для удобства чтения.
Это останавливается, когда происходит ошибка (по крайней мере после 15 итераций). Если ваши библиотеки C используют буферизованный ввод / вывод, вы можете не увидеть никаких выходных данных до segfault. Если так, проверьте с этим кодом:
#include<stdio.h>
main(){char*p,*s,*r,x[99]="1",t[99];for(;r=t,puts(p=x),fflush(stdout),1;
strcpy(x,t))for(;*p;*r++=p-s+48,*r++=*s,*r=0)for(s=p;*++p==*s;);}
Это добавляет fflush
после каждого выхода.
Без швов это выглядело бы примерно так:
int main(){
char *p, *start, *result, number[99] = "1", temp[99];
while(1){ /* loop forever */
puts(number);
result = temp; /* we'll be incrementing this pointer as we write */
p = number; /* we'll be incrementing this pointer as we read */
while(*p){ /* loop till end of string */
start = p; /* keep track of where we started */
while(*p == *start) /* find all occurrences of this character */
p++;
*result++ = '0' + p - start; /* write the count of characters, */
*result++ = *start; /* the character just counted, */
*result = 0; /* and a terminating null */
}
strcpy(number, temp); /* copy the result back to our working buffer */
}
}
Вы можете увидеть это в действии на ideone.
С дополнительным кредитом код выглядит так:
main(){char*p,*s,*r,x[99],t[99];for(scanf("%s",x);r=t,puts(p=x);strcpy(x,t))
for(;*p;*r++=p-s+48,*r++=*s,*r=0)for(s=p;*++p==*s;);}
C ж / Дополнительный кредит, 242 (или 184)
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define s malloc(1<<20)
main(int z,char**v){char*j=s,*k=s;strcpy(k,*++v);for(;;){strcpy(j,k);z=1;*k=0;while(*j){if(*j-*++j)sprintf(k+strlen(k),"%d%c",z,*(j-1)),z=1;else++z;}puts(k);}}
Вы можете сохранить еще ~60 символов, если не включить include, gcc все равно будет компилироваться с предупреждениями.
$ ./a.out 11111111 | head
81
1811
111821
31181211
132118111221
1113122118312211
31131122211813112221
132113213221181113213211
111312211312111322211831131211131221
3113112221131112311332211813211311123113112211
Python - 92 символа
98 с дополнительным кредитом
Выходы бесконечно. Я рекомендую перенаправить вывод в файл и быстро нажать Ctrl+C.
x=`1`;t=''
while 1:
print x
while x:c=x[0];n=len(x);x=x.lstrip(c);t+=`n-len(x)`+c
x,t=t,x
Для дополнительной версии кредита замените
x=`1`
с
x=`input()`