Calcular uma rocha rolando ladeira abaixo


15

Introdução

Sísifo estava tendo alguns problemas no trabalho recentemente. Parece que ele simplesmente nunca faz nada e gostaria de encontrar uma solução para esse problema.

Seu emprego atual exige rolar uma pedra morro acima. Ele costuma fazer bem seu trabalho, mas toda vez que está perto do topo da colina, ele desce novamente.

Ele está realmente frustrado com seu trabalho e quer resolver o problema cientificamente, fazendo com que um computador simule a rocha rolando ladeira abaixo.

Acontece que Sísifo não é particularmente bom em programação, então talvez você possa ajudá-lo?

O desafio

Após esta introdução boba, vamos aos negócios. Seu programa receberá uma ilustração da colina e da rocha parecida com esta:

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

Onde #representa uma parte da colina e orepresenta a rocha.

Agora você precisa implementar um programa que move a camada 1 do rock para baixo. Por exemplo, a saída do acima deve ser:

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

Se houver uma área horizontalmente plana, a colina rola horizontalmente, então ...

o
######## 

... isso faria a pedra rolar para o lado.

 o
######## 

Se houver uma área vertical, a rocha cai um passo, então ...

#o
#
#
##### 

... renderia ...

#
#o
#
##### 

Você também receberá a largura e a altura da imagem, respectivamente, em uma linha acima da imagem. Portanto, em resumo, nossa amostra de entrada seria assim:

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

(Observe que os espaços em branco aqui são espaços. Selecione o texto e veja o que quero dizer.)

Alguns detalhes

  • Quando o rock já está na última linha ao executar o programa, você pode optar por encerrar o programa ou emitir a entrada inalterada
  • A colina só desce
  • Seu programa deve formatar a saída exatamente da mesma forma que a entrada (incluindo as dimensões); portanto, se você canalizar a saída do programa para si próprio, ele calculará a próxima etapa.

  • Você pode assumir que sempre existe um caminho para o final, portanto, a entrada em que o caminho está "bloqueado" pode causar um comportamento indefinido

  • Você pode assumir que sempre há um espaço na última linha. A rocha deve "descansar" lá, então, depois de chamar o programa algumas vezes, sempre canalizando sua saída para si mesma, você deve acabar com a rocha na última linha, colocando onde estava o espaço anteriormente.

  • Você pode aceitar qualquer forma que desejar (stdin, arquivo, ...). Você precisa postar o programa INTEIRO (para que todas as variáveis ​​pré-inicializadas contem como código).

  • As linhas são terminadas com \n.

  • Você pode obter alguns exemplos de entradas aqui (certifique-se de copiar os espaços corretamente!)

  • Isso é , então a submissão de trabalho com o mínimo de bytes vence.

  • O vencedor será escolhido em 26 de julho de 2014. Você pode postar soluções depois disso, mas não poderá vencer

Se você tiver alguma dúvida, me informe nos comentários.

Feliz golfe!


Haverá uma coluna de espaço em branco à direita, como no seu último exemplo? (porque os outros não o têm)
Martin Ender

@ m.buettner No último exemplo, existem apenas 9 #s, então existe um espaço no final porque a largura é 10. Nesse caso (após algumas iterações), a rocha ficava onde o espaço em branco está (portanto, na parte inferior) -Esquina direita).
Christoph Böhmwalder

Sim, percebi que estava pensando se podemos assumir que esse é sempre o caso, porque não é para seus outros exemplos. (Dito isto, seus outros exemplos não têm nenhum espaço em branco à direita).
Martin Ender

6
Perdeu uma grande chance de chamá-lo de "Rock and Roll"
qwr 19/07/14

1
@HackerCow você está certo. Corrigido removendo um personagem: D
Martin Ender

Respostas:


33

Regex (.NET, Perl, PCRE, JavaScript, ... sabores), 25 bytes

Sim, isso criará algum debate novamente, se uma expressão regular é um programa válido, mas vou antecipar isso e dizer que esse envio é apenas por diversão e não precisa ser considerado para o vencedor. (Ao contrário da variante Perl de 31 bytes na parte inferior;).)

Então, aqui está uma solução pura de substituição de regex.

Padrão (observe o espaço à direita):

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

Substituição (observe o espaço à esquerda):

 $1o

A contagem de bytes é para a soma dos dois.

Você pode testá-lo em http://regexhero.net/tester/ . Certifique-se de escolher finais de linha no estilo Unix e "preservar a formatação colada" ao colar. Se ainda assim não funcionar, você ainda colou as terminações de linha no estilo do Windows. A correção mais fácil nesse caso é substituir \ncom \r\nno padrão para ver que ele funciona.

Aqui está uma função ECMAScript 6 de 48 bytes usando este

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

Finalmente, eu também tenho um programa real. São 31 bytes de Perl (incluindo dois bytes para pe 0sinalizadores; graças a Ventero pela sugestão!).

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

Se você quiser testá-lo, nem salve em um arquivo, apenas faça

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

