Раскрытие секретов одномерному лабиринту


41

Задний план

Вы просыпаетесь, чтобы оказаться потерянным в одномерном лабиринте! Появляется мистический джинн (или что-то в этом роде), объясняющий, что перед вами лежит выход, но между вами и выходом есть ряд проблем. По мере продвижения вперед вы понимаете, что все так называемые вызовы - это просто запертые двери. Сначала вы видите дверь с отверстием для ключа в Tформе тройника и, не имея такого ключа самостоятельно, проследите свои шаги в поисках ключа с формой.

Разочарованный, вы найдете алфавитный суп из ключей на земле, ни один из которых не соответствует двери, с которой вы столкнулись. Каким-то гениальным ходом (или идиотизмом) вы решаете, что tстрочный ключ в форме буквы может уместиться в слоте, если вы зажмете его там достаточно сильно. Когда вы подходите к двери с tключом в нижнем регистре в руке, Tотверстие горит зеленым, и дверь распадается перед вами.

Один вниз, еще много, чтобы пойти ...

Вызов

Цель этого задания - указать, сколько шагов вам нужно, чтобы выйти из лабиринта.

Вход этой задачи - лабиринт: одна строка, содержащая только символы [A-Za-z^$ ]. Глоссарий:

  • ^- Стартовое пространство. Вход будет содержать ровно один ^.
  • $- Выход (свобода!). Вход будет содержать ровно один $.
  • [A-Z]- Прописные буквы обозначают двери. Вы можете пройти через эту дверь, только если уже собрали необходимый ключ.
  • [a-z]- Строчные буквы обозначают клавиши. Вы собираете эти ключи, идя на место, где находится ключ.

На входе будет не более одной заглавной буквы. Это означает, что общее количество дверей будет от 0 до 26 включительно.

Каждая запертая дверь [A-Z]будет иметь только один соответствующий ключ в нижнем регистре [a-z]. Во входе может быть любое количество пробелов ( ).

Все двери будут справа от начала и слева от выхода. При этом не будет лишних дверей. Все входные данные будут разрешимыми.

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

Алгоритм

Ваш методичный подход к выходу из этого жалкого места заключается в следующем:

  • Начать с начала (^ ) и двигайтесь вперед (вправо), собирая любые ключи, с которыми вы сталкиваетесь.
  • Когда вы сталкиваетесь с дверью, если у вас есть правильный ключ, вы идете вперед к двери. Если у вас нет правильного ключа, вы идете назад (влево), собирая ключи, с которыми сталкиваетесь, пока не найдете ключ для самой последней двери, которую вы не могли открыть.
  • Как только вы соберете ключ от текущей проблемной двери, вы поворачиваете назад направо и продолжаете идти дальше.
  • Повторяйте этот процесс, пока не наступите на выход ( $).

Опытные игроки в гольф поймут, что ваш код не должен реализовывать этот специфический алгоритм, если он выдает тот же результат, как если бы вы запускали этот алгоритм.

Counting

Каждый раз, когда вы переходите от одного квадрата к другому, это считается одним шагом. Поворот на 180º не требует дополнительного шага. Вы не можете выйти на дверь без необходимого ключа. Вы должны встать на ключ, чтобы забрать его, и должны выйти на выход, чтобы выиграть. После вашего первого хода начальная пробел ( ^) ведет себя так же, как и любой другой обычный пробел.

Примеры

В этих примерах я оставил пробелы в качестве подчеркивания для удобства чтения.

Вход есть _a_^_A__$__. Выход есть 11. Вы делаете 1шаг вперед, замечаете, что у вас нет ключа от Aдвери, а затем около лица. Вы идете назад, пока не займете пространство, содержащее a( 3шаги назад, теперь 4всего). Затем вы идете вперед, пока не займете пространство, содержащее выход ( 7шаги вперед,11 всего).

Вход есть b__j^__a_AJB_$. В результате 41вы совершаете две отдельные поездки в заднюю часть лабиринта: одна для получения jключа, а вторая для получения bключа.

Вход есть __m__t_^__x_T_MX_$____. Выход есть 44. Вы не совершите дополнительную поездку, чтобы получить xключ, так как подобрали его по пути от начала до двери T.

Вход есть g_t_^G_T$. Выход есть 12. Вы не можете выйти на Gпространство без ключа и сразу же повернуть лицом к лицу. Вам посчастливилось поднять tключ на пути к gключу и, таким образом, открыть обе двери на пути к свободе.

Вход есть _^_____$. Выход есть 6. Это было просто.

