Допоможіть, я потрапив у пастку на нескінченному заводі!


26

Цей виклик дуже натхненний грою Zachtronics Infinifactory .

Вам надається вид зверху вниз прямокутної сітки конвеєрів, представлених символом >v<^. Можуть бути комірки без конвеєрів, представлені пробілами. Ось приклад:

> <vv    <
 v ^ >v v 
  >v^^>vv^
    ^>^ v 
>  v<v  >>
  >v v<^  

Цей параметр неявно оточений нескінченною кількістю пробілів.

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

Звичайно, вантаж, ймовірно, охоплює відразу кілька конвеєрів, тому ось правила визначення напрямку вантажу на кожному кроці:

  1. Протилежні конвеєри скасовують один одного. Отже, якщо вантаж 3х2 покриває будь-який з наступних патчів (накреслений дефісами та трубами для наочності), результат буде таким самим:

    +---+   +---+   +---+
    |>>^|   |  ^|   |v^^|
    |^<<|   |^  |   |^^v|
    +---+   +---+   +---+
    

    Те саме стосується і таких:

    +---+   +---+   +---+
    |v^<|   |   |   |><>|
    |>>>|   |>> |   |>><|
    +---+   +---+   +---+
    

    Оскільки точне положення транспортера під вантажем не має значення, не важливо, які пари ви скасуєте.

    Це скасування застосовується перед іншими правилами. Тому для інших правил будуть лише конвеєри, щонайменше, у двох напрямках.

  2. Якщо вантаж взагалі не покриває жодних конвеєрів (або тому, що всі конвеєри скасовуються, тому що він покриває лише простір, або тому, що він повністю перемістився з сітки), він перебуває у спокої.
  3. Якщо вантаж охоплює більше транспортерів одного напрямку, ніж іншого, вантаж рухається в цьому напрямку. Наприклад, якщо вантаж 3х2 покрив наступний пластир

    >>
    ^>^
    

    вона буде рухатися вправо, тому що є більш >ніж ^. З іншого боку, якщо вона охоплювала

    >>^
      ^
    

    це правило не застосовуватиметься, оскільки існує зв'язок між >та ^.

  4. Це залишає лише випадки, коли між сусідніми напрямками існує зв'язок (зв’язок між протилежними напрямками скасувався б). У цьому випадку вантаж продовжує рухатись по осі, по якій він вже рухається. Наприклад, якщо вантаж, що рухається праворуч або рухається ліворуч 3х2, тепер покриває пластир

    >>^
    ^  
    

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

Детальні приклади

Розгляньте конвеєрну сітку вгорі та вантаж 3х2. Далі йде покрокова візуалізація процесу. Кожен крок складається з сітки з вантажем, представленим #невеликою коробкою, на якій зображені транспортери, накриті вантажем, ще одна коробка з конвеєрами після відміни та правило, яке визначає, куди рухається вантаж:

 ###vv    <    > <vv    <    > <vv    <    > <vv    <    > <vv    <    > <vv    <
 ###^ >v v     ###^ >v v      v ^ >v v      v ^ >v v      v ^ >v v      v ^ >v v 
   >v^^>vv^    ###v^^>vv^    ###v^^>vv^     ###^^>vv^      ###^>vv^      >###>vv^
     ^>^ v         ^>^ v     ### ^>^ v      ###^>^ v       ###>^ v        ###^ v 
 >  v<v  >>    >  v<v  >>    >  v<v  >>    >  v<v  >>    >  v<v  >>    >  v<v  >>
   >v v<^        >v v<^        >v v<^        >v v<^        >v v<^        >v v<^  

