Lazer Ayna Portal Partisi


27

Bir 2D kurulu olacak aşağıdaki nesneleri içerir:

  • ^, >, v, Veya <: bir lazer yukarı bakacak yayıcı, sağa, aşağı veya sırasıyla bıraktı. Birden fazla olabilir. Lazerler boş alanda düz bir çizgide ilerleyecektir (boş alan bir nokta ile gösterilir .). Lazerler vericilerden geçmez.
  • *: Bir hedef. Lazerler hedeflerden geçer . Birden fazla olabilir.

Kurulu olabilir aşağıdaki nesneler içerir:

  • @: Sağlam bir duvar. Lazer buradan geçmeyecek.
  • \: Bir eğimli reflektör. Lazerlerin yönünü aşağıdaki tabloya göre değiştirir:

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

    Reflektörlerin nasıl çalıştığı konusunda oldukça sezgisel olmalıdır. Onları gerçek bir iki taraflı ayna olarak hayal edin; yol tarifleri açık olmalıdır.

  • /: Bir eğimli reflektör. Lazerlerin yönünü aşağıdaki tabloya göre değiştirir:

    Direction laser is travelling     Direction of laser after hitting reflector
    Up                                Right
    Right                             Up
    Down                              Left
    Left                              Down
    
  • 1, 2, 3... 9: Bir portalı . Sayı, portalın kanalını gösterir - aynı kanalın tam olarak iki portalı olacak (örneğin, üç tane olmayacak 1). Portal değiştiren pozisyonlar , aynı kanalın diğer portalında konumuna lazerlerin. Örneğin:

    >     1     @     1     *
    

    Lazer hedefi vurur, çünkü birinciye çarptığında diğer taraftaki 1ikinciye ışınlanır 1. Lazerler daha önce bulundukları yönü korurlar.

    Bir portal, lazeri farklı bir kanalın portalına 1ışınlamaz (yani, bir lazeri bir ışınlamayacaktır) 9.

Programınız kartın 2B gösterimini girdi olarak alacak. Tahta her zaman dikdörtgen şeklinde olacaktır. Çıktı, Truetüm hedeflerin içinden geçen lazerler veya Falsebaşka şekilde olması durumunda olmalıdır .

