Tính một hòn đá lăn xuống một ngọn đồi


15

Giới thiệu

Sisyphus đã gặp một số rắc rối trong công việc gần đây. Có vẻ như anh ta không bao giờ làm được gì, và anh ta rất thích tìm giải pháp cho vấn đề này.

Việc làm hiện tại của anh ta đòi hỏi phải lăn một tảng đá lên một ngọn đồi. Anh ấy thường làm tốt công việc của mình, nhưng mỗi lần anh ấy ở gần đỉnh đồi thì lại lăn xuống.

Anh ta đang thực sự thất vọng với công việc của mình và muốn giải quyết vấn đề một cách khoa học bằng cách có một máy tính mô phỏng tảng đá lăn xuống đồi.

Điều đó xảy ra khi Sisyphus không giỏi lập trình, vì vậy có lẽ bạn có thể giúp anh ta?

Các thách thức

Sau phần giới thiệu ngớ ngẩn này, chúng ta hãy đến với doanh nghiệp. Chương trình của bạn sẽ nhận được một minh họa về ngọn đồi và tảng đá trông giống như thế này:

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

Nơi #đại diện cho một phần của ngọn đồi vào đại diện cho đá.

Bây giờ bạn phải thực hiện một chương trình di chuyển lớp đá 1 xuống. Ví dụ: đầu ra của ở trên phải là:

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

Nếu có một khu vực theo chiều ngang, ngọn đồi chỉ cuộn theo chiều ngang, vì vậy ...

o
######## 

... điều này sẽ làm cho đá lăn sang một bên.

 o
######## 

Nếu có một khu vực thẳng đứng, tảng đá rơi xuống một bước, vì vậy ...

#o
#
#
##### 

... sẽ mang lại ...

#
#o
#
##### 

Bạn cũng sẽ nhận được chiều rộng và chiều cao của hình ảnh tương ứng trong một dòng phía trên hình ảnh. Vì vậy, hoàn thành, đầu vào mẫu của chúng tôi sẽ trông như thế này:

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

(Lưu ý rằng khoảng trắng ở đây là khoảng trắng. Chọn văn bản và xem ý tôi là gì.)

Một số chi tiết

  • Khi rock đã ở dòng cuối cùng khi chạy chương trình, bạn có thể chọn chấm dứt chương trình hoặc xuất đầu vào không thay đổi
  • Ngọn đồi chỉ đi xuống
  • Chương trình của bạn nên định dạng đầu ra chính xác giống như đầu vào (bao gồm cả kích thước), vì vậy nếu bạn đặt đầu ra của chương trình cho chính nó, nó sẽ tính bước tiếp theo.

  • Bạn có thể giả sử luôn có một cách ở phía dưới, vì vậy, đầu vào nơi đường dẫn bị "chặn" có thể gây ra hành vi không xác định

  • Bạn có thể cho rằng luôn có một khoảng trống ở dòng cuối cùng. Đá nên "nghỉ ngơi" ở đó, vì vậy sau khi gọi chương trình một vài lần, luôn luôn đưa đầu ra của nó vào chính nó, bạn nên kết thúc với tảng đá ở dòng cuối cùng, đặt nơi không gian trước đó.

  • Bạn có thể chấp nhận đầu vào dưới bất kỳ hình thức nào bạn thích (stdin, file, ...). Bạn phải đăng chương trình WHOLE (vì vậy tất cả các biến được khởi tạo trước được tính là mã).

  • Các dòng được kết thúc với \n.

  • Bạn có thể lấy một số ví dụ đầu vào ở đây (đảm bảo bạn sao chép chính xác các khoảng trắng!)

  • Đây là , vì vậy bài dự thi có ít byte nhất sẽ thắng.

  • Người chiến thắng sẽ được chọn vào ngày 26 tháng 7 năm 2014. Bạn có thể đăng các giải pháp sau đó, nhưng bạn không thể thắng

Nếu bạn có bất kỳ câu hỏi, cho tôi biết trong các ý kiến.

Chúc bạn chơi golf vui vẻ!


Sẽ có một cột dấu cách của khoảng trắng như trong ví dụ cuối cùng của bạn? (vì những người khác không có nó)
Martin Ender

@ m.buettner Trong ví dụ trước chỉ có 9 #s, do đó, có một khoảng trống ở cuối vì chiều rộng là 10. Trong trường hợp này (sau một vài lần lặp), tảng đá sẽ nằm trong khoảng trắng (ở dưới cùng -góc phải).
Christoph Böhmwalder

