Brainf * ckish 방향


14

당신의 임무는 당신이 그것을 받아들이도록 선택해야합니다 – 왼쪽 또는 오른쪽으로 방향을주는 토큰의 문자열 (왼쪽에서 오른쪽으로 그리고 임의의 길이로)을 구문 분석하고 평가하는 프로그램을 만드는 것입니다. 네 가지 가능한 토큰과 그 의미는 다음과 같습니다.

>  go right one single step
<  go left one single step
-> go right the total amount of single steps that you've gone right, plus one,
   before you previously encountered this token and reset this counter to zero
<- go left the total amount of single steps that you've gone left, plus one,
   before you previously encountered this token and reset this counter to zero

프로그램이 구문 분석 할 수 있어야하는 방향의 토큰은 다음과 같은 형식으로 표시됩니다.

<<->-><<->->>->>->

다시 말해서, 그것들은 연결되어 있으며 올바른 방향의 우선 순위와 수행해야 할 단계의 양을 미리 파악하는 것이 프로그램의 임무입니다. 우선 순위는 다음과 같습니다 (가장 높은 순서에서 가장 낮은 순서로).

  1. ->
  2. <-
  3. >
  4. <

당신이 발생하면 <-시작 이후 또는 마지막 재설정 이후 왼쪽으로 단계를 수행하지 않은 , 왼쪽으로 한 단계 씩 이동하십시오. 같은 규칙이 적용 ->되지만 오른쪽으로 이동합니다.

프로그램은 0에서 시작해야하며 결과는 최종 종료 위치를 나타내는 부호있는 정수 여야합니다.

입력이 항상 유효 할 것으로 예상 할 수 있습니다. <--->>--< 예를 들어).

입력 예 :

><->><-<-><-<>>->

이 예의 단계 :

 step | token | amount | end position
------+-------+--------+--------------
   1. |   >   |     +1 |           1  
   2. |   <   |     -1 |           0  
   3. |  ->   |     +2 |           2  
   4. |   >   |     +1 |           3  
   5. |   <-  |     -2 |           1  
   6. |   <   |     -1 |           0  
   7. |  ->   |     +2 |           2  
   8. |   <-  |     -2 |           0  
   9. |   <   |     -1 |          -1  
  10. |   >   |     +1 |           0  
  11. |   >   |     +1 |           1  
  12. |  ->   |     +3 |           4  

명확히하기 위해 : 프로그램의 출력은 부호있는 정수로만 최종 끝 위치에 있어야합니다. 위의 표는 내 예제에서 수행 한 단계를 보여주기위한 것입니다. 이러한 테이블, 테이블 행 또는 단계의 끝 위치 만 출력 할 필요가 없습니다. 부호있는 정수로서 최종 종료 위치 만 필요합니다.

일주일 후 가장 짧은 코드가 이깁니다.


4
우선 순위 규칙을 올바르게 이해하면 호출 할 수있는 유일한 시간 <-은 바로 뒤에 <또는 a가 오는 것입니다 ->. 순서를 대표하는이 언어의 방법은 없습니다 <-다음 >이 될 것입니다 - go left the total amount of single steps that you've gone left, plus one, then go right one single step. 이것이 정확하고 의도적 인 것입니까?
Adam Davis

@AdamDavis 당신이 맞아요. 불행히도 그것은 저를 조금 부주의했습니다.
괜찮은 Dabbler

답변:


6

GolfScript, 46 자

'->'/')'*.'<-'-.')'/);+,\'>)'-.'<-'/);\'-'-+,-

