Derribar paredes en un laberinto

10

Reglas:

En este juego comienzas en la parte superior de una cuadrícula rectangular de tamaño N x M compuesta de paredes y espacios abiertos. La entrada es N líneas de M caracteres, donde a .especifica un espacio abierto y a xespecifica un muro. Su programa debería generar el número K más pequeño de manera que exista una ruta desde la esquina superior izquierda a la esquina inferior derecha (sin diagonales) que cruza las paredes K.

Por ejemplo, dada la entrada:

..x..
..x..
xxxxx
..x..
..x..

su programa debería salir 2.

Otros ejemplos:

salida 4:

xxxxx
x.x.x
x.x.x
x..xx

salida 0:

.xxxxxxxx
.x...x...
.x.x.x.x.
.x.x...x.
...xxxxx.

salida 6:

xx
xx
xx
xx
xx

Cositas extra:

Si le facilita la vida, puede especificar N y M como parámetros de línea de comando.

Crédito adicional si puede hacer que su programa imprima la ruta de una forma u otra.

Despistado
fuente
44
: bostezo: Dijkstra, con un montón que es una V [2] [] y un contador.
Peter Taylor
44
@ Peter Taylor Pero, ¿qué tan corto puedes hacer ese código?
migimaru

Respuestas:

3

Rubí 1.9 (235) (225) (222) (214)

No sé si esto es más corto que un programa basado en Dijkstra, pero pensé que probaría un enfoque diferente. Esto usa expresiones regulares en un bucle para marcar cada espacio con el número mínimo de paredes requeridas para alcanzarlo.

