Downhill Maze Solver

9

Лабиринт под уклоном представлен в виде ряда строк, разделенных пробелами от 0 до 9 включительно, плюс один «S» и один «X», где S обозначает начало, а X обозначает конец. В спусковом лабиринте вы можете идти только в пространство, которое находится рядом с вами на севере, юге, востоке или западе (без диагоналей), и вы можете ходить только в пространства со значением, которое меньше или равно значению, которое вы в настоящее время включены.

Программа должна выводить путь для навигации по лабиринту в том же формате, что и ввод, только "все" пройденные пробелы должны иметь "." в них и во всех не посещаемых местах должно быть "#". Начальная и конечная ячейки также должны сохранять свои «S» и «X» соответственно. Вы можете предположить, что всегда есть решение лабиринта.

Пример ввода:

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

Пример вывода:

. . . . # # S . #
. # # . . # # . .
. # # # . # # # .
. # # # . # # # .
. . X # . . . . .
Люк Д
источник
3
Вы можете перейти к и от Sи Xв любом направлении? Всегда ли лабиринт разрешим?
Увлечения Кэлвина
Кроме того, можем ли мы предположить, что все строки имеют одинаковую длину? И, чтобы уточнить, «цифра» означает одну десятичную цифру от 0до 9включительно, верно?
Ильмари Каронен,
1
@ Calvin Да, вы можете двигаться к и от S и X в любом направлении. Предполагается, что лабиринт разрешим.
Люк Д
1
@IImari Да, все строки имеют одинаковую длину, и да, «цифра» - это одна цифра от 0 до 9 включительно.
Люк Д

Ответы:

3

JavaScript (ES6) 219

Функция, возвращающая истину или ложь. Решение (если найдено) выводится на консоль. Он не пытается найти оптимальное решение.

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)

Неутоленный до смерти и объяснил больше, чем нужно

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
}

Тест в консоли Firefox / FireBug

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

Вывод

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

true  
edc65
источник
Мы, кажется, разделяем непостижимость взаимного кода.
seequ
1
@ Сиг, почему, разве это не кристально ясно? Я добавлю объяснение завтра
edc65
@ Сиг, более понятный?
edc65
Действительно, понятно.
seequ
4

C # - 463

Принимает ввод через STDIN и должен давать оптимальный путь, проверенный для данного контрольного примера, но не иначе. Предполагается, что всегда есть решение.

Я немного тороплюсь, у меня есть срок в 7 часов, но это выглядело слишком весело, чтобы его пропустить. Я тоже вне практики. Это может быть очень неловко, если это пойдет не так, но это разумно.

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]);}}

Код с комментариями:

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
источник