Vâng, tôi nhận ra rằng, tôi chỉ tự hỏi liệu chúng ta có thể cho rằng luôn luôn như vậy không, bởi vì nó không dành cho các ví dụ khác của bạn. (Như đã nói, các ví dụ khác của bạn không có bất kỳ khoảng trắng nào ở cuối.)
Martin Ender

6
Bỏ lỡ một cơ hội tuyệt vời để gọi nó là "Rock and Roll"
qwr

1
@HackerCow bạn nói đúng. Đã sửa bằng cách xóa ký tự: D
Martin Ender

Câu trả lời:


33

Regex (.NET, Perl, PCRE, JavaScript, ... hương vị), 25 byte

Vâng, điều này sẽ tạo ra một số cuộc tranh luận một lần nữa, cho dù một biểu thức chính quy là một chương trình hợp lệ, nhưng tôi sẽ nói trước điều đó và nói rằng bài nộp này chỉ để giải trí và không cần phải xem xét cho người chiến thắng. (Trái ngược với biến thể Perl 31 byte ở phía dưới;).)

Vì vậy, đây là một giải pháp thay thế regex tinh khiết.

Mẫu (lưu ý không gian dấu):

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

Thay thế (lưu ý không gian hàng đầu):

 $1o

Tổng số byte là tổng của hai.

Bạn có thể kiểm tra nó tại http://regexhero.net/tester/ . Đảm bảo chọn các kết thúc dòng theo kiểu Unix và "giữ nguyên định dạng đã dán" khi dán. Nếu nó vẫn không hoạt động, bạn vẫn dán các kết thúc dòng kiểu Windows. Cách khắc phục dễ nhất trong trường hợp đó là thay thế \nbằng\r\n trong mẫu để thấy rằng nó hoạt động.

Đây là một hàm ECMAScript 6 48 byte bằng cách sử dụng này

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

Cuối cùng, tôi cũng đã có một chương trình thực tế. Đó là 31 byte Perl (bao gồm hai byte cho p0cờ; nhờ Ventero cho gợi ý!).

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

Nếu bạn muốn kiểm tra nó, thậm chí không lưu nó trong một tệp, chỉ cần làm

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

Thật không may cho tôi không may (trong thử nghiệm trực tuyến). Nó chỉ luôn luôn di chuyển đá sang phải. 40 byte là một khởi đầu tuyệt vời, điều đó sẽ khó đánh bại!
Christoph Böhmwalder

@HackerCow Bạn nói đúng, tôi chỉ nhận thấy có một vấn đề. Đang sửa chữa ...
Martin Ender

@HackerCow Không, tôi nghĩ rằng nó thực sự hoạt động, nhưng "giữ gìn định dạng" ghi đè dòng kết thúc, vì vậy nếu bạn dán dòng cuối của Windows theo phong cách nó không làm việc (thử thay thế \nbằng \r\n)
Martin Ender

Đối với tôi, tảng đá không rơi khi vào tường bên phải, tức là. nó chỉ phù hợp với nó khi nó có một không gian dấu.
BrunoJ

4
Làm thế nào tôi có thể đánh bại điều này? Giải pháp tuyệt vời
qwr 18/07/14

3

Con trăn - 190

Cắt lát và ghép kinh dị, cùng với quá nhiều biến số. Tôi chắc chắn điều này có thể được đánh gôn nhiều hơn, nhưng tôi không thể nghĩ ra bất kỳ chức năng trăn thông minh nào ngay bây giờ. Đầu vào được lưu trữ trong chuỗi 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)

Vì chuỗi trăn là bất biến, tôi thay thế một ký tự bằng cách ghép tất cả các ký tự trước, ký tự mới của tôi và tất cả các ký tự sau. Tôi sử dụng chiều rộng của ngọn đồi và lập chỉ mục để xác định nơi đá nên lăn đến.


3
Mắt tôi đau. +1
Christoph Böhmwalder

2

Ruby, 65/55 ký tự

Hình tôi sẽ thấy một giải pháp là bao lâu mà không chỉ đưa ra một biểu thức chính thức cho vấn đề.

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

Như mong đợi, nó không ngắn như giải pháp regex của m.buettner - nhưng cũng không lâu hơn.

Khi sử dụng cờ thông dịch, có thể rút ngắn thành 55 ký tự (53 cho mã, 2 cho các cờ):

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

Chạy mã như thế này:

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

2

HTML JavaScript - ký tự 251

