Calcular una roca rodando cuesta abajo

17

Introducción

Sísifo estaba teniendo algunos problemas en el trabajo últimamente. Parece que nunca hace nada, y le encantaría encontrar una solución a este problema.

Su empleo actual requiere rodar una roca cuesta arriba. Por lo general, hace bien su trabajo, pero cada vez que está cerca de la cima de la colina, cae de nuevo.

Se está realmente frustrado con su trabajo y quiere resolver el problema científicamente haciendo que una computadora simule la roca rodando cuesta abajo.

Da la casualidad de que Sísifo no es particularmente bueno en la programación, ¿entonces tal vez puedas ayudarlo?

El reto

Después de esta tonta introducción, vamos a los negocios. Su programa recibirá una ilustración de la colina y la roca que se parece a esto:

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

Donde #representa una parte de la colina y orepresenta la roca.

Ahora debe implementar un programa que mueva la capa de roca 1 hacia abajo. Por ejemplo, el resultado de lo anterior debe ser:

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

Si hay un área horizontalmente pareja, la colina simplemente rueda horizontalmente, así que ...

o
######## 

... esto solo haría que la piedra ruede de lado.

 o
######## 

Si hay un área vertical, la roca cae un escalón, así que ...

#o
#
#
##### 

... cedería ...

#
#o
#
##### 

También recibirá el ancho y el alto de la imagen, respectivamente, en una línea sobre la imagen. Entonces, en total, nuestra entrada de muestra se vería así:

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

(Tenga en cuenta que los espacios en blanco aquí son espacios. Seleccione el texto y vea lo que quiero decir).

Algunos detalles

  • Cuando la roca ya está en la última línea al ejecutar el programa, puede optar por finalizar el programa o generar la entrada sin cambios.
  • La colina solo baja
  • Su programa debe formatear la salida exactamente igual que la entrada (incluidas las dimensiones), por lo que si canaliza la salida del programa a sí mismo, calcula el siguiente paso.

  • Puede suponer que siempre hay un camino hacia abajo, por lo que la entrada donde la ruta está "bloqueada" puede causar un comportamiento indefinido

  • Puede suponer que siempre hay un espacio en la última línea. La roca debe "descansar" allí, así que después de llamar al programa varias veces, siempre conectando su salida en sí misma, debe terminar con la roca en la última línea, colocando donde estaba el espacio anteriormente.

  • Puede aceptar la entrada en cualquier forma que desee (stdin, archivo, ...). Debe publicar el programa ENTERO (para que todas las variables preinicializadas cuenten como código).

  • Las líneas se terminan con \n.

  • Puede obtener algunas entradas de ejemplo aquí (¡asegúrese de copiar los espacios correctamente!)

  • Este es el , por lo que gana la presentación de trabajo con la menor cantidad de bytes .

  • El ganador será elegido el 26 de julio de 2014. Después de eso, puede publicar soluciones, pero no puede ganar.

Si tiene alguna pregunta, hágamelo saber en los comentarios.

¡Feliz golf!

Christoph Böhmwalder
fuente
¿Habrá una columna de espacios en blanco al final como en su último ejemplo? (porque los otros no lo tienen)
Martin Ender
@ m.buettner En el último ejemplo, solo hay 9 #s, por lo que hay un espacio al final porque el ancho es 10. En este caso (después de algunas iteraciones) la roca se colocaría donde está el espacio en blanco (por lo tanto, en la parte inferior -esquina derecha).
Christoph Böhmwalder
Sí, me doy cuenta de eso, me preguntaba si podemos asumir que ese es siempre el caso, porque no es para sus otros ejemplos. (Dicho esto, sus otros ejemplos no tienen ningún espacio en blanco al final.)
Martin Ender
66
Perdí una gran oportunidad de llamarlo "Rock and Roll"
qwr
1
@HackerCow tienes razón. Solucionado al eliminar un personaje: D
Martin Ender

Respuestas:

35

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

Sí, esto creará cierto debate nuevamente, si una expresión regular es un programa válido, pero lo adelantaré y diré que esta presentación es solo por diversión y no necesita ser considerada para el ganador. (A diferencia de la variante Perl de 31 bytes en la parte inferior;).)

Así que aquí hay una solución de reemplazo de expresiones regulares puras.

Patrón (tenga en cuenta el espacio final):

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

Reemplazo (tenga en cuenta el espacio inicial):

 $1o

El recuento de bytes es para la suma de los dos.

Puede probarlo en http://regexhero.net/tester/ . Asegúrese de elegir las terminaciones de línea de estilo Unix y "conservar el formato pegado" al pegar. Si todavía no funciona, todavía ha pegado los finales de línea al estilo de Windows. La solución más fácil en ese caso es reemplazar \ncon \r\nen el patrón para ver que funciona.

Aquí hay una función ECMAScript 6 de 48 bytes que usa esto

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

Finalmente, también tengo un programa real. Son 31 bytes de Perl (incluidos dos bytes para py 0banderas; ¡gracias a Ventero por la sugerencia!).

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

Si quieres probarlo, ni siquiera lo guardes en un archivo, solo hazlo

perl -p0e 's/o(( *)\n#*)(?=\2) |o / $1o/' < hill.txt
Martin Ender
fuente
Desafortunadamente no funciona para mí (en el probador en línea). Simplemente siempre mueve la roca hacia la derecha. Sin embargo, 40 bytes es un gran comienzo, ¡será difícil de superar!
Christoph Böhmwalder
@HackerCow Tienes razón, acabo de notar que hay un problema. Arreglando ...
Martin Ender
@HackerCow No, creo que realmente funciona, pero "preservar el formato" sobrescribe el final de línea, por lo que si pega los finales de línea al estilo de Windows no funciona (intente reemplazar \ncon \r\n)
Martin Ender
Para mí, la roca no cae cuando está contra la pared derecha, es decir. solo coincide cuando tiene un espacio final.
BrunoJ
44
¿Cómo se supone que voy a vencer esto? Gran solución
qwr
3

Python - 190

Corte y concatenación de terror, junto con demasiadas variables. Estoy seguro de que esto se puede jugar más, pero no puedo pensar en ninguna función inteligente de Python en este momento. La entrada se almacena en cadena 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)

Dado que las cadenas de python son inmutables, reemplazo un personaje concatenando todos los caracteres anteriores, mi nuevo personaje y todos los caracteres posteriores. Utilizo el ancho de la colina y la indexación para determinar hacia dónde debe rodar la roca.

qwr
fuente
3
Me duelen los ojos. +1
Christoph Böhmwalder
2

Ruby, 65/55 caracteres

Pensé que vería cuánto dura una solución que no solo arroje una expresión regular sobre el problema.

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

Como se esperaba, no es tan corto como la solución de expresión regular de m.buettner, pero tampoco mucho más.

Cuando se usan banderas de intérprete, esto se puede acortar a 55 caracteres (53 para el código, 2 para las banderas):

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

Ejecute el código así:

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

JavaScript HTML - 251 caracteres

( 251 si cuenta el código dentro de las comillas simples que lee la entrada y devuelve la salida. 359 si cuenta el cuadro de entrada, la cadena de entrada, el botón, etc. 192 si cuenta solo eso funciona).

Código de 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
haga clic en "Ir" una y otra vez
Haga clic en "Ir" una y otra vez.

Método

Utilizo String.match () para dividir la colina en 5 partes, luego cambio una o dos partes. Estoy aprendiendo JavaScript, por lo que cualquier sugerencia sería apreciada.

Código legible

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

Hice algunas mejoras significativas, pero esto sigue siendo terrible. Se pueden guardar un par de bytes más al convertir esto a Python 3, pero no puedo identificarlo.

Primero, encuentro la roca. Si el carácter inmediatamente debajo está '#', reemplace cada instancia de 'o 'con ' o'. Como se garantiza que habrá un espacio adicional al final, esto siempre moverá la roca hacia la derecha.

Independientemente de si acabo de hacer eso o no, transpongo toda la cuadrícula con zip(*m). Luego, hago otro reemplazo de 'o 'con ' o'. Si hay un espacio a la derecha de la roca, eso significa que en la cuadrícula real hay un espacio debajo, por lo que se mueve. Luego lo transpongo e imprimo.

metro subterráneo
fuente
¿No arruinaría esto el tercer ejemplo del OP, donde hay un espacio vacío a la derecha y debajo de la roca, y moverlo en diagonal?
Pomo de la puerta
@dor No debería. Solo me muevo hacia la derecha si el espacio de abajo es #, y hago esa verificación antes de hacer la verificación para moverme verticalmente.
undergroundmonorail
1

Pitó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='')
Ian D. Scott
fuente
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}'

Más legible

    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
fuente
0

php 485 484 caracteres

Sé que esto es enorme en comparación con la entrada de m.buettner, pero es lo mejor que puedo hacer por ahora. Creo que debe haber una forma más rápida de convertir la cadena de entrada en una matriz multidimensional, pero ahora es muy tarde.

Y aunque no es competitivo, me gustó este rompecabezas. Quisiera que la extensión muestre dónde termina la pelota, o después de un número determinado de pasos, quizás agregado después del ancho y la altura en la línea de entrada. Podría agregar eso muy fácilmente a esta versión.

Aquí está mi código: la entrada está en la primera variable.

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

Puedes verlo aquí en acción en el teclado

Editar: se modificó el código y el código anterior, ya que generaba 0 en lugar de o, lo que causó un problema cuando intenté alimentar la salida nuevamente en el programa. ¡Arreglado ahora y guardado un personaje!

Paul Drewett
fuente
0

Maravilloso - 263 261 256 caracteres

Golfizado Lea el archivo en una cadena y use una función ppara emular una función 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

Sin golf (algo):

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
fuente
Agradable. No sé el idioma, pero estoy casi seguro de que puedes deshacerte de (al menos) dos bytes si escribes en try{lugar de try {y en catch(Exceptionlugar de catch (Exception.
Christoph Böhmwalder
¡En efecto! Gracias por la nota ...
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="")

La manipulación de cuerdas no es el punto más fuerte de R.

Más legible:

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

O, si realmente quieres leer el 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);
}
Ian D. Scott
fuente
0

Clojure - 366 caracteres

Sin expresiones regulares. Archivo de entrada requerido llamado "d". Golfizado:

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

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

Ejecución de muestra (solo un caso, por brevedad):

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

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

Soy un novato Sugerencias de bienvenida.

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

La parte dolorosa es la entrada del archivo. El cálculo real sería de solo 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]);
knedlsepp
fuente