Hitung batu yang meluncur menuruni bukit

15

pengantar

Sisyphus mengalami masalah di tempat kerja akhir-akhir ini. Sepertinya dia tidak pernah menyelesaikan apa pun, dan dia akan senang menemukan solusi untuk masalah ini.

Pekerjaannya saat ini membutuhkan menggulingkan batu ke atas bukit. Ia biasanya melakukan pekerjaannya dengan baik, tetapi setiap kali ia berada di dekat puncak bukit, ia berguling lagi.

Dia menjadi benar-benar frustrasi dengan pekerjaannya dan ingin menyelesaikan masalah secara ilmiah dengan memiliki komputer yang mensimulasikan batu yang bergulir menuruni bukit.

Kebetulan Sisyphus tidak pandai pemrograman, jadi mungkin Anda bisa membantunya?

Tantangan

Setelah perkenalan konyol ini, mari kita berbisnis. Program Anda akan menerima ilustrasi bukit dan batu yang terlihat mirip dengan ini:

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

Dimana #mewakili bagian dari bukit dan omewakili batu.

Anda sekarang harus mengimplementasikan program yang memindahkan lapisan batu ke bawah. Sebagai contoh, output di atas harus:

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

Jika ada daerah yang rata secara horizontal, bukit hanya berguling secara horizontal, jadi ...

o
######## 

... ini hanya akan membuat gulungan batu ke samping.

 o
######## 

Jika ada area vertikal, batu itu jatuh ke bawah satu langkah, jadi ...

#o
#
#
##### 

... akan menghasilkan ...

#
#o
#
##### 

Anda juga akan menerima lebar dan tinggi gambar masing-masing dalam satu baris di atas gambar. Jadi, secara lengkap, input sampel kami akan terlihat seperti ini:

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

(Perhatikan bahwa spasi putih di sini adalah spasi. Pilih teks dan lihat apa yang saya maksud.)

Beberapa detail

  • Ketika rock sudah berada di baris terakhir saat menjalankan program, Anda dapat memilih untuk menghentikan program atau output input yang tidak berubah
  • Bukit hanya turun ke bawah
  • Program Anda harus memformat output persis sama dengan input (termasuk dimensi), jadi jika Anda menyalurkan output program itu sendiri, ia menghitung langkah selanjutnya.

  • Anda dapat mengasumsikan selalu ada jalan ke bawah, jadi masukan tempat jalur "diblokir" dapat menyebabkan perilaku yang tidak ditentukan

  • Anda dapat mengasumsikan selalu ada spasi di baris terakhir. Batu itu harus "beristirahat" di sana, jadi setelah memanggil program beberapa kali, selalu menyalurkan outputnya ke dalam dirinya sendiri, Anda harus berakhir dengan batu di baris terakhir, meletakkan di tempat ruang sebelumnya.

  • Anda dapat menerima input dalam bentuk apa pun yang Anda suka (stdin, file, ...). Anda harus memposting program SELURUH (sehingga semua variabel pra-diinisialisasi dihitung sebagai kode).

  • Garis diakhiri dengan \n.

  • Anda bisa mendapatkan beberapa input contoh di sini (pastikan Anda menyalin spasi dengan benar!)

  • Ini adalah , sehingga pengiriman karya dengan byte paling sedikit akan menang.

  • Pemenang akan dipilih pada 26 Juli 2014. Anda dapat memposting solusi setelah itu, tetapi Anda tidak bisa menang

Jika Anda memiliki pertanyaan, beri tahu saya di komentar.

Selamat bermain golf!

Christoph Böhmwalder
sumber
Apakah akan ada kolom tambahan spasi putih seperti pada contoh terakhir Anda? (karena yang lain tidak memilikinya)
Martin Ender
@ m.buettner Dalam contoh terakhir hanya ada 9 #s, jadi ada satu ruang di ujungnya karena lebarnya adalah 10. Dalam hal ini (setelah beberapa iterasi) batu akan terletak di tempat spasi putih (jadi di bagian bawah -pojok kanan).
Christoph Böhmwalder
Ya, saya menyadari itu, saya hanya ingin tahu apakah kita dapat berasumsi bahwa itu selalu terjadi, karena itu bukan untuk contoh Anda yang lain. (Seperti yang dikatakan, contoh-contoh Anda yang lain tidak memiliki spasi spasi sama sekali.)
Martin Ender
6
Kehilangan kesempatan besar untuk menyebutnya "Rock and Roll"
qwr
1
@HackerCow Anda benar. Diperbaiki dengan menghapus karakter: D
Martin Ender

