HexaRegex: Cống hiến cho Martin Ender


37

Martin Ender gần đây đã đạt 100 nghìn và đã đưa ra một số ngôn ngữ khá tuyệt vời . Chúng tôi sẽ có một chút niềm vui với một trong số họ, Hexagony (và một chút regex cho Retina )

Như một tổng quan ngắn gọn, bạn cần viết chương trình nhập vào lưới Hexagony và xác định xem có đường dẫn nào trên lưới đó khớp với một chuỗi văn bản không

Tạo

Hexagony tạo ra các hình lục giác từ một chuỗi văn bản bằng các bước sau:

  1. Tính kích thước hình lục giác tối thiểu (lấy chiều dài của chuỗi và làm tròn đến số lục giác gần nhất )
  2. Gói văn bản thành một hình lục giác có kích thước trên
  3. Điền vào các vị trí còn lại với ..

Ví dụ: chuỗi văn bản abcdefghijklmyêu cầu một hình lục giác có độ dài cạnh 3 và do đó trở thành:

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

Bây giờ, lưu ý rằng có 6 hướng có thể bạn có thể đi trong một hình lục giác. Ví dụ, trong hình lục giác trên, eliền kề abfjid.

Bao bì

Hơn nữa, trong Hexagony, hexagons bọc:

   . . . .          . 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 . .   

Nếu bạn nhìn vào ví dụ thứ 2 và thứ 4, hãy chú ý cách akở cùng một điểm, mặc dù thực tế là bạn đang quấn theo các hướng khác nhau. Do thực tế này, những điểm này chỉ liền kề với 5 địa điểm khác .

Để làm cho điều này rõ ràng hơn:

   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. Edges bọc cho hàng xóm đối diện của họ ( b->IG->j).
  2. Góc trên / dưới bao quanh góc trung tâm đối diện và lên / xuống ( d->K,pH->a,v).
  3. Các góc trung tâm bao bọc cả góc trên cùng và dưới cùng ( v->a,H)

Đường dẫn

Một đường dẫn là một chuỗi các vị trí liền kề mà không quay lại cùng một vị trí.

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

Trong hình lục giác trên, aefkgmlà một đường dẫn hợp lệ. Tuy nhiên, abfdkhông phải là đường dẫn hợp lệ ( fdkhông liền kề) và abeakhông hợp lệ (trở về avị trí).

Chúng ta có thể sử dụng các đường dẫn này để khớp văn bản (như regex) . Một ký tự chữ và số khớp với chính nó (và chỉ chính nó) và .khớp với bất kỳ ký tự nào. Ví dụ, con đường aej..lgmsẽ phù hợp với aej..lgm, aejAAlgm, aeja.lgm, hoặc aej^%gm.

Đầu ra đầu vào

Chương trình của bạn nên có hai chuỗi (theo thứ tự bất kỳ). Chuỗi đầu tiên sẽ không trống và chỉ bao gồm các ký tự chữ và số [a-zA-Z0-9]. Điều này sẽ đại diện cho hình lục giác bạn đang hoạt động. Chuỗi thứ hai sẽ bao gồm các ký tự có thể in được.

Bạn cần trả về một giá trị trung thực nếu có một đường dẫn trong hình lục giác khớp với chuỗi văn bản đã cho, nếu không thì là giá trị giả.

Các trường hợp thử nghiệm

Sự thật:

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

Giả mạo:

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

Đây là một , vì vậy hãy đưa ra câu trả lời của bạn càng ngắn càng tốt bằng ngôn ngữ yêu thích của bạn.


21
Ai đó nên làm điều này trong Hexagony. : D
DJMcMayhem


9
Ban đầu tôi rất bối rối bởi các ví dụ trung thực cho đến khi tôi nhận ra rằng hình lục giác là nguồn của regex (es) , có thể nói, không phải là chuỗi thứ hai. Vẫn còn đang suy nghĩ ...: P
El'endia Starman

5
@DrGreenEggsandIronMan tôi sẽ đưa ra một tiền thưởng 500 đại diện nếu ai đó không làm điều này trong Hexagony.
admBorkBork

2
@Blue Một ví dụ về hình lục giác không hàn là rất quan trọng. Quan trọng hơn, tôi đã phân biệt giữa "con đường" và "regex".
Nathan Merrill

Câu trả lời:


14

Võng mạc , 744 byte

Xin lỗi mọi người, không có Hexagony lần này ...

Số lượng byte giả định mã hóa ISO 8859-1.

