Обчисліть скелю, що котиться в гору


17

Вступ

Сизіф останнім часом мав деякі проблеми на роботі. Здається, він просто ніколи нічого не робить, і він би хотів знайти рішення цієї проблеми.

Його теперішня робота вимагає кочення скелі в гору. Зазвичай він добре виконує свою роботу, але щоразу, коли знаходиться біля вершини пагорба, він знову котиться вниз.

Він дуже засмучений своєю роботою і хоче вирішити проблему науково за допомогою комп'ютера, що імітує скелю, котившись у гору.

Так трапляється, що Сизіф не особливо хороший у програмуванні, тож, може, ти можеш йому допомогти?

Змагання

Після цього дурного вступу, давайте приступимо до справи. Ваша програма отримає ілюстрацію пагорба та скелі, яка виглядає приблизно так:

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

Де #являє собою частину пагорба і oявляє собою скелю.

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

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

Якщо є горизонтально рівна ділянка, пагорб просто котиться горизонтально, так що ...

o
######## 

... це просто зробить камінний рулон набік.

 o
######## 

Якщо є вертикальна площа, скеля падає вниз на один крок, тому ...

#o
#
#
##### 

... принесуть ...

#
#o
#
##### 

Ви також отримаєте ширину та висоту зображення відповідно в одному рядку над зображенням. Таким чином, в нашому прикладі вибірки буде виглядати приблизно так:

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

(Зверніть увагу, що пробіли тут є пробілами. Виберіть текст і подивіться, що я маю на увазі.)

Деякі деталі

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

  • Ви можете припустити, що завжди є шлях до низу, тому введення, де шлях «заблокований», може спричинити не визначену поведінку

  • Можна припустити, що в останньому рядку завжди є пробіл. Скеля повинна там «відпочити», тому після виклику програми декілька разів, завжди прокладаючи її вихід у себе, ви повинні в кінцевому підсумку зі скелею в останньому рядку, лежачи там, де раніше був простір.

  • Ви можете прийняти вхід у будь-якій формі, яку вам подобається (stdin, файл, ...). Ви повинні розмістити програму WHOLE (тому всі попередньо ініціалізовані змінні вважаються кодом).

  • Лінії закінчуються с \n.

  • Ви можете отримати деякі приклади входів тут (переконайтеся , що ви скопіювали прогалини правильно!)

  • Це , тому робоче подання з найменшими байтами виграє.

  • Переможець буде обраний 26 липня 2014 року. Ви можете розміщувати рішення після цього, але ви не можете перемогти

Якщо у вас є якісь питання, повідомте мене в коментарях.

Щасливого гольфу!


Чи буде стовпець пробілу, як у вашому останньому прикладі? (тому що у інших цього немає)
Мартін Ендер

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

Так, я розумію, що мені було просто цікаво, чи можна вважати, що це завжди так, бо це не для інших ваших прикладів. (За словами, у ваших інших прикладів взагалі немає пробілу пробілу.)
Мартін Ендер


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прапори; завдяки Вентеро за пропозицію!).

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

3

Пітон - 190

Жах нарізки та конкатенації, а також занадто багато змінних. Я впевнений, що це може бути більше гольфу, але я не можу придумати жодних розумних функцій пітона. Введення зберігається в рядку 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
натискайте кнопку "Перейти" знову і знову
Клацніть "Перейти" знову та знову.

Метод

Я використовую 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

Пітон 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'. Якщо праворуч від скелі є пробіл, це означає, що в реальній сітці є простір під нею, тому він рухається. Потім перекладаю назад і друкую.


Хіба це не зіпсує третій приклад ОП, де порожній простір праворуч від скелі та під нею, і не перемістить його по діагоналі?
Дверна ручка

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

Гольф. Прочитайте файл у String та використовуйте функцію 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

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]);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.