Infelizmente, não funciona para mim (no testador online). Ele sempre move a pedra para a direita. 40 bytes é um ótimo começo, porém, será difícil de vencer!
Christoph Böhmwalder

@HackerCow Você está certo, acabei de perceber que há um problema. Consertando ...
Martin Ender

@HackerCow Não, eu acho que ele realmente funciona, mas "preservar a formatação" substitui a linha que termina, por isso, se você colar finais de linha de estilo do Windows não funciona (tente substituir \ncom \r\n)
Martin Ender

Para mim, a pedra não cai quando está contra a parede direita, ou seja. ele só corresponde quando tem um espaço à direita.
brunoJ

4
Como vou vencer isso?
Boa

3

Python - 190

Horror em fatias e concatenação, junto com muitas variáveis. Estou certo de que isso pode ser mais divertido, mas não consigo pensar em nenhuma função python inteligente no momento. A entrada é armazenada na strings .

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)

Como as strings python são imutáveis, substituo um caracter concatenando todos os caracteres anteriores, meu novo caractere e todos os caracteres posteriores. Eu uso a largura da colina e a indexação para determinar para onde a rocha deve rolar.


3
Meus olhos doem. +1
Christoph Böhmwalder

2

Ruby, 65/55 caracteres

Imaginei que veria quanto tempo uma solução é que não apenas lança uma expressão regular sobre o problema.

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

Como esperado, não é tão curto quanto a solução de regex de m.buettner - mas também não muito mais.

Ao usar sinalizadores de intérprete, isso pode ser reduzido para 55 caracteres (53 para o código, 2 para os sinalizadores):

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

Execute o código assim:

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

2

HTML JavaScript - 251 caracteres

( 251 se você contar o código entre aspas simples que lê a entrada e retornar a saída. 359 se você contar a caixa de entrada, a seqüência de caracteres de entrada, o botão etc. 192 se contar apenas o que faz o trabalho).

Código de golfe:

<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
clique em "Ir" repetidamente
Clique em "Ir" repetidamente.

Método

Eu uso String.match () para quebrar a colina em 5 partes, depois altero uma ou duas partes. Como estou aprendendo JavaScript, qualquer sugestão será apreciada.

Código legível

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

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

Fiz algumas melhorias significativas, mas isso ainda é terrível. Mais alguns bytes podem ser salvos convertendo-os em Python 3, mas não posso ser eliminado.

Primeiro, encontro a rocha. Se o caractere imediatamente abaixo dele estiver '#', substitua todas as instâncias de 'o 'por ' o'. Como é garantido que há um espaço extra no final, isso sempre moverá a rocha para a direita.

Independentemente de eu ter feito isso ou não, transponho toda a grade zip(*m). Então, eu faço outra substituição de 'o 'com ' o'. Se houver um espaço à direita da rocha, isso significa que na grade real há um espaço abaixo dela, para que ela seja movida. Depois transponho de volta e imprimo.


Isso não atrapalharia o terceiro exemplo do OP, onde há espaço vazio à direita e abaixo da rocha e movê-lo na diagonal?
Maçaneta

@dor Não deveria. Eu só movo para a direita se o espaço abaixo for #, e faço essa verificação antes de fazer a verificação para mover verticalmente.
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='')

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}'

Mais legível

    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 chars

Eu sei que isso é enorme em comparação com a entrada de m.buettner, mas é o melhor que posso fazer por enquanto. Eu acho que deve haver uma maneira mais rápida de transformar a string de entrada em uma matriz multidimensional, mas é muito tarde agora.

E apesar de não ser competitivo, gostei deste quebra-cabeça. Deseja que a extensão mostre onde a bola termina, ou após um número definido de etapas, talvez adicionado após a largura e a altura na linha de entrada. Poderia adicionar isso muito facilmente a esta versão.

Aqui está o meu código: A entrada está na primeira variável.

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

Você pode vê-lo aqui em ação no codepad

Edit: O codepad alterado e o código acima, como estava produzindo 0 em vez de o, causaram problemas quando tentei alimentar a saída novamente no programa. Corrigido agora e salvou um caractere!


0

Groovy - 263 261 256 caracteres

Golfed. Leia o arquivo em uma String e use uma função ppara emular uma função 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 (um pouco):

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

Agradável. Eu não sei o idioma, mas estou quase certo que você pode se livrar de (pelo menos) dois bytes se você escrever try{em vez de try {e catch(Exceptionem vez de catch (Exception.
Christoph Böhmwalder

De fato! Obrigado pela nota ....
Michael Páscoa

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

A manipulação de cordas não é o ponto mais forte de R.

Mais facilmente:

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

Ou, se você realmente quiser ler o código:

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 caracteres

Sem regex. Arquivo de entrada obrigatório chamado "d". Golfe:

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

Amostra de execução (apenas um caso, por questões de brevidade):

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

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

Eu sou um novato. Sugestões são bem-vindas.


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

A parte dolorosa é a entrada do arquivo. O cálculo real seria de apenas 114 bytes:

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]);
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.