Решите ледяной лабиринт

19

Ледяные лабиринты были одной из моих любимых игр Покемонов с момента их дебюта в Pokémon Gold и Silver. Ваша задача будет сделать программу, которая решает эти типы проблем.

Ледяные лабиринты в основном состоят, как следует из названия, изо льда. Как только игрок движется в направлении на льду, он будет продолжать двигаться в этом направлении, пока не столкнется с каким-либо препятствием. Существует также почва, которая может свободно перемещаться и остановит любого игрока, движущегося по ней. Последнее препятствие - камень. Камень не может занимать то же пространство, что и игрок, и если игрок попытается войти в него, он остановится, прежде чем сможет.

Вы получите двумерный контейнер значений, такой как список списков или строку, разделенную новыми строками, содержащую 3 различных значения для каждого из 3 типов напольных покрытий (Ice, Soil и Stone). Вы также получите две пары (или другие эквивалентные два контейнера значений), которые указывают начальную и целевую координаты в лабиринте. Это может быть ноль или один индекс.

Вы должны вывести список ходов (4 различных значения с биекцией на N, E, S, W), которые позволят игроку достигнуть конца при выполнении.

Вход всегда будет иметь замкнутый периметр камня вокруг лабиринта, поэтому вам не придется беспокоиться о выходе игрока из лабиринта.

Это поэтому побеждает меньше всего байтов

Тестовые случаи

Здесь .будет изображать лед, ~будет представлять почву, и Oбудет представлять собой камень. Координаты 1 проиндексированы. Каждая буква в решении представляет направление, начинающееся с этой буквы (например, N= Север)


вход

OOOOO
OO.OO
O...O
OOOOO

Start : 3,3
End   : 3,2

Выход

N

вход

OOOOOOOOOOOOOOOOO
O........O.....OO
O...O..........OO
O.........O....OO
O.O............OO
OO.......O.....OO
O.............OOO
O......O.......~O
O..O...........~O
O.............OOO
O.......O......OO
O.....O...O....OO
O..............OO
OOOOOOOOOOOOOO~~O
OOOOOOOOOOOOOOOOO

Start : 15,12
End   : 16,8

Выход

N,W,N,E,N,E,S,W,N,W,S,E,S,E,N,E,N

вход

OOOOOOOOOOOOOOOO
O~~~~~OOOOO~~~~O
O~~O~OOOOOOO~~OO
O...O..........O
O........O.....O
O..............O
OO.............O
O.............OO
O....~....O....O
O..............O
O..............O
OOOOOOOOOOOOOOOO

Start : 2,2
End   : 14,3

Выход

E,S,S,W,N,E,N

вход

OOOOOOOOOOOOOOOOOOO
O~~~~~~~OOOOOOOOOOO
O~~~~...OOOOOOOOOOO
OO~O~..OOOOOOOOOOOO
O..OO.............O
O..............O..O
O....O............O
O.O............~..O
O........OOOO.....O
O.......OOOOO.....O
O.......O~~~O.....O
O.......~~~~~.....O
O.......~~~~~.....O
O..........O......O
O..O..~...........O
O...............O.O
O.....O...........O
O.................O
OOOOOOOOOOOOOOOOOOO

Start : 2,2
End   : 11,11

Выход

