Abattre les murs dans un labyrinthe

10

Règles:

Dans ce jeu, vous commencez au sommet d'une grille rectangulaire de taille N x M composée de murs et d'espaces ouverts. L'entrée est N lignes de M caractères, où a .spécifie un espace ouvert et a xspécifie un mur. Votre programme doit afficher le plus petit nombre K de sorte qu'il existe un chemin du coin supérieur gauche au coin inférieur droit (pas de diagonales) qui traverse les murs K.

Par exemple, étant donné l'entrée:

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

votre programme devrait sortir 2.

Autres exemples:

sortie 4:

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

sortie 0:

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

sortie 6:

xx
xx
xx
xx
xx

Petits morceaux supplémentaires:

Si cela vous facilite la vie, vous pouvez spécifier N et M comme paramètres de ligne de commande.

Crédit supplémentaire si vous pouvez demander à votre programme d'imprimer le chemin sous une forme ou une autre.

Aucune idée
la source
4
: bâillement: Dijkstra, avec un tas qui est un V [2] [] et un compteur.
Peter Taylor
4
@Peter Taylor Mais combien de temps pouvez-vous faire ce code?
migimaru

Réponses:

3

Rubis 1,9 (235) (225) (222) (214)

Je ne sais pas si c'est plus court qu'un programme basé sur Dijkstra, mais j'ai pensé que j'essaierais une approche différente. Cela utilise l'expression régulière dans une boucle pour marquer chaque espace avec le nombre minimal de murs requis pour l'atteindre.

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)

L'entrée est spécifiée sous forme de fichier sur la ligne de commande, c'est-à-dire

> ruby1.9.1 golf.rb maze.txt

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

Tout à fait dans le même sens que la solution de migimaru, uniquement avec cette touche supplémentaire de Perl. 5.10 est nécessaire pour \Kin s///.

Hobbs
la source
Est-ce que cela gère correctement les labyrinthes qui nécessitent de traverser plus de 9 murs?
migimaru
@migimaru Non. Je pourrais le faire jusqu'à 45 ou plus avec seulement une augmentation modeste de caractères, et jusqu'à un nombre presque illimité avec une autre petite augmentation - mais ce ne serait pas aussi joli.
hobbs
2

Python 406 378 360 348 418 caractères

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 simplifié, car les mouvements avec poids sont sur le xterrain. Cela se fait en "vagues", première boucle avec recherche des .champs touchant l'avant et les mettre sur le même poids, qu'une fois trouver les xchamps touchant l'avant et les mettre sur le +1poids. Répétez tant qu'il n'y a plus de champs non visités.

À la fin, nous connaissons le poids pour chaque domaine.

L'entrée est spécifiée sous forme de fichier sur la ligne de commande:

python m.py m1.txt

Mise à jour: imprime le chemin.

Ante
la source
1

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

Implémente l'algorithme de Dijkstra.

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