Calcola una roccia che rotola giù da una collina


17

introduzione

Sisifo stava avendo dei problemi al lavoro ultimamente. Sembra che non riesca mai a fare nulla e gli piacerebbe trovare una soluzione a questo problema.

Il suo attuale impiego richiede di far rotolare una roccia su una collina. Di solito fa bene il suo lavoro, ma ogni volta che si trova vicino alla cima della collina rotola di nuovo giù.

Si sta davvero frustrando per il suo lavoro e vuole risolvere scientificamente il problema facendo simulare al computer un rock che rotola giù per la collina.

Accade così che Sisifo non sia particolarmente bravo a programmare, quindi forse puoi aiutarlo?

La sfida

Dopo questa stupida introduzione, veniamo al mondo degli affari. Il tuo programma riceverà un'illustrazione della collina e della roccia simile a questa:

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

Dove #rappresenta una parte della collina e orappresenta la roccia.

Ora devi implementare un programma che sposta lo strato rock 1 verso il basso. Ad esempio, l'output di quanto sopra dovrebbe essere:

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

Se c'è un'area uniformemente orizzontale, la collina rotola solo orizzontalmente, quindi ...

o
######## 

... questo farebbe solo rotolare lateralmente la pietra.

 o
######## 

Se c'è un'area verticale, la roccia cade di un gradino, quindi ...

#o
#
#
##### 

... cederebbe ...

#
#o
#
##### 

Riceverai anche la larghezza e l'altezza dell'immagine rispettivamente in una riga sopra l'immagine. Quindi, in totale, il nostro input di esempio sarebbe simile al seguente:

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

(Nota che gli spazi bianchi qui sono spazi. Seleziona il testo e vedi cosa intendo.)

Alcuni dettagli

  • Quando il rock è già nell'ultima riga durante l'esecuzione del programma, è possibile scegliere di terminare il programma o emettere l'input invariato
  • La collina scende sempre e solo verso il basso
  • Il tuo programma dovrebbe formattare l'output esattamente come l'input (comprese le dimensioni), quindi se installi l'output del programma su se stesso, calcola il passaggio successivo.

  • Si può presumere che ci sia sempre una strada verso il fondo, quindi l'input in cui il percorso è "bloccato" può causare un comportamento indefinito

  • Puoi presumere che ci sia sempre uno spazio nell'ultima riga. Il rock dovrebbe "riposare" lì, quindi dopo aver richiamato il programma alcune volte, convogliando sempre il suo output su se stesso, dovresti finire con il rock nell'ultima riga, posizionando dove era lo spazio in precedenza.

  • Puoi accettare l'input in qualsiasi forma ti piaccia (stdin, file, ...). Devi pubblicare il programma INTERO (quindi tutte le variabili pre-inizializzate contano come codice).

  • Le linee sono terminate con \n.

  • Puoi ottenere alcuni input di esempio qui (assicurati di copiare correttamente gli spazi!)

  • Questo è , quindi vince l'invio funzionante con il minor numero di byte .

  • Il vincitore verrà scelto il 26 luglio 2014. Successivamente puoi pubblicare soluzioni, ma non puoi vincere

Se avete domande, fatemi sapere nei commenti.

Buon golf!