( 251 nếu bạn đếm mã bên trong các dấu ngoặc đơn đọc đầu vào và trả về đầu ra. 359 nếu bạn đếm hộp đầu vào, chuỗi đầu vào, nút, v.v. 192 nếu bạn chỉ tính công việc đó.)

Mã golf:

<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
bấm "Đi" nhiều lần
Nhấp vào "Đi" nhiều lần.

phương pháp

Tôi sử dụng String.match () để chia đồi thành 5 phần, sau đó tôi thay đổi một hoặc hai phần. Tôi đang học JavaScript, vì vậy mọi đề xuất sẽ được đánh giá cao.

Mã dễ đọc

<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

Con trăn 2 - 289 252 byte

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))))))

Tôi đã thực hiện một số cải tiến đáng kể nhưng điều này vẫn còn khủng khiếp. Có thể lưu thêm một vài byte bằng cách chuyển đổi nó thành Python 3 nhưng tôi không thể truy cập được.

Đầu tiên, tôi tìm đá. Nếu ký tự ngay bên dưới nó '#', thay thế mọi trường hợp 'o 'bằng ' o'. Vì cuối cùng được đảm bảo là một không gian thừa, điều này sẽ luôn di chuyển hòn đá sang phải.

Bất kể tôi có làm như vậy hay không, tôi chuyển đổi toàn bộ lưới với zip(*m). Sau đó, tôi làm một thay thế khác của'o ' với ' o'. Nếu có một khoảng trống ở bên phải của tảng đá, điều đó có nghĩa là trong lưới thực sự có một khoảng trống bên dưới nó, vì vậy nó sẽ được di chuyển. Sau đó tôi chuyển trở lại và in.


Điều này có làm xáo trộn ví dụ thứ 3 của OP không, nơi có không gian trống ở bên phải và bên dưới tảng đá, và di chuyển nó theo đường chéo?
Doorknob

@dor Không nên. Tôi chỉ di chuyển sang phải nếu không gian bên dưới là #và tôi thực hiện kiểm tra đó trước khi thực hiện kiểm tra để di chuyển theo chiều dọc.
undergroundmonorail

1

Con trăn (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

ôi, 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}'

Dễ đọc hơn

    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 ký tự 485 484

Tôi biết điều này là rất lớn so với mục nhập của m.buettner nhưng tốt nhất tôi có thể làm bây giờ. Tôi nghĩ rằng phải có một cách nhanh hơn để biến chuỗi đầu vào thành một mảng đa chiều nhưng bây giờ đã rất muộn.

Và mặc dù nó không cạnh tranh, tôi thích câu đố này. Muốn phần mở rộng hiển thị nơi bóng kết thúc hoặc sau một số bước đã đặt, có thể được thêm sau chiều rộng và chiều cao trên dòng đầu vào. Có thể thêm nó rất dễ dàng vào phiên bản này.

Đây là mã của tôi: Đầu vào là trong biến đầu tiên.

<?
$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";}

Bạn có thể thấy nó ở đây trong hành động trên codepad

Chỉnh sửa: Đã thay đổi codepad và mã ở trên như xuất ra 0 thay vì o, điều này gây ra vấn đề khi tôi cố gắng đưa đầu ra trở lại chương trình. Đã sửa bây giờ và lưu một char!


0

Groovy - 263 261 256 ký tự

Chơi gôn. Đọc tệp thành Chuỗi và sử dụng hàm pđể mô phỏng hàm 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

Ungolfed (phần nào):

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

Đẹp. Tôi không biết ngôn ngữ này, nhưng tôi gần như chắc chắn rằng bạn có thể loại bỏ (ít nhất) hai byte nếu bạn viết try{thay vì try {catch(Exceptionthay vì catch (Exception.
Christoph Böhmwalder

Thật! Cảm ơn bạn đã ghi chú ....
Michael Easter

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="")

Thao tác chuỗi không phải là điểm mạnh nhất của R.

Dễ đọc hơn:

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

Hoặc, nếu bạn thực sự muốn đọc mã:

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 - 365 ký tự

Không có regex. Tập tin đầu vào cần thiết có tên "d". Chơi gôn

(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)))

Ung dung:

(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)))

Chạy mẫu (chỉ một trường hợp, cho ngắn gọn):

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

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

Tôi là người mới. Gợi ý chào mừng.


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

Phần đau đớn là đầu vào tập tin. Tính toán thực tế sẽ chỉ có 114 byte:

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]);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.