HexaRegex: Martin Ender'e Bir Övgü


37

Martin Ender kısa süre önce 100.000’e ulaştı ve bazı harika dilleri buldu . Onlardan biriyle biraz eğleneceğiz, Hexagony (ve Retina için biraz regex )

Kısa bir bakış olarak, bir Hexagony ızgarası girişini yapan ve bu ızgara üzerinde bir metin dizesiyle eşleşen bir yol olup olmadığını belirleyen bir program yazmanız gerekir.

Yaratma

Hexagony, aşağıdaki adımları kullanarak bir metin dizesinden altıgenler oluşturur:

  1. Minimum altıgen boyutunu hesaplayın (dize uzunluğunu alın ve en yakın altıgen numarasına yuvarlayın )
  2. Metni yukarıdaki boyutta bir altıgenin içine sarma
  3. Kalan yerleri ile doldurma ..

Örneğin, metin dizgisi, abcdefghijklm3 yan uzunlukta bir altıgen gerektirir ve bu nedenle şöyle olur:

   a b c
  d e f g
 h i j k l
  m . . .
   . . .

Şimdi, altıgen şeklinde gidebileceğiniz 6 yol tarifi olduğuna dikkat edin. Örneğin, yukarıdaki altıgen içinde, ebitişiktir abfjid.

Sarma

Ayrıca, Hexagony'de, hexagons kaydırılır:

   . . . .          . a . .          . . f .          . a . .   
  a b c d e        . . b . .        . . g . .        . b . . f  
 . . . . . .      g . . c . .      . . h . . a      . c . . g . 
. . . . . . .    . h . . d . .    . . u . . b .    . d . . h . .
 f g h i j k      . i . . e .      . j . . c .      e . . i . . 
  . . . . .        . j . . f        k . . d .        . . j . .  
   . . . .          . k . .          . . e .          . k . .   

2. ve 4. örneğe bakarsanız, farklı yönlerde sarılmanıza rağmen, aynı noktalarda ave nasıl kolduklarını görün. Bu nedenden ötürü, bu lekeler sadece 5 diğer yere bitişiktir .

Bunu daha net yapmak için:

   a b c d
  e f g h i
 j k l m n o
p q r s t u v
 w x y z A B
  C D E F G
   H I J K
  1. Kenarlar zıt komşularına ( b->Ive G->j) sarılır .
  2. Üst / alt köşeler karşı merkez köşeye ve yukarı / aşağı ( d->K,pve H->a,v) sarılır .
  3. Merkez köşeleri hem üst hem de alt köşelere kaydırılır ( v->a,H)

Yollar

Bir yol, aynı konuma geri dönmeden bitişik konumlarda bir dizi olduğu için.

   a b c
  d e f g
 h i f k l
  m . . .
   . . .

Yukarıdaki altıgen, aefkgmgeçerli bir yoldur. Bununla birlikte, abfdgeçerli bir yol değildir ( fve dkomşu olmayan) ve abeageçerli (döner değildir akonumu).

Bu yolları metne uydurmak için kullanabiliriz (regex gibi) . Bir alfa sayısal karakter kendisi (ve yalnızca kendisi) ile .eşleşir ve herhangi bir karakterle eşleşir. Örneğin, yol aej..lgmeşleşir aej..lgm, aejAAlgm, aeja.lgm, veya aej^%gm.

Giriş çıkış

Programınız iki sıra almalıdır (herhangi bir sıra ile). İlk dize boş olacak ve sadece alfanümerik karakterlerden oluşacak [a-zA-Z0-9]. Bu, üzerinde işlemekte olduğunuz altıgeni temsil edecektir. İkinci dize yazdırılabilir karakterlerden oluşacaktır.

Altıgende verilen metin dizesiyle eşleşen bir yol varsa, aksi takdirde sahte bir değer varsa, bir gerçeği döndürmeniz gerekir.

Test durumları

Truthy:

