计算一块岩石从山上滚下来


17

介绍

西西弗斯(Sisyphus)最近在工作中遇到了一些麻烦。看来他只是什么都做不完,他很想找到解决这个问题的办法。

他目前的工作需要在山上滚石。他通常会做好工作,但是每次他靠近山顶时,都会再次滚落。

他的工作真的很沮丧,他想通过计算机模拟岩石滚下山坡来科学地解决问题。

碰巧西西弗斯不是特别擅长编程,所以也许您可以帮助他?

挑战

经过这个愚蠢的介绍之后,我们开始做生意。您的程序将收到一个山丘和岩石的插图,其外观类似于此:

#o        
##
###
######
######## 

其中#代表山的一部分,o代表岩石。

现在,您必须实现一个程序,将岩石向下移动1层。例如,上面的输出应为:

#        
##o
###
######
######## 

如果有一个水平的区域,那么小山就只是水平滚动,所以...

o
######## 

...这只会使石头向侧面滚动。

 o
######## 

如果有垂直区域,岩石会掉下一步,所以...

#o
#
#
##### 

...会产量...

#
#o
#
##### 

您还将在图像上方的一行中分别接收图像的宽度和高度。因此,总的来说,我们的示例输入如下所示:

10 5
#o        
##        
###       
######    
######### 

(请注意,这里的空格是空格。选择文本并查看我的意思。)

一些细节

  • 当运行程序时岩石已经在最后一行时,您可以选择终止程序或输出未更改的输入
  • 这座山只有下山了
  • 您的程序应将输出的格式设置为与输入(包括尺寸)完全相同的格式,因此,如果将程序的输出通过管道传递给自身,则它将计算下一步。

  • 您可以假设总有一条通向底部的道路,因此路径被“阻塞”的输入可能会导致未定义的行为

  • 您可以假设最后一行始终有一个空格。岩石应该“停在”那里,因此,在几次调用该程序之后,始终将其输出通过管道传递到自身中,您应该最后将岩石放在最后一行,放置以前的空间。

  • 您可以接受任何喜欢的格式的输入(stdin,file等)。您必须发布WHOLE程序(因此所有预初始化的变量都计为代码)。

  • 这些行以终止\n

  • 您可以在此处获得一些示例输入(确保正确复制空格!)

  • 这是,因此使用最少字节的工作提交将获胜。

  • 优胜者将在2014年7月26日被选中。您可以在此之后发布解决方案,但您不能赢

如有任何疑问,请在评论中让我知道。

打高尔夫球快乐!


就像您上一个示例一样,是否会有空白的结尾列?(因为其他人没有)
Martin Ender 2014年

@ m.buettner在最后一个示例中,只有9 #s,所以末尾只有一个空格,因为宽度为10。在这种情况下(经过几次迭代),岩石将放置在空格所在的位置(因此位于底部) -右上角)。
ChristophBöhmwalder2014年

是的,我意识到,我只是想知道我们是否可以假定情况始终如此,因为这不是您的其他示例。(话虽这么说,您的其他示例根本没有任何尾随空格。)
Martin Ender 2014年

6
错过了一个很好的机会来称它为“摇滚乐”
qwr

1
@HackerCow你是对的。通过移除字符来修复:D
马丁·恩德

Answers:


35

正则表达式(.NET,Perl,PCRE,JavaScript等),25字节

是的,这将再次引起人们关于正则表达式是否有效的争论,但是我将先发制人并说,此提交只是出于娱乐目的,不需要考虑获胜者。(与底部的31字节Perl变体相反;)。

因此,这里是一个纯正则表达式替换解决方案。

模式(注意尾随空格):

