Зробіть BackFlip для ais523!


16

Цей виклик є призом для ais523 за перемогу в категорії « Новачок року » у « Кращому PPCG 2016 ». Вітаємо!


BackFlip - це езотерична мова програмування, створена користувачем ais523 , який створив понад 30 інших цікавих езолангів .

BackFlip - це двовимірна мова на зразок Befunge або > <>, де вказівник інструкції перетинає сітку тексту (програма), рухаючись вгору, вниз, вліво та вправо, змінюючи напрямок залежно від символу, на якому він входить. Критично, сітка в програмі BackFlip змінюється під час її проходження, схоже на мурашник Ленґтона .

Для цього виклику ви можете припустити, що програма BackFlip - це завжди прямокутна сітка тексту (всі рядки однакової довжини), розміром 1 × 1 мінімум, містить лише символи ./\<>^V. ( .використовується для наочності, а не для простору.) Семантично BackFlip, який ми будемо використовувати тут, ідентичний оригіналу .

Покажчик інструкцій (IP) у BackFlip завжди починається зліва від верхнього лівого кута програми, заголовок праворуч. Існує три типи команд, з якими він може зіткнутися:

  1. .є не-оп. ІС триває в тому напрямку, в якому він йшов. Неоперативний залишається не-оп.

  2. /і \є дзеркалами. Вони відображають ІР у напрямку, вказаному їх кутом, потім переходять у дзеркало іншого типу .

    • Наприклад, якщо IP-голова залишилася в a \, вона починає рухатися вгору, а не вліво, і вона \стає a /.
  3. <, >, ^, І Vє стрілки. Вони переспрямовують IP в той напрямок, в якому вони вказують, потім перетворюються на стрілку, яка вказує в напрямку, з якого прийшов IP (навпроти напрямку, по якому рухався IP) .

    • Наприклад, якщо IP спрямовується вниз >, він починає рухатися направо, а не вниз, і >стає ^тим, що це напрямок, з якого пішов IP.

Програма BackFlip припиняється, коли IP виходить за межі, тобто виходить з мережі. Виявляється, всі програми BackFlip врешті-решт закінчуються, оскільки безмежні петлі неможливі. (Ви можете припустити, що це правда.)

Ваша мета в цьому виклику - написати програму або функцію, яка виконує програму BackFlip і видає кількість рухів, які вказує вказівник до закінчення програми. Тобто, скільки кроків виконує ІР під час роботи програми? Сюди входить початковий крок до сітки та останній крок від неї.

Наприклад, покажчик інструкцій робить 5 кроків у тривіальній сітці ....:

 ....  <- empty 4×1 grid
012345 <- step number of the IP

Таким чином, вихід ....є 5.

У більш складній сітці 4 × 2

\...
\.><

IP виходить з сітки на своєму 9-му кроці, тому вихід 9:

step  grid  IP position (@)
0     \...  @....
      \.><   ....

1     \...   @...
      \.><   ....

2     /...   ....
      \.><   @...

3     /...   ....
      /.><   .@..

4     /...   ....
      /.><   ..@.

5     /...   ....
      /.<<   ...@

6     /...   ....
      /.<<   ..@.

7     /...   ....
      /.><   .@..

8     /...   ....
      /.><   @...

9     /...   ....
      \.><   ....
             @

Виграє найкоротший код у байтах.

Ви можете приймати введення як масив рядків або матрицю символів замість багаторядкового рядка, якщо бажано, але ви повинні використовувати символи ./\<>^V(не цілочисельні опкоди). Ви можете використовувати простір замість, .якщо бажаєте. Це добре, якщо такі символи \потрібно уникати у введенні. Вихід завжди є цілим числом більше одного.

Випробування

....
5

\...
\.><
9

.
2

..
3

.
.
2

\
2

^
2

.^.
3

<.
2

\\
\/
7

>V
^<
6

>\
>/
6

\><
2

\><
\><
7

\><
\><
\><
12

\.V.
\.\<
5

\.V.
\./<
9

V./\
V./\
>./<
..\/
14

\V..
.^..
\/><
.V..
.^..
20

\.V.V.
\./.\<
.>\<..
..^.^.
31

\.V.V.V.
\./>/.\<
.>\>\<..
..^.^.^.
69

\.V.V.V.V.
\./>/>/.\<
.>\>\>\<..
..^.^.^.^.
145

\.V.V.V.V.V.V.V.V.V.V.
\./>/>/>/>/>/>/>/>/.\<
.>\>\>\>\>\>\>\>\>\<..
..^.^.^.^.^.^.^.^.^.^.
9721