"a","a"
"ab","a"
"ab","b"
"ab","ba"
"ab","aba"
"ab","&"
"ab","#7.J!"
"ab","aaaaaa"
"ab","bgjneta"
"ab","cebtmaa"
"abcdefg","dfabcg"
"AbCDeFG","GCbAeFD"
"aaaabbb","aaababb"
"abcdefghijklmnopqrs","alq"
"abcdefghijklmnopqrs","aqnmiedh"
"abcdefghijklmnopqrs","adhcgkorbefjimnqlps"
"11122233344455","12341345123245"
"abcdefgh","h%a"
"abcdefghijklm","a)(@#.*b"
"abcdefghijklm","a)(@#.*i"
"abcdefghij","ja"
"abcdefghijklmno","kgfeia"
"abcdefghijklmno","mmmmmiea"
"abcdefghijklmno","mmmmmlae"
"abcdefghijklmno","ja"
"abcdefghijklmnopqrs","eijfbadhmnokgcsrql"

Falsy:

"a","b"
"a","%"
"a","."
"a","aa"
"a","a."
"ab","#7.J!*"
"ab","aaaaaaa"
"ab","aaaabaaa"
"ab","123456"
"abcdefg","bfgedac"
"abcdefg","gecafdb"
"abcdefg","GCbaeFD"
"aaaabbb","aaaaabb"
"abcdefghijklmnopqrs","aqrcgf"
"abcdefghijklmnopqrs","adhlcgknbeifjm"
"abcdefghijklmnopqrs","ja"
"abcdefghijklm","a)(@#.*&"
"abcdefghijklmno","a)(@bfeijk"
"abcdefghijklmno","kgfeic"
"abcdefghijklmno","mmmmmmiea"

Bu bir , bu nedenle cevaplarınızı en sevdiğiniz dilde mümkün olduğunca kısa yapın.


21
Birisi bunu Hexagony'de yapmalı. : D
DJMcMayhem


9
Altıgenin regex (ler) in kaynağı olduğunu anlayana kadar , ikinci dize değil , başlangıçta çok şaşırdım . Akılda hala
bükülüyor

5
@DrGreenEggsandIronMan Birisi bunu Hexagony'de yaparsa 500 rep ödül alırım.
AdmBorkBork,

2
@Mavi Dolgusuz altıgen bir örnek önemlidir. Daha da önemlisi, "yol" ile "regex" arasındaki ayrımı yaptım.
Nathan Merrill,

Yanıtlar:


14

Retina , 744 bayt

Üzgünüm millet, bu sefer altıgen yok ...

Bayt sayısı, ISO 8859-1 kodlamasını varsayar.

.+¶
$.'$*_¶$&
^_¶
¶
((^_|\2_)*)_\1{5}_+
$2_
^_*
$.&$*×_$&$&$.&$*×
M!&m`(?<=(?=×*(_)+)\A.*)(?<-1>.)+(?(1)!)|^.*$
O$`(_)|.(?=.*$)
$1
G-2`
T`d`À-É
m`\A(\D*)(?(_)\D*¶.|(.)\D*¶\2)((.)(?<=(?<4>_)\D+)?((?<=(?<1>\1.)\4\D*)|(?<=(?<1>\D*)\4(?<=\1)\D*)|(?<=\1(.(.)*¶\D*))((?<=(?<1>\D*)\4(?>(?<-7>.)*)¶.*\6)|(?<=(?<1>\D*)(?=\4)(?>(?<-7>.)+)¶.*\6))|(?<=(×)*¶.*)((?<=(?<1>\1.(?>(?<-9>¶.*)*))^\4\D*)|(?<=(?<1>\D*)\4(?>(?<-9>¶.*)*)(?<=\1)^\D*)|(?<=(?<1>\1\b.*(?(9)!)(?<-9>¶.*)*)\4×*¶\D*)|(?<=(?<1>\D*\b)\4.*(?(9)!)(?<-9>¶.*)*(?<=\1.)\b\D*))|(?<=(?<1>\1.(?>(?<-11>.)*)¶.*)\4(.)*¶\D*)|(?<=(?<1>\1(?>(?<-12>.)*)¶.*)\4(.)*¶\D*)|(?<=(?<1>\1.(?>(?<-13>.)*¶\D*))\4(\w)*\W+.+)|(?<=(?<1>.*)\4(?>(?<-14>.)*¶\D*)(?<=\1.)(\w)*\W+.+))(?<=\1(\D*).+)(?<!\1\15.*(?<-1>.)+))*\Z

İlk satırdaki hedef dizgiyi ve girişin ikinci satırındaki altıgeni bekler. 0Veya 1buna göre yazdırır .

Çevrimiçi deneyin! (İlk satır, ¦bir satır besleme yerine ayırmak için kullanılan her satırın bir sınama durumu olduğu bir test takımını etkinleştirir .)