Руководство по вводу / выводу и критерий выигрыша

Применяются стандартные правила ввода / вывода. Это вызов .


17
Помимо приятной задачи, я хотел бы отметить, насколько хороши формулировка и объяснение
Луис Мендо

4
«Таким образом, не будет лишних дверей». Я думаю , что Aв bA^aB$не будет лишним ни. ;)
Мартин Эндер

4
@ orlp Мне больше интересно посмотреть, как люди играют в гольф по этому алгоритму блуждающих в темноте. Кажется тривиальным сделать оптимальное решение: «иди, возьми все ключи, иди и открой все двери».
турбулентность

2
@PeterTaylor и turbulencetoo Нет, это не так, кто сказал, что все ключи находятся слева, а все двери справа? И лишние ключи / двери тоже были бы интересны. Это было бы довольно интересно, так как это означало бы решение графа зависимостей.
orlp

5
У каждой двери есть ключ. У каждого ключа есть дверь?
user2357112 поддерживает Monica

Ответы:


3

CJam, 45

1q_'$#<'^/~\W%:A;ee{~32+A#)_T>{:T+2*+}&]0=)}/

Попробуйте онлайн

Объяснение:

1         initial step count; this 1 is actually for the last step :)
q_'$#<    read the input and only keep the part before the '$'
'^/~      split by '^' and dump the 2 pieces on the stack
\W%:A;    take the first piece, reverse it and store it in A
ee        enumerate the other piece (making [index char] pairs)
{…}/      for each [index char] pair
  ~32+    dump the index and character on the stack, and add 32 to the character;
           uppercase letters become lowercase and other chars become garbage
  A#)     find the index of this character in A and increment it (not found -> 0)
  _T>     check if this index (number of steps from '^' back to the key)
           is greater than T (which is initially 0)
  {…}&    if that's true (we need to go back), then
    :T    store that index in T (keeping track of how far we go back before '^')
    +     add to the other index (from the pair, number of steps we took after '^')
    2*    double the result (going back and forth)
    +     add it to the step count
  ]0=     keep only the first value from the bottom of the stack (step count)
           (if the condition above was false, we'd have 2 extra values)
  )       increment the step count (for the current step)

7

Pyth, 51 байт

JxQ"^"K-xQ"$"JVQI&}NrG1>JxQrN0=JxQrN0=+K*2t-xQNJ;pK

Суммируйте расстояние между дверью и ее ключом (удвоенное, чтобы совершить поездку в оба конца), игнорируя «вложенные» ключи и расстояние от начала до конца:

JxQ"^"                                              #Initialize the farther point with the starting position
      K-xQ"$"J                                      #Initialize the step counter with the difference between the exit and the start
              VQ                                    #iterate over the input
                I&}NrG1>JxQrN0                      #check if is upper and if the keys is father than one stored (to eliminate nested keys)
                              =JxQrN0               #update the farther key
                                     =+K*2t-xQNJ;   #update step counter with the round trip door<>key
                                                 pK #print the step counter

тот же алгоритм в python2.7:

lab=raw_input()
farther_key=lab.index('^')
steps = lab.index('$') - farther_key
for i in lab:
    if i.isupper():
        if farther_key> lab.index(i.lower()):
            farther_key=lab.index(i.lower())
            steps+=((lab.index(i) - farther_key)-1)*2
print steps

5

Python 2, 155 154 134 128 байт

Редактировать: Спасибо @ user2357112 и @loovjo за их комментарии, которые помогли мне убрать еще 20 26 байтов из моего решения!

def f(l):
 i=l.index;b=i('^');t=i('$')-b
 for d in filter(str.isupper,l):
  k=i(d.lower())
  if k<b:b=k;t+=2*(i(d)-k-1)
 print t

1
Вы можете объединить вторую и третью строку точкой с запятой, сохранив один байт. Кроме того, переменная i кажется ненужной в цикле.
Loovjo

Договорились на 2-й и 3-й строке, @Loovjo, но почему вы говорите, что iэто не нужно? iотслеживает положение двери, обрабатываемой в данный момент, и требуется, если ее ключ еще не был поднят (т. е. если k- положение ключа - меньше, чем f- крайний левый угол, который мы прошли, - то нам нужно добавить 2*(i-k-1)шаги к нашему общему количеству (идем налево, чтобы получить ключ, и идем обратно к двери) ...?
Кен «Джои» Мошер,

1
Но нельзя iли заменить l.index(d)на пятую строку, а назначение удалить на четвертой?
Loovjo

Отдельные eи fпеременные выглядят избыточными. Кроме того, вы можете сохранить несколько символов, сохранив l.indexпеременную.
user2357112 поддерживает Monica

@loovjo: Да, вы правы ... Я сначала неправильно понял ваш комментарий. @ user2357112: абсолютно правильно. xтакже является избыточным. Похоже, мой гольф-нуб-инесс показывает. :) Спасибо за помощь!
Кен «Джои» Мошер

