脑力激荡的方向


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 <或a 紧随其后->。有没有在这种语言没有办法代表序列<-,然后>-这将是go left the total amount of single steps that you've gone left, plus one, then go right one single step。这是正确的设计吗?
亚当·戴维斯(

@AdamDavis你是对的。不幸的是,那让我有点疏忽。
体面的涉猎者2014年

Answers:


6

GolfScript,46个字符

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

这是我编写过的最线性的GolfScript程序之一-其中没有单个循环,条件或变量分配。一切都使用字符串操作完成:

  • 首先,我代替所有出现->)。由于输入被保证是有效的,因此可以确保剩余的任何出现都-必须是的一部分<-

  • 接下来,我将字符串复制两个。在第一个副本中,我删除了字符<-,仅保留>)。然后,我复制结果,从第二个副本中删除所有)s和>最后一个之后的所有s ),将它们连接起来并计算字符。因此,实际上,我指的是:

    • +1每一个)
    • +1每个>在最后),和
    • >最后一个+2 )
  • 接下来,我对其他副本执行相同的操作,除了这次是计数<<-而不是>and ),并-在最终字符计数之前删除s。因此,我数:

    • +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;')

现在这是可以使用执行的有效python代码exec。没错,宝贝:Nested execs让我对需要对code执行字符串操作的代码使用string操作。有人请杀了我。

其余的内容非常简单:每个命令都被替换为可跟踪三个变量的代码:当前位置,自最后一个以来的权利数量->,以及与left和相同的代码<-。整个过程运行并打印位置。

您会注意到我raw_input(';')使用';' 作为提示,而不是raw_input()没有提示。这样可以以一种不直观的方式保存字符:如果这样做raw_input(),我将不得不用填充元组).replace(',并且除第一个实例外,每个实例之前%s都应带有'; \' 。提示会产生更多的冗余,因此我可以节省更多的字符。


2
“ 在找不到字符时list.index()返回-1”。erm号。它引发一个IndexError。您可能将其与混淆了str.find。实际上,您可以替换[list('><rl').index(c)]['><rl'.find(c)]
Bakuriu 2014年

...嗯,我在文档中查询了它,并可能发誓说它返回-1。专门用于列表的页面,所以我不知道自己读了什么。无论如何,感谢您的帮助,我将其编辑为答案。
地下

5

Perl中,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 /减少另外2个字符,但这并不是我真正的风格。


4

Perl,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 2014年

@skibrianski:感谢您修复复制和粘贴错误。
Heiko Oberdiek

可以打更多的高尔夫球:65个字节 或者不使用-p74个字节在每种情况下, 我都将您s/>//g更改y/>//为保存一个字节,这也允许删除表达式中的括号。
Xcali

2

Ruby,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 2014年

实际上,使用eval方法,您可以提取一些前缀/后缀以节省更多。这是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,您可以使用ruby -p
Paul Prestidge

1

D-243

Golfed

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

所需的输出最初是在问题中。我现在已突出显示它,并添加了进一步的说明。
体面的涉猎者2014年

正确,我已经编辑了答案以立即输出结果。
Tony Ellis 2014年

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

打高尔夫球的空间可能更大。我大都放弃了尝试在捕获左值的三元数中操纵4个变量(它不断出现更长的时间,然后变得更晚),但是第一次通过并不坏。非常简单的数组传递。将输入作为命令行参数,通过返回值输出。

您需要 -std=c99使用gcc进行编译标志。

编辑: 是的,很晚了-错过了一些明显的东西。


您可以在参数列表中删除两个空格mainmain(char*x,char**v)。然后你有138,而不是140
海科Oberdiek

有一个错误:>><-给出0而不是1或><->给出0而不是2
的Heiko Oberdiek

如果您在char和之间删除空格*并替换(*(x+1)==45)?(x++,o-=l+2,l=0):(o--,l++)为,则可以节省4个字节(*++x==45)?(o-=l+2,l=0):(x--,o--,l++)
Mathieu Rodic

1

JavaScript 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

的Javascript(116,122130

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

JavaScript [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;

您可以使用赢得2个字符str_split($i)1第二个参数的默认值。)而且$i可能应该$c正确吗?
体面的达布尔2014年

第一行错了(是$i):P修复了!
Vereos

0

另一个perl解决方案,共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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.