Bu zorluğu çözmenin doğru yolu elbette ki regex. ;) Ve bu zorluğun altıgenin açılma prosedürünü de içermemesi gerçeği olmasaydı, bu cevap aslında ~ 600 bayt uzunluğundaki tek bir regex'ten başka bir şeyden oluşmuyordu.

Bu henüz en iyi şekilde golf oynamadı, ancak sonuçtan oldukça memnunum (ilk çalışan sürümüm, adlandırılmış grupları ve akıl sağlığı için gereken diğer şeyleri çıkardıktan sonra 1000 bayt civarındaydı). Ben dize ve altıgen sırasını değiştirerek yaklaşık 10 bayt tasarruf edebileceğimi düşünüyorum ama sonunda regex tam bir yeniden yazma gerektirir, bu şu anda kadar hissetmiyorum. GSahneyi atlayarak 2 baytlık bir tasarruf da var , ancak çözümü oldukça yavaşlatıyor, bu yüzden elimden geldiğince golf oynayana kadar bu değişikliği yapmayı bekleyeceğim.

açıklama

Bu çözümün ana kısmı, dengeleme gruplarını kapsamlı bir şekilde kullanır , bu yüzden bunların nasıl çalıştığını anlamak istiyorsanız, onları okumanızı öneririm (eğer yapmazsanız sizi suçlamam ...).

Çözümün ilk kısmı (yani, son iki satır dışındaki her şey), Hexagony kaynak kodunu çözme yanıtımın değiştirilmiş bir versiyonudur . Hedef dizgiye dokunulmadan bırakarak altıgeni inşa eder (ve gerçekte hedef dizgiden önce altıgen oluşturur). Baytları kaydetmek için önceki kodda bazı değişiklikler yaptım:

  • Arkaplan karakteri ×bir boşluk yerine girişteki potansiyel boşluklarla çatışmayacak şekildedir.
  • No-op / joker karakter _yerine ., ızgara hücreleri güvenilir bir şekilde kelime karakterleri olarak tanımlanabilir.
  • Altıgen ilk yapıldıktan sonra herhangi bir boşluk veya girintiye eklemem. Bu bana eğimli bir altıgen veriyor, ancak bu gerçekten çalışmak için daha uygun ve bitişik kurallar oldukça basit.

İşte bir örnek. Aşağıdaki test durumu için:

ja
abcdefghij

Biz alırız:

××abc
×defg
hij__
____×
___××
ja

Bunu altıgenin normal mizanpajıyla karşılaştırın:

  a b c
 d e f g
h i j _ _
 _ _ _ _
  _ _ _

Komşuların, kuzey-batı ve güney-doğu komşuları hariç, şimdi her zamanki 8 Moore-komşusunun tümü olduğunu görebiliyoruz. Bu nedenle yatay, dikey ve güney-batı / kuzey-doğu komşulığını kontrol etmemiz gerekiyor (peki ve sonra sarma kenarları var). Bu daha küçük yerleşimi kullanmak ××, ihtiyaç duyduğumuzda anında altıgenin boyutunu belirlemek için sonunda bunları kullanabileceğimiz avantajına da sahip .

Bu form oluşturulduktan sonra, dizgenin tamamında bir değişiklik daha yaparız:

T`d`À-É

Bu, rakamları genişletilmiş ASCII harfleriyle değiştirir.

ÀÁÂÃÄÅÆÇÈÉ

Hem altıgen hem de hedef dizgede değiştirildiklerinden bu, dizginin eşleşip eşleşmediğini etkilemez. Ayrıca, çünkü onlar harfler \wve \bhala altıgen hücre olarak tanımlamak. Bu ikame yapmanın faydası \D, şimdiki regex'te herhangi bir karakterle (özellikle satır çizgileri ve satır çizgisi olmayan karakterler) eşleşmek için kullanabileceğimizdir . Bunu sgerçekleştirmek için seçeneği kullanamayız , çünkü .birkaç yerde satır içi olmayan karakterlerle eşleşmemiz gerekir .