w=".{#{/\s/=~s=$<.read}}?"
j="([.x])"
s[0]=v=s[0]<?x??0:?1
(d=v[-1];n=v.succ![-1]
0while(s.sub!(/#{j}(#{w+d})/m){($1<?x?d: n)+$2}||s.sub!(/(#{d+w})#{j}/m){$1+($2<?x?d: n)}))while/#{j}/=~q=s[-2]
p v.to_i-(q==n ?0:1)

La entrada se especifica como un archivo en la línea de comando, es decir

> ruby1.9.1 golf.rb maze.txt

Sin golf:

# read in the file
maze = $<.read

# find the first newline (the width of the maze)
width = /\s/ =~ maze

# construct part of the regex (the part between the current cell and the target cell)
spaces = ".{#{width}}?"

# construct another part of the regex (the target cell)
target = "([.x])"

# set the value of the first cell, and store that in the current wall count
maze[0] = walls = (maze[0] == "x" ? "1" : "0")

# loop until the goal cell is not "." or "x"
while /#{target}/ =~ (goal = s[-2])

  # store the current wall count digit and the next wall count digit, while incrementing the wall count
  current = walls[-1]; next = walls.succ![-1]

  # loop to set all the reachable cells for the current wall count
  begin

    # first regex handles all cells above or to the left of cells with the current wall count
    result = s.sub!(/#{target}(#{spaces + current})/m) {
      ($1 == 'x' ? next : current) + $2
    }

    # second regex handles all cells below or to the right of cells with the current wall count
    result = result || s.sub!(/(#{current + spaces})#{target}/m) {
      $1 + ($2 == 'x' ? next : current)
    }
  end while result != nil
end

# we reached the goal, so output the wall count if the goal was a wall, or subtract 1 if it wasn't
puts walls.to_i - (goal == next ? 0 : 1)
migimaru
fuente
2

Perl 5.10 (164)

undef$/;$_=<>;/\n/;$s="(.{$-[0]})?";substr$_,0,1,($n=/^x/||0);
until(/\d$/){1while s/([.x])($s$n)/$n+($1eq x).$2/se
+s/$n$s\K[.x]/$n+($&eq x)/se;$n++}
/.$/;print"$&\n"

Muy similar a la solución de migimaru, solo con ese toque adicional de Perl. 5.10 es necesario para \Kadentro s///.

hobbs
fuente
¿Esto maneja adecuadamente laberintos que requieren pasar a través de más de 9 paredes?
migimaru
@migimaru No. Podría obtener hasta 45 más o menos con solo un modesto aumento de caracteres y hasta un número casi ilimitado con otro pequeño aumento, pero no sería tan bonito.
hobbs
2

Python 406 378 360 348 418 caracteres

import sys
d={}
n=0
for l in open(sys.argv[1]):
 i=0
 for c in l.strip():m=n,i;d[m]=c;i+=1
 n+=1
v=d[0,0]=int(d[0,0]=='x')
X=lambda *x:type(d.get(x,'.'))!=str and x
N=lambda x,y:X(x+1,y)or X(x-1,y)or X(x,y+1)or X(x,y-1)
def T(f):s=[(x,(v,N(*x))) for x in d if d[x]==f and N(*x)];d.update(s);return s
while 1:
 while T('.'):pass
 v+=1
 if not T('x'):break
P=[m]
s,p=d[m]
while p!=(0,0):P.insert(0,p);x,p=d[p]
print s, P

Dijkstra simplificado, ya que los movimientos con peso están en el xcampo. Se realiza en "ondas", primer bucle con encontrar .campos tocando el frente y establecerlos en el mismo peso, que una vez encontrar xcampos tocando el frente y establecerlos en el +1peso. Repita mientras no haya más campos no visitados.

Al final sabemos el peso de cada campo.

La entrada se especifica como un archivo en la línea de comando:

python m.py m1.txt

Actualización: imprime la ruta.

Apuesta inicial
fuente
1

Versión C ++ (610 607 606 584)

#include<queue>
#include<set>
#include<string>
#include<iostream>
#include<memory>
#define S second
#define X s.S.first
#define Y s.S.S
#define A(x,y) f.push(make_pair(s.first-c,make_pair(X+x,Y+y)));
#define T typedef pair<int
using namespace std;T,int>P;T,P>Q;string l;vector<string>b;priority_queue<Q>f;set<P>g;Q s;int m,n,c=0;int main(){cin>>m>>n;getline(cin,l);while(getline(cin,l))b.push_back(l);A(0,0)while(!f.empty()){s=f.top();f.pop();if(X>=0&&X<=m&&Y>=0&&Y<=n&&g.find(s.S)==g.end()){g.insert(s.S);c=b[X][Y]=='x';if(X==m&&Y==n)cout<<-(s.first-c);A(1,0)A(-1,0)A(0,1)A(0,-1)}}}

Implementa el algoritmo de Dijkstra.

Sin golf:

#include<queue>
#include<set>
#include<string>
#include<iostream>
#include<memory>

using namespace std;
typedef pair<int,int>P;
typedef pair<int,P>Q;

int main()
{
    int             m,n;
    string          line;
    vector<string>  board;

    cin >> m >> n;getline(cin,l);
    while(getline(cin,line))
    {
        board.push_back(line);
    }

    priority_queue<Q>   frontList;
    set<P>              found;
    frontList.push(make_pair(0,make_pair(0,0)));
    while(!frontList.empty())
    {
        Q s=frontList.top();
        frontList.pop();
        if(   s.second.first>=0
           && s.second.first<=m
           && s.second.second>=0
           && s.second.second<=n
           && found.find(s.second)==found.end()
        )
        {
            found.insert(s.second);
            int c=board[s.second.first][s.second.second]=='x';
            if(  s.second.first==m
              && s.second.second==n
            )
            {   cout<<-(s.first-c);
            }
            frontList.push(make_pair(s.first-c,make_pair(s.second.first+1,s.second.second)));
            frontList.push(make_pair(s.first-c,make_pair(s.second.first-1,s.second.second)));
            frontList.push(make_pair(s.first-c,make_pair(s.second.first,s.second.second+1)));
            frontList.push(make_pair(s.first-c,make_pair(s.second.first,s.second.second-1)));
        }
    }
}
Martin York
fuente