Jawaban:

33

Regex (.NET, Perl, PCRE, JavaScript, ... rasa), 25 byte

Ya, ini akan menimbulkan perdebatan lagi, apakah ekspresi reguler adalah program yang valid, tetapi saya akan mencegahnya dan mengatakan bahwa pengajuan ini hanya untuk bersenang-senang dan tidak perlu dipertimbangkan untuk pemenang. (Berbeda dengan varian Perl 31 byte di bagian bawah;).)

Jadi di sini adalah solusi penggantian regex murni.

Pola (perhatikan ruang trailing):

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

Penggantian (perhatikan ruang utama):

 $1o

Hitungan byte adalah untuk jumlah keduanya.

Anda dapat mengujinya di http://regexhero.net/tester/ . Pastikan untuk memilih ujung garis bergaya Unix dan "pertahankan format yang disisipkan" saat menempel. Jika masih tidak berhasil, Anda masih telah menempelkan ujung garis gaya Windows. Perbaikan termudah dalam hal itu adalah untuk mengganti \ndengan \r\ndalam pola untuk melihat itu berfungsi.

Berikut adalah fungsi 48 byte ECMAScript 6 yang menggunakan ini

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

Akhirnya, saya juga punya program yang sebenarnya. Ini 31 byte Perl (termasuk dua byte untuk pdan 0bendera; terima kasih kepada Ventero untuk sarannya!).

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

Jika Anda ingin mengujinya, jangan menyimpannya dalam file, lakukan saja

perl -p0e 's/o(( *)\n#*)(?=\2) |o / $1o/' < hill.txt
Martin Ender
sumber
Sayangnya tidak berfungsi untuk saya (dalam tester online). Itu hanya selalu memindahkan batu ke kanan. 40 byte adalah awal yang baik, itu akan sulit dikalahkan!
Christoph Böhmwalder
@ HackCow Kau benar, aku baru tahu ada masalah. Memperbaiki ...
Martin Ender
@HackerCow Tidak, saya pikir ini benar-benar berfungsi, tetapi "pertahankan pemformatan" menimpa akhir baris, jadi jika Anda menempelkan ujung garis gaya Windows tidak berfungsi (coba ganti \ndengan \r\n)
Martin Ender
Bagi saya batu itu tidak jatuh ketika berhadapan dengan dinding kanan, yaitu. itu hanya cocok ketika memiliki ruang tambahan.
BrunoJ
4
Bagaimana saya bisa mengalahkan ini? Solusi hebat
qwr
3

Python - 190

Mengiris dan merangkai horor, serta terlalu banyak variabel. Saya yakin ini bisa bermain golf lebih banyak, tapi saya tidak bisa memikirkan fungsi python yang pintar saat ini. Input disimpan dalam 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)

Karena string python tidak dapat diubah, saya mengganti karakter dengan menggabungkan semua karakter sebelumnya, karakter baru saya, dan semua karakter setelahnya. Saya menggunakan lebar bukit dan pengindeksan untuk menentukan di mana batu harus menggulung.

qwr
sumber
3
Mataku sakit. +1
Christoph Böhmwalder
2

Ruby, 65/55 karakter

Kupikir saya akan melihat berapa lama solusi itu tidak hanya membuang masalah pada masalah.

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

Seperti yang diharapkan, ini tidak sesingkat solusi regex m.buettner - tetapi juga tidak lebih lama.

Saat menggunakan bendera juru bahasa, ini dapat disingkat menjadi 55 karakter (53 untuk kode, 2 untuk bendera):

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

Jalankan kode seperti ini:

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

JavaScript HTML - 251 karakter

( 251 jika Anda menghitung kode di dalam tanda kutip tunggal yang membaca input dan mengembalikan output. 359 jika Anda menghitung kotak input, string input, tombol, dll. 192 jika Anda menghitung hanya itu yang berfungsi.)

