Downhill Maze Solver

9

Ein Downhill-Labyrinth besteht aus einer Reihe von durch Leerzeichen getrennten Ziffern von 0 bis einschließlich 9 plus einem "S" und einem "X", wobei das S den Start und das X das Ziel bezeichnet. In einem Abfahrtslabyrinth dürfen Sie nur zu einem Feld gehen, das im Norden, Süden, Osten oder Westen neben Ihnen liegt (keine Diagonalen), und Sie dürfen nur zu Feldern gehen, deren Wert kleiner oder gleich dem Wert ist, den Sie haben sind derzeit auf.

Das Programm sollte einen Pfad ausgeben, um im gleichen Format wie die Eingabe durch das Labyrinth zu navigieren. Nur alle durchquerten Bereiche sollten ein "." in ihnen, und alle nicht besuchten Räume sollten ein "#" in ihnen haben. Die Start- und Endzellen sollten auch ihr "S" bzw. "X" behalten. Sie können davon ausgehen, dass es für das Labyrinth immer eine Lösung gibt.

Beispieleingabe:

3 3 3 3 2 1 S 8 9
3 1 1 3 3 0 6 8 7
1 2 2 4 3 2 5 9 7
1 2 1 5 4 3 4 4 6
1 1 X 6 4 4 5 5 5

Beispielausgabe:

. . . . # # S . #
. # # . . # # . .
. # # # . # # # .
. # # # . # # # .
. . X # . . . . .
Luke D.
quelle
3
Können Sie sich von und nach Sund Xin eine beliebige Richtung bewegen ? Ist das Labyrinth immer lösbar?
Calvins Hobbys
Können wir auch annehmen, dass alle Zeilen die gleiche Länge haben? Und nur zur Verdeutlichung bedeutet eine "Ziffer" eine einzelne Dezimalstelle von 0bis 9einschließlich, oder?
Ilmari Karonen
1
@Calvin Ja, Sie können sich in jede Richtung von und nach S und X bewegen. Das Labyrinth wird als lösbar angenommen.
Luke D
1
@IImari Ja, alle Zeilen haben die gleiche Länge, und ja, eine "Ziffer" ist eine einzelne Ziffer von 0 bis einschließlich 9.
Luke D

Antworten:

3

JavaScript (ES6) 219

Eine Funktion, die true oder false zurückgibt. Die Lösung (falls gefunden) wird auf der Konsole ausgegeben. Es wird nicht versucht, eine optimale Lösung zu finden.

f=o=>(r=(m,p,w=0,v=m[p])=>
v>':'
  ?console.log(' '+m.map(v=>v<0?'#':v,m[f]='X').join(' '))
  :v<=w&&[1,-1,y,-y].some(d=>r([...m],d+p,v),m[p]='.')
)(o.match(/[^ ]/g).map((v,p)=>v>'S'?(f=p,0):v>':'?v:v<'0'?(y=y||~p,v):~v,y=0),f)

Zu Tode ungolfed und erklärte mehr als nötig

f=o=>{
  var r = ( // recursive search function
    m, // maze array (copy of)
    p, // current position
    w  // value at previous position
  )=> 
  {
    var v = m[p]; // get value at current position
    if (v == 'S') // if 'S', solution found, output and return true
    {
      m[f] = 'X'; // put again 'X' at finish position
      m = m.map(v => { // scan array to obtain '#'
        if (v < 0) // a numeric value not touched during search
          return '#'
        else  
          return v  
      }).join(' '); // array to string again, with added blanks (maybe too many)
      console.log(' '+m) // to balance ' '
      return true; // return false will continue the search and find all possible solutions
    }
    if (v <= w) // search go on if current value <= previous (if numeric, they both are negative)
    {
      m[p]='.'; // mark current position 
      return [1,-1,y,-y].some(d=>r([...m], d+p, v)) // scan in all directions
    }
    // no more paths, return false and backtrack
    return false
  }

  var f, // finish position (but it is the start of the search)
      y = 0; // offset to next/prev row
  o = o.match(/[^ ]/g) // string to char array, removing ' 's
  .map((v,p) => // array scan to find f and y, and transform numeric chars to numbers 
   {  
     if (v > 'S') // check if 'X'
     {
       f = p;
       return 0; // 'X' position mapped to min value
     }
     if (v > ':') // check if 'S'
       return v; // no change
     if (v < '0') // check if newline
     {
       if (!y) y = ~p; // position of first newline used to find y offset
       return v; // no change
     }
     return ~v; // map numeric v to -v-1 so have range (-1..-10)
   })

  return r(o, f, 0) // start with a fake prev value
}