Şimdi son bit: herhangi bir yolun verilen dizgimize eşleşip eşleşmediğini belirleme. Bu tek canavarca bir regex ile yapılır. Kendine neden sorabilirsin ? Peki, bu temelde bir geri izleme sorunudur: bir yere başlarsınız ve dizeyle eşleştiği sürece bir yol denersiniz ve bir kez geri dönüp, çalışan son karakterden farklı bir komşu denemezsiniz. bir şeyregex ile çalışırken ücretsiz olarak alabilmeniz geri izlemedir. Kelimenin tam anlamıyla regex motorunun yaptığı tek şey bu. Dolayısıyla, geçerli bir yolu tanımlamanın bir yolunu bulursak (bu tür bir sorun için yeterince zor, ancak kesinlikle dengeleme gruplarıyla mümkün), o zaman regex motoru bizim için olası olanların arasından bu yolu bulacaktır. Aramanın birden fazla aşamada ( ve daha önce de yaptım) elle yapılması kesinlikle mümkün olacaktır , ancak bu özel durumda daha kısa olacağından şüpheliyim.

Bunun bir regex ile uygulanmasındaki bir sorun, regex motorunun imlecini geri izleme sırasında (yol yukarı veya aşağı gidebileceğinden beri ihtiyacımız olan) dizge boyunca keyfi olarak öremememizdir. Bunun yerine, yakalama grubundaki kendi "imlecimizi" izliyor ve her adımda bunu güncelliyoruz (imleci geçici olarak bir bakış açısıyla hareket ettirebiliriz). Bu aynı zamanda, daha önce mevcut pozisyonu ziyaret etmediğimizi kontrol etmek için kullanacağımız tüm pozisyonları kaydetmemizi sağlar.

Öyleyse başlayalım. İşte regex'in biraz daha akılda kalıcı hali, isimlendirilmiş gruplar, girintiler, daha az rastgele komşular sırası ve bazı yorumlar:

\A
# Store initial cursor position in <pos>
(?<pos>\D*)
(?(_)
  # If we start on a wildcard, just skip to the first character of the target.
  \D*¶.
|
  # Otherwise, make sure that the target starts with this character.
  (?<first>.)\D*¶\k<first>
)
(?:
  # Match 0 or more subsequent characters by moving the cursor along the path.
  # First, we store the character to be matched in <next>.
  (?<next>.)
  # Now we optionally push an underscore on top (if one exists in the string).
  # Depending on whether this done or not (both of which are attempted by
  # the engine's backtracking), either the exact character, or an underscore
  # will respond to the match. So when we now use the backreference \k<next>
  # further down, it will automatically handle wildcards correctly.
  (?<=(?<next>_)\D+)?
  # This alternation now simply covers all 6 possible neighbours as well as
  # all 6 possible wrapped edges.
  # Each option needs to go into a separate lookbehind, because otherwise
  # the engine would not backtrack through all possible neighbours once it
  # has found a valid one (lookarounds are atomic). 
  # In any case, if the new character is found in the given direction, <pos>
  # will have been updated with the new cursor position.
  (?:
    # Try moving east.
    (?<=(?<pos>\k<pos>.)\k<next>\D*)
  |
    # Try moving west.
    (?<=(?<pos>\D*)\k<next>(?<=\k<pos>)\D*)
  |
    # Store the horizontal position of the cursor in <x> and remember where
    # it is (because we'll need this for the next two options).
    (?<=\k<pos>(?<skip>.(?<x>.)*¶\D*))
    (?:
      # Try moving north.
      (?<=(?<pos>\D*)\k<next>(?>(?<-x>.)*)¶.*\k<skip>)
    |
      # Try moving north-east.
      (?<=(?<pos>\D*)(?=\k<next>)(?>(?<-x>.)+)¶.*\k<skip>)
    )
  |
    # Try moving south.
    (?<=(?<pos>\k<pos>.(?>(?<-x>.)*)¶.*)\k<next>(?<x>.)*¶\D*)
  |
    # Try moving south-east.
    (?<=(?<pos>\k<pos>(?>(?<-x>.)*)¶.*)\k<next>(?<x>.)*¶\D*)
  |
    # Store the number of '×' at the end in <w>, which is one less than the
    # the side-length of the hexagon. This happens to be the number of lines
    # we need to skip when wrapping around certain edges.
    (?<=(?<w>×)*¶.*)
    (?:
      # Try wrapping around the east edge.
      (?<=(?<pos>\k<pos>.(?>(?<-w>¶.*)*))^\k<next>\D*)
    |
      # Try wrapping around the west edge.
      (?<=(?<pos>\D*)\k<next>(?>(?<-w>¶.*)*)(?<=\k<pos>)^\D*)
    |
      # Try wrapping around the south-east edge.
      (?<=(?<pos>\k<pos>\b.*(?(w)!)(?<-w>¶.*)*)\k<next>×*¶\D*)
    |
      # Try wrapping around the north-west edge.
      (?<=(?<pos>\D*\b)\k<next>.*(?(w)!)(?<-w>¶.*)*(?<=\k<pos>.)\b\D*)
    )
  |
    # Try wrapping around the south edge.
    (?<=(?<pos>\k<pos>.(?>(?<-x>.)*¶\D*))\k<next>(?<x>\w)*\W+.+)
  |
    # Try wrapping around the north edge.
    (?<=(?<pos>.*)\k<next>(?>(?<-x>.)*¶\D*)(?<=\k<pos>.)(?<x>\w)*\W+.+)
  )
  # Copy the current cursor position into <current>.
  (?<=\k<pos>(?<current>\D*).+)
  # Make sure that no matter how many strings we pop from our stack of previous
  # cursor positions, none are equal to the current one (to ensure that we use
  # each cell at most once).
  (?<!\k<pos>\k<current>.*(?<-pos>.)+)
)*
# Finally make sure that we've reached the end of the string, so that we've
# successfully matched all characters in the target string.
\Z