İşte bazı test durumları:

  1. Giriş

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

    Çıktı

    True
    
  2. Giriş

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

    Çıktı

    True
    
  3. Giriş

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

    Çıktı

    False
    
  4. Giriş

    ../\.
    >./**
    

    Çıktı

    False
    
  5. Giriş

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

    Çıktı

    True
    
  6. Giriş

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

    Çıktı (en sağdaki hedefi not edin)

    False
    

Sağa eğimli bir yansıtıcı (/) lazer ışınının yönünü sola (←) aşağıdan (↓) değiştirirse daha anlamlı olmaz mıydı?
pembemsi ossifrage 10:14

@squeamish ossifrage Üzgünüm, sorunuzu anlamıyorum. Sence sol eğilimli reflektör masaya hangi yansıma kural yanlıştır?
pelin otu

Sanırım sola ve sağa
karışıksınız

1
Lazer ızgara sınırına ulaşırsa ne olur?
DavidG

2
@DavidG Hiçbir şey veya geldiği gibi geri sekiyor. (Bu durumda bunlar eşdeğerdir). Örnek 6'dan görülebileceği gibi 'etrafa
sarılmaz'

Yanıtlar:


8

Python, 310 302 287 278 277 260

Bence, mevcut Python post'undan kökten farklı değil, fakat bir veya iki kayda değer hileci var. Ayrıca, "sonlandırılmayan" bir girdi gibi işler 1>1. EDIT : Hata! yayıcılar lazerleri bloke eder.

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 dizelerin bir listesini alır (giriş satırları) ve bir boolean sonuç döndürür.

İşte kod aşağı golf oynuyor güzel bir gif:

görüntü tanımını buraya girin

EDIT : Awsome gif, Will'in izniyle. Teşekkürler Will!


Teknik özellik "Lazerlerin yayıcılardan geçmediğini" belirtir . bu yüzden 1>1sona erecek. Çok fazla çaba harcamamış olmama rağmen uygulamam için gerçekleşmeyeceğini varsaydığım halde, sona ermeyen bir şey bulamadım. Tabii birisini sunabilir mi diye bir daha düşüneceğim
VisualMelon

4
@VisualMelon: Kurallar, lazerlerin doğduğu veya öldüğü noktalar haricinde, zamanla simetriktir; bu, her şeyin sona ermesi gerektiği anlamına gelir (çünkü onu her zaman benzersiz bir şekilde, doğduğu noktaya kadar izleyebilirsin ve yayıcılar kendileri olamazlar) bir döngü).
Micah,

@Micah hehe, doğru bir açıklama için teşekkürler, sezgiyle başladım ve çok endişelenmedim dediğim gibi, kutuma başka bir araç koyduğunuz için teşekkürler.
VisualMelon

Evet, yanlış okudum.
Ell

Ell'e şapka çıkartın! Çok iyi yapmışsın. Bence .find(d)bulunmazsa -1 döndüren gerçeği kullanarak birkaç baytı daha tıraş edebilirsiniz . Eğer kaldırırsanız if-1<d:deyimi ve yapılacak yerine j+=[-1,1,w,-w,-i][d]ise döngü üstünde bir-bulunamadı -1 ekleyerek dönüşecektir son o dizideki eleman jyapacak, jbiz biliyoruz 0, @...?
Will

7

Perl, 647

Bu benim ilk kez kod-golf denemem ve biraz utandım C # puanı bile geçmedim, ama her şeyi bir şey gibi yapmanın ilginç (veya eğlenceli veya sadece mazoşist) olacağını düşündüm. regex ikameleri dizisi. (Perl'i tazelemenin eğlenceli olacağını düşündüm, ama sonunda Ruby veya Python'da uygulamadığıma pişman oldum.)

Çok fazla test yapmadım, ama sanırım her durumda halletmesi gerektiğini .

Şebeke STDIN üzerinden girilir. Girişte en az bir yeni satır olmalı (örn. Yeni satır olmadan tek satır çalışmayacaktır).

%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"

Açıklama: Kod, lazerlerin içinden geçen ızgara dizgisini yinelemeli olarak günceller. -yatay lazer temsil eder, |dikey bir lazer, +çapraz lazerler, Kbir \lazer üst, çarparak ayna k, bir /lazer alt, çarparak ayna Z, bir \alt sıçrayan bir lazerle aynası ve Wbir /lazer çarparak ayna üst. %Bir olduğu /süre, her iki tarafta lazerlerle ayna Xbir olan \her iki tarafta lazerlerle ayna. (Bunlar büyük / küçük harfe duyarlıdır. Biraz uygun görünen mektuplar seçmeye çalıştım - örneğin kveKbiraz belirgin seçimlerdir - ancak ne yazık ki etkisi gerçekten o kadar da yardımcı değil. Bu bilgiyi gerçekten bir tabloya koymalıyım ama şu anda çok yoruldum.)

Portalların aynı şekilde kullanılması (yani her bir basamağa, olası giriş / çıkış lazer konumlarına bağlı olarak ekstra karakter kümesinin atanması), 144 karakter (orijinal 9 dahil), yani bir lazer bir "giriş" portalına çarptığında, "Çıkış" portal karakterini, doğru yönde bir lazer yayan karakter kümesine ekliyorum. (Bu, giriş ve çıkış portalları arasında ayrım yapılmasını gerektirir; bunun için harfleri kullandım qwertyuio.)

Biraz golf oynamayı bıraktığımda, baskı ifadeleriyle, yerine geçenleri görebiliyorsunuz (her bir ikame lazerin ilerlemesinin bir "turunu temsil ediyor)" ve anaya geklenen bayrak s///çok fazla yineleme yapmaz.

# 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"

Python'da bu tür bir yaklaşımla (regex yerine bool dizileri kullanarak) denedim, ancak bu kadar küçük bir yere yaklaşamadım. Bence bu gerçekten düşündürücü bir yaklaşım! Denemelerim yanlış başlıkla catpad.net/michael/apl tarafından güzel bir vid ile youtube.com/watch?v=a9xAKttWgP4 ve petercollingridge.co.uk/blog/python-game-of-life-in-one-line
Will

1
@ Will Teşekkürler! Çabalarımın çabalarım boyunca GoL'le ne kadar benzer olduğunu kesinlikle anladım, ancak bir porta girip çıkan her lazer kombinasyonu için farklı bir karakter kullanmanın ne kadar mümkün olduğunu anladım. Sanırım birkaç karakter daha traş olabilir, ama ... bu açıkça en uygun yaklaşım değil!
Kyle Strand

Ayrıca, biri ilk kaçıştaki karakter sınıflarında üçlü kaçanlarla başa çıkmanın daha iyi bir yolunu bilen biri olursa, bu iyi olurdu ...
Kyle Strand

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

Büyütülmemiş sürümüm aslında tahta üzerindeki lazer yollarını çiziyor:

>-+--\
..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 bayt

C # programını tamamlayın, Will'inki gibi hoş bir çıktı yok. Her biri için ayrı ayrı yayılan lazer yolunu takip ederek ve hangi hücreleri ziyaret ettiğimizi takip ederek çalışır, böylece sonunda tüm yıldızları ziyaret ettiğimizi kontrol edebiliriz. Düzenleme: her şeyi 1B yaparak ve mevcut karakteri saklamak için int yerine bir char kullanarak çok sayıda bayt çizgili

w0lf bana kodumun tam ortasındaki bir for-loop kullandığımı hatırlattı, bu yüzden son bir çaba sarf edip çalışmaya başladığımı düşündüm, ve şimdi mutlak asgari kıvrım sayısına düşüyorum parantez. Saniyenin döngü için çöküşünü sevmiş gibi davranmayacağım, kod şimdi korkunç düzensiz, ancak birkaç bayt kurtardı. Bu süreçte portal işlemeyi yeniden yazdım. Ayrıca, "koşulu" gerçekleştirmek için toplanmış koşullu işlem yerine yuvalanmış olan daha kısa bir yöntem buldum.

Golf kodu:

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);}}

Daha az golf kodu:

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);
    }
}

Yeni portal işleme kodu, String.IndexOf işlevinin dizginin ötesinde 1 karakter aramaya başladığını sorarsanız mutlu bir şekilde -1 döndürür (yani char bulunamadı). Bu bana haber oldu, ama bu durumda çok uygun oldu.


+1 Harika golf! Ben sadece bir hile düşündü: Eğer alabilir m+=(d>0?d-2:0)+(d<3?d-1:0)*W;ve sapla forbu gibi: for(char c;i-->0;m+=(d>0?d-2:0)+(d<3?d-1:0)*W). Bu şekilde, bir karakter kaydedersiniz, çünkü noktalı virgül kaybedersiniz.
Cristian Lupascu

@ w0lf son bir çaba sarf etti ve dürtmeler için teşekkürler, döngüler için tamamen çökertmeyi başardı;)
VisualMelon
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.