E,E,E,E,E,S,S,E,N,W,S,E,N,N,N
Мастер пшеницы
источник
Будет ли вход всегда иметь хотя бы одно правильное решение?
Павел
@Pavel Вы можете так предположить.
Волшебник Пшеницы
Тестовые случаи (строка, столбец) или (столбец, строка)? 1 или 0 проиндексировано? Края доски считаются стенами?
MildlyMilquetoast
5
Связанные
Питер Тейлор
2
@busukxuan Вы можете навсегда оказаться в ловушке в лабиринте (см.
Мастер пшеницы

Ответы:

4

Mathematica, 247 байтов

(p=x#[[##&@@x]];m={c,v}Switch[p[c+v],0,m[c+v,v],1,c+v,_,c];g=Cases[Array[List,Dimensions@#],c_/;p@c<2,{2}];a=cm[c,#]&/@{{1,0},{-1,0},{0,1},{0,-1}};e=Flatten[Table[#->c,{c,a@#}]&/@g,1];Normalize/@Differences@FindPath[Graph[e],#2,#3][[1]])&

С переносами строк:

(
p=x#[[##&@@x]];
m={c,v}Switch[p[c+v],0,m[c+v,v],1,c+v,_,c];
g=Cases[Array[List,Dimensions@#],c_/;p@c<2,{2}];
a=cm[c,#]&/@{{1,0},{-1,0},{0,1},{0,-1}};
e=Flatten[Table[#->c,{c,a@#}]&/@g,1];
Normalize/@Differences@FindPath[Graph[e],#2,#3][[1]]
)&

Моя непосредственная идея состояла в том, чтобы представить позиции льда и почвы в виде узлов на графике с направленными краями, соответствующими законным движениям, а затем использовать FindPath. Кто-то может подумать, что определение юридических шагов будет легкой частью, а поиск решения будет сложной. Для меня это было наоборот. Откройте для предложений о том, как вычислить края.

Первый аргумент #- это двумерный массив, 0представляющий лед, 1почву и 2камень.

Второй аргумент #2и третий аргумент #3являются начальной и конечной точками, соответственно, в форме {row,column}.

является 3 байта частного использования символов , U+F4A1представляющий \[Function].

объяснение

p=x#[[##&@@x]];

Определяет функцию, pкоторая принимает список xформы {row,column}и результатов #[[row,column]]; то есть значение лед / почва / камень по этой координате.

m={c,v}Switch[p[c+v],0,m[c+v,v],1,c+v,_,c]

Определяет функцию, mкоторая принимает начальную позицию cи вектор направления vи рекурсивно определяет, где вы окажетесь. Если c+vэто лед, то мы продолжаем скользить от этой точки, поэтому она возвращается m[c+v,v]. Если c+vэто почва, то мы идем c+vи останавливаемся. В противном случае (если c+vэто камень или за пределы), вы не двигаетесь. Обратите внимание, что это предназначено только для положения на льду или почве.

g=Cases[Array[List,Dimensions@#],c_/;p@c<2,{2}];

Определяет список gпозиций льда и почвы ( pзначение меньше, чем 2).

a=cm[c,#]&/@{{1,0},{-1,0},{0,1},{0,-1}}; 

Определяет функцию , aкоторая принимает стартовую позицию cи возвращают результаты перемещения в {1,0}, {-1,0}, {0,1}и {0,-1}направлениях. Там может быть некоторая избыточность. Опять же, это предполагает, что cсоответствует льду или почве.

e=Flatten[Table[#->c,{c,a@#}]&/@g,1];

Определяет список eнаправленных ребер, представляющих допустимые ходы. Для каждой позиции #в g, вычислите таблицу ребер #->cдля каждого cдюйма a@#. Затем, поскольку мы получим подсписок для каждой позиции #, я выравниваю первый уровень. Там может быть несколько петель и несколько ребер.

Normalize/@Differences@FindPath[Graph[e],#2,#3][[1]]

Graph[e]это график, где узлами являются допустимые позиции (лед или почва), а края представляют собой законные движения (возможно, натыкаясь на камень и не двигаясь). Затем мы используем, FindPathчтобы найти путь от #2к #3представленному в виде списка узлов. Поскольку FindPathдля поиска более одного пути могут использоваться дополнительные аргументы, результатом будет список, содержащий один путь, поэтому я использую первый элемент [[1]]. Затем я беру последовательные Differencesкоординаты и Normalizeих. Таким образом, вверх есть {-1,0}, вниз есть {1,0}, справа есть, {0,1}а слева есть {0,-1}.

Контрольные примеры

введите описание изображения здесь

введите описание изображения здесь

введите описание изображения здесь

введите описание изображения здесь

введите описание изображения здесь

ngenisis
источник
4

JavaScript (ES6) 180 183

(m,[x,y],[t,u],o=~m.search`
`,s=[[x-y*o,[]]],k=[])=>eval("for(i=0;[p,l]=s[i++],k[p]=t-u*o-p;)[-1,o,1,-o].map(d=>k[q=(M=p=>+m[p+=d]?m[p]<8?M(p):p:p-d)(p)]||s.push([q,[...l,d]]));l")

Используя BFS , как я сделал, чтобы решить эту связанную проблему

Входные данные
Карта лабиринта представляет собой многострочную строку, использующую Oили 0для камня, 8для почвы и любую ненулевую цифру меньше 8 для льда ( 7выглядит хорошо).
Начальная и конечная позиции начинаются с нуля.

Выходные данные
Список смещений, где -1 равно W1 E, отрицательное меньше -1 Nи положительное больше 1S

Меньше гольфа

(m,[x,y],[t,u])=>{
  o=~m.search`\n`
  s=[[x-y*o,[]]]
  k=[]
  for(i=0; [p,l]=s[i++], k[p]=1, t-u*o != p;)
  {
    [-1,o,1,-o].map(d=>(
      M=p=>+m[p+=d] ? m[p]<8 ? M(p) : p : p-d,
      q=M(p),
      k[q]||s.push([q,[...l,d]])
    ))
  }
  return l
}

Тестовое задание

Solve=
(m,[x,y],[t,u],o=~m.search`
`,s=[[x-y*o,[]]],k=[])=>eval("for(i=0;[p,l]=s[i++],k[p]=t-u*o-p;)[-1,o,1,-o].map(d=>k[q=(M=p=>+m[p+=d]?m[p]<8?M(p):p:p-d)(p)]||s.push([q,[...l,d]]));l")

function Go(maze) {
  var map = maze.textContent;
  var [sx,sy, dx,dy] = map.match(/\d+/g)
  --sx, --sy // zero based
  --dx, --dy // zero based
  map = map.split('\n').slice(1).join('\n') // remove first line
  var result = Solve(map.replace(/\./g, 7).replace(/~/g, 8), [sx,sy], [dx,dy])
  S.textContent = result
  Animate(maze, map, result, sx, sy)
}

function Display(maze, map, pos) {
  var row0 = maze.textContent.split('\n')[0]
  map = [...map]
  map[pos] = '☻'
  maze.textContent = row0+'\n'+map.join('')
}

function Animate(maze, map, moves, x, y) {
  console.log('A',moves)
  var offset = map.search('\n')+1
  var curPos = x + offset * y
  var curMove = 0
  var step = _ => {
    Display(maze, map, curPos)
    if (curMove < moves.length) 
    {
      curPos += moves[curMove]
      if (map[curPos] == 'O')
      {
        curPos -= moves[curMove]
        ++curMove
      }  
      else 
      {
        if (map[curPos] == '~') {
          ++curMove
        }
      }
      setTimeout(step, 100)
    }
    else
      setTimeout(_=>Display(maze,map,-1),500)
  }
  step()
}
td { 
  border: 1px solid #888;
}
Select maze<pre id=S></pre>
<table cellspacing=5><tr>
<td valign=top><input type=radio name=R onclick='Go(M1)'><br>
<pre id=M1>3,3 to 3,2  
OOOOO
OO.OO
O...O
OOOOO</pre></td>
<td valign=top><input type=radio name=R onclick='Go(M2)'><br>
<pre id=M2>15,12 to 16,8
OOOOOOOOOOOOOOOOO
O........O.....OO
O...O..........OO
O.........O....OO
O.O............OO
OO.......O.....OO
O.............OOO
O......O.......~O
O..O...........~O
O.............OOO
O.......O......OO
O.....O...O....OO
O..............OO
OOOOOOOOOOOOOO~~O
OOOOOOOOOOOOOOOOO</pre></td>
<td valign=top><input type=radio name=R onclick='Go(M3)'><br>
<pre id=M3>2,2 to 14,3
OOOOOOOOOOOOOOOO
O~~~~~OOOOO~~~~O
O~~O~OOOOOOO~~OO
O...O..........O
O........O.....O
O..............O
OO.............O
O.............OO
O....~....O....O
O..............O
O..............O
OOOOOOOOOOOOOOOO</pre></td>
<td valign=top><input type=radio name=R onclick='Go(M4)'><br>
<pre id=M4>2,2 to 11,11
OOOOOOOOOOOOOOOOOOO
O~~~~~~~OOOOOOOOOOO
O~~~~...OOOOOOOOOOO
OO~O~..OOOOOOOOOOOO
O..OO.............O
O..............O..O
O....O............O
O.O............~..O
O........OOOO.....O
O.......OOOOO.....O
O.......O~~~O.....O
O.......~~~~~.....O
O.......~~~~~.....O
O..........O......O
O..O..~...........O
O...............O.O
O.....O...........O
O.................O
OOOOOOOOOOOOOOOOOOO</pre></td>
</tr></table>

edc65
источник