Вечірка порталу лазерного дзеркала


27

2D - плата буде містити наступні об'єкти:

  • ^, >, v, Або <: лазерний випромінювач лицьовою стороною вгору, вправо, вниз, вліво або відповідно. Їх може бути більше. Лазери будуть рухатись по прямій лінії в порожньому просторі (порожній простір представлений крапкою .). Лазери не проходять через випромінювачі.
  • *: Ціль. Лазери проходять через цілі. Їх може бути більше.

Дошка може також містити такі об'єкти:

  • @: Суцільна стіна. Лазер тут не пройде.
  • \: Відбивач ліворуч . Змінює напрямок лазерів відповідно до наступної таблиці:

    Direction laser is travelling     Direction of laser after hitting reflector
    Up                                Left
    Right                             Down
    Down                              Right
    Left                              Up
    

    Це має бути досить інтуїтивно зрозумілим, як працюють рефлектори. Просто уявіть їх як фактичне двостороннє дзеркало, і напрямки повинні бути чіткими.

  • /: Відбивач правого нахилу . Змінює напрямок лазерів відповідно до наступної таблиці:

    Direction laser is travelling     Direction of laser after hitting reflector
    Up                                Right
    Right                             Up
    Down                              Left
    Left                              Down
    
  • 1, 2, 3... 9: портал . Цифра вказує на канал порталу - буде рівно два портали одного каналу (наприклад, трьох не буде 1). Портал змінює положення лазерів на положення іншого порталу того ж каналу. Наприклад:

    >     1     @     1     *
    

    Лазер вразить ціль, оскільки, потрапивши в перший 1, він телепортується на другий1 з іншого боку. Лазери зберігають той самий напрямок, в якому були раніше.

    Портал не телепортує лазер на портал іншого каналу (тобто 1не телепортує лазер на a 9.

Ваша програма отримає 2D-представлення дошки як вхідного. Дошка завжди буде прямокутної форми. Вихід повинен бути, Trueякщо всі цілі мають лазери, що проходять через них, або Falseіншим чином.

Ось кілька тестових випадків:

  1. Вхідні дані

    >....\
    ..*...
    >./../
    ..*...
    

    Вихідні дані

    True
    
  2. Вхідні дані

    >..........\
    1........../
    2..........1
    3..........2
    4..........3
    5..........4
    6..........5
    7..........6
    8..........7
    9..........8
    *..........9
    

    Вихідні дані

    True
    
  3. Вхідні дані

    >.@............*
    >..@...........*
    >...@..........*
    >....@.........*
    >.....@........*
    >...*..@........
    >.......@......*
    

    Вихідні дані

    False
    
  4. Вхідні дані

    ../\.
    >./**
    

    Вихідні дані

    False
    
  5. Вхідні дані

    /.......*.......\/3.....
    @..............//\.\....
    *.............2\.1\/\...
    \..............///.....<
    .........*...//\\/.....\
    >.............\.1.///.4.
    4.......*/...\2\/3/\/..^
    

    Вихідні дані

    True
    
  6. Вхідні дані

    vvvvvvvvvvvvvvvvv
    \\\\\\\\\\\\\\\\\
    /////////////////
    \\\\\\\\\\\\\\\\\
    /////////////////
    \\\\\\\\\\\\\\\\\
    /////////////////
    *****************
    

    Виведіть (відзначте ціль в крайньому правому куті)

    False
    

Чи не було б більше сенсу, якби праворуч відбивач (/) змінив напрямок лазерного променя зліва (←) на вниз (↓)?
писклива косточка

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

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

1
Що станеться, якщо лазер досягне межі сітки?
DavidG

2
@DavidG Нічого, або воно відскакує тому, як воно прийшло. (У цьому випадку вони рівноцінні). Це не «загортається», як видно з прикладу 6.
Денніс Джахеруддін,

Відповіді:


8

Пітон, 310 302 287 278 277 260

Не радикально відрізняється від існуючого допису Python, але, мабуть, має один-два примітних хитрощі. Він також обробляє "незакінчений" вхід, наприклад 1>1. Редагувати : На жаль! випромінювачі блокують лазери.

def t(b):
 w=len(b[0])+1;B=list('@'*w+'@'.join(b));i=l=len(B);C="<>^v@"
 while i:
    j=l-i;i-=1;d=C.find(B[j]);c='.'
    while c not in C:
     if'+'>c:B[j]='.'
     if'0'<c<C:j=(B*2).index(c,j+1)%l
     elif'.'<c:d^=2+(c<C)
     j-=[1,-1,w,-w,j][d];c=B[j%l]
 return'*'not in B

t приймає список рядків (рядків введення) і повертає бульний результат.

Ось приємний подарунок коду, який виграєте в гольф:

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

EDIT : Чудова gif ввічливість Вілл. Дякую Волі!


Специфікація вказує, що "Лазери не проходять через випромінювачі". так 1>1буде припинено. Мені не вдалося знайти те, що не припиняється, хоча я не доклав до цього великих зусиль і, напевно, припустив, що це не відбувається для моєї реалізації. Я, звичайно, перегляну, якщо хтось може її представити.
VisualMelon

4
@VisualMelon: Правила симетричні, за винятком тих місць, де лазери народжуються або гинуть, а це означає, що все має припинятися (оскільки ви завжди можете однозначно простежити це до того місця, де воно народилося, і випромінювачі не можуть самі бути частиною петлі).
Міхей

@Micah hehe, дякую за правильне пояснення, як я сказав, що я пішов з інтуїцією і не хвилювався з цього приводу, дякую, що поклав ще один інструмент у свою скриньку.
VisualMelon

Так, я неправильно прочитав.
Ell

Капелюхи до Елл! Дуже красиво зроблено. Я думаю, ви можете поголити ще кілька байт, скориставшись тим, що .find(d)повертає -1, якщо його не знайдено. Якщо ви видалите if-1<d:оператор і замість цього зробите j+=[-1,1,w,-w,-i][d]у верхній частині циклу while, не знайдений -1 перетвориться на додавання останнього елемента до цього масиву до j, який зробить j0, який ми знаємо, що це @...?
Буде чи

7

Перл, 647

Це моя перша в історії спроба коду-гольфу, і я трохи збентежений, що навіть не побив рахунок C #, але я подумав, що було б цікаво (або весело, або просто мазохістично) робити всю справу як серія підстановок регулярних виразів. (Я також думав, що було б приємно зайнятися моїм Perl, але до кінця я дуже пошкодував, що не реалізував це в Ruby чи Python.)

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

Сітка вводиться через STDIN. У вхідному документі має бути принаймні один новий рядок (тобто один рядок без нового рядка не працюватиме).

%s=(d,'[|+#$vk%ZX]',u,'[|+#$^W%KX]',r,'[-G+#>k%KX]',l,'[-G+#<W%ZX]');%o=(d,'[-.*G/k\\\\Z',u,'[-.*G/W\\\\K',r,'[|.*$\\\\/kK',l,'[|.*$\\\\/ZW');for$d(d,u,r,l){$o{$d}.='123456789qwertyuio]'}%u=(d,'.|-+*$G#/Wk%\KZX',u,'.|-+*$G#/kW%\ZKX',r,'.-|+*G$#/Wk%\ZKX',l,'.-|+*G$#/kW%\KZX');@q=split//,"qwertyuio";local$/;$_=<STDIN>;for$i(1..9){$m{$i}=$q[$i-1];$m{$m{$i}}=$i;s/$i/$m{$i}/e}/.*?\n/;$l='.'x((length$&)-1);do{$c=0;for$d(d,u,r,l){%p=(d,"(?<=$s{d}$l)$o{d}",u,"$o{u}(?=$l$s{u})",r,"(?<=$s{r})$o{r}",l,"$o{l}(?=$s{l})");%h=split//,$u{$d};$c+=s!$p{$d}!$h{$&}||($v=$&,($o{$d}=~s/$v// && $s{$d}=~s/]/$m{$v}]/),$v)!es}}while($c);print/\*/?"False\n":"True\n"

Пояснення: код ітераційно оновлює сітку рядка, коли лазери проходять через неї. -являє собою горизонтальний лазер, |вертикальний лазер, +схрещені лазери, Kа \дзеркало з лазерним відбиваючись від вершини, kа /дзеркало з лазерним відбиваючись від дна, Zа \дзеркало за допомогою лазера відбиваючись від дна, а Wна /дзеркало з лазерним відскакуючи вершина. %це /дзеркало з допомогою лазерів з обох сторін, в той час як Xце \дзеркало з допомогою лазерів з обох сторін. (Це чутливі до регістру. Я намагався підібрати літери, які виглядають дещо підходящим - наприклад, kтаKє дещо очевидним вибором - але, на жаль, ефект насправді не такий корисний. Мені справді слід покласти цю інформацію в таблицю, але я зараз вичерпана.)

Для обробки порталів таким же чином (тобто присвоєння кожній цифрі набору додаткових символів на основі можливих позицій лазера введення / виводу) потрібно 144 символи (включаючи початкові 9), тож замість того, коли лазер потрапляє на портал "вхід", Я додаю символу порталу "вихід" до набору символів, які випромінюють лазер у потрібному напрямку. (Для цього потрібно розрізняти вхідні та вихідні портали; qwertyuioдля цього я використовував букви .)

Дещо без поля, з друкованими висловлюваннями, щоб ви могли бачити заміну (кожна заміна являє собою один "раунд" лазерної прогресії), а gпрапор додається до основного, s///щоб він не займав стільки ітерацій:

# Throughout, d,u,r,l represents lasers going down, up, left, or right
# `sources` are the character classes representing laser "sources" (i.e. any
# character that can, on the next round, cause a laser to enter the space
# immediately adjacent to it in the proper direction)
%sources=(d,'[|+#$vk%ZX]',u,'[|+#$^W%KX]',r,'[-G+#>k%KX]',l,'[-G+#<W%ZX]');
# `open` characters will not block a laser
%open=(d,'[-.*G/k\\\\Z',u,'[-.*G/W\\\\K',r,'[|.*$\\\\/kK',l,'[|.*$\\\\/ZW');
# One of each portal is changed into the corresponding letter in `qwertyuio`.
# At the start, each portal is 'open' and none of them is a source.
for$d(d,u,r,l){$open{$d}.='123456789qwertyuio]'}
# A mapping of 'open' characters to the characters they become when a laser
# goes through them. (This is used like a hash of hashes; see the assignment
# of `%h` below.)
%update=(d,'.|-+*$G#/Wk%\KZX',
    u,'.|-+*$G#/kW%\ZKX',
    r,'.-|+*G$#/Wk%\ZKX',
    l,'.-|+*G$#/kW%\KZX');
@q=split//,"qwertyuio";
local$/;$_=<STDIN>;
for$i(1..9){
    $m{$i}=$q[$i-1];
    $m{$m{$i}}=$i;
    s/$i/$m{$i}/e}
print "After substituting portals:\n";
print;
print "\n";
# Find the number of characters in each line and create a string of `.`'s,
# which will be used to correlate characters above/below one another in the
# grid with each other.
/.*?\n/;
$l='.'x((length$&)-1);
do{
    $changes=0;
    for$d(d,u,r,l){
        # `patterns` is a mapping from each direction to the regex representing
        # an update that must occur (i.e. a place where a laser must progress).
        # Each pattern is either a lookahead or lookbehind plus the necessary
        # "open" character class.
        %patterns=(d,"(?<=$sources{d}$l)$open{d}",
            u,"$open{u}(?=$l$sources{u})",
            r,"(?<=$sources{r})$open{r}",
            l,"$open{l}(?=$sources{l})");
        %h=split//,$update{$d};
        # Match against the pattern for each direction. Note whether any
        # matches were found.
        $changes+=s!$patterns{$d}!
            # If the "open" character for a map is in the `update` map, return
            # the corresponding value. Otherwise, the "open" character is a
            # portal.
            $h{$&} || ($v=$&,
                        # For portals, remove the input portal from the
                        # proper "open" list and add the output portal to
                        # the proper "source" list.
                       ($open{$d}=~s/$v// && $sources{$d}=~s/]/$m{$v}]/),
                       $v)
                    # This whole substitution should allow `.` to match
                    # newlines (see the definition of `$l` above), and the
                    # replacement must be an expression rather than a string
                    # to facilitate the portal logic. The `g` allows multiple
                    # updates per "frame"; it is left out of the golfed code.
                    !egs
    }
    # Print the next "frame".
    print;
    print "\n";
# Continue updating until no "open" spaces are found.
}while($changes);
# Print whether `*` is still present in the input.
print/\*/?"False\n":"True\n"

Я експериментував з таким підходом (використовуючи масиви bool, а не регулярні виразки) в Python, але не зміг наблизитися до цього малого. Я думаю, що це дійсно підхід, що викликає роздуми! На мої спроби невдало вплинули catpad.net/michael/apl з приємними видами youtube.com/watch?v=a9xAKttWgP4 та petercollingridge.co.uk/blog/python-game-of-life-in-one-line
буде чи

1
@ Дякую! Я, безумовно, зрозумів, наскільки мої зусилля були для GoL приблизно в той час, коли я працював, наскільки можливо було б використовувати різний персонаж для кожної можливої ​​комбінації лазерів, що надходять на портал і виходять з нього. Я думаю, що я міг би поголити ще декількох персонажів, але ... це явно не є оптимальним підходом!
Кайл Странд

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

6

Пітон 338 351

def t(b):
 L=len;w=L(b[0])+3;b=list("@"*w+"@@".join(b)+"@"*w);w-=1;I=b.index
 for i in range(L(b)):
  c=b[i];d={"^":-w,"<":-1,">":1,"v":w}.get(c)
  if d:
   while c!='@':
    i+=d;c=b[i]
    if c=='*':b[i]='.'
    elif c in '/\\':d={-w:-1,w:1,1:w,-1:-w}[d]*(-1 if c=='/' else 1)
    elif c>'0':i+=I(c)-i or I(c,i+1)-i
 return "*" not in b

Моя немініфікована версія насправді розміщує лазерні доріжки на платі, що досить:

>-+--\
..X..|
>-/--/
..X...

>----------\
1----------/
2----------1
3----------2
4----------3
5----------4
6----------5
7----------6
8----------7
9----------8
X----------9

>-@............*
>--@...........*
>---@..........*
>----@.........*
>-----@........*
>---X--@........
>-------@......*

/-------X+------\/3.....
@........|.....//\+\....
X........|....2\+1\/\...
\--------+----+///+++--<
.........X...//\\/+++--\
>--------+---+\+1+///-4|
4-------X/...\2\/3/\/..^

vvvvvvvvvvvvvvvvv
\\\\\\\\\\\\\\\\\
/////////////////
\\\\\\\\\\\\\\\\\
/////////////////
\\\\\\\\\\\\\\\\\
/////////////////
XXXXXXXXXXXXXXXX*

def debug(board,x,y):
    emit_dir = {
        "^":    ( 0, -1),
        "<":    (-1,  0),
        ">":    ( 1,  0),
        "v":    ( 0,  1),
    }
    class PortalException(Exception): pass
    xdir, ydir = emit_dir[board[y][x]]
    while True:
        # print "step (%d, %d) (%d, %d)" % (x, y, xdir, ydir)
        x += xdir
        y += ydir
        if y < 0 or y >= len(board) or x < 0 or x >= len(board[y]):
            return
        ch = board[y][x]
        if ch == '/':
            xdir, ydir = -ydir, -xdir
        elif ch == '\\':
            xdir, ydir = ydir, xdir
        elif ch in '@^><v':
            return
        elif ch == '*':
            board[y] = board[y][:x] + 'X' + board[y][x+1:]
        elif ch in '.-|':
            ch = ('-' if xdir else '|') if ch == '.' else '+'
            board[y] = board[y][:x] + ch + board[y][x+1:]
        elif ch in '123456789':
            try:
                for r in range(len(board)):
                    for c in range(len(board[r])):
                        if board[r][c] == ch and (r != y or c != x):
                            x, y = c, r
                            raise PortalException()
                raise Exception("could not find portal %s (%d,%d)" % (ch, x, y))
            except PortalException:
                pass

5

C # - 515 414 400 байт

Повна програма C #, не такий приємний вихід, як у Will. Працює, дотримуючись лазерного шляху для кожного випромінюваного окремо, та зберігаючи масив клітин, які ми відвідали, щоб ми могли перевірити, що ми відвідали всі зірки наприкінці. Редагувати: смугаста велика кількість байтів, зробивши все 1D і використовуючи char замість int для зберігання поточного char

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

Код для гольфу:

using C=System.Console;class P{static void Main(){var S=C.In.ReadToEnd().Replace("\r","");int W=S.IndexOf('\n')+1,l=S.Length,i=l,d,m,n;var M=new int[l];for(char c;i-->0;)for(d="^<v>".IndexOf(c=S[m=i]);c>14&d>-1;d=(m+=d==2?W:d>0?d-2:-W)>=0&m<l&&"@^<v>".IndexOf(c=S[m])<0?d:-1)for(d=c==47?3-d:c==92?d^1:d,M[n=m]=1;c%49<9&&(m=S.IndexOf(c,m+1))==n|m<0;);for(;l-->0;)W*=S[l]==42?M[l]:1;C.WriteLine(W>0);}}

Менше коду для гольфу:

using C=System.Console;

class P
{
    static void Main()
    {
        var S=C.In.ReadToEnd().Replace("\r",""); // read the grid, remove pesky carriage returns
        int W=S.IndexOf('\n')+1,l=S.Length,i=l,d,m,n; // find "width"
        var M=new int[l]; // defaults to 0s

        for(char c;i-->0;) // for each cell

            for(d="^<v>".IndexOf(c=S[m=i]); // find initial direction, if any
                c>14&d>-1; // loop only if we have direction
                d=(m+=d==2?W:d>0?d-2:-W) // move (after iteration)
                >=0&m<l&&"@^<v>".IndexOf(c=S[m])<0?d:-1) // terminate if we hit something or go off edge

                for(d=c==47?3-d:c==92?d^1:d, // mirrors
                    M[n=m]=1; // we have seen this spot
                    c%49<9&&(m=S.IndexOf(c,m+1))==n|m<0;); // portals

        for(;l-->0;) // for each cell
            W*=S[l]==42?M[l]:1; // if *, then mul by whether seen

        C.WriteLine(W>0);
    }
}

Новий код обробки порталу використовує той факт, що функція String.IndexOf щасливо повертає -1 (тобто знака не знайдено), якщо ви попросите його почати шукати 1 символ поза рядком (викидає виняток, якщо ви попросите його почати далі за межі). Це було для мене новиною, але в цьому випадку було надзвичайно зручно.


+1 Чудовий гольф! Я просто подумав , що підступ: ви могли б взяти m+=(d>0?d-2:0)+(d<3?d-1:0)*W;і засунути його в for, як це: for(char c;i-->0;m+=(d>0?d-2:0)+(d<3?d-1:0)*W). Таким чином, ви збережете одну табличку, бо втратите крапку з комою.
Крістіан Лупаску

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