.+¶
$.'$*_¶$&
^_¶
¶
((^_|\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

Yêu cầu chuỗi đích trên dòng đầu tiên và hình lục giác trên dòng thứ hai của đầu vào. In 0hoặc 1theo đó.

Hãy thử trực tuyến! (Dòng đầu tiên cho phép một bộ kiểm tra, trong đó mỗi dòng là một trường hợp thử nghiệm, sử dụng ¦để phân tách thay vì một nguồn cấp dữ liệu.)

Cách thích hợp để giải quyết thách thức này là với một regex tất nhiên. ;) Và nếu thực tế là thách thức này cũng liên quan đến thủ tục mở ra của hình lục giác , thì câu trả lời này thực sự sẽ không có gì ngoài một regex dài ~ 600 byte.

Điều này chưa hoàn toàn được đánh gôn, nhưng tôi khá hài lòng với kết quả này (phiên bản làm việc đầu tiên của tôi, sau khi loại bỏ các nhóm được đặt tên và các thứ khác cần thiết cho sự tỉnh táo, là khoảng 1000 byte). Tôi nghĩ rằng tôi có thể tiết kiệm khoảng 10 byte bằng cách hoán đổi thứ tự của chuỗi và hình lục giác nhưng nó sẽ yêu cầu viết lại hoàn toàn regex ở cuối, điều mà tôi không cảm thấy ngay bây giờ. Ngoài ra còn có tiết kiệm 2 byte bằng cách bỏ qua Ggiai đoạn, nhưng nó làm chậm giải pháp một cách đáng kể, vì vậy tôi sẽ chờ đợi để thực hiện thay đổi đó cho đến khi tôi chắc chắn rằng tôi đã chơi golf tốt nhất có thể.

Giải trình

Phần chính của giải pháp này sử dụng rộng rãi các nhóm cân bằng , vì vậy tôi khuyên bạn nên đọc chúng, nếu bạn muốn hiểu cách thức hoạt động của chi tiết này (tôi sẽ không đổ lỗi cho bạn nếu bạn không ...).

Phần đầu tiên của giải pháp (tức là tất cả mọi thứ trừ hai dòng cuối cùng) là phiên bản sửa đổi của câu trả lời của tôi để mở ra mã nguồn Hexagony . Nó xây dựng hình lục giác, trong khi không để lại chuỗi đích (và nó thực sự xây dựng hình lục giác trước chuỗi mục tiêu). Tôi đã thực hiện một số thay đổi đối với mã trước đó để lưu byte:

  • Ký tự nền ×thay vì một khoảng trắng để nó không xung đột với các khoảng trắng tiềm năng trong đầu vào.
  • _Thay vào đó ., ký tự no-op / wildcard thay vào đó , để các ô lưới có thể được xác định một cách đáng tin cậy là các ký tự từ.
  • Tôi không chèn bất kỳ khoảng trắng hoặc thụt nào sau khi hình lục giác được xây dựng lần đầu tiên. Điều đó mang lại cho tôi một hình lục giác nghiêng, nhưng nó thực sự thuận tiện hơn nhiều để làm việc và các quy tắc kề là khá đơn giản.

Đây là một ví dụ. Đối với trường hợp thử nghiệm sau:

ja
abcdefghij

Chúng tôi nhận được:

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

So sánh điều này với bố cục thông thường của hình lục giác:

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

Chúng ta có thể thấy rằng những người hàng xóm bây giờ là tất cả của 8 người hàng xóm Moore thông thường, ngoại trừ những người hàng xóm phía tây bắc và đông nam. Vì vậy, chúng ta cần kiểm tra sự phụ thuộc ngang, dọc và tây nam / đông bắc (tốt và sau đó là các cạnh bao bì). Sử dụng bố cục nhỏ gọn hơn này cũng có phần thưởng là chúng ta sẽ có thể sử dụng những thứ đó ××ở cuối để xác định kích thước của hình lục giác khi đang cần.

Sau khi hình thức này được xây dựng, chúng tôi thực hiện thêm một thay đổi cho toàn bộ chuỗi:

T`d`À-É

Điều này thay thế các chữ số bằng các chữ cái ASCII mở rộng

ÀÁÂÃÄÅÆÇÈÉ

Vì chúng được thay thế cả trong hình lục giác và trong chuỗi mục tiêu, điều này sẽ không ảnh hưởng đến việc chuỗi có khớp hay không. Ngoài ra, vì chúng là các chữ cái \w\bvẫn xác định chúng là các ô lục giác. Lợi ích của việc thực hiện thay thế này là bây giờ chúng ta có thể sử dụng \Dtrong regex sắp tới để khớp với bất kỳ ký tự nào (cụ thể là các nguồn cấp dữ liệu cũng như các ký tự không phải là dòng cấp dữ liệu). Chúng tôi không thể sử dụng stùy chọn để thực hiện điều đó, bởi vì chúng tôi sẽ cần .khớp các ký tự không phải là nguồn cấp dữ liệu ở một số nơi.

Bây giờ là bit cuối cùng: xác định xem có đường dẫn nào khớp với chuỗi đã cho của chúng tôi không. Điều này được thực hiện với một regex quái dị duy nhất. Bạn có thể tự hỏi tại sao?!?! Chà, về cơ bản đây là một vấn đề quay lui: bạn bắt đầu ở đâu đó và thử một con đường miễn là nó khớp với chuỗi, và một khi nó không quay lại và thử một người hàng xóm khác với nhân vật cuối cùng hoạt động. Các một điềumà bạn nhận được miễn phí khi làm việc với regex là quay lại. Đó thực sự là điều duy nhất mà động cơ regex làm. Vì vậy, nếu chúng ta chỉ tìm cách mô tả một đường dẫn hợp lệ (đủ khó cho loại vấn đề này, nhưng chắc chắn là có thể với các nhóm cân bằng), thì công cụ regex sẽ sắp xếp tìm ra đường dẫn đó trong số tất cả các đường có thể cho chúng ta. Chắc chắn có thể thực hiện tìm kiếm thủ công với nhiều giai đoạn ( và tôi đã làm như vậy trong quá khứ ), nhưng tôi nghi ngờ nó sẽ ngắn hơn trong trường hợp cụ thể này.

Một vấn đề khi thực hiện điều này với regex là chúng ta không thể tùy ý dệt con trỏ của công cụ regex qua lại chuỗi trong quá trình quay lui (mà chúng ta cần vì đường dẫn có thể đi lên hoặc xuống). Vì vậy, thay vào đó, chúng tôi theo dõi "con trỏ" của chính mình trong một nhóm bắt giữ và cập nhật nó ở mỗi bước (chúng tôi có thể tạm thời di chuyển đến vị trí của con trỏ bằng một cái nhìn). Điều này cũng cho phép chúng tôi lưu trữ tất cả các vị trí trong quá khứ mà chúng tôi sẽ sử dụng để kiểm tra xem chúng tôi chưa từng truy cập vị trí hiện tại trước đây.

Vì vậy, hay thực hiện ngay bây giơ. Đây là một phiên bản nhẹ hơn của regex, với các nhóm được đặt tên, thụt lề, thứ tự ít ngẫu nhiên hơn của hàng xóm và một số nhận xét:

\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

Tôi hy vọng rằng ý tưởng chung là gần như rõ ràng từ điều này. Để làm ví dụ cho cách một trong những chuyển động dọc theo đường dẫn hoạt động, chúng ta hãy nhìn vào bit di chuyển con trỏ về phía nam:

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

Hãy nhớ rằng các giao diện nên được đọc từ phải sang trái (hoặc từ dưới lên trên), vì đó là thứ tự chúng được thực hiện theo:

(?<=
  (?<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).
)

Lưu ý rằng không cần thiết phải đặt một cái neo ở phía trước \k<pos>để đảm bảo rằng điều này thực sự đến đầu chuỗi. <pos>luôn luôn bắt đầu với một lượng ×không thể tìm thấy ở bất kỳ nơi nào khác, vì vậy điều này hoạt động như một mỏ neo ngầm.

Tôi không muốn viết bài này nhiều hơn mức cần thiết, vì vậy tôi sẽ không đi sâu vào 11 trường hợp khác một cách chi tiết, nhưng về nguyên tắc tất cả chúng đều hoạt động tương tự nhau. Chúng tôi kiểm tra <next>có thể tìm thấy theo một số hướng cụ thể (được chấp nhận) từ vị trí con trỏ cũ với sự trợ giúp của các nhóm cân bằng, và sau đó chúng tôi lưu trữ chuỗi lên đến khớp với vị trí con trỏ mới <pos>.


13

Python 3, 990 943 770 709 byte

Câu trả lời đầu tiên, yay!

EDIT: Lập danh sách kề kề golfed. Bây giờ tôi sử dụng một công thức hơi khác

EDIT 2: Loại bỏ lông tơ không cần thiết, chơi golf nhiều hơn nữa.

EDIT 3: Rút ngắn mã để chuyển đổi từ chỉ mục trong danh sách sang tọa độ, đánh gôn thêm một vài điều.

Phần lớn các byte liên quan đến việc tạo danh sách kề (nó có tiềm năng nhất để được đánh gôn). Từ đó, vấn đề đơn giản là bắt buộc giải pháp (mà tôi có thể làm được với ít byte hơn).

Chơi gôn

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 / giải thích:

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

Rất gần với Retina! :( Yay, đánh bại Retina!


5

Javascript (ES6), 511 500 496 byte

(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 và bình luận

// 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
}

Các trường hợp thử nghiệm

Đoạn mã dưới đây sẽ đi qua tất cả các trường hợp thử nghiệm trung thực và giả mạo.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.