이것은 내가 작성한 것 중 가장 선형적인 GolfScript 프로그램 중 하나입니다. 단일 루프, 조건부 또는 변수 할당이 없습니다. 모든 것은 문자열 조작을 사용하여 수행됩니다.

  • 먼저 모든 발생을 ->로 바꿉니다 ). 입력이 유효 함을 보장하므로 나머지 발생은 -의 일부 여야합니다 <-.

  • 다음으로 두 줄의 사본을 만듭니다. 첫 번째 사본에서, 나는 문자를 제거 <하고 -, 단지 떠나 >). 그런 다음 결과를 복제하고 모든 )s를 제거 >하고 마지막을 따르는 모든 것을 제거하십시오.) 두 번째 사본에서 을 연결하여 문자를 계산합니다. 따라서 실제로, 나는 세고 있습니다 :

    • 각 +1 ) ,
    • >마지막 이후에 +1) , 및
    • >마지막 전에 각각 +2 ).
  • 다음으로,이 시간 계산을 제외하고, 다른 사본에 대해 동일 할 <<-대신 >하고 ), 그리고 제거 -마지막 글자 수 전에들. 따라서 나는 계산합니다 :

    • 각각 +1<- ,
    • 각 +1 <지난 후<- , 및
    • <마지막 전에 각각 +2 <-.
  • 마지막으로 첫 번째 카운트에서 두 번째 카운트를 빼고 결과를 출력합니다.


6

파이썬 2.7 - (154) 147 134 128 바이트

l=r=p=0
exec"exec raw_input('%s->','p+=r+1;r=0%s<-','p-=l+1;l=0%s>','r+=1;p+=1%s<','l+=1;p-=1;')"%((";').replace('",)*4)
print p

이 프로그램의 작동 방식이 크게 변경되었습니다. 이 답변의 편집 기록에서 찾을 수있는 이전 설명을 제거했습니다.

이것은 총입니다.

이 질문에 대한 다른 답변과 거의 같은 방식으로 입력의 문자를 해당 언어의 유효한 문으로 바꾸고 실행합니다. 그러나 한 가지 큰 차이점 replace이 있습니다. 긴 단어입니다. 망쳐

채팅에서 @ProgrammerDan은 문자열 ;').replace('을 4 번 사용하여 튜플 을 사용하여 str.format()텍스트 서식을 지정 하는 사전 방법 을 사용 한다는 아이디어를 얻었습니다 . 네 번째 인스턴스는 %s두 번째 줄의 문자열에 있으며, 각 인스턴스 는 끝에있는 튜플의 관련 요소에서 값을 가져옵니다. 모두 동일하므로 각각 %s이로 대체됩니다 ;').replace('. 작업을 수행하면 다음 문자열이 나타납니다.

exec raw_input(';').replace('->','p+=r+1;r=0;').replace('<-','p-=l+1;l=0;').replace('>','r+=1;p+=1;').replace('<','l+=1;p-=1;')

이것은 이제 실행할 수있는 유효한 파이썬 코드입니다 exec. 맞아, baby : Nests exec는 code에서 문자열 연산을 수행해야하는 코드에서 문자열 연산을 사용할 수있게 해 준다 . 누군가 제발 날 죽여줘

나머지 명령은 매우 간단합니다. 각 명령은 세 가지 변수를 추적하는 코드로 대체됩니다. 현재 위치, 마지막 이후의 권한 수 ->, left 및 <-. 모든 것이 실행되고 위치가 인쇄됩니다.

