C #, 600 574 байта
Завершить программу, принимает ввод из STDIN, вывод в STDOUT.
Редактировать: была ошибка в обработке переноса (не нарушалась ни в одном из приведенных тестовых случаев), которая добавляла 1 байт, поэтому я сделал немного больше игры в гольф, чтобы компенсировать это.
using Q=System.Console;struct P{int p,d;static void Main(){string D="",L;int w=0,W=0,o,n=1;for(;(L=Q.ReadLine())!=null;D+=L)w=(o=(L+="X").Length+1)>w?o:w;for(;W<D.Length;)D=D.Insert(W+1,"".PadLeft(D[W++]>87?w-W%w:0));P[]K=new P[W*6];var T=new string[W*6];P c=K[o=0]=new P{p=D.IndexOf('S')};for(System.Action A=()=>{if(c.p>=0&c.p<W&System.Array.IndexOf(K,c)<0&&D[c.p]%8>0){T[n]=T[o]+L;K[n]=c;n=D[c.p]==69?-n:n+1;}};o<n;o++){c=K[o];L="R";c.d=++c.d%6;A();L="L";c.d=(c.d+4)%6;A();L="F";c=K[o];c.p+=new[]{~w,1-w,2,1+w,w-1,-2}[c.d%6];A();}Q.WriteLine(n>0?"Invalid maze!":T[-n]);}}
Это начинается с чтения на карте, добавляя (
к каждой строке, чтобы он знал, где она заканчивается, и может вернуться назад и добавить множество пробелов, чтобы сделать карту прямоугольной, и с рядом пробелов по правой стороне (это сохраняет мы делаем проверку упаковки, как будет объяснено ниже). Он определяет ширину прямоугольника в некоторой точке и определяет общую длину карты.
Затем он инициализирует все для поиска в ширину. Созданы два массива biggish: один для хранения всех состояний, которые мы должны исследовать в нашем поиске, другой для записи маршрута, который мы выбрали, чтобы добраться до каждого состояния. Начальное состояние добавляется в должный массив с указателями головы и хвоста, предварительно установленными как-то выше. Все 1 проиндексировано.
Затем мы повторяем, пока хвост не врезается в голову, или, по крайней мере, не появляется , что врезался в голову. Для каждого состояния, которое мы посетили, мы пытаемся добавить новое состояние в ту же позицию, где мы поворачиваемся влево или вправо, а затем в то, где мы продвинулись. Направления индексируются, причем начальное направление (по умолчанию 0
) соответствует значению «вверх-влево».
Когда мы пытаемся поставить в очередь состояние, оно проверяется с привязкой, но не с проверкой на перенос, из-за столбцов пробелов с правой стороны, на которые указывает «мы можем быть здесь?» проверить (вам не разрешено находиться на пробелах). Если состояние ставится в очередь, мы затем проверяем, находится ли оно в E
ячейке, и если оно есть, мы устанавливаем начало очереди как минус, что приводит к выходу из основного цикла, и выдает последнюю строку программы для печати. соответствующий маршрут, а не сообщение об ошибке (которое показывает, если у нас кончаются состояния для расширения (хвост врезается в голову)).
using Q=System.Console;
// mod 8 table (the block of zeros is what we are after - it's everywhere we /can't/ go)
// 0 (space)
// O 0
// X 0
// S 3
// + 3
// E 5
struct P
{
int p,d;
static void Main()
{
// it's probably a bad thing that I have my own standards for naming this stupid read sequence by now
string D="", // map
L; // line/path char
int w=0, // width
W=0, // full length
o, // next state to expand
n=1; // next state to fill
for(;(L=Q.ReadLine())!=null;D+=L) // read in map
w=(o=(L+="X").Length+1)>w?o:w; // assertain max length (and mark end, and remove any need for wrap checking)
// now we need to add those trailing spaces...
for(;W<D.Length;)
D=D.Insert(W+1,"".PadLeft(D[W++]>87?w-W%w:0)); // inject a load of spaces if we hit an X
P[]K=new P[W*6]; // create space for due states (can't be more states than 6*number of cells)
var T=new string[W*6]; // create space for routes (never done it this way before, kind of exciting :D)
P c=K[o=0]=new P{p=D.IndexOf('S')}; // set first state (assignment to c is just to make the lambda shut up about unassigned variables)
// run bfs
for(
System.Action A=()=> // this adds c to the list of states to be expanded, if a whole load of checks pass
{
if(//n>0& // we havn't already finished - we don't need this, because we can't win on the first turn, so can't win unless we go forward, which we check last
c.p>=0&c.p<W& // c is within bounds
System.Array.IndexOf(K,c)<0&& // we havn't seen c yet (the && is to prevent the following lookup IOBing)
D[c.p]%8>0) // and we can move here (see table at top of code)
{
T[n]=T[o]+L; // store route
K[n]=c; // store state
n=D[c.p]==69?-n:n+1; // check if we are at the end, if so, set n to be negative of itself so we know, and can look up the route (otherwise, increment n)
}
}
;o<n;o++) // o<n also catches n<0
{
c=K[o]; // take current
L="R"; // say we are going right
c.d=++c.d%6; // turn right
A(); // go!
L="L"; // say we are going left
c.d=(c.d+4)%6; // turn left
A(); // go!
L="F"; // say we - you get the picture
c=K[o];
c.p+=new[]{~w,1-w,2,1+w,w-1,-2}[c.d%6]; // look up direction of travel (~w = -w-1)
A();
}
// check if we visited the end
Q.WriteLine(n>0?"Invalid maze!":T[-n]); // if n<0, then we found the end, so spit out the corresponding route, otherwise, the maze is invlida
}
}
Как и большинство моих поисков по графику на этом сайте, я хорошо использую структуры C #, которые по умолчанию сравниваются по буквальному значению.