Ci sarà una colonna finale di spazi bianchi come nel tuo ultimo esempio? (perché gli altri non ce l'hanno)
Martin Ender,

@ m.buettner Nell'ultimo esempio ci sono solo 9 #s, quindi alla fine c'è uno spazio perché la larghezza è 10. In questo caso (dopo alcune iterazioni) la roccia giaceva dove si trova lo spazio bianco (quindi in fondo -angolo destro).
Christoph Böhmwalder,

Sì, me ne rendo conto, mi stavo solo chiedendo se possiamo supporre che sia sempre così, perché non è per i tuoi altri esempi. (Detto questo, i tuoi altri esempi non hanno alcuno spazio bianco finale.)
Martin Ender,

6
Ho

1
@HackerCow hai ragione. Risolto rimuovendo un personaggio: D
Martin Ender il

Risposte:


35

Regex (.NET, Perl, PCRE, JavaScript, ... flavours), 25 byte

Sì, questo creerà di nuovo un certo dibattito, se un'espressione regolare è un programma valido, ma lo prevederò e dirò che questa presentazione è solo per divertimento e non deve essere considerata per il vincitore. (A differenza della variante Perl a 31 byte in basso;).)

Quindi ecco una soluzione di sostituzione regex pura.

Pattern (notare lo spazio finale):

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

Sostituzione (notare lo spazio iniziale):

 $1o

Il conteggio dei byte è per la somma dei due.

Puoi provarlo su http://regexhero.net/tester/ . Assicurati di scegliere le terminazioni di linea in stile Unix e di "preservare la formattazione incollata" quando incolli. Se il problema persiste, hai comunque incollato i finali di linea in stile Windows. La soluzione più semplice in quel caso è sostituirla \ncon \r\nnel modello per vedere che funziona.

Ecco una funzione ECMAScript 6 a 48 byte che utilizza questa

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

Finalmente, ho anche un vero programma. Sono 31 byte di Perl (inclusi due byte per pe 0flag; grazie a Ventero per il suggerimento!).

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

Se vuoi provarlo, non salvarlo nemmeno in un file, fallo e basta

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

Purtroppo non funziona per me (nel tester online). Sposta sempre la roccia verso destra. 40 byte è un ottimo inizio, ma sarà difficile da battere!
Christoph Böhmwalder,

@HackerCow Hai ragione, ho appena notato che c'è un problema. Riparazione ...
Martin Ender,

@HackerCow No, penso che funzioni davvero, ma "preserva la formattazione" sovrascrive la fine della linea, quindi se incolli le terminazioni di linea in stile Windows non funziona (prova a sostituire \n con \r\n)
Martin Ender,

Per me la roccia non cade quando è contro la parete destra, cioè. lo abbina solo quando ha uno spazio finale.
BrunoJ,

4
Come dovrei batterlo? Ottima soluzione
qwr

3

Python - 190

Affetto e concatenazione horror, insieme a troppe variabili. Sono certo che questo può essere giocato di più, ma non riesco a pensare a nessuna funzione di pitone intelligente in questo momento. L'input è memorizzato nella stringa 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)

Poiché le stringhe di pitone sono immutabili, sostituisco un personaggio concatenando tutti i personaggi precedenti, il mio nuovo personaggio e tutti i personaggi dopo. Uso la larghezza e l'indicizzazione della collina per determinare dove deve rotolare la roccia.


3
Mi fanno male gli occhi. +1
Christoph Böhmwalder,

2

Rubino, 65/55 caratteri

Ho pensato di vedere quanto tempo è una soluzione che non si limita a gettare una regex sul problema.

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

Come previsto, non è breve come la soluzione regex di m.buettner - ma non molto più a lungo.

Quando si usano flag di interprete, questo può essere ridotto a 55 caratteri (53 per il codice, 2 per i flag):

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

Esegui il codice in questo modo:

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

2

HTML JavaScript - 251 caratteri

( 251 se si conteggia il codice tra virgolette singole che legge l'input e restituisce l'output. 359 se si contano la casella di input, la stringa di input, il pulsante, ecc. 192 se contate solo che funzioni.)

Codice 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
fai clic su "Vai" più e più volte
Fai clic su "Vai" più volte.

Metodo

Uso String.match () per dividere la collina in 5 parti, quindi cambio una o due parti. Sto imparando JavaScript, quindi ogni suggerimento sarebbe apprezzato.

Codice leggibile

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

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

Ho apportato alcuni miglioramenti significativi, ma questo è ancora terribile. Un paio di byte in più possono essere salvati convertendoli in Python 3 ma non posso essere risolto.

Innanzitutto, trovo la roccia. Se il carattere immediatamente sotto è '#', sostituisci ogni istanza di 'o 'con ' o'. Dato che alla fine c'è uno spazio extra garantito, questo sposta sempre la roccia verso destra.

Indipendentemente dal fatto che lo abbia fatto o meno, traspongo l'intera griglia con zip(*m). Quindi, faccio un'altra sostituzione di 'o 'con ' o'. Se c'è uno spazio a destra della roccia, ciò significa che nella griglia reale c'è uno spazio sotto di essa, quindi viene spostato. Quindi traspondo e stampo.


Non rovinerebbe il terzo esempio dell'OP, dove c'è spazio vuoto a destra e sotto la roccia, e lo sposta in diagonale?
Maniglia della porta

@dor Non dovrebbe. Mi sposto a destra solo se lo spazio qui sotto è #e lo faccio prima di fare il controllo per spostarmi 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}'

Più leggibile

    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 caratteri

So che questo è enorme rispetto all'ingresso di m.buettner, ma per ora è meglio che possa fare. Penso che ci debba essere un modo più veloce per trasformare la stringa di input in un array multidimensionale, ma ormai è molto tardi.

E anche se non competitivo, questo puzzle mi è piaciuto. Vorrebbe che l'estensione mostrasse dove finisce la palla, o dopo un determinato numero di passi, forse aggiunto dopo la larghezza e l'altezza sulla linea di input. Potrebbe aggiungerlo molto facilmente a questa versione.

Ecco il mio codice: l'input è nella prima variabile.

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

Puoi vederlo qui in azione sul codepad

Modifica: modificato il codepad e il codice sopra come era in uscita 0 invece di o, il che ha causato problemi quando ho provato a reinserire l'output nel programma. Risolto ora e salvato un carattere!


0

Groovy - 263 261 256 caratteri

Golfed. Leggi il file in una stringa e usa una funzione pper emulare una funzione 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 (un po '):

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

Bello. Non conosco la lingua, ma sono quasi sicuro che puoi sbarazzarti di (almeno) due byte se scrivi try{invece di try {e catch(Exceptioninvece di catch (Exception.
Christoph Böhmwalder,

Infatti! Grazie per 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 manipolazione delle stringhe non è il punto di forza di R.

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

Oppure, se vuoi davvero leggere il codice:

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 caratteri

Senza regex. File di input richiesto denominato "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)))

Esempio di esecuzione (solo un caso, per brevità):

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

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

Sono un novizio. Suggerimenti benvenuti.


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 è l'input del file. Il calcolo effettivo sarebbe solo 114 byte:

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]);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.