Рассчитайте скалу, катящуюся по склону


17

Вступление

В последнее время у Сизифа были проблемы на работе. Кажется, он просто ничего не делает, и ему очень хотелось бы найти решение этой проблемы.

Его текущая работа требует, чтобы катить камень в гору. Обычно он хорошо выполняет свою работу, но каждый раз, когда он оказывается на вершине холма, он снова падает.

Он очень расстроен своей работой и хочет научиться решать эту проблему с помощью компьютера, имитирующего скалу, катящуюся по склону.

Случилось так, что Сизиф не особенно хорош в программировании, так что, может быть, вы можете помочь ему?

Соревнование

После этого глупого вступления давайте перейдем к делу. Ваша программа получит иллюстрацию холма и скалы, которая выглядит примерно так:

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

Где #представляет собой часть холма и oпредставляет скалу.

Теперь вам нужно реализовать программу, которая перемещает слой на 1 слой вниз. Например, результат вышеупомянутого должен быть:

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

Если есть горизонтальная ровная область, холм просто катится горизонтально, так что ...

o
######## 

... это просто заставит камень катиться в сторону.

 o
######## 

Если есть вертикальная зона, камень падает на один шаг, так что ...

#o
#
#
##### 

... уступил бы ...

#
#o
#
##### 

Вы также получите ширину и высоту изображения соответственно в одну строку над изображением. Итак, в целом, наш пример ввода будет выглядеть так:

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

(Обратите внимание, что пробелами здесь являются пробелы. Выделите текст и посмотрите, что я имею в виду.)

Некоторые детали

  • Когда рок уже находится в последней строке при запуске программы, вы можете либо завершить программу, либо вывести неизмененный ввод
  • Холм спускается только вниз
  • Ваша программа должна форматировать выходные данные точно так же, как и входные данные (включая размеры), поэтому, если вы передаете выходные данные программы себе, она вычисляет следующий шаг.

  • Вы можете предположить, что всегда есть путь ко дну, поэтому ввод, где путь «заблокирован», может вызвать неопределенное поведение

  • Вы можете предположить, что в последней строке всегда есть пробел. Камень должен «отдыхать» там, так что после вызова программы несколько раз, всегда направляя ее вывод в себя, вы должны в конечном итоге получить камень в последней строке, лежащий там, где ранее было пространство.

  • Вы можете принимать ввод в любой форме, которая вам нравится (стандартный, файл, ...). Вы должны опубликовать ВЕСЬ программу (поэтому все предварительно инициализированные переменные считаются кодом).

  • Строки оканчиваются на \n.

  • Вы можете получить некоторые примеры ввода здесь (убедитесь, что вы правильно скопировали пробелы!)

  • Это , поэтому выигрывает рабочая подача с наименьшим количеством байтов .

  • Победитель будет выбран 26 июля 2014 года. После этого вы можете публиковать решения, но не можете выиграть

Если у вас есть какие-либо вопросы, дайте мне знать в комментариях.

Удачного игры в гольф!


Будет ли в конце последний столбец пробелов, как в вашем последнем примере? (потому что у других его нет)
Мартин Эндер

@ m.buettner В последнем примере всего 9 #с, так что в конце есть один пробел, потому что ширина равна 10. В этом случае (после нескольких итераций) камень будет лежать там, где есть пробел (так внизу) -правый угол).
Кристоф Бемвальдер

Да, я понимаю, что мне просто интересно, можем ли мы предположить, что это всегда так, потому что это не для других ваших примеров. (Это, как говорится, ваши другие примеры не имеют никаких пробелов вообще.)
Мартин Эндер

6
Упустил отличный шанс назвать это "Рок-н-ролл"
qwr

1
@HackerCow ты прав. Исправлено путем удаления персонажа: D
Мартин Эндер

Ответы:


35

Regex (.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')

Наконец, у меня также есть актуальная программа. Это 31 байт Perl (включая два байта для pи 0флаги; спасибо Ventero за предложение!).

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

Если вы хотите проверить это, даже не сохраняйте его в файл, просто сделайте

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

К сожалению, у меня не работает (в онлайн-тестере). Просто он всегда двигает камень вправо. 40 байтов - отличное начало, но победить будет сложно!
Кристоф Бемвальдер

@HackerCow Вы правы, я только что заметил, что есть проблема. Исправление ...
Мартин Эндер

@HackerCow Нет, я думаю, что это на самом деле работает, но «сохранение форматирования» перезаписывает конец строки, поэтому, если вы вставляете окончания строк в стиле Windows, это не работает (попробуйте заменить \nна \r\n)
Мартин Эндер,

Для меня скала не падает, когда против правой стены, т.е. это только соответствует этому, когда у этого есть завершающий пробел.
BrunoJ

4
Как я должен победить это? Отличное решение
qwr 18.07.14

3

Питон - 190

Ужас нарезки и объединения, а также слишком много переменных. Я уверен, что это может быть больше в гольфе, но я не могу сейчас думать о каких-либо умных функциях Python. Ввод сохраняется в строке 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
Кристоф Бемвальдер

2

Рубин, 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
нажимайте «Go» снова и снова
Нажмите «Перейти» снова и снова.

метод

Я использую 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'. Если есть пространство справа от скалы, это означает, что в реальной сетке есть пространство под ним, поэтому он перемещается. Затем я перевожу обратно и печатаю.


Разве это не испортило бы 3-й пример ОП, где есть пустое пространство справа и ниже камня, и переместило его по диагонали?
дверная ручка

@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 символов

Golfed. Считайте файл в строку и используйте функцию 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.
Кристоф Бемвальдер

В самом деле! Спасибо за примечание ....
Майкл Пасха

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

С (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". Golfed:

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

Ungolfed:

(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]);
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.