Umarım genel fikir bundan kabaca netleşir. Yol boyunca bu hareketlerden birinin nasıl çalıştığına bir örnek olarak imleci güneye hareket ettiren bit'e bakalım:

(?<=(?<pos>\k<pos>.(?>(?<-x>.)*)¶.*)\k<next>(?<x>.)*¶\D*)

Gözbebeklerinin sağdan sola (ya da alttan üste) okunması gerektiğini unutmayın, çünkü onların uygulandıkları sıra budur:

(?<=
  (?<pos>
    \k<pos>       # Check that this is the old cursor position.
    .             # Match the character directly on top of the new one.
    (?>(?<-x>.)*) # Match the same amount of characters as before.
    ¶.*           # Skip to the next line (the line, the old cursor is on).
  )               # We will store everything left of here as the new 
                  # cursor position.
  \k<next>        # ...up to a match of our current target character.
  (?<x>.)*        # Count how many characters there are...
  ¶\D*            # Skip to the end of some line (this will be the line below
                  # the current cursor, which the regex engine's backtracking
                  # will determine for us).
)

\k<pos>Bunun gerçekte dizenin başına ulaştığından emin olmak için önüne bir çapa koymak gerekli olmadığını unutmayın . <pos>her zaman ×başka hiçbir yerde bulunamayan bir miktarla başlar , bu yüzden bu zaten kapalı bir çapa görevi görür.

Bu gönderiyi gereğinden fazla şişirmek istemiyorum, bu yüzden diğer 11 vakayı da ayrıntılı olarak ele almayacağım, ancak prensip olarak hepsi aynı şekilde çalışıyor. <next>Dengeleme gruplarının yardımıyla eski imleç konumundan belirli (kabul edilebilir) bir yönde bulunup bulunmadığını kontrol ettik ve ardından yeni imleç konumu olarak dizgiyi bu maça uydurduk <pos>.


13

Python 3, 990 943 770 709 bayt

İlk cevap yay!

EDIT: Golf bitişik liste yapımı. Şimdi biraz farklı bir formül kullanıyorum

2 EDIT: Gereksiz tüyler kaldırıldı, çok daha fazla golf oynadı.

EDIT 3: Listedeki indeks listesinden koordinatlara dönüştürme kodunu kısalttı, birkaç şey daha attı.

Baytların büyük çoğunluğu, bitişiklik listesini yapmakla ilgilidir (golf oynamak için en büyük potansiyele sahiptir). O zamandan beri, çözümü zorla basit bir mesele (daha az byte olarak yapabildiğim).

golfed:

