Подтвердить что ты не робот

Код машины Тьюринга

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

Код будет содержать последовательность символов "0" и "1", целое число, представляющее символ, с которого начинается машина, и целое число, представляющее состояние программы (в определенном порядке), и выводят конечный результат операций над строкой, а также конечную позицию. Примеры:

Пример 1:

1010 state A(0)
   ^ (3)
1011 state B(1)
  ^ (2)
1011 state B(1)
 ^ (1)
1111 state A(0)
  ^ (2)
1111 state C(0)
   ^ (3)
1111 HALT
  ^ (2)

Пример 2:

110100 state B(1)
   ^ (3)
110100 state B(1)
  ^ (2)
111100 state A(0)
   ^ (3)
111100 state C(2)
    ^ (4)
111110 state B(1)
     ^ (5)
1111110 state A(0)
      ^ (6, tape has been extended to right)
1111111 state B(1)
     ^ (5)
1111111 state B(1)
    ^ (4)
1111111 state B(1)
   ^ (3)
1111111 state B(1)
  ^ (2)
1111111 state B(1)
 ^ (1)
1111111 state B(1)
^ (0)
01111111 state B(1)
^ (0, tape has been extended to left)
11111111 state A(0)
 ^ (1)
11111111 state C(2)
  ^ (2)
11111111 HALT
 ^ (1)

Разное:

  • Ваш код должен правильно обрабатывать попытки записи в "пробелы" на ленте, путем расширения строки по мере необходимости.
  • Поскольку указанный конечный автомат не указывает какого-либо действия "пустой ленты", обрабатывайте все пустые значения как 0.
  • Вы должны учитывать только метод, который обрабатывает оценку строки с начальным состоянием, как вы выводите эти данные для вас.
  • Движение вправо на ленте увеличивается (позиция строки 0 находится полностью слева), состояние 0 равно A, состояние 1 - B, а состояние 2 - C.

(надеюсь) окончательное редактирование: Я приношу свои самые искренние извинения в связи с путаницей и проблемами, которые я вызвал с этим вопросом: я неправильно прочитал представленную таблицу состояний, которую я перечислил, и получил ее назад. Надеюсь, вы простите меня за то, что потратили свое время; это было совершенно непреднамеренно!

4b9b3361

Ответ 1

Функция Perl 101 char

sub f{($_,$S,$p)[email protected]_;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. Эти два трюка подразумевают некоторое тривиальное декодирование вывода, но я считаю, что все в порядке. Я также не считал окончательную полуколону в своей функции, поскольку гнибблер не считал его в своем гольф-поле.

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

Функция Perl 112 char

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

@res = [email protected];
print @res," H $p\n";

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

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

sub f{($_,$S,$p)[email protected]_;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 char

Этот тоже находится на слиянии, но по-другому. Он просто использует глобальные переменные для передачи параметров внутри функции. Следовательно, вы устанавливаете переменные вне функции, а не внутри. Таким образом удаление 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";

Ответ 2

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

testcases

assert f("1010",3,0) == ([1, 1, 1, 1], 2)
assert f("110100",3,1) == ([1, 1, 1, 1, 1, 1, 1, 1], 1)

Ответ 3

C - 282 44 98 символов (включая все объявления цикла и таблицы внутри цикла)

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

Ответ 4

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

Я изменил формат ввода, чтобы поместить состояние в это положение в строке. Я вообще не чувствую себя виноватым, так как в противном случае большая часть кода будет использоваться для управления границами, когда голова из строки. Даже в этой версии строковое управление границами стоит 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

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

Ответ 5

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

Ответ 6

С# - 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<int> как ленту, поэтому ее можно развернуть до тех пор, пока память ее позволяет.

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

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

Ответ 7

Чтобы уточнить, эта программа имитирует машину Busy Beaver Turing точно так, как описано в статье wikipedia, а не 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

Ответ 8

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

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

Идея: Переменная $_ содержит 0 и 1, кроме под головкой. Под головой, 0 в состоянии А дает 2, 1 в состоянии А дает 3, 0 в состоянии B дает 4, 1 в состоянии B дает 5, 0 в состоянии С дает 6, 1 в C-состоянии дает 7.

поэтому, следуя первому примеру "1010" (позиция 3, состояние A), выдается "1051", затем "1411", "1131", "1117" (1111, состояние C, позиция 3) и останавливается (плюс перемещает ленту на справа)

Ответ 9

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

Ответ 10

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

Хорошо, так определенно не самое короткое, но обучение. Если кто-то может помочь получить String.mapi для использования function, а затем fun match with, я был бы признателен, я продолжаю получать "дискриминатор шаблона x не определен". Кто-нибудь знает сайт, в котором подробно описаны правила использования ключевого слова function в лямбда?

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. Комментарии и предложения (конструктивные просьбы) приветствуются и поощряются.

Ответ 11

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 ответ re-golfed, 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)
  • использует оператор ... для назначения входных параметров
  • использует and и or вместо операторов if при сокращении
  • заменил elseif на else только else, допустив допустимые входные/состояния
  • удаленные пробелы после парнеров, оператор эллипса и конечные кавычки

Ответ 12

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