Лазерный Зеркальный Портал Вечеринка

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не будет телепортироваться лазер на 9.

Ваша программа получит двухмерное представление доски в качестве входных данных. Доска всегда будет прямоугольной формы. Вывод должен быть, 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

Python, 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 берет список строк (входные строки) и возвращает логический результат.

Вот хороший гиф кода, играющего в гольф:

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

РЕДАКТИРОВАТЬ : Awsome GIF любезно Уилл. Спасибо, Уилл!

флигель
источник
В спецификации указано, что «лазеры не проходят через излучатели». так 1>1кончится. Я не смог найти что-то, что не заканчивается, хотя я не приложил много усилий и предположил, что этого не произойдет для моей реализации. Я, конечно, пересмотрю, если кто-то может представить один.
VisualMelon
4
@VisualMelon: правила являются симметричными по времени, за исключением мест, где лазеры рождаются или умирают, что означает, что все должно заканчиваться (поскольку вы всегда можете однозначно отследить его до того места, где оно родилось, а излучатели сами не могут быть частью петли).
Михей
@Micah хе-хе, спасибо за правильное объяснение, как я уже сказал, что я пошел с интуицией и не сильно беспокоился об этом, спасибо за то, что поместил еще один инструмент в мою коробку.
VisualMelon
Да, я прочитал это неправильно.
Ell
Снимаю шляпу перед Элл! Очень красиво сделано. Я думаю, что вы можете сбрить еще несколько байтов, используя тот факт, что .find(d)возвращает -1, если не найден. Если вы удалите if-1<d:оператор и вместо этого сделаете j+=[-1,1,w,-w,-i][d]в верхней части цикла while, не найденный -1 превратится в добавление последнего элемента в этом массиве j, что даст j0, который, как мы знаем, @...?
Будет
7

Perl, 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, а не regex) в Python, но не смог подобраться так близко к этому маленькому. Я думаю, что это действительно заставляющий задуматься подход! На мои попытки напрасно повлияли catpad.net/michael/apl с хорошим видео youtube.com/watch?v=a9xAKttWgP4 и petercollingridge.co.uk/blog/python-game-of-life-in-one-line
Будет
1
@ Буду благодарен! Я определенно осознал, насколько схожи мои усилия с GoL в то время, когда я выяснил, насколько возможно было бы использовать разные символы для каждой возможной комбинации лазеров, входящих и выходящих из портала. Я думаю, что я мог бы сбрить еще несколько персонажей, но ... это явно не оптимальный подход!
Кайл Стрэнд,
Кроме того, если кто-нибудь знает лучший способ обработать тройные экранированные `` в классах персонажей в первых нескольких строках, это было бы прекрасно ...
Кайл Стрэнд,
6

Python 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 #, нет хороших результатов, как у Уилла. Работает, следуя пути лазерного луча для каждого испускаемого индивидуально, и сохраняя массив ячеек, которые мы посетили, чтобы мы могли проверить, что мы посетили все звезды в конце. Редактировать: чередовать большое количество байтов, делая все 1D и используя char вместо int для хранения текущего char

w0lf напомнил мне, что в середине моего кода у меня был недоиспользуемый цикл for, поэтому я решил, что лучше приложить еще одну попытку и заставить его работать, и теперь я дошел до абсолютного минимального числа фигурных брекеты. Я не буду притворяться, что мне нравится сворачивание второго цикла for, код теперь ужасно беспорядочный, но он сэкономил несколько байтов. В процессе я переписал портальную обработку. Я также нашел более короткий метод для выполнения «перемещения» с помощью вложенной, а не агрегированной условной операции.

Гольф-код:

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 символ за строкой (выдает исключение, если вы просите его начать дальше). Это было для меня новостью, но в данном случае это было очень удобно.

VisualMelon
источник
+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 сделал последнее усилие и сумел полностью свернуть циклы for, спасибо за толчок;)
VisualMelon