from math import*
b=abs
c=max
e=range
f=len
A=input()
B=input()
C=ceil(sqrt((f(A)-.25)/3)+.5)
D=3*C*~-C+1
E=2*C-1
F=C-1
A+='.'*(D-f(A))
G=[set()for x in e(D)]
I=lambda H:sum(E+.5-b(t-F+.5)for t in e(int(H+F)))
for x in e(D):
 r=sum([[J-F]*(E-b(J-F))for J in e(E)],[])[x];q=x-I(r);s=-q-r;a=lambda q,r:G[x].add(int(q+I(r)));m=c(map(b,[q,r,s]))
 if m==F:
  if q in(m,-m):a(-q,-s)
  if r in(m,-m):a(-s,-r)
  if s in(m,-m):a(-r,-q)
 for K,L in zip([1,0,-1,-1,0,1],[0,1,1,0,-1,-1]):
  M,H=q+K,r+L
  if c(map(b,[M,H,-M-H]))<C:a(M,H)
def N(i,O,P):
 Q=O and O[0]==A[i]or'.'==A[i];R=0
 if(2>f(O))*Q:R=1
 elif Q:R=c([(x not in P)*N(x,O[1:],P+[i])for x in G[i]]+[0])
 return R
print(c([N(x,B,[])for x in e(D)])*(f(B)<=D))

Ungolfed w / açıklama:

from math import*

#Rundown of the formula:
# * Get data about the size of the hexagon
# * Create lookup tables for index <-> coordinate conversion
#   * q=0, r=0 is the center of the hexagon
#   * I chose to measure in a mix of cubic and axial coordinates,
#     as that allows for easy oob checks and easy retrevial  
# * Create the adjacency list using the lookup tables, while
#   checking for wrapping
# * Brute-force check if a path in the hexagon matches the
#   expression

# shorten functions used a lot
b=abs
c=max
e=range

# Get input

prog=input()
expr=input()

# sdln = Side length
# hxln = Closest hexagonal number
# nmrw = Number of rows in the hexagon
# usdl = one less than the side length. I use it a lot later

sdln=ceil(sqrt((len(prog)-.25)/3)+.5)
hxln=3*sdln*~-sdln+1
nmrw=2*sdln-1
usdl=sdln-1

# Pad prog with dots

prog+='.'*(hxln-len(prog))

# nmbf = Number of elements before in each row
# in2q = index to collum
# in2r = index to row

nmbf=[0]*nmrw
in2q=[0]*hxln
in2r=[0]*hxln

#  4    5
#   \  /
# 3 -- -- 0
#   /  \ 
#  2    1

# dirs contains the q,r and s values needed to move a point
# in the direction refrenced by the index

qdir=[1,0,-1,-1,0,1]
rdir=[0,1,1,0,-1,-1]

# generate nmbf using a summation formula I made

for r in e(nmrw-1):
    nmbf[r+1]=int(nmbf[r]+nmrw+.5-b(r-sdln+1.5))

# generate in2q and in2r using more formulas
# cntr = running counter

cntr=0
for r in e(nmrw):
    bgnq=c(-r,1-sdln)
    for q in e(nmrw-b(r-sdln+1)):
        in2q[cntr]=bgnq+q
        in2r[cntr]=r-usdl
        cntr+=1

# adjn = Adjacency sets

adjn=[set()for x in e(hxln)]

# Generate adjacency sets

for x in e(hxln):
    #Get the q,r,s coords
    q,r=in2q[x],in2r[x]
    s=-q-r
    # a = function to add q,r to the adjacency list
    a=lambda q,r:adjn[x].add(q+nmbf[r+usdl])
    # m = absolute value distance away from the center
    m=c(map(b,[q,r,s]))
    # if we are on the edge (includes corners)...
    if m==usdl:
        # add the only other point it wraps to
        if q in(m,-m):
            a(-q,-s)
        if r in(m,-m):
            a(-s,-r)
        if s in(m,-m):
            a(-r,-q)
    # for all the directions...
    for d in e(6):
        # tmp{q,r,s} = moving in direction d from q,r,s
        tmpq,tmpr=q+qdir[d],r+rdir[d]
        # if the point we moved to is in bounds...
        if c(map(b,[tmpq,tmpr,-tmpq-tmpr]))<sdln:
            # add it
            a(tmpq,tmpr)

# Recursive path checking function
def mtch(i,mtst,past):
    # dmch = Does the place we are on in the hexagon match
    #        the place we are in the expression?
    # out = the value to return
    dmch=mtst and mtst[0]==prog[i]or'.'==prog[i]
    out=0
    # if we are at the end, and it matches...
    if(2>len(mtst))*dmch:
        out=1
    # otherwise...
    elif dmch:
        # Recur in all directions that we haven't visited yet
        # replace '*' with 'and' to speed up the recursion
        out=c([(x not in past)*mtch(x,mtst[1:],past+[i])for x in adjn[i]]+[0])
    return out

