Гольф кода машины Тьюринга

необходимо просто быть в состоянии назвать его путем ввода в имени файла. Вам, вероятно, придется назвать ./a.exe, как текущий каталог обычно находится не на пути из соображений безопасности.

16
задан 11 revs, 2 users 99% 27 November 2009 в 02:50
поделиться

12 ответов

Perl function 101 char

sub f{($_,$S,$p)=@_;for(%h=map{$i++,$_}split//;7^$S;$p-=$S<=>3){$S=7&236053>>3*($S%4*2+!!$h{$p}++)}};

f(@ARGV);
@allpos = sort keys %h;
for (@allpos){
    print $h{$_}?1:0;
}
print " H ".($p-$allpos[0])."\n";

Было интересно найти эту функцию. Две хитрости. Он использует хеш для ленты, и знаете что? Хэш автоматически расширяется, поэтому больше не нужно заботиться о границах ленты. Другой трюк заключается в объединении чтения и записи доступной ячейки. Просто нужно было изменить внутренние соглашения: 0 и пробел означает 0, а любое другое значение означает 1. Эти два трюка подразумевают некоторое тривиальное декодирование вывода, но я считаю, что это нормально. Я также не считал последнюю точку с запятой в своей функции, так как gnibbler не считал свою в своем сценарии гольфа.

Если кому-то интересно, я также могу опубликовать свои другие попытки. Они немного длиннее, но используют забавные трюки. Например, один основан на регулярных выражениях и работает непосредственно с лентой как строка, другой - своего рода бит-фу.

Perl function 112 char

sub f{($_,$S,$p)=@_;for(split//;7^$S;@_=($p=0,@_)if($p-=$S<=>3)<0){$S=7&236053>>3*($S%4*2+$_[$p]);$_[$p]=1}@_};

@res = f@ARGV;
print @res," H $p\n";

Я подсчитал только функцию, и она принимает строку, номер состояния и позицию в указанном порядке. Функция возвращает новое состояние ленты в виде массива.

Другой вариант 106 char

sub f{($_,$S,$p)=@_;for(split//;7^$S;$p-=$S<=>3){$S=7&236053>>($S%4*6+$_[$p]*3);$_[$p++]=1;@_=(0,@_)}@_};`

@res = f(@ARGV);
print @res," H $p\n";

Не ясно, читерская эта лента или нет. Он дает правильные результаты и автоматически удлиняет ленту (без фиксированного предела), но чтобы избежать тестирования, необходимо или не растягивать ленту, он делает это каждый шаг и корректирует индекс.

Другой вариант 98 символов

Этот также является на слиянии, но по-другому. Он просто использует глобальные переменные для передачи параметров внутри функции. Следовательно, вы устанавливаете свои переменные вне функции, а не внутри. Таким образом удаляется 14 символов из тела функции.

sub f{for(split//;7^$S;@_=($p=0,@_)if($p-=$S<=>3)<0){$S=7&236053>>3*($S%4*2+$_[$p]);$_[$p]=1}@_};

($_,$S,$p) = @ARGV;
@res = f();
print @res," H $p\n";
6
ответ дан 30 November 2019 в 16:19
поделиться

C - 282 44 98 символов (including all inner-loop var and table declarations)

#include<stdio.h>
#include<string.h>

char*S="  A2C1C2  C3A2A0";
f(char*p,char c){char*e;while(c){e=S+*p*8+c*2;*p=1;p+=*e++-66;c=*e-48;}}

char T[1000];
main()
{
  char *p;
        char c;
        char *e;

    int initial;
    scanf("%s %d %c",&T[500],&initial,&c);
    c = c - '0' + 1;

    for(p=&T[500]; *p; p++)
        *p -= '0';

    p = &T[500+initial];

    f(p, c);

    char *left = T;
    while((left < T+500)&&(!*left))
        left++;

    char *right = T+sizeof(T)-1;
    while((right > T+500)&&(!*right))
        right--;

    initial = p - left;

    for(p=left; p<=right; p++)
        *p+='0';

    printf("%.*s %d\n\n",right-left+1,left,initial);
}
9
ответ дан 30 November 2019 в 16:19
поделиться

Perl 142 символа (не считая аргументов чтения в командной строке и окончательной печати. ​​Ну, большая часть кода - это программа beaver, сам движок состоит только из 46 символов.

Я изменил формат ввода чтобы поместить состояние в его позицию в строке. Я не чувствую себя виноватым, поскольку в противном случае большая часть кода была бы управлением границами, когда голова была вне строки. Даже в этой версии управление границами строки стоило 17 символов ... Хитрость заключается в том, чтобы просто запомнить, что вы можете выражать машины Тьюринга как цепи Маркова ... что я сделал с регулярными выражениями.

perl -e '$b=shift;%p=qw(A0|A$ 1B ^A1|0A1 C01 1A1 C11 0B0|^B0 A01 1B0|1B$ A11 B1 1B 0C0|^C0 B01 1C0|1C$ B11 C1 1H);while($b!~/H/){$b=~s/$_/$p{$_}/for keys%p}print"$b\n"' 00A1011

111H1111

Примечание: на самом деле это еще не совсем игра в гольф, а просто наивная первая попытка. Я могу вернуться с чем-нибудь очень коротким.

3
ответ дан 30 November 2019 в 16:19
поделиться

Golfscript - 102 символа

{:s;{\:$;:^0<{0.:^$+:$}{^$}if.,@>!'0'*+.^=1&s.++:c;.^<1+\^)>+:$[^(^).^(^)^(]c=:^3"120113"c=3&:s-}do}:f

;
["1010" 3 0 f]p
["110100" 3 1 f]p
["1000000" 3 1 f]p

106 символов

{:s;\:$;:i{0<{0.:i$+:$}{i$}if.,@>!'0'*+.i=1&s.++:c;.i<1+\i)>+:$;[i(i).i(i)i(]c=:i 3"120113"c=3&:s-}do$\}:f

113 символов
Чтение всей программы из stdin

' '/(:$;(~:i;~~:s;{0i>{0.:i$+:$}{i$}if.,@>!'0'*+.i=1&s.++:c;.i<1+\i)>+:$;[i(i).i(i)i(]c=:i;3"120113"c=3&:s-}do$`i

примеры

$ echo -n 1010 3 0 |../golfscript.rb turing.gs 
"1111"2
$ echo -n 110100 3 1 |../golfscript.rb turing.gs 
"11111111"1
3
ответ дан 30 November 2019 в 16:19
поделиться

Чтобы уточнить, эта программа имитирует машину Тьюринга занятого бобра точно так, как описано в статье в Википедии, а не OP (OP имеет переключение R и L)

Python 255 char

def f(k,i,s):
 t=map(int,k)
 while s<3:
    if i==len(t):t+=[0]
    if i<0:t=[0]+t;i=0
    x=t[i],s
    if x==(0,0):t[i]=1;i-=1;s=1
    if x==(0,1):t[i]=1;i+=1;s=0
    if x==(0,2):t[i]=1;i+=1;s=1
    if x==(1,0):i+=1;s=2
    if x==(1,1):i-=1;s=1
    if x==(1,2):i-=1;s=3
 return t,i
2
ответ дан 30 November 2019 в 16:19
поделиться

Lua:

Полуавтоматическая версия:

a=arg
t=a[1]
i=a[2]+1
s=a[3]+0
r=string.rep
b=string.sub;z="0";o="1";while true do if i<1 then
        t=z..t
        i=1
    elseif i>#t then
        t=t..z
    end
    c=b(t,i,i)
    if i>0 then
        t=b(t,0,i-1)..o..b(t,i+1,#t)
    else
        t="1"..b(t,i+1,#t)
    end
    if s==0 then
        if c==z then
            i=i-1
            s=1
        elseif c==o then
            i=i+1
            s=2
        end
    elseif s==1 then
        if c==z then
            i=i+1
            s=0
        elseif c==o then
            i=i-1
        end
    elseif s==2 then
        if c==z then
            i=i+1
            s=1
        elseif c==o then
            i=i-1
            break
        end
    end
end
print(t,i-1)

Уплотненная версия с весом 441 символов:

a=arg t=a[1] i=a[2]+1 s=a[3]+0 r=string.rep b=string.sub;z="0";o="1";while true do if i<1 then t=z..t i=1 elseif i>#t then t=t..z end c=b(t,i,i) if i>0 then t=b(t,0,i-1)..o..b(t,i+1,#t) else t="1"..b(t,i+1,#t) end if s==0 then if c==z then i=i-1 s=1 elseif c==o then i=i+1 s=2 end elseif s==1 then if c==z then i=i+1 s=0 elseif c==o then i=i-1 end elseif s==2 then if c==z then i=i+1 s=1 elseif c==o then i=i-1 break end end end print(t,i-1)

Передача аргументов в виде ленты, указателя инструкции , укажите следующее:

turing.lua 1010 3 0
1
ответ дан 30 November 2019 в 16:19
поделиться

F # - 275 символов

Итак, определенно не самый короткий, но обучающий. Если кто-нибудь может помочь с тем, чтобы String.mapi использовал функцию , а не забавное совпадение с , я был бы признателен, я продолжаю получать «Дискриминатор шаблона x не определен». Кто-нибудь знает сайт, на котором подробно описаны правила использования ключевого слова функции в лямбде?

let rec t s i p=
    match s with
    |3->(p,i)
    |_->let g=[[(1,1);(-1,2)];[(-1,0);(1,1)];[(-1,1);(1,3)]]
        let p=match i with|_ when i<0 ->"0"+p|_ when i=p.Length->p+"0"|_->p
        let i=max 0 i
        let m,n=g.Item(s).Item((int p.[i])-48)
        String.mapi(fun x c->match x with|_ when x=i->'1'|_->c) p |> t n (i+m)

Использование

t 1 2 "101011" |> printfn "%A"

Вот расширенная версия для удобства чтения:

let rec tur state index tape =
    printfn "Index %d: State %d: Tape %s:" index state tape
    match state with
    |3 -> (tape, index)
    |_ -> let prog = [[(1,1);(-1,2)];[(-1,0);(1,1)];[(-1,1);(1,3)]]
          let tape = match index with |_ when index<0 ->"0"+tape |_ when index=tape.Length->tape+"0" |_->tape
          let index = max 0 index
          let move,newstate = prog.Item(state).Item((int tape.[index])-48)
          String.mapi (fun i c -> match i with |_ when i=index->'1' |_->c) tape
          |> tur newstate (index+move)

Я также пытаюсь придумать лучший способ справиться с манипуляциями со строкой, что-то другое, кроме String.mapi . Комментарии и предложения (пожалуйста, конструктивные) приветствуются и приветствуются.

1
ответ дан 30 November 2019 в 16:19
поделиться

Python - 133 символа

По крайней мере какое-то время нужно побеждать Perl :)

def f(t,i,s):
 t=map(int,t) 
 while s<3:t=[0]*-i+t+[0][:i>=len(t)];i*=i>0;c,t[i]=s*4+t[i]*2,1;i+=1-(2&2178>>c);s=3&3401>>c
 return t,i

Python - 172 символа

def f(t,i,s):
 t=map(int,t)
 while s<3:
  t=[0]*-i+t+[0]*(i-len(t)+1);i=max(0,i);c,t[i]=t[i],1;i,s=[[(i-1,1),(i+1,2)],[(i+1,0),(i-1,s)],[(i+1,1),(i-1,3)]][s][c]
 return t,i

тестовые примеры

assert f("1010",3,0) == ([1, 1, 1, 1], 2)
assert f("110100",3,1) == ([1, 1, 1, 1, 1, 1, 1, 1], 1)
10
ответ дан 30 November 2019 в 16:19
поделиться

C # - 157 символов

void T(List<int>t,ref int p,int s){while(s!=3){if(p<0)t.Insert(0,p=0);if(p==t.Count)t.Add(0);var c=t[p]==1;t[p]=1;p+=s==0==c?1:-1;s=s==1==c?1:c?s==0?2:3:0;}}

Метод принимает List в качестве ленты, поэтому его можно расширять, пока позволяет память.

Утверждение :

List<int> tape;
int pos;

tape = "1010".Select(c => c - '0').ToList();
pos = 3;
T(tape, ref pos, 0);
Debug.Assert(String.Concat(tape.Select(n => n.ToString()).ToArray()) == "1111" && pos == 2);

tape = "110100".Select(c => c - '0').ToList();
pos = 3;
T(tape, ref pos, 1);
Debug.Assert(String.Concat(tape.Select(n => n.ToString()).ToArray()) == "11111111" && pos == 1);

Если мы обманем и выделим достаточно большой массив с самого начала, 107 символов :

void X(int[]t,ref int p,int s){while(s!=3){var c=t[p]==1;t[p]=1;p+=s==0==c?1:-1;s=s==1==c?1:c?s==0?2:3:0;}}
3
ответ дан 30 November 2019 в 16:19
поделиться

Ruby, 129

( при удалении отступа)

def pr t,z,s      # DEBUG
  p [t,s]     # DEBUG
  p [' '*z + '^'] # DEBUG
end       # DEBUG


def q t,z,s
  s*=2
  (t=t.ljust z+1
    (t=' '+t;z=0)if z<0
    a=t[z]&1
    t[z]=?1
    b=s>0?1-a: a
    s="240226"[s|a]&7
    z+=b*2-1)while s!=6
  [t,z]
end

p q "1010",3,0
p q "110100",3,1
0
ответ дан 30 November 2019 в 16:19
поделиться

Lua, 232

Теперь используется поиск по таблице.

j={{-1,1},{1,-1},{1,-1}}u={{1,2},{-1,0},{-1,1}}t,i,s=...i=i+1
s=s+1 z="0"o="1"while s<4 do if i<1 then t=z..t i=1
elseif i>#t then t=t..z end c=t:sub(i,i):byte()-47
t=t:sub(0,i-1)..o..t:sub(i+1)i=i+j[s][c]s=s+u[s][c]end print(t,i-1)

Это всего лишь ответ RCIX с переформатированием, 332 символа.

t,i,s=...i=i+1 s=s+0 r=string.rep b=string.sub z="0"o="1"while s<3 do if i<1 then
t=z..t i=1 elseif i>#t then t=t..z end c=b(t,i,i)t=b(t,0,i-1)..o..b(t,i+1,#t)if
s<1 then i=i+(c==o and 1 or -1)s=c==z and 1 or 2 elseif s<2 then i=i+(c==o and
-1 or 1)s=c==z and 0 or s else i=i+(c==o and -1 or 1)s=c==z and 1 or 3 end end
print(t,i-1)
  • использует . .. оператор для назначения входных параметров
  • использует и и или вместо операторов if , когда более короткий
  • заменяет некоторые elseif на просто else , предполагая, что ввод / состояния
  • удалены пробелы после скобок, оператора эллипса и конечных кавычек
1
ответ дан 30 November 2019 в 16:19
поделиться

Perl, 97 (на самом деле 96, потому что заключительный ";" является необязательным для подблока)

sub f{($_,$a,pos)=@_;s/\G./$&+2*$a+2/e;1while s!(.?)(2|5)|(3|4|6)(.?)!$2?4+$1.1:8+$4+$3+5*/3/!e}
f@ARGV;
#output
s/7/1/;print;print " H ",(-1+length$`);

Идея: Переменная $ _ содержит нули и единицы, кроме заголовка. Под головой, 0 в состоянии A дает 2, 1 в состоянии A дает 3, 0 в состоянии B дает 4, 1 в состоянии B дает 5, 0 в состоянии C дает 6, 1 в состоянии C дает 7.

поэтому, следуя первому примеру «1010» (поз. 3, состояние A) дает «1051», затем «1411», «1131», «1117» (1111, состояние C, поз. 3) и остановитесь (плюс переместите ленту вправо)

2
ответ дан 30 November 2019 в 16:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: