Calculer un rocher dévalant une colline

17

introduction

Sisyphe éprouvait récemment des problèmes au travail. Il semble qu'il n'obtienne jamais rien et il aimerait trouver une solution à ce problème.

Son emploi actuel nécessite de faire rouler un rocher sur une colline. Il fait généralement bien son travail, mais chaque fois qu'il est près du sommet de la colline, il redescend.

Il devient vraiment frustré par son travail et veut résoudre le problème scientifiquement en ayant un ordinateur simulant le rocher qui roule sur la colline.

Il se trouve que Sisyphe n'est pas particulièrement bon en programmation, alors peut-être pourriez-vous l'aider?

Le défi

Après cette introduction stupide, passons aux affaires. Votre programme recevra une illustration de la colline et du rocher qui ressemble à ceci:

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

#représente une partie de la colline et oreprésente le rocher.

Vous devez maintenant implémenter un programme qui déplace la couche de roche 1 vers le bas. Par exemple, la sortie de ce qui précède devrait être:

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

S'il y a une zone horizontale uniforme, la colline roule simplement horizontalement, alors ...

o
######## 

... cela ferait juste rouler la pierre sur le côté.

 o
######## 

S'il y a une zone verticale, le rocher tombe d'un pas, alors ...

#o
#
#
##### 

... céderait ...

#
#o
#
##### 

Vous recevrez également la largeur et la hauteur de l'image respectivement sur une ligne au-dessus de l'image. Donc, au complet, notre exemple d'entrée ressemblerait à ceci:

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

(Notez que les espaces blancs ici sont des espaces. Sélectionnez le texte et voyez ce que je veux dire.)

Quelques détails

  • Lorsque la roche est déjà dans la dernière ligne lors de l'exécution du programme, vous pouvez choisir de terminer le programme ou de sortir l'entrée inchangée
  • La colline ne descend que vers le bas
  • Votre programme doit formater la sortie exactement la même que l'entrée (y compris les dimensions), donc si vous dirigez la sortie du programme vers lui-même, il calcule l'étape suivante.

  • Vous pouvez supposer qu'il y a toujours un chemin vers le bas, donc l'entrée où le chemin est "bloqué" peut provoquer un comportement indéfini

  • Vous pouvez supposer qu'il y a toujours un espace dans la dernière ligne. La roche doit "reposer" là-bas, donc après avoir appelé le programme plusieurs fois, en dirigeant toujours sa sortie en elle-même, vous devriez vous retrouver avec la roche dans la dernière ligne, en posant où l'espace était auparavant.

  • Vous pouvez accepter des entrées sous n'importe quelle forme que vous souhaitez (stdin, fichier, ...). Vous devez publier le programme ENTIER (donc toutes les variables pré-initialisées comptent comme du code).

  • Les lignes se terminent par \n.

  • Vous pouvez obtenir des exemples d'entrées ici (assurez-vous de bien copier les espaces!)

  • C'est du , donc la soumission de travail avec le moins d' octets est gagnante.

  • Le gagnant sera choisi le 26 juillet 2014. Vous pouvez poster des solutions après cela, mais vous ne pouvez pas gagner

Si vous avez des questions, faites-le moi savoir dans les commentaires.

Bon golf!

Christoph Böhmwalder
la source
Y aura-t-il une colonne de fin d'espace comme dans votre dernier exemple? (parce que les autres ne l'ont pas)
Martin Ender
@ m.buettner Dans le dernier exemple, il n'y a que 9 #s, donc il y a un espace à la fin car la largeur est de 10. Dans ce cas (après quelques itérations), la roche reposerait là où se trouve l'espace (donc en bas) -le coin droit).
Christoph Böhmwalder
Oui, je m'en rends compte, je me demandais simplement si nous pouvons supposer que c'est toujours le cas, car ce n'est pas pour vos autres exemples. (Cela étant dit, vos autres exemples n'ont aucun espace de fin.)
Martin Ender
6
Manqué une grande chance de l'appeler "Rock and Roll"
qwr
1
@HackerCow vous avez raison. Corrigé en supprimant un personnage: D
Martin Ender

Réponses:

35

Regex (.NET, Perl, PCRE, JavaScript, ... saveurs), 25 octets

Oui, cela créera à nouveau un débat, si une expression régulière est un programme valide, mais je vais anticiper cela et dire que cette soumission est juste pour le plaisir et n'a pas besoin d'être considérée pour le gagnant. (Par opposition à la variante Perl de 31 octets en bas;).)

Voici donc une solution de remplacement pure regex.

Modèle (notez l'espace de fin):

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

Remplacement (notez l'espace de tête):

 $1o

Le nombre d'octets correspond à la somme des deux.

Vous pouvez le tester sur http://regexhero.net/tester/ . Assurez-vous de choisir des fins de ligne de style Unix et de "conserver la mise en forme collée" lors du collage. Si cela ne fonctionne toujours pas, vous avez toujours collé des fins de ligne de style Windows. La solution la plus simple dans ce cas est de remplacer \npar\r\n dans le modèle pour voir si cela fonctionne.

Voici une fonction ECMAScript 6 de 48 octets utilisant ce

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

Enfin, j'ai également un programme réel. C'est 31 octets de Perl (dont deux octets pour pet 0drapeaux; merci à Ventero pour la suggestion!).

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

Si vous voulez le tester, ne l’enregistrez même pas dans un fichier, faites

perl -p0e 's/o(( *)\n#*)(?=\2) |o / $1o/' < hill.txt
Martin Ender
la source
Ne fonctionne pas pour moi malheureusement (dans le testeur en ligne). Il déplace toujours le rocher vers la droite. 40 octets, c'est un bon début, ce sera difficile à battre!
Christoph Böhmwalder
@HackerCow Vous avez raison, je viens de remarquer qu'il y a un problème. Réparation ...
Martin Ender
@HackerCow Non, je pense que cela fonctionne réellement, mais "conserver le formatage" écrase la fin de ligne, donc si vous collez des fins de ligne de style Windows, cela ne fonctionne pas (essayez de remplacer \npar \r\n)
Martin Ender
Pour moi, le rocher ne tombe pas quand il est contre le mur droit, c'est-à-dire. il ne correspond que s'il a un espace de fin.
BrunoJ
4
Comment suis-je censé battre ça? Grande solution
qwr
3

Python - 190

Horreur de découpage et de concaténation, avec beaucoup trop de variables. Je suis certain que cela peut être joué plus, mais je ne peux penser à aucune fonction intelligente de python pour le moment. L'entrée est stockée dans une chaîne 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)

Étant donné que les chaînes de python sont immuables, je remplace un caractère en concaténant tous les caractères avant, mon nouveau caractère et tous les caractères après. J'utilise la largeur de la colline et l'indexation pour déterminer où la roche doit rouler.

qwr
la source
3
Mes yeux me font mal. +1
Christoph Böhmwalder
2

Ruby, 65/55 caractères

Je pensais que je verrais combien de temps est une solution qui ne se contente pas de jeter une expression rationnelle sur le problème.

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

Comme prévu, ce n'est pas aussi court que la solution regex de m.buettner - mais pas beaucoup plus non plus.

Lorsque vous utilisez des drapeaux d'interpréteur, cela peut être raccourci à 55 caractères (53 pour le code, 2 pour les drapeaux):

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

Exécutez le code comme ceci:

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

HTML JavaScript - 251 caractères

( 251 si vous comptez le code entre guillemets simples qui lit l'entrée et renvoie la sortie. 359 si vous comptez la zone de saisie, la chaîne d'entrée, le bouton, etc. 192 si vous comptez juste cela fait le travail.)

Code 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
cliquez sur "Aller" encore et encore
Cliquez sur "Aller" encore et encore.

Méthode

J'utilise String.match () pour diviser la colline en 5 parties, puis je change une ou deux parties. J'apprends JavaScript, donc toute suggestion serait appréciée.

Code lisible

<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
la source
1

Python 2 - 289 252 octets

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

J'ai fait des améliorations importantes mais c'est toujours terrible. Quelques octets supplémentaires peuvent être enregistrés en les convertissant en Python 3 mais je ne peux pas être arsé.

Tout d'abord, je trouve le rocher. Si le caractère juste en dessous se trouve '#', remplacez chaque instance de 'o 'par ' o'. Puisqu'il est garanti qu'il y aura un espace supplémentaire à la fin, cela déplacera toujours le rocher vers la droite.

Peu importe si je viens de le faire ou non, je transpose toute la grille avec zip(*m). Ensuite, je fais un autre remplacement de 'o 'avec ' o'. S'il y a un espace à droite du rocher, cela signifie que dans la vraie grille, il y a un espace en dessous, donc il est déplacé. Ensuite, je transpose en arrière et j'imprime.

métro monorail
la source
Cela ne gâcherait-il pas le 3e exemple de l'OP, où il y a un espace vide à droite et en dessous du rocher, et le déplacerait-il en diagonale?
Poignée de porte
@dor Ça ne devrait pas. Je ne me déplace vers la droite que si l'espace ci-dessous est #, et je vérifie avant de vérifier verticalement.
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
la source
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}'

Plus lisible

    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
la source
0

php 485 484 caractères

Je sais que c'est énorme par rapport à l'entrée de m.buettner mais c'est mieux que je puisse faire pour l'instant. Je pense qu'il doit y avoir un moyen plus rapide de transformer la chaîne d'entrée en un tableau multidimensionnel, mais il est très tard maintenant.

Et bien qu'il ne soit pas compétitif, j'ai aimé ce puzzle. Souhaiterait que l'extension montre où la balle se termine, ou après un nombre défini d'étapes, peut-être ajouté après la largeur et la hauteur sur la ligne d'entrée. Pourrait l'ajouter très facilement à cette version.

Voici mon code: l'entrée est dans la première 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";}

Vous pouvez le voir ici en action sur codepad

Edit: le codepad et le code ci-dessus ont été modifiés, comme la sortie 0 au lieu de o, ce qui a causé un problème lorsque j'ai essayé de réinjecter la sortie dans le programme. Fixé maintenant et enregistré un caractère!

Paul Drewett
la source
0

Groovy - 263 261 256 caractères

Golfé. Lisez le fichier dans une chaîne et utilisez une fonction ppour émuler une fonction 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

Non golfé (un peu):

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
la source
Agréable. Je ne connais pas la langue, mais je suis presque sûr que vous pouvez vous débarrasser de (au moins) deux octets si vous écrivez à la try{place de try {et catch(Exceptionau lieu de catch (Exception.
Christoph Böhmwalder
En effet! Merci pour la note ....
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 manipulation de chaînes n'est pas le point fort de R.

Plus lisible:

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
la source
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, si vous voulez réellement lire le code:

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
la source
0

Clojure - 366 caractères

Sans regex. Fichier d'entrée requis nommé "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)))

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

Exemple d'exécution (un seul cas, par souci de concision):

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

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

Je suis débutant. Suggestions bienvenues.

Michael Easter
la source
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 partie douloureuse est l'entrée de fichier. Le calcul réel ne serait que de 114 octets:

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
la source