1
Це така ганьба, що ви не можете прийняти рішення BackFlip для цього ...
HyperNeutrino

Плутати про дзеркала ... чи / перевертає напрямки як ліворуч => вгору і вгору => ліворуч?
officialaimm

1
@officialaimm Повернення ліворуч /вгору зробить IP-адресу вгору, а голова вгору /зробить IP-адресу направо, немовби м'яч відскакував від стіни. (Але пам’ятайте про /зміни в косому куті після того, як IP торкнеться її.)
Захоплення Кальвіна

чому '\\' <LF> '\ /' дорівнює 7, а не 6?
tsh

Відповіді:


3

JavaScript (ES6), 158 байт

f=(a,x=0,y=0,d=3)=>a[x]&&(c=a[x][y])?(a[x][y]=c=='.'?c:c=='/'?(d^=3,'\\'):c=='\\'?(d^=1,'/'):'v>^<'[d][d='^<v>'.search(c),0],f(a,d<3?x+d-1:x,d?y+d-2:y,d)+1):1

Розроблений незалежно від відповіді @ tsh, хоча вражаюче схожий.

Відображення напрямків ^<v>до цілих чисел 0-3 регулюється тим, що .search('^')повертає 0, оскільки ^є метасимволом регулярного виразів.


Я відчуваю себе так міцно побитий. Нарешті я був дуже розгублений, поки не зрозумів, що х і у були перевернуті порівняно з тим, що я очікував.
Ørjan Johansen

@ ØrjanJohansen Це хороший момент; можливо, я мушу поміняти x на y скрізь, щоб було легше зрозуміти.
Ніл

2

Haskell , 333 325 байт

Редагувати:

  • -8 байт: Зроблено fточково і об'єднано в b.

bбере список Strings і повертає Integer.

data C a=C{c::a->(a,C a)}
b g=[0,0]#([0,1],map(maybe(C$m 1)C.(`lookup`zip"./^>V<"[n,m(-1),a[-1,0],a[0,1],a[1,0],a[0,-1]]))<$>g)
[y,x]#(d,g)|g&y||g!!0&x=1|n@([f,e],_)<-(($d).c)?x?y$g=1+[y+f,x+e]#n
l&i=i<0||i>=length l
(f?i)l|(p,a:r)<-splitAt i l=(p++).(:r)<$>f a
n d=(d,C n)
a v d=(v,C$a$(0-)<$>d)
m s[d,e]=([s*e,s*d],C$m(-s))

Спробуйте в Інтернеті!

Як це працює

  • C a- це тип даних, який використовується, оскільки Haskell не дозволить рекурсивному типу, не заявляючи про це явно. Cтакож є конструктором для обгортки і cє відповідною функцією розгортання. Він використовується тільки з a=[Int].
    • Тип C [Int]являє собою команду комірки, як функцію, яка приймає [Int]аргумент напрямку ( ) і повертає пару нового напрямку та нового C [Int]значення.
  • bє основною функцією. Він перетворює кожен символ у Cзначення, а потім викликає #.
    • g - сітка як список рядків.
    • Оскільки \потрібно уникати, і такий найдовший символ потрібно згадати, його результат використовується як значення за замовчуванням для пошуку списку.
  • #запускає основне моделювання, перевіряючи межі &та генеруючи нові сітки за допомогою ?. [y,x]- поточне положення, dпоточний напрямок та gпоточна сітка. [f,e]є наступним напрямком, і nє його пара і наступна сітка.
  • l&iперевіряє, чи не є індекс iпоза межами списку l. (Він повертається Trueпоза межами, оскільки це дозволяє уникнути умови оберігання манекена #.)
  • Коли f(l!!i)==(d,x), (f?i)l==(d,m)де mзнаходиться список lіз iзаміненим елементом th x.
    • Технічно (?i)це більш загальний об'єктив, орієнтований на i-й елемент списку, в даному випадку використовується з (,) [Int]екземпляром функтора.
  • n - це функція, що представляє крапку.
  • a v- це функція, що представляє стрілку в напрямку v.
  • m s- функція, що представляє дзеркало; s==1за \\і s==-1за /.

1

JavaScript, 172 байти

f=(a,d=3,x=0,y=0,n=1)=>(p=a[y]||[],q=p[x])?(p[x]=~(t='^<V>'.indexOf(q))?'^<V>'[d^2]:q=='/'?(t=3-d,'\\'):q=='\\'?(t=d^1,'/'):(t=d,q),f(a,t,x+(t&1&&t-2),y+(~t&1&&t-1),n+1)):n

Але я не можу перевірити останній тестовий зразок, оскільки на моїй машині переповнюється стек. (повинен працювати, якщо є машина з більшим таран)

Ми використовуємо число для напрямку:

  • 0: ^
  • 1: <
  • 2: V
  • 3:>

Нехай dбуде номер напрямку ...

  • якщо ми зустрінемо '/', нам потрібно d = 3 - d;
  • якщо ми зустрінемо '\', нам потрібно d = d ^ 1;
  • якщо ми зустрінемо '^ <V>', нам потрібно d = '^ <V>' .indexOf (примітка)

Нехай (x, y)буде поточний стан, таке положення: x+(t&1&&t-2),y+(~t&1&&t-1)

Примітка:

Функція приймає один параметр у такому форматі:

[ [ '\\', '.', 'V', '.', 'V', '.', 'V', '.', 'V', '.' ],
  [ '\\', '.', '/', '>', '/', '>', '/', '.', '\\', '<' ],
  [ '.', '>', '\\', '>', '\\', '>', '\\', '<', '.', '.' ],
  [ '.', '.', '^', '.', '^', '.', '^', '.', '^', '.' ] ]

Тестуйте це тут

f=(a,d=3,x=0,y=0,n=1)=>(p=a[y]||[],q=p[x])?(p[x]=~(t='^<V>'.indexOf(q))?'^<V>'[d^2]:q=='/'?(t=3-d,'\\'):q=='\\'?(t=d^1,'/'):(t=d,q),f(a,t,x+(t&1&&t-2),y+(~t&1&&t-1),n+1)):n

    ;k=x=>x.split('\n').map(t=>t.split(''));
<textarea id=v>\.V.V.V.V.
\./>/>/.\<
.>\>\>\<..
..^.^.^.^.</textarea><br/><button onclick="r.textContent=f(k(v.value))">Solve</button>
<p>Result: <output id=r></output></p>


Тільки для документування я отримую Uncaught RangeError: Maximum call stack size exceeded16 Гб оперативної пам’яті.
Зеб МакКоркл

1
@ZebMcCorkle ага, просто дізнайся, що "використовувати суворо" та varдекларація змушує його пройти останню контрольну скриньку (js-інтерпретатор робить хвостовий дзвінок оптимізувати в суворому режимі)
tsh

1

C, 232 221 байт

d,n,t,m[4]={1,-1};char*w="><^V/\\.",*P;main(o,v)char**v;{for(P=v[1],m[2]=-(m[3]=strchr(P,10)-P+1);P>=v[1]&&P<strchr(v[1],0)&&*P^10;++n)*P=w[((o=d,t=strchr(w,*P)-w)<4)?d=t,o^1:(t<6)?d^=t-2,9-t:6],P+=m[d];printf("%d",n+1);}

Вводить перший аргумент, друкує результат. Потрібно, щоб вхід містив принаймні 1 новий рядок (тому, якщо є лише 1 рядок, він повинен закінчуватися новим рядком)

Приклад використання:

./backflip '....
';

Зламатися:

d,                                          // Direction
n,                                          // Step counter
t,
m[4]={1,-1};                                // Movement offsets
char*w="><^V/\\.",                          // Command lookup
*P;                                         // Cursor location
main(o,v)char**v;{
    for(P=v[1],                             // Begin at 0,0
        m[2]=-(m[3]=strchr(P,10)-P+1);      // Find width of grid
        P>=v[1]&&P<strchr(v[1],0)&&*P^10;   // While inside grid:
        ++n)                                //  Increment step
        *P=w[                               //  Update the current cell
            ((o=d,t=strchr(w,*P)-w)         //  (store current direction & command)
              <4)?d=t,o^1:                  //   If <>^V, write backflip & set dir
            (t<6)?d^=t-2,9-t:               //   If / or \, write flip & bounce
            6],                             //   If ., write unchanged & continue
        P+=m[d];                            //  Move
    printf("%d",n+1);                       // Print result
}

1

Python 3 , 286 байт

[f () приймає введення у вигляді, {(0,0):'/',(0,1):'.'}тому я також написав функцію g () для перетворення масиву рядків у цю форму]

def f(r):
 x=y=0;d='>';s=1
 while 1:
  try:c=r[y,x];m='>^<V'.find(d)
  except:break
  if(c=="\\"):d='V<^>'[m];r[y,x]="/"
  elif(c=="/"):d='^>V<'[m];r[y,x]="\\"
  elif(c!="."):r[y,x]='<V>^'[m];d=c
  x+=1if(d=='>')else-1if(d=='<')else 0;y+=1if(d=='V')else-1if(d=='^')else 0;s+=1
 return s

Спробуйте в Інтернеті!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.