o(( *)\n#*)(?=\2) |o 

替换(注意前导空格):

 $1o

字节计数是两者之和。

您可以在http://regexhero.net/tester/上对其进行测试。确保选择Unix样式的行尾,并在粘贴时“保留粘贴的格式”。如果仍然无法使用,则您仍然粘贴了Windows样式的行尾。在这种情况下,最简单的解决方法是在模式中替换\n\r\n,以查看其是否有效。

这是一个48字节的 ECMAScript 6函数,使用此函数

f=(s)=>s.replace(/o(( *)\n#*)(?=\2) |o /,' $1o')

最后,我还有一个实际的程序。它是Perl 的31个字节(包括2个字节的for p0flags;感谢Ventero的建议!)。

s/o(( *)\n#*)(?=\2) |o / $1o/

如果要测试,甚至不要将其保存在文件中,只需执行

perl -p0e 's/o(( *)\n#*)(?=\2) |o / $1o/' < hill.txt

不幸的是,这对我不起作用(在在线测试仪中)。它只是总是将岩石向右移动。虽然40字节是一个很好的开始,但是很难克服!
ChristophBöhmwalder2014年

@HackerCow你是对的,我只是注意到有一个问题。正在修复...
Martin Ender 2014年

@HackerCow不,我认为它确实可行,但是“保留格式”会覆盖行尾,因此,如果粘贴Windows样式的行尾,则行不通(尝试替换\n\r\n
Martin Ender 2014年

对我来说,岩石靠在右边的墙壁上就不会掉落。仅当它有尾随空格时才匹配它。
BrunoJ 2014年

4
我应该如何打败这个?伟大的解决方案
qwr

3

蟒蛇-190

切片和串联恐怖,以及太多变量。我敢肯定,这可以打更多,但是我现在想不出任何聪明的python函数。输入存储在string中s

r=" "
o="o"
i=s.index(o)
b=i+int(s.split(r)[1])
q=s[:i]+r
x=s[b+3:]
try:
 a=s[b+1:b+3]
 if a[0]==r:s=q+s[i+1:b+1]+o+r+x
 elif a[1]==r:s=q+s[i+1:b+2]+o+x
 else:s=q+o+s[i+2:]
except:1
print(s)

由于python字符串是不可变的,因此我通过串联之前的所有字符,新字符以及之后的所有字符来替换字符。我使用山宽和索引来确定岩石应滚动到的位置。


3
我眼睛疼。+1
ChristophBöhmwalder2014年

2

Ruby,65/55个字符

想通了,我会看到一个解决方案要花多长时间,而不仅仅是解决这个问题。

r=gets p
r[r[(r[k=1+~/o/+x=r.to_i,2]=~/ /||-x)+k]&&=?o]=" "
$><<r

不出所料,它不比m.buettner的正则表达式解决方案短-但也不会更长。

使用解释器标志时,可以将其缩短为55个字符(代码为53个字符,标志为2个字符):

sub$_[($_[k=1+~/o/+x=$_.to_i,2]=~/ /||-x)+k]&&=?o," "

运行如下代码:

ruby -p0e 'sub$_[($_[k=1+~/o/+x=$_.to_i,2]=~/ /||-x)+k]&&=?o," "' < input

2

HTML JavaScript-251个字符

251如果您计算读取输入并返回输出的单引号内的代码。359如果您计算输入框,输入字符串,按钮等。 192如果算上只是做的工作。)

高尔夫球代码:

<pre id="i">10 5
#o        
##        
##        
######    
######### </pre><button onclick='i=document.getElementById("i");h=i.innerHTML;if(p=h.
match(/([\s\S]*?)([# ]+)(o *\n)(#+)([\s\S]*)/)){if(p[4].length>p[2].length+1)p[3]=p[3].
replace("o "," o");else{p[3]=p[3].replace("o"," ");p[5]="o"+p[5].substr(1);}p[0]="";
h=p.join("");}i.innerHTML=h;'>Go</button>

http://goo.gl/R8nOIK
一遍又一遍地单击“转到”
一遍又一遍地单击“转到”。

方法

我使用String.match()将山分成5个部分,然后更改一两个部分。我正在学习JavaScript,因此任何建议将不胜感激。

可读代码

<pre id="io">10 5
#o        
##        
##        
######    
######### </pre>

<button onclick='

    // get image
    io = document.getElementById("io");
    image = io.innerHTML;

    // break image into five parts
    // 1(10 5\n#         \n##        \n) 2(### ) 3(o     \n) 4(######) 5(    \n######### )
    if (parts = image.match(/([\s\S]*?)([# ]+)(o *\n)(#+)([\s\S]*)/)) {

        // move rock to the right
        if (parts[4].length > parts[2].length + 1)
            parts[3] = parts[3].replace("o ", " o");

        // or move rock down
        else {
            parts[3] = parts[3].replace("o", " ");
            parts[5] = "o" + parts[5].substr(1);
        }

        // return new image
        parts[0] = "";
        image = parts.join("");

        // MAP io:i image:h parts:p
    }
    io.innerHTML = image;
'>Go</button>

1

Python 2- 289 252字节

p=raw_input
w,h=map(int,p().split())
m=[p()for a in[0]*h]
j=''.join
f=lambda s:s.replace('o ',' o')
for i,r in enumerate(m):
 x=r.find('o')
 if x+1:y=i;break
if m[y+1][x]=='#':m=map(f,m);x+=1
print w,h
print'\n'.join(map(j,zip(*map(f,map(j,zip(*m))))))

我做了一些重大改进,但这仍然很糟糕。可以通过将其转换为Python 3来节省更多字节,但是我不能担心。

首先,我找到了石头。如果角色正下方是'#',更换的每个实例'o '' o'。由于保证在末尾有额外的空间,所以这将始终使岩石向右移动。

不管是否执行此操作,我都将使用调换整个网格zip(*m)。然后,我'o '用替换另一个' o'。如果岩石的右边有一个空间,则意味着在真实的网格下面有一个空间,因此它被移动了。然后我转回并打印。


这会不会搞乱OP的第三个示例,在岩石的右侧和下方有一个空白空间,并沿对角线移动它?
门把手

@dor不应该。如果下面的空间是#,我只会向右移动,并且在进行垂直移动检查之前会先进行检查。
地下

1

蟒蛇(201)

import sys
print(input())
g=list(sys.stdin.read())
o='o'
x=g.index(o)
n=x+g.index('\n')+1
try:
 if g[n]==' ':g[n]=o
 elif g[n+1]==' ':g[n+1]=o
 else:g[x+1]=o
 g[x]=' '
except:1
print(*g,sep='',end='')

1

awk,152

awk 'NR==1{w=$2}{if(NR<=w&&$0~/o/){r=index($0,"o");g=$0;getline;if(index($0,"# ")<=r){sub("o"," ",g);sub(" ","o")}else{sub("o "," o",g)}print g}print}'

更易读

    awk '
  NR==1{  //If we're at the first line, set the width from the second column in the header.
    width=$2
  }
  {
    if(NR<=width && $0~/o/){   //If not at the bottom, look for the line with the rock.
      rockIndex=index($0,"o"); //Set the position of the rock.
      orig=$0;                 //Remember the current line so we can compare it to the next.
      getline;                 //Get the next line.

      if(index($0,"# ")<= rockIndex){  //Move down: if the rock is on a cliff or on a slope,
        sub("o"," ",orig);             //update the orig so that the rock is removed
        sub(" ", "o")                  //and update the current (first available position).
      }                                         
      else {                           //Move right: if the rock is on flat ground,
        sub("o "," o", orig)           //update the orig so the the rock is advanced.
      }
      print orig                       //Print the line we skipped (but stored      
    }                                  //and updated based on the line we're now on).
    print                              //Print the line we're now on.
  }
'

0

PHP 485 484个字符

我知道,与m.buettner的参赛作品相比,这是很庞大的,但是我现在最好的办法是。我认为必须有一种更快的方法将输入字符串转换为多维数组,但是现在已经很晚了。

尽管它没有竞争力,但我还是喜欢这个难题。想要扩展名以显示球的最终位置,或经过一定数量的步长,也许在输入线上的宽度和高度之后添加。可以很容易地将其添加到此版本中。

这是我的代码:输入在第一个变量中。

<?
$a.='10 5
#o         
##       
###       
######    
#########';$b=array();$c=explode("\n",$a);$d=explode(" ",$c[0]);$e=$d[0];$f=$d[1];unset($c[0]);$g=0;foreach($c as $h){$b[$g]=str_split($h);++$g;}for($i=0;$i<$f;++$i){for($j=0;$j<$e;++$j){if($b[$i][$j]=='o'){$k=$j;$l=$i;$b[$i][$j]=' ';}}}if($b[$l+1][$k]!='#'){$b[$l+1][$k]='o';}else if($b[$l+1][$k+1]!='#'){$b[$l+1][$k+1]='o';}else{$b[$l][$k+1]='o';}echo"$e $f\n";for($i=0;$i<$f;++$i){for($j=0;$j<$e;++$j){echo $b[$i][$j];}echo "\n";}

你可以在这里看到在键盘上

编辑:更改了上面的键盘和代码,将其输出为0而不是o,这在我尝试将输出反馈到程序中时引起了问题。立即修复并保存一个字符!


0

Groovy中- 263 261 256个字符

打高尔夫球。将文件读入一个字符串,然后使用一个函数p来模拟一个函数String.putAtIndex(index,value)

o="o"
b=" "
s=new File(args[0]).text
z={s.size()-it}
s=s[0..z(2)]
w=s.find(/\n.*?\n/).size()-1
p={i,v->s=s[0..i-1]+v+((i<z(0)-2)?s[i+1..z(1)]:"")}
try{
t=s.indexOf o
i=w+t
j=i+1
x=t+1
(s[i]==b)?x=i:(s[j]==b)?x=j:0
p x,o
p t,b
}catch(Exception e){}
print s

松散(有点):

o = "o"
b = " "
s = new File(args[0]).text
z = {s.size()-it}
s = s[0..z(2)]
w = s.find(/\n.*?\n/).size()-1

putAtIndex = { i,val -> 
    s = s[0..i-1] + val + ((i<z(0)-2)?s[i+1..z(1)]:"") 
}

try {
    t=s.indexOf o
    i=w+t
    j=i+1
    x=t+1
    // default x as horizontal move
    // check for (a) directly below (b) below and over one
    (s[i]==b) ? x=i : ( (s[j]==b) ? x=j : 0)
    putAtIndex x,o
    putAtIndex t,b
} catch (Exception e) {}
print s

真好 我不知道的语言,但我几乎可以肯定,你可以得到,如果你写摆脱(至少)两个字节try{,而不是try {catch(Exception代替catch (Exception
ChristophBöhmwalder2014年

确实!感谢您的笔记....
迈克尔复活节

0

R,234

require(stringr)
g=scan(,"")
g=do.call(rbind,strsplit(str_pad(g,m<-max(nchar(g)),"r"),""))
if(g[(x<-which(g=="o"))+1]==" "){g[x+1]="o";g[x]=""}else{if(!is.na(g[x+1])){g[x+(n<-nrow(g))]="o";g[x]=""}}
for(i in 1:n) cat(g[i,],"\n",sep="")

字符串操作不是R的强项。

更具可读性:

require(stringr) # load package `stringr`, available from CRAN. required for `str_pad`
g=scan("")       # read input from console
g=do.call(       # applies the first argument (a function) to the second argument (a list of args to be passed) 
  rbind,         # "bind" arguments so that each one becomes the row of a matrix
  strsplit(      # split the first argument by the second
    str_pad(g,max(nchar(g)),"r"," "), # fill each row with whitespace
    "")
)
if(g[(x<-which(g=="o"))+1]==" ") { # if the next element down from the "o" is " "...
  g[x+1]="o";g[x]=""               # make it an "o" and replace the current element with ""
} else {
  if(!is.na(g[x+1])) {             # if the next element down is not empty (i.e. out of range)
    g[x+nrow(g)]="o"; g[x]=""      # move "o" right
  }
}
for(i in 1:n) cat(g[i,],"\n",sep="") # print to console

0

C(182)

char b[1024],*x,*n;main(z){read(0,b,1024);n=index(b,10)+1;x=index(n,'o');z=index(n,10)-n;n=x+z+1;if(n[1]){if(*n==32)*n='o';else if(n[1]==32)n[1]='o';else x[1]='o';*x=32;}printf(b);}

或者,如果您实际上想阅读代码:

char b[1024],*x,*n; //1024 byte buffer hard coded
main(z){
    read(0,b,1024);
    n=index(b,10)+1; //start of line 2
    x=index(n,'o');
    z=index(n,10)-n; //10='\n'
    n=x+z+1; //reusing n
    if(n[1]){ //if not 0
        if(*n==32) //32=' '
            *n='o';
        else if(n[1]==32)
            n[1]='o';
        else
            x[1]='o';
        *x=32;
    }
    printf(b);
}

0

Clojure-366个字符

没有正则表达式。必需的输入文件名为“ d”。打高尔夫球:

(def s(slurp "d"))(def w(-(.length(re-find #"\n.*?\n" s))2))(def t(.indexOf s "o"))(def i(+ t w 1))(defn g[i,j,x,c](cond (= x i) \ (= x j) \o :else c))(defn j[i,j] (loop[x 0](when(< x (.length s))(print(g i j x (.charAt s x)))(recur(inc x)))))(try(cond(= \ (.charAt s i))(j t i)(= \ (.charAt s (inc i)))(j t (inc i)):else (j t (inc t)))(catch Exception e (print s)))

取消高尔夫:

(def s (slurp "d"))
(def w (- (.length (re-find #"\n.*?\n" s)) 2))
(def t (.indexOf s "o"))
(def i (+ t w 1))
(defn g [i,j,x,c] (cond (= x i) \ (= x j) \o :else c))

(defn j [i,j] (loop [x 0]
     (when (< x (.length s))
     (print (g i j x (.charAt s x))) (recur (inc x)))))

(try (cond (= \ (.charAt s i)) (j t i)
           (= \ (.charAt s (inc i))) (j t (inc i))
           :else (j t (inc t)))(catch Exception e (print s)))

样品运行(为简便起见,仅一种情况):

bash-3.2$ cat d
6 7
#     
#     
#     
## o  
####  
####  
##### 

bash-3.2$ java -jar clojure-1.6.0.jar hill.clj 
6 7
#     
#     
#     
##    
####o 
####  
##### 

我是新手。欢迎提出建议。


0

MATLAB,160

function r(f)
F=cell2mat(table2array(readtable(f)));
m=@(d)mod(d-1,size(F,1));C=find(F=='o');P=find(F==' ');N=min(P(P>C&m(P)>=m(C)));F([C,N])=F([N,C]);
disp(F);

痛苦的部分是文件输入。实际的计算只有114个字节:

function F=r(F)
m=@(d)mod(d-1,size(F,1));C=find(F=='o');P=find(F==' ');N=min(P(P>C&m(P)>=m(C)));F([C,N])=F([N,C]);
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.