Kode 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
klik "Pergi" berulang-ulang
Klik "Pergi" berulang kali.

metode

Saya menggunakan String.match () untuk memecah bukit menjadi 5 bagian, lalu saya mengubah satu atau dua bagian. Saya sedang belajar JavaScript, jadi saran apa pun akan dihargai.

Kode yang Dapat Dibaca

<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>
JeffSB
sumber
1

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

Saya membuat beberapa perbaikan signifikan tetapi ini masih mengerikan. Beberapa byte lagi dapat disimpan dengan mengonversikannya ke Python 3 tetapi saya tidak dapat menambahkannya.

Pertama, saya menemukan batu itu. Jika karakter tepat di bawahnya '#', ganti setiap instance 'o 'dengan ' o'. Karena dijamin ada ruang ekstra di ujungnya, ini akan selalu memindahkan batu ke kanan.

Terlepas dari apakah saya hanya melakukan itu atau tidak, saya memindahkan seluruh grid dengan zip(*m). Lalu, saya melakukan penggantian lain 'o 'dengan ' o'. Jika ada ruang di sebelah kanan batu, itu berarti bahwa di kotak nyata ada ruang di bawahnya, jadi itu akan dipindahkan. Kemudian saya memindahkan kembali dan mencetak.

monmon bawah tanah
sumber
Bukankah ini akan mengacaukan contoh OP 3, di mana ada ruang kosong di sebelah kanan dan di bawah batu, dan memindahkannya secara diagonal?
Gagang pintu
@dor Tidak seharusnya. Saya hanya bergerak ke kanan jika ruang di bawahnya #, dan saya melakukan pemeriksaan itu sebelum saya melakukan pemeriksaan untuk bergerak secara vertikal.
undergroundmonorail
1

Python (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='')
Ian D. Scott
sumber
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}'

Lebih Mudah Dibaca

    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.
  }
'
Julian Peeters
sumber
0

php 485 484 karakter

Saya tahu ini sangat besar dibandingkan dengan entri oleh m.buettner tetapi yang terbaik yang bisa saya lakukan untuk saat ini. Saya pikir pasti ada cara yang lebih cepat untuk mengubah string input menjadi array multi dimensi tetapi sekarang sudah sangat terlambat.

Dan meskipun tidak kompetitif saya menyukai puzzle ini. Ingin ekstensi untuk menunjukkan di mana bola berakhir, atau setelah sejumlah langkah, mungkin ditambahkan setelah lebar dan tinggi pada jalur input. Dapat menambahkan itu dengan sangat mudah ke versi ini.

Ini kode saya: Input ada di variabel pertama.

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

Anda dapat melihatnya di sini dalam aksi di codepad

Sunting: Mengubah codepad dan kode di atas seperti mengeluarkan 0 bukan o, yang menyebabkan masalah ketika saya mencoba untuk memberi makan keluaran kembali ke program. Memperbaiki sekarang dan menyimpan satu char!

Paul Drewett
sumber
0

Groovy - 263 261 256 karakter

Golf. Baca file menjadi String, dan gunakan fungsi puntuk meniru suatu fungsi 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

Tidak digabungkan (agak):

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
Michael Easter
sumber
Bagus. Saya tidak tahu bahasanya, tapi saya hampir yakin Anda bisa menyingkirkan (setidaknya) dua byte jika Anda menulis try{alih- alih try {dan catch(Exceptionbukannya catch (Exception.
Christoph Böhmwalder
Memang! Terima kasih atas catatannya ...
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="")

Manipulasi string bukan titik terkuat R.

Lebih mudah dibaca:

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

Atau, jika Anda benar-benar ingin membaca kode:

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);
}
Ian D. Scott
sumber
0

Clojure - 366 karakter

Tanpa regex. File input yang diperlukan bernama "d". Golf:

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

Tidak Disatukan:

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

Contoh dijalankan (hanya satu kasus, untuk singkatnya):

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

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

Saya seorang pemula. Saran diterima.

Michael Easter
sumber
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);

Bagian yang menyakitkan adalah input file. Perhitungan aktual hanya akan menjadi 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]);
knedlsepp
sumber