raw_input(';')';'를 사용하여 내가하는 것을 알 수 있습니다 . 프롬프트가 아닌 raw_input()프롬프트로 표시됩니다. 이것은 직관적 방법으로 문자를 저장합니다 내가 그랬다면 raw_input(), 나는 가득 튜플이해야 할 것 ).replace(', 그리고 모든 인스턴스 %s것을 '; \' '가되기 전에 첫 번째를 제외시켰다 . 프롬프트가 있으면 중복성이 높아 지므로 전체적으로 더 많은 문자를 저장할 수 있습니다.


2
" 문자를 찾지 못하면 list.index()반환합니다 -1.".. erm no. 를 발생 IndexError시킵니다. 와 혼동했을 수 있습니다 str.find. 실제로으로 바꿀 수 [list('><rl').index(c)]있습니다 ['><rl'.find(c)].
Bakuriu

... 어떻게 문서에서 찾아서 -1을 반환한다고 맹세했을 수 있습니다. 특별히 목록을위한 페이지 였으므로 내가 무엇을 읽었는지 전혀 모른다. 어쨌든 도움을 주셔서 감사합니다. 답변으로 수정하겠습니다.
undergroundmonorail

5

134 131 ... 99 95 바이트

sub f{$p+=$d;$&=~/-/?($p+=$s,$s=0):($s+=$d)}$_=<>;$d=1;s/-?>/f/eg;$s=0;$d=-1;s/<-?/f/eg;print$p

stdin에서 입력을 한 줄로받습니다. 예 :

ski@anito:~$ perl -le 'sub f{$p+=$d;$&=~/-/?($p+=$s,$s=0):($s+=$d)}$_=<>;$d=1;s/-?>/f/eg;$s=0;$d=-1;s/<-?/f/eg;print$p'
><->><-<-><-<>>->
4

또는:

ski@anito:~$ echo "><->><-<-><-<>>->" | perl -le 'sub f{$p+=$d;$&=~/-/?($p+=$s,$s=0):($s+=$d)}$_=<>;$d=1;s/-?>/f/eg;$s=0;$d=-1;s/<-?/f/eg;print$p'
4

지침을 "오른쪽"연산자 ( ">"및 "->")와 "왼쪽"연산자 ( "<"및 "<-")로 나누었습니다. 이것의 장점은 왼쪽과 오른쪽 연산자 사이의 병렬 처리를보다 쉽게 ​​이용할 수 있다는 점이며, 문자열을 토큰 화하기 위해 멋진 작업을 수행 할 필요가 없습니다. 각 "방향"은 다른 대체 작업에 의해 처리되는 반대 방향을 무시하고 해당 방향으로 취한 단계 수만큼 누계를 조정하는 대체 작업으로 처리됩니다. 다음은이 코드의 조상이 일종의 문서입니다.

sub f {
  $dir=shift;
  if($1 =~ /-/) {
    $pos+=$side+$dir;
    $side=0;
  } else {
    $pos+=$dir;
    $side+=$dir;
  }
}

$_=<>;

s/(-?>)/f(1)/eg;
$side=0;
s/(<-?)/f(-1)/eg;

print $pos

이 코드의 이전 반복에서 대체는 모두 한 번에 완료되었습니다. 이는 $ p / $ pos와 특정 시점에 반환되는 위치 사이에 직접 매핑을 유지하는 이점이 있었지만 더 많은 바이트를 차지했습니다.

5.10.0을 사용하려면 s / print / say /를 사용하여 카운트에서 다른 두 문자를 깎을 수는 있지만 실제로는 내 스타일이 아닙니다.


4

펄, 88 77 바이트

$_=<>;print s/->/F/g+2*s/>(?=.*F)//g+s/>//g-(s/<-/B/g+2*s/<(?=.*B)//g+s/<//g)

STDIN을 통해 입력이 예상됩니다 (예 :

echo '><->><-<-><-<>>->'|perl -e '$_=<>;print s/->/F/g+2*s/>(?=.*F)//g+s/>//g-(s/<-/B/g+2*s/<(?=.*B)//g+s/<//g)'
4

최신 정보

문자열을 요약으로 변환 할 필요가 없습니다. s//이미 계산 . :-)

첫 번째 버전

$_=<>;s/->/+1/g;s/>(?=.*1)/+2/g;s/>/+1/g;s/<-/-1/g;s/<(?=.*-)/-2/g;s/</-1/g;print eval

STDIN을 통해 입력이 예상됩니다 (예 :

echo '><->><-<-><-<>>->'|perl -e '$_=<>;s/->/+1/g;s/>(?=.*1)/+2/g;s/>/+1/g;s/<-/-1/g;s/<(?=.*-)/-2/g;s/</-1/g;print eval'
4

설명:

아이디어는 결과를 간단한 결과로 출력하도록 방향 문자열을 합산으로 변환하는 것입니다 print eval.

>->한 번에 한 단계 씩 다음 단계에서 두 단계를 거치기 전에 ->. 문제 ->중 하나 이상을 따르는 것은 중요하지 않습니다 . 내부 카운터가 다음 리셋 후 ->따라서, >상기 단계 왜냐하면, 최대 두 단계하지 않는다. 그런 다음 ->하나의 단계를 추가 >하고 마지막 단계 이후에 남은 단계를 수행하십시오 ->.

양의 단계 수 대신 음수로 역방향 방향도 마찬가지입니다.

예 : ><->><-<-><-<>>->

s/->/+1/: ->우선 순위가 가장 높 으므로 정방향으로 시작 합니다.
예 :><+1><-<+1<-<>>+1

s/>(?=.*1)/+2/g: 미리보기 패턴은 >이전 항목 만 ->변환되도록합니다.
예 :+2<+1+2<-<+1<-<+2+2+1

s/>/+1/g: 이제 나머지 >는 다룹니다.
예 :+2<+1+2<-<+1<-<+2+2+1

s/<-/-1/g: 역방향으로 아날로그.
예 :+2<+1+2-1<+1-1<+2+2+1

s/<(?=.*-)/-2/g: 미리보기 패턴 에서 방향 기호가 남아 있지 않기 때문에 -1전자 의 전체 <-가 필요하지 않습니다 -.
예 :+2-2+1+2-1-2+1-1<+2+2+1

s/</-1/g: <마지막 이후 의 나머지 <-가 변환됩니다.
예 :+2-2+1+2-1-2+1-1-1+2+2+1

print eval: 결과를 계산하여 출력합니다.
예 :4


좋아요 어젯밤 에이 개념을 사용하고 있었지만 오늘까지 그것을 구현할 기회는 없었습니다. 좋은 점은 게시물을 확인하고 당신이 이미 =)
skibrianski

@skibrianski : 복사 및 붙여 넣기 오류를 수정 해 주셔서 감사합니다.
Heiko Oberdiek

: 좀 더 golfed 수 65 바이트를 사용하지 않고, 또는 -p: 74 바이트 난 당신을 변경 s/>//g하기 위해 y/>//또한 표현의 괄호의 제거를 허용 각각의 경우에 바이트를 저장합니다.
Xcali

2

루비, 141 바이트

l=1;r=1;o=0
gets.gsub('->',?R).gsub('<-',?L).chars{|c|case c
when'<';o-=1;l+=1
when'>';o+=1;r+=1
when'L';o-=l;l=1
when'R';o+=r;r=1
end}
$><<o

언 골프 드 :

parsed = gets.gsub('->', 'R')
             .gsub('<-', 'L')
countL = 1
countR = 1
result = 0
parsed.each_char do |c|
    case c
    when '<'
        result -= 1
        countL += 1
    when '>'
        result += 1
        countR += 1
    when 'L'
        result -= countL
        countL = 1
    when 'R'
        result += countR
        countR = 1
    end
end
puts result

몇 가지 빠른 승리 : l=1;r=1가능 l=r=1하고 $><<o가능합니다 p o. 나는 당신이 그 사건 진술을 덜 부피가 큰 것으로 대체함으로써 많은 것을 면도 할 수 있다고 생각합니다.eval %w(o-=1;l+=1 o+=1;r+=1 o-=l;l=1 o+=r;r=1)['<>LR'.index c]
Paul Prestidge

실제로 평가 방법을 사용하면 접두사 / 접미사를 가져와 더 많이 절약 할 수 있습니다. 이것은 98 문자입니다 : l=r=1;o=0;gets.gsub('->',??).scan(/<-|./){eval"o+=#{%w[-1;l+ -l;l 1;r+ r;r][$&[-1].ord%4]}=1"};p o, 당신은 사용하여 94로 내려갈 수 있습니다ruby -p
Paul Prestidge

1

D-243

골프 :

import std.regex,std.stdio;void main(string[]a){int s,c,v;auto t=a[1].matchAll("->|<-(?!>)|>|<".regex);foreach(m;t){auto r=m.hit;if(r=="->"){s+=c+1;c=0;}else if(r=="<-"){s-=v+1;v=0;}else if(r==">"){++s;++c;}else if(r=="<"){--s;++v;}}s.write;}}

언 골프 :

import std.regex, std.stdio;

void main( string[] a )
{
    int s, c, v;
    auto t = a[1].matchAll( "->|<-(?!>)|>|<".regex );

    foreach( m; t )
    {
        auto r = m.hit;

        if( r == "->" )
        {
            s += c + 1;
            c = 0;
        }
        else if( r == "<-" )
        {
            s -= v + 1;
            v = 0;
        }
        else if( r == ">" )
        {
            ++s;
            ++c;
        }
        else if( r == "<" )
        {
            --s;
            ++v;
        }
    }

    s.write;
}

필요한 출력은 원래 문제였습니다. 나는 지금 그것을 강조 표시하고 추가 설명을 추가했습니다.
괜찮은 Dabbler

그렇습니다. 결과를 출력하기 위해 답변을 편집했습니다.
Tony Ellis

1

C, 148 (141) 140

140 :

r,l,o;main(char *x,char **v){for(x=v[1];*x;x++)(*x^45)?(*x^60)?(r++,o++):(*(x+1)==45)?(x++,o-=l+2,l=0):(o--,l++):(o+=r+1,r=0,x++);return o;}

141 :

r,l,o;main(char *x,char **v){for(x=v[1];*x;x++)(*x^45)?(*x^60)?(r++,o++):(*(x+1)==45)?(x++,o=o-l-2,l=0):(o--,l++):(o+=r+1,r=0,x++);return o;}

148 :

r,l,o;main(char *x,char **v){for(x=v[1];*x;x++){if(*x^45){if(*x^60)r++,o++;else{o--,l++;if(*(x+1)==45)x++,o-=l,l=0;}}else o+=r+1,r=0,x++;}return o;}

공백으로 :

r,l,o;
main(char *x,char **v) 
{
    for(x=v[1];*x;x++)
    (*x^45) ?
        (*x^60) ?
            (r++,o++)
            :
            (*(x+1)==45) ?
                (x++,o-=l+2,l=0)
            :(o--,l++)
        :(o+=r+1,r=0,x++);
    return o;
}

아마 골프를 할 공간이 훨씬 많을 것입니다. 나는 주로 lvalues ​​(더 이상 나오고 나중에 점점 더 나옴)를 캡처 한 3 진 변수에서 4 개의 변수를 조작하려고 시도했지만 나쁜 첫 번째 패스는 아닙니다. 매우 간단한 배열 패스. 입력을 명령 행 인수로 사용하고 리턴 값을 통해 출력합니다.

-std=c99gcc로 컴파일 하려면 플래그가 필요합니다 .

편집 : 네, 늦었습니다-몇 가지 명백한 것들을 놓쳤습니다.


인수 목록에서 두 공백을 제거 할 수 있습니다 main.main(char*x,char**v) . 그런 다음 138 대신 140을
HEIKO Oberdiek

버그가 있습니다 : >><-1 대신 0을 주거나><-> 대신 0을 제공 2 대신 0을 제공합니다.
Heiko

char와 사이에 공백을 제거하면 4 바이트를 절약 할 수 있습니다* , 그리고 교체 (*(x+1)==45)?(x++,o-=l+2,l=0):(o--,l++)와 함께 (*++x==45)?(o-=l+2,l=0):(x--,o--,l++).
Mathieu Rodic

1

자바 스크립트, 136

z=0;l=r=1;c=["--z;++l;",/</g,"++z;++r;",/>/g,"z-=l;l=1;",/<-/g,"z+=r;r=1;",/->/g];for(a=8;a--;s=s.replace(c[a--],c[a]));eval(s);alert(z)

미완성 :

s="><->><-<-><-<>>->";
z=0;
l=r=1;
c=[
    "--z;++l;", /</g,
    "++z;++r;", />/g,
    "z-=l;l=1;", /<-/g,
    "z+=r;r=1;", /->/g
];
for(a=8;a--;s=s.replace(c[a--],c[a]));
eval(s);
alert(z) // Output (4)

작동 원리

다음과 s같이 문자열 입력이 주어집니다 .

s="><->><-<-><-<>>->";

정규식을 사용하여 각 명령을 수정 z(끝 위치), l(왼쪽 이동 r저장 ) 및 오른쪽 이동 저장 명령 세트로 대체합니다 . 각 정규식은 우선 순위에 따라 수행됩니다.

위 입력의 경우 다음과 같이 변환 s됩니다.

"++z;++r;--z;++l;z+=r;r=1;++z;++r;z-=l;l=1;--z;++l;z+=r;r=1;z-=l;l=1;--z;++l;++z;++r;++z;++r;z+=r;r=1;"

예쁘지 않아요

마지막으로 우리 eval(s)는 지침을 수행 z하고 종료 위치를 포함하는 경고 를합니다.


1

자바 스크립트 (116, 122 , 130 )

116 :

for(l=r=p=i=0;c='<>-0'.indexOf(a.replace(/->/g,0)[i++])+1;p--)c-4?c-3?c-2?l++:(r++,p+=2):(p-=l-2,l=0):(p+=r+2,r=0);p

122 :

for(l=r=p=i=0,a=a.replace(/->/g,0);c='<>-0'.indexOf(a[i])+1;i++,p--)c-4?c-3?c-2?l++:(r++,p+=2):(p-=l-2,l=0):(p+=r+2,r=0);p

130 :

for(l=r=p=i=0;c='<>-'.indexOf(a[i])+1;i++,p--)c-3?c-1?(r++,p+=2):a[i+1]=='-'?a[i+2]=='>'?l++:(p-=l,l=0,i++):l++:(p+=r+2,r=0,i++);p

0

자바 스크립트 [217 바이트]

prompt(x=l=r=0,z='replace',f='$1 $2 ')[z](/(>.*?)(->)/g,f)[z](/(<.*?)(<-)/g,f)[z](/(<|>)(<|>)/g,f)[z](/<-?|-?>/g,function(c){c=='>'&&(x++,r++),c=='<'&&(x--,l++),c=='->'&&(x+=++r,r*=0),c=='<-'&&(x-=++l,l*=0)}),alert(x)

아마 조금 더 단축 될 수 있습니다 ...


0

PHP, 284 282

정규식이 없습니다.

$i=fgets(STDIN);$c=$a=0;$s=str_split($i);while($c<count($s)){switch($s[$c]){case"<":if($s[$c+1]=="-"){if($s[$c+2]==">"){$c+=3;$a+=$rr;$rr=0;$ll++;}else{$c+=2;$a+=-($ll+1);$ll=0;}}else{$c++;$a--;$ll++;}break;case">":$c++;$a++;$rr++;break;case"-":$c+=2;$a+=$rr+1;$rr=0;break;}}echo$a;

언 골프 드 :

$i=fgets(STDIN);
$c=$a=0;
$s=str_split($i);
while($c<count($s)){
    switch($s[$c]){
    case "<":
        if($s[$c+1]=="-"){
            if($s[$c+2]==">"){
                $c+=3;$a+=$rr;$rr=0;$ll++;
            }
            else{
                $c+=2;$a+=-($ll+1);$ll=0;
            }
        }
        else{
            $c++;$a--;$ll++;
        }
    break;
    case ">":
        $c++;$a++;$rr++;
        break;
    case "-":
        $c+=2;$a+=$rr+1;$rr=0;
        break;
    }
}
echo $a;

str_split($i)( 1두 번째 인수의 기본값입니다.)로 2 문자를 이길 수 있습니다 . 그리고 $i아마도 $c맞습니까?
괜찮은 Dabbler

첫 번째 줄이 잘못되었습니다 ( $i) : P 수정했습니다!
Vereos

0

또 다른 펄 솔루션, 113 자

이미 이길 두 가지 답변이 있습니다. 그것은 단지 웃음입니다. 토큰의 가치에 대한 Ilmari의 관찰을 기반으로 한 접근법을 사용합니다.

$_=<>;chomp;s/->/#/g;s/<-/%/g;s/>(?=.*#)/?/g;s/<(?=.*%)/;/g;s/#/>/g;s/%/</g;$t+=ord for split//;print$t-61*length

조금 폭발 :

$_=<>;
chomp;
s/->/#/g;
s/<-/%/g;
s/>(?=.*#)/?/g;
s/<(?=.*%)/;/g;
s/#/>/g;
s/%/</g;
$t+=ord for split//;
print$t-61*length
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.