4

C 136 байтов

q,x,p[300],z,c,k;main(i){for(;p[c=getchar()]=++i,c-36;z&&(k+=(x=p[c+32])&&x<q?(q=q>x?x:q,2*i-2*x-1):1))z=p[94],q||(q=z);printf("%d",k);}

4

PHP 5.3, 123 байта

Это мой первый пост на Code Golf, надеюсь, он достаточно высокого качества для первого поста. Определенно веселый вызов и потрясающий вопрос!

function n($m){while('$'!=$o=$m[$i++])$o=='^'?$b=$i+$c=0:$o>'Z'||$b<=$k=stripos($m,$o))?$c++:$c+=2*$i-3-2*$b=$k;return$c;}

Эта программа злоупотребляет тем фактом, что PHP не требует предварительного объявления каких-либо переменных перед их использованием.

Кроме того, в моем конечном решении оказалось, что на пару байт короче начинать с 0 и сбрасывать счетчик шагов при обнаружении начального символа, а не начинать с «^».

Любые советы, безусловно, приветствуются!


3

JavaScript (ES6), 110 байт

s=>(i=c=>s.indexOf(c),p=i`^`,l=i`$`-p,s.replace(/[A-Z]/g,(c,j)=>p>(t=i(c.toLowerCase()))?l+=j-(p=t)-1<<1:0),l)

Порт @ Роба Pyth ответ.


2

Python 2.7, 234 199 179

a=raw_input()
x=a.index
v=x('^')
b=x('$')-v
l=filter(str.islower,a[:v])[::-1]
for i in filter(str.isupper,a):
 k=i.lower()
 if k in l:b+=(x(i)-x(k)-1)*2;l=l[l.index(k)+1:]
print b

1

AWK, 174 байта

func f(xmS){x+=S
c=a[x]
if(c~/^[A-Z]/&&!k[c]){C=c
S=-S
s--}else{c=toupper(c)
k[c]=1
s++
if(c==C){S=-S;C=9}}if(c=="$"){print s}else f(x,S)}{split($0,a,"")
f(index($0,"^"),1)}

Там, вероятно, более жесткий алгоритм, но это то, что я придумал.

Обратите внимание, что я использую gawk. Некоторые реализации AWKмогут не разбивать строку ""таким образом.


1

C #, 309 байт

class P{static void Main(string[]a){string m=Console.ReadLine(),k="";var f=true;char b,c=b=' ';int j=m.IndexOf('^'),t=0;for(;m[j]!='$';j+=f?1:-1){c=m[j];if(char.IsUpper(c)){if(k.IndexOf(char.ToLower(c))<0){f=!f;b=c;t--;}}if(char.IsLower(c)){k+=c;if(char.ToUpper(c)==b){f=!f;t--;}}t++;}Console.WriteLine(t);}}

Безголовая версия:

    class P
{
    static void Main(string[] a)
    {
        string m = Console.ReadLine(), k = "";
        var f = true;
        char b, c = b = ' ';
        int j = m.IndexOf('^'), t = 0;
        for (; m[j] != '$'; j += f ? 1 : -1)
        {
            c = m[j];
            if (char.IsUpper(c))
            {
                if (k.IndexOf(char.ToLower(c)) < 0)
                {
                    f = !f; b = c; t--;
                }
            }

            if (char.IsLower(c))
            {
                k += c;
                if (char.ToUpper(c) == b) { f = !f; t--; }
            }


            t++;
        }
        Console.WriteLine(t);
        Console.ReadKey();

    }
}

Ничего особенного в этом нет, просто перебирайте строку и меняйте направление в зависимости от символа и от того, содержится ли ключ в строке ключей.

м = лабиринт

k = строка ключей

F = направление (истина вперед в лабиринте)

b = ключ для поиска при возврате

c = заполнитель для m [j] для сохранения некоторых байтов из-за частого использования

j = индекс символа строки для просмотра

т = количество

Все еще относительно новичок в гольфе, так что, если вы видите где-нибудь, я могу уменьшить его, дайте мне знать!

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.