Abbatti i muri in un labirinto


10

Regole:

In questo gioco inizi nella parte superiore di una griglia rettangolare di dimensioni N x M formata da pareti e spazi aperti. L'input è N righe di M caratteri, dove a .specifica uno spazio aperto e a xspecifica un muro. Il tuo programma dovrebbe generare il numero K più piccolo in modo tale che esista un percorso dall'angolo in alto a sinistra all'angolo in basso a destra (senza diagonali) che attraversa i muri K.

Ad esempio, dato l'input:

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

il tuo programma dovrebbe uscire 2.

Altri esempi:

uscita 4:

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

uscita 0:

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

uscita 6:

xx
xx
xx
xx
xx

Bocconcini extra:

Se ti semplifica la vita, puoi specificare N e M come parametri della riga di comando.

Credito extra se puoi avere il tuo programma stampare il percorso in un modo o nell'altro.


4
: sbadiglio: Dijkstra, con un heap che è una V [2] [] e un contatore.
Peter Taylor,

4
@Peter Taylor Ma quanto tempo riesci a fare quel codice?
migimaru,

Risposte:


3

Ruby 1.9 (235) (225) (222) (214)

Non so se questo è più breve di un programma basato su Dijkstra, ma ho pensato che avrei provato un approccio diverso. Questo utilizza regex in un ciclo per contrassegnare ogni spazio con il numero minimo di pareti necessarie per raggiungerlo.

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'input è specificato come file sulla riga di comando, ad es

> ruby1.9.1 golf.rb maze.txt

Ungolfed:

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

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"

Assolutamente sulla stessa linea della soluzione di migimaru, solo con quel tocco in più di Perl. 5.10 è necessario per \Kin s///.


Questo gestisce correttamente labirinti che richiedono il passaggio attraverso più di 9 muri?
migimaru,

@migimaru No. Potrei arrivare a 45 o giù di lì con solo un modesto aumento dei personaggi, e fino a un numero quasi illimitato con un altro piccolo aumento - ma non sarebbe altrettanto carino.
Hobbs,

2

Python 406 378 360 348 418 caratteri

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 semplificato, poiché le mosse con peso sono sul xcampo. Viene fatto in "onde", primo ciclo con trovare i .campi che si toccano davanti e impostarli sullo stesso peso, che una volta trovare i xcampi che toccano davanti e impostarli sul +1peso. Ripeti finché non ci sono più campi non visitati.

Alla fine conosciamo il peso per ogni campo.

L'input è specificato come file nella riga di comando:

python m.py m1.txt

Aggiornamento: stampa il percorso.


1

Versione 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 l'algoritmo di Dijkstra.

Un-giocato a 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)));
        }
    }
}
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.