Test in der Firefox / FireBug-Konsole

f('3 3 3 3 2 1 S 8 9\n3 1 1 3 3 0 6 8 7\n1 2 2 4 3 2 5 9 7\n1 2 1 5 4 3 4 4 6\n1 1 X 6 4 4 5 5 5')

Ausgabe

. . . . # # S . #   
. # # . . # # . .   
. # # # . # # # .   
. # # # . # # # .   
. . X # . . . . .  

true  
edc65
quelle
Wir scheinen eine gegenseitige Unergründlichkeit des Kodex zu teilen.
siehe
1
@Sieg warum, ist es nicht kristallklar? Ich werde morgen eine Erklärung hinzufügen
edc65
@Sieg ergründlicher?
edc65
In der Tat unergründlich.
siehe
4

C # - 463

Akzeptiert Eingaben über STDIN und sollte einen optimalen Pfad erzeugen, der für den gegebenen Testfall getestet wurde, aber nicht anders. Vorausgesetzt, es gibt immer eine Lösung.

Ich habe es etwas eilig, ich habe eine Frist in 7 Stunden, aber das sah einfach nach zu viel Spaß aus, um es zu verpassen. Ich bin auch außer Übung. Es könnte sehr peinlich sein, wenn dies schief geht, aber es ist einigermaßen Golf gespielt.

using C=System.Console;class P{static void Main(){var S=C.In.ReadToEnd().Replace("\r","").Replace('X','+');int s=S.IndexOf('S'),e=S.IndexOf('+'),w=S.IndexOf('\n')+1,L=S.Length,i,j=L;var K=new int[L];for(K[s]=s+2;j-->0;)for(i=0;i<L;i+=2){System.Action<int>M=z=>{if((z+=i)>=0&z<L&&S[z]<=S[i]&K[z]<1&K[i]>0&(i%w==z%w|i/w==z/w))K[z]=i+1;};M(2);M(-2);M(w);M(-w);}for(w=e;w!=s+1;w=i){i=K[w]-1;K[w]=-1;}for(;++j<L;)C.Write(j%2<1?K[j]<0?j==s?'S':j==e?'X':'.':'#':S[j]);}}

Code mit Kommentaren:

using C=System.Console;

class P
{
    static void Main()
    {
        var S=C.In.ReadToEnd().Replace("\r","").Replace('X','+'); // read in the map, replace X with + because + < 0
        int s=S.IndexOf('S'),e=S.IndexOf('+'),w=S.IndexOf('\n')+1,L=S.Length,i,j=L; // find start, end, width, length

        var K=new int[L]; // this stores how we got to each point as loc+1 (0 means we havn't visited it)

        for(K[s]=s+2; // can't risk this being 0
            j-->0;) // do L passes
            for(i=0;i<L;i+=2) // each pass, look at every location
            {
                // if a whole load of bouds checks, point new location (i+z) at i
                System.Action<int>M=z=>{if((z+=i)>=0&z<L&&S[z]<=S[i]&K[z]<1&K[i]>0&(i%w==z%w|i/w==z/w))K[z]=i+1;};
                // try and move in each direction
                M(2);
                M(-2);
                M(w);
                M(-w);
            }

        for(w=e;w!=s+1;w=i) // find route back
        {
            i=K[w]-1; // previous location
            K[w]=-1; // set this so we know we've visited it
        }

        for(;++j<L;) // print out result
            C.Write(j%2<1?K[j]<0?j==s?'S':j==e?'X':'.':'#':S[j]); // if K < 0, we visit it, otherwise we don't
    }
}
VisualMelon
quelle