# Start function at all the locations in the hexagon
# Automatically return false if the expression is longer
# than the entire hexagon
print(c([mtch(x,expr,[])for x in e(hxln)])*(len(expr)<=hxln))

Retina'ya çok yakın! :( Yay, Retina'yı yendi!


5

Javascript (ES6), 511 500 496 bayt

(H,N)=>{C=(x,y)=>(c[x]=c[x]||[])[y]=y;S=d=>(C(x,y=x+d),C(y,x),C(s-x,s-y),C(s-y,s-x));r=(x,p,v)=>{p<N.length?(v[x]=1,c[x].map(n=>!v[n]&&(H[n]==N[p]||H[n]=='.')&&r(n,p+1,v.slice()))):K=1};for(e=x=K=0;(s=3*e*++e)<(l=H.length)-1;);H+='.'.repeat(s+1-l);for(a=[],b=[],c=[[]],w=e;w<e*2;){a[w-e]=x;b[e*2-w-1]=s-x;for(p=w;p--;x++){w-e||S(s-e+1);w<e*2-1&&(S(w),S(w+1));p&&S(1)}a[w]=x-1;b[e*3-++w]=s-x+1}a.map((v,i)=>S(b[i]-(x=v)));[N[0],'.'].map(y=>{for(x=-1;(x=H.indexOf(y,x+1))>-1;r(x,1,[]));});return K}

Ungolfed ve yorum yaptı

// Entry point
//   H = haystack (the string the hexagon is filled with)
//   N = needle (the substring we're looking for)
(H, N) => {
  // C(x, y) - Helper function to save a connection between two locations.
  //   x = source location
  //   y = target location
  C = (x, y) => (c[x] = c[x] || [])[y] = y;

  // S(d) - Helper function to save reciprocal connections between two locations
  //        and their symmetric counterparts.
  //   d = distance between source location (x) and target location
  S = d => (C(x, y = x + d), C(y, x), C(s - x, s - y), C(s - y, s - x));

  // r(x, p, v) - Recursive path search.
  //   x = current location in hexagon
  //   p = current position in needle
  //   v = array of visited locations
  r = (x, p, v) => {
    p < N.length ?
      (v[x] = 1, c[x].map(n => !v[n] && (H[n] == N[p] || H[n] == '.') &&
      r(n, p + 1, v.slice())))
    :
      K = 1
  };

  // Compute e = the minimum required edge width of the hexagon to store the haystack.
  // Also initialize:
  //   x = current location in hexagon
  //   l = length of haystack
  //   s = size of hexagon (number of locations - 1)
  //   K = fail/success flag
  for(e = x = K = 0; (s = 3 * e * ++e) < (l = H.length) - 1;);

  // Pad haystack with '.'
  H += '.'.repeat(s + 1 - l);

  // Build connections c[] between locations, using:
  //   x = current location
  //   w = width of current row
  //   p = position in current row
  // Also initialize:
  //   a[] = list of locations on top left and top right edges
  //   b[] = list of locations on bottom left and bottom right edges
  for(a = [], b = [], c = [[]], w = e; w < e * 2;) {
    a[w - e] = x;
    b[e * 2 - w - 1] = s - x;

    for(p = w; p--; x++) {
      // connection between top and bottom edges
      w - e || S(s - e + 1);
      // connections between current location and locations below it
      w < e * 2 - 1 && (S(w), S(w + 1));
      // connection between current location and next location
      p && S(1)
    }
    a[w] = x - 1;
    b[e * 3 - ++w] = s - x + 1
  }

  // Save connections between top left/right edges and bottom left/right edges.
  a.map((v, i) => S(b[i] - (x = v)));

  // Look for either the first character of the needle or a '.' in the haystack,
  // and use it as the starting point for the recursive search. All candidate
  // locations are tried out.
  [N[0], '.'].map(y => {
    for(x = -1; (x = H.indexOf(y, x + 1)) > -1; r(x, 1, []));
  });

  // Return fail/success flag.
  return K
}

Test durumları

Aşağıdaki kod parçası, tüm hakikat ve sahtekarlık test davalarında yürüyecek.

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.