+---+  +---+  +---+  +---+  +---+  +---+  +---+  +---+  +---+  +---+  +---+  +---+
|> <|  |   |  | v |  | v |  |  >|  |  >|  | >v|  | >v|  |>v^|  |> ^|  |v^^|  | ^^|
| v |  | v |  |  >|  |  >|  |   |  |   |  |   |  |   |  |  ^|  |   |  | ^>|  |  >|
+---+  +---+  +---+  +---+  +---+  +---+  +---+  +---+  +---+  +---+  +---+  +---+

   Rule 3        Rule 4        Rule 3        Rule 4        Rule 4        Rule 3

 ================================================================================

 > <vv    <    > <###   <    > <vv    <
  v ###v v      v ###v v      v ###v v 
   >###>vv^      >v^^>vv^      >###>vv^
     ^>^ v         ^>^ v         ^>^ v 
 >  v<v  >>    >  v<v  >>    >  v<v  >>
   >v v<^        >v v<^        >v v<^  

+---+  +---+  +---+  +---+  +---+  +---+
|^ >|  |  >|  |vv |  | v |  |^ >|  |  >|
|v^^|  | ^^|  |^ >|  |  >|  |v^^|  | ^^|
+---+  +---+  +---+  +---+  +---+  +---+

   Rule 3        Rule 4        Rule 3

У цей момент вантаж потрапляє в петлю між останніми двома рамками.

А тепер розгляньте замість вантажу 2х3:

 ##<vv    <    >##vv    <    > <vv    <    > <vv    <    > <vv    <    > <vv    <
 ## ^ >v v      ##^ >v v      ##^ >v v      v ^ >v v      v ^ >v v      v ^ >v v 
 ##>v^^>vv^     ##v^^>vv^     ##v^^>vv^     ##v^^>vv^      ##^^>vv^      >v^^>vv^
     ^>^ v         ^>^ v      ## ^>^ v      ## ^>^ v       ##^>^ v       ##^>^ v 
 >  v<v  >>    >  v<v  >>    >  v<v  >>    >##v<v  >>    > ##<v  >>    > ##<v  >>
   >v v<^        >v v<^        >v v<^        >v v<^        >v v<^        ## v<^  

 +--+  +--+    +--+  +--+    +--+  +--+    +--+  +--+    +--+  +--+    +--+  +--+
 |> |  |> |    | <|  |  |    |v |  |v |    | >|  | >|    |>v|  |>v|    |  |  |  |
 | v|  | v|    |v |  |v |    | >|  | >|    |  |  |  |    |  |  |  |    | v|  | v|
 |  |  |  |    | >|  |  |    |  |  |  |    |  |  |  |    | v|  | v|    |>v|  |>v|
 +--+  +--+    +--+  +--+    +--+  +--+    +--+  +--+    +--+  +--+    +--+  +--+

   Rule 4        Rule 3        Rule 4        Rule 3        Rule 3        Rule 3

 ================================================================================

 > <vv    <    > <vv    <    > <vv    <
  v ^ >v v      v ^ >v v      v ^ >v v 
   >v^^>vv^      >v^^>vv^      >v^^>vv^
     ^>^ v         ^>^ v         ^>^ v 
 > ##<v  >>    >  v<v  >>    >  v<v  >>
   ## v<^        ## v<^        >v v<^  
   ##            ##            ##
                 ##            ##
                               ##

 +--+  +--+    +--+  +--+    +--+  +--+
 | v|  | v|    |>v|  |>v|    |  |  |  |
 |>v|  |>v|    |  |  |  |    |  |  |  |
 |  |  |  |    |  |  |  |    |  |  |  |
 +--+  +--+    +--+  +--+    +--+  +--+

   Rule 3        Rule 4        Rule 2

На останньому кроці застосовується правило 2, оскільки вантаж перемістився з сітки, тому він перебуває в спокої і не буде петлі.

Правила та припущення

Вашим входом буде сітка транспортера, як описано вище, разом із шириною та висотою вантажу. Ви можете приймати ці три параметри в будь-якому зручному порядку та форматі. Для сітки це означає, що ви можете прочитати один рядок з рядками, розділеними новими рядками або іншими символами, або масив рядків або масив масивів символів, поки окремі комірки сітки все ще представлені символами >v<^та пробіли.

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

Ви можете припустити, що сітка буде забита прямокутником з пробілами, і що вантаж спочатку поміститься в сітку.

Ви можете написати програму або функцію, взявши введення через STDIN (або найближчу альтернативу), аргумент командного рядка або аргумент функції та вивівши результат через STDOUT (або найближчу альтернативу), значення повернення функції або параметр функції (out).

Це кодовий гольф, тому найкоротша відповідь (у байтах) виграє.

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

Тестові приклади групуються за сітками.

Grid (2x2):

>v
^<

Width  Height  Loop?
1      1       True
1      2       True
2      1       True
2      2       False

Grid (3x3):

> v

^ <

Width  Height  Loop?
1      1       False
1      2       False
1      3       False
2      1       False
2      2       True
2      3       True
3      1       False
3      2       True
3      3       False

Grid (4x3):

>^>v
v^v 
^ <<

Width  Height  Loop?
2      2       False

Grid (6x5):

>v>v>v
^v^v^v
^v^v^v
^>^>^v
^<<<<<

Width  Height  Loop?
1      1       True
1      2       False
2      1       True
2      2       True
2      4       True
2      5       False
3      1       False
3      2       True
3      3       True
3      5       True
6      2       False
6      3       True
6      5       False

Grid (10x6):

> <vv    <
 v ^ >v v 
  >v^^>vv^
    ^>^ v 
>  v<v  >>
  >v v<^  

Width  Height  Loop?
1      1       False
2      3       False
2      6       False
3      2       True
5      4       False
6      1       True
10     6       False

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

Я перевірив усі тестові справи вручну, тому повідомте мені, якщо ви думаєте, що я помилився.



4
@Fatalize Я отримую флешбеки Pokemon Players ...
undergroundmonorail

"Вашим вкладом буде сітка транспортера, як описано вище, разом із шириною та висотою вантажу. Ви можете приймати ці три параметри в будь-якому зручному порядку та форматі." - це означає, що ми можемо мати сітку конвеєра взято як масив масивів? Тобто сітка 2x2 з [^^/v<]стає [[0,1] [0,1];[0,-1] [-1,0]]? Або ви маєте на увазі, що це від нас, чи це STDIN, рядок введення, вхід масиву char тощо, але це все одно має бути у формі ^, v,> та <?
Glen O

@GlenO Можна взяти розділений рядок з нового рядка (або іншого символу), масив рядків або масив масивів символів, але кожна комірка все ж повинна бути представлена ​​символами ><^vабо пробілом. Я це уточню.
Мартін Ендер

То що станеться, якщо вантаж рухається на конфлікт, коли подальший напрямок не є одним із варіантів? Тобто, якщо він рухався праворуч, то тепер треба вибирати між вгору та зліва.
Джошуа

Відповіді:


7

Рубі, 306 298 251 204 198

->g,w,h{m=->y,x,d,v=[]{q=y,x
r=->s{([""]*h+g)[y+h,h].map{|l|(?x*w+l)[x+w,w]}.join.count s}
z=k=r[?v]-r[?^],j=r[?>]-r[?<]
q[d=[d,1,0][j*j<=>k*k]]+=z[d]<=>0
v&[q<<d]!=[]?q!=v[-1]:m[*q,v<<q]}
m[0,0,1]}

Редагувати: Дякую Вентеро, який дуже скоротив код, застосувавши кілька дивовижних хитрощів!

Вхід і вихід

Код являє собою функцію рубіна, яка приймає три параметри:

  • сітка, представлена ​​як масив рядків (кожен рядок - різний рядок)
  • ширина вантажу
  • висота вантажу

Він повертається 1(truthy) у випадку, якщо є петля, або nil(фальшивий) у випадку, якщо вантаж опирається.

Тести

Ось він проходить усі тести Мартіна: http://ideone.com/zPPZdR

Пояснення

У коді немає розумних хитрощів; це досить просто реалізація правил.

У наведеному нижче коді moveє рекурсивна функція, яка робить рух відповідно до правил, і:

  • повертає truthy у випадку циклу
  • повертає помилкове у випадку відпочинку
  • інакше закликає себе виконати наступний хід

Більш читана версія доступна тут .

Примітка: код гольфу зазнав декількох модифікацій і більше не схожий на читану версію.


Оскільки не має значення, чи rмістять додаткові записи окрім чотирьох напрямків, r[y>=0&&x>=0&&g[y]&&g[y][x]]+=1слід зберегти кілька байтів.
Вентеро

Я трохи пізніше взяв на себе гольф, сподіваюся, ви не заперечуєте: ideone.com/k69BmH
Вентеро

@ Вентеро Вау, ви зробили дивовижні речі в коді. Я б ніколи не думав про перетворення хешу на лямбда. Я випробовував деякі свої ідеї, щоб скоротити програму, але ніде не було того, що ви робили. Дуже дякую!
Крістіан Лупаску

2
Знизився до 200 через дещо коротше обробку негативних показників, думаю, я покину це на цьому: ideone.com/k69BmH
Вентеро

2
Власне, 198: ideone.com/ptKrzf :)
Вентеро

8

Python 2, 207 байт

def f(L,w,h,u=0,v=0,D=1,S=[]):a,b,c,d=map(`[r[u*(u>0):u+w]for r in L[v*(v>0):v+h]]`.count,"v^><");D=cmp(abs(a-b),abs(c-d))<D;T=u,v,D;return T in S or a-b|c-d and f(L,w,h,u+cmp(c,d)*D,v+cmp(a,b)*0**D,D,S+[T])

Введіть сітку у вигляді списку рядків, наприклад

['>v>v>v', '^v^v^v', '^v^v^v', '^>^>^v', '^<<<<<']

слідом за шириною та висотою. Повертається 0або Trueвідповідно.

Пояснення

def f(L,          # Grid
      w,h,        # Width, height of cargo
      u=0,v=0,    # Position of top-left of cargo, initially (0, 0)
      D=1,        # Moving left/right = 1, up/down = 0
      S=[]        # Seen (pos, axis) pairs, initially empty
     ):     

     # Arrows under cargo - no need for "".join since we only need to count v^<>
     A = `[r[u*(u>0):u+w]for r in L[v*(v>0):v+h]]`

     # Count for each arrow
     a,b,c,d=map(A.count,"v^><")

     # Golfed form of abs(a-b) < abs(c-d) or (abs(a-b) == abs(c-d) and D == 1)
     D=cmp(abs(a-b),abs(c-d))<D
     T=u,v,D

     return (T in S                # Return True if (pos, axis) previously seen
             or a-b|c-d               # Return 0 if all conveyors cancel
             and f(L,w,h,             # Otherwise, recurse
                   u+cmp(c,d)*D,      # Update u if moving left/right
                   v+cmp(a,b)*0**D,   # Update v if moving up/down
                   D,
                   S+[T]          # Add (pos, axis) to seen
                  )
            )

Ви не можете скоротити його, призначивши cmpзмінну?
Синій

Чи достатньо виявити цикли, перевіривши вже відвідані позиції? Виходячи з правила 4, на наступний крок також може впливати попередній напрям. Тож можливо здається, що ви могли б дійти до однієї і тієї ж позиції двічі, але не мати циклу, оскільки рухаєтесь в різних напрямках, грунтуючись на різних попередніх напрямках.
Рето Коради

@muddyfish Це просто зламає
Sp3000

@RetoKoradi Сподіваємось виправлено
Sp3000

Так, додавання Dдо позиційного ключа повинно це зробити.
Рето Коради

8

Джулія - 394 300 246 214 байт

f(A,x,y)=(Z=sign;(S,T)=size(A);X=x+1;Y=y+1;G=fill(5,S+2y,T+2x);G[Y:S+y,X:T+x]=A;C=0G;D=1;while C[Y,X]!=D C[Y,X]=D;i,j=sum(i->1-[19 8]i%82%3,G[Y:Y+y-1,X:X+x-1]);D=Z(2i^2-2j^2+(i!=0)D);X+=Z(i+D*i);Y+=Z(j-D*j)end;D^2)

Повертає 1, якщо вантаж замикається, і 0, якщо він зупиняється. Це не "строго" truthy / falesy, в тому, що Джулія не дозволяє 0 і 1 в булевих контекстах ... але я вважаю значення, xдля яких bool(x)==trueправдиві і хибні bool(x)==false.

Введення Aмає бути у формі символьного масиву. Якщо ви копіюєте / вставляєте сітку конвеєра, вам потрібно буде перевести її у відповідну форму. Щоб врятувати вас від необхідності вручну обробляти це, скористайтеся наступним:

A=foldl(hcat,map(collect,split("""(PASTE GRID HERE)""","\n")))'

Там, де очевидно, (PASTE GRID HERE)слід замінити саму сітку. Двічі перевірте пробіли в кінці кожного рядка, щоб переконатися, що в ньому насправді є всі пробіли (він не перевіряє, щоб усі рядки були однакової довжини). Зауважте, що цей рядок не є частиною фактичного коду рішення, а лише зручним фрагментом коду, щоб полегшити використання коду рішення.

Безголівки:

function f(A,x,y)
  # Determine size of grid for use later
  (S,T)=size(A)
  # Initialise starting position (performed here to save characters)
  X=x+1
  Y=y+1
  # Create an expanded field that is functionally "spaces" (to provide
  # spaces at edges for the cargo to stop in)
  G=fill(5,S+2y,T+2x)
  # Put the conveyor grid into centre of the expanded field
  G[Y:S+y,X:T+x]=A
  # Create an array storing the most recent movement direction:
  # will use 1=horizontal, -1=vertical, 0=stopped
  C=0G
  # Initialise current direction (same system as C)
  D=1
  # Loop until it finds itself repeating a coordinate/direction pair
  while C[Y,X]!=D
    # Mark current coordinate/direction pair in array
    C[Y,X]=D
    # Determine the net coordinate pairing, stored in two variables
    # for golf purposes *SEE NOTE*
    i,j=sum(i->1-[19 8]i%82%3,G[Y:Y+y-1,X:X+x-1])
    # Determine new movement axis (if D=0, cargo stopped)
    D=sign(2i^2-2j^2+(i!=0)D)
    # Update X or Y depending on signs of D and the appropriate direction
    X+=sign(i+D*i)
    Y+=sign(j-D*j)
  end
  # if D=±1, return 1 (cargo is still moving), otherwise return 0
  return D^2
end

Примітка: 1-[19 8]i%82%3було обрано для відображення п'яти можливих символів до відповідних пар координат найефективнішим методом, який я міг знайти. Це також причина використання 5 для заповнення пробілів під час створення G- це одноцифровий символ, на який відображається [0 0].

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

julia> A=foldl(hcat,map(collect,split(""">v>v>v
       ^v^v^v
       ^v^v^v
       ^>^>^v
       ^<<<<<""","\n")))';

julia> f(A,2,1)
true

julia> f(A,3,3)
true

julia> f(A,5,2)
false

f(A,x,y)=коротше, ніж f=(A,x,y)->.
Олексій А.

@AlexA. - Правда, але тоді я, мабуть, видаляю f=та зроблю це анонімною функцією, коли закінчу гольф.
Глен О

1
Він буде однакової довжини, якщо це названа функція проти анонімної функції, коли є кілька параметрів. f()=проти ()->.
Олексій А.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.