Thiết kế ngôn ngữ: Kết hợp mẫu 2 chiều


49

Đây là Thử thách nửa đêm # 6 . Chủ đề: Thiết kế ngôn ngữ

một phòng chat cho thử thách này. Hãy đến và tham gia với chúng tôi nếu bạn muốn thảo luận về ý tưởng!

Và bây giờ cho một cái gì đó hoàn toàn khác nhau...

Hai tuần này, chúng tôi muốn thử nghiệm một loại thử thách mới. Trong thử thách này, bạn sẽ được thiết kế một ngôn ngữ! Khớp mẫu là một vấn đề rất phổ biến trong lập trình và thường rất hữu ích cho môn đánh gôn. Các biểu thức thông thường, ví dụ, có thể được sử dụng để phát hiện một mẫu trong một dòng văn bản. Tuy nhiên, không có bất kỳ phương pháp được thiết lập nào để mô tả và phát hiện các mẫu hai chiều.

Các thách thức

Bạn đang thiết kế một ngôn ngữ khớp mẫu, cho phép mô tả các mẫu hai chiều trong các khối văn bản. Các phương thức hoạt động của ngôn ngữ của bạn sẽ tương tự như biểu thức thông thường (mặc dù ngôn ngữ của bạn không nhất thiết phải có bất cứ điều gì tương đồng với regex khác):

  • Là đầu vào, bạn sẽ nhận được một khối văn bản hình chữ nhật. Bạn có thể giả sử rằng văn bản chỉ bao gồm các ký tự ASCII có thể in (0x20 đến 0x7E) cũng như các dòng mới (0x0A) để phân tách các hàng của lưới.
  • Nếu một trận đấu, theo mô tả mẫu, có thể được tìm thấy dưới dạng bất kỳ tập hợp con nào của khối văn bản này, thì trận đấu này phải được trả lại hoặc in. Nếu trận đấu có thể không phải là hình chữ nhật, thì nó phải được đệm vào một khu vực hình chữ nhật với một số ký tự dành riêng. Nếu có một vài trận đấu hợp lệ, bạn có thể quyết định cách chọn trận đấu được trả về (lớn nhất, nhỏ nhất, đầu tiên, v.v.).

Đối với một số ứng dụng, có thể hữu ích nếu việc triển khai của bạn có thể trả về vị trí của một trận đấu thay vì chính trận đấu đó, nhưng đây không phải là một yêu cầu.

Ít nhất, ngôn ngữ của bạn sẽ có thể khớp với một mẫu như là một tiểu vùng hình chữ nhật liền kề của đầu vào của nó.

Câu trả lời của bạn nên chứa:

  • Một mô tả về ngôn ngữ.
  • Một công việc thực hiện . Đây có thể là một chương trình, hoặc một tập hợp các hàm / lớp bằng ngôn ngữ bạn chọn.
  • Bạn nên thể hiện ngôn ngữ của mình bằng cách hiển thị cách sử dụng ngôn ngữ này để giải quyết các ví dụ được cung cấp dưới đây . Ngôn ngữ của bạn không phải có khả năng phù hợp với tất cả chúng, nhưng bạn phải có khả năng phù hợp với ít nhất 8 trong số này. Nếu ngôn ngữ của bạn có thể làm điều gì đó lạ mắt mà chúng tôi không nghĩ tới, hãy thoải mái đưa nó vào.

Nếu câu trả lời của bạn dựa trên các ý tưởng hiện có, điều đó tốt, nhưng vui lòng cung cấp tín dụng khi đến hạn.

Tiện ích mở rộng

Trên đây mô tả mức tối thiểu mà một bài nộp hợp lệ phải đáp ứng. Tuy nhiên, một số khái quát hóa có thể làm cho một ngôn ngữ khớp mẫu như vậy thậm chí còn hữu ích hơn, bao gồm nhưng không giới hạn ở:

  • Có thể neo mẫu vào một hoặc nhiều cạnh, để người ta có thể kiểm tra xem toàn bộ khu vực đầu vào có một mẫu nhất định hay không.
  • Sản xuất tất cả các trận đấu thay vì chỉ một. Bạn có thể chọn ngữ nghĩa của các trận đấu chồng chéo.
  • Lấy văn bản không phải hình chữ nhật làm đầu vào.
  • Cho phép các mẫu để chỉ định khớp không phải hình chữ nhật. Trong trường hợp như vậy, đầu ra nên được đệm vào một hình chữ nhật với một số ký tự dành riêng.
  • Cho phép các mẫu để xác định khớp với lỗ.
  • Cho phép các trận đấu không liền kề nhau, giống như hai nhân vật xuất hiện với một độ lệch nhất định.
  • Dễ dàng đặc điểm kỹ thuật của các phép quay và phản xạ.
  • Tùy chọn xử lý đầu vào theo chu kỳ như một hình trụ hoặc hình xuyến, sao cho các cạnh đối diện được coi là liền kề.

Chấm điểm

Mục tiêu chính của thử thách này là tạo ra một ngôn ngữ phù hợp với mô hình 2D hiệu quả có thể được sử dụng trong tương lai. Như vậy, một hệ thống tính điểm như "độ dài kết hợp ngắn nhất để giải các ví dụ" sẽ dẫn đến việc mã hóa cứng các chức năng nhất định với chi phí sử dụng chung. Do đó, chúng tôi đã quyết định rằng thử thách này là cuộc thi nổi tiếng nhất. Bài nộp với số phiếu bầu nhiều nhất sẽ thắng. Mặc dù chúng tôi không thể ép buộc mọi người bỏ phiếu như thế nào, đây là một vài hướng dẫn cho những gì cử tri nên tìm kiếm một cách lý tưởng:

  • Biểu cảm. Ngôn ngữ có thể giải quyết một loạt các vấn đề, thậm chí vượt ra ngoài các ví dụ được trình bày trong câu hỏi này không? Nó có hỗ trợ bất kỳ tiện ích mở rộng được đề xuất nào không?
  • Dễ đọc. Làm thế nào trực quan là ký hiệu (ít nhất là cho những người biết cú pháp cơ bản)?
  • Sân gôn. Đây vẫn là CodeGolf.SE. Đối với mục đích của trang web này, tất nhiên sẽ rất tuyệt nếu có một ngôn ngữ phù hợp cần rất ít mã để mô tả một mẫu.

Các vấn đề mẫu

Đoạn mã sau đây cho thấy 16 vấn đề mẫu mà ngôn ngữ khớp mẫu 2 chiều có thể giải quyết được. Mỗi ví dụ chứa một mô tả vấn đề ngắn và sau đó thường được theo sau bởi một ví dụ đầu vào nơi có thể tìm thấy kết quả khớp và một ví dụ không tìm thấy kết quả khớp nào (nếu có).

Như đã nêu ở trên, ngôn ngữ của bạn chỉ cần có thể giải quyết 8 vấn đề này. Tất cả mọi thứ trên đó là tùy chọn, nhưng tất nhiên sẽ làm tăng số phiếu bạn nhận được.

(Không, bạn không cần phải đọc mã HTML đó. Nhấn nút "Chạy đoạn mã" để trình duyệt được hiển thị độc đáo, sau đó bạn cũng có thể xem toàn màn hình.)


Có giới hạn thời gian chung cho những vấn đề này? Tôi rất quan tâm đến việc giải quyết vấn đề này nhưng tôi rất bận rộn, tôi có thể dễ dàng mất 2 tuần để làm.
Devon Parsons

7
@DevonParsons Không có thời hạn nhập cảnh.
PhiNotPi 3/03/2015

Có vẻ thú vị, đặc biệt là khi bạn tạo một thẻ mới cho việc này. Tôi nghĩ nên có điểm thưởng cho việc tạo ngôn ngữ 2 chiều cho nó.
mbomb007 ngày

1
@ mbomb007 Có điểm thưởng khi tạo ngôn ngữ 2 chiều. Tôi khá chắc chắn rằng nó sẽ nhận được một lượng lớn upvote. ;)
Martin Ender

@ MartinBüttner Tôi thậm chí không biết cách tạo ra một ngôn ngữ. Có thể là một cái gì đó (đơn giản?) Khi tạo một chương trình Python lấy một tệp mã ngôn ngữ mới của bạn (và diễn giải / thực thi nó dựa trên cú pháp đã xác định của bạn) và tạo đầu ra?
mbomb007 ngày

Câu trả lời:


32

RắnEx

Giải quyết 15/16 vấn đề cho đến nay!

Phiên dịch trực tuyến ! - Thông số ngôn ngữ đầy đủ - Nguồn Javascript

ảnh chụp màn hình phiên dịch

Ý tưởng đằng sau ngôn ngữ này là xác định 'rắn' di chuyển xung quanh các ký tự kiểm tra văn bản bằng cú pháp giống như biểu thức chính quy.

Một chương trình trong SnakeEx bao gồm một danh sách các định nghĩa cho rắn bằng các chuỗi lệnh khác nhau. Rắn có thể sinh ra những con rắn khác bằng cách sử dụng các định nghĩa này, đó là nơi SnakeEx có được hầu hết sức mạnh của nó - chúng ta có thể khớp các cấu trúc phân nhánh và thậm chí thực hiện đệ quy (xem ví dụ Paren Match).

Mọi chương trình về cơ bản sẽ trông giống như một tập hợp các biểu thức chính quy, nhưng với việc bổ sung các lệnh điều hướng có dạng <dir>thay đổi hướng của con rắn và gọi các lệnh có dạng {label<dir>params}sinh ra nhiều con rắn hơn.

Đối với một điểm vào, thông dịch viên sinh ra một con rắn bằng cách sử dụng định nghĩa đầu tiên, di chuyển sang phải.

Nó không ngắn gọn khủng khiếp, nhưng nó rất mạnh mẽ và (tôi nghĩ) khá dễ đọc.

Cập nhật

  • Thay đổi! logic không và ~ để không đánh dấu phù hợp
  • Đã thêm <!>để giải quyết colinear
  • Giải quyết phù hợp chéo
  • Giải cờ vua theo cách ít kinh khủng hơn
  • Đã thêm cú pháp đóng giới hạn %{min,max}
  • Đã thêm ví dụ đệ quy

Các giải pháp

15 giải quyết, 1 trong tiến trình

Bạn có thể dễ dàng dùng thử các chương trình này bằng Trình thông dịch trực tuyến được liên kết ở trên!

Vấn đề 1 - Tìm bàn cờ

m:{v<R>2}{h<>1}
v:{c<L>A1}+
h:{c<R>A2}+
c:_?(#_)+#?

Để có phần giới thiệu chi tiết, hãy bắt đầu ở Bài toán 3.

Vấn đề 2 - Xác minh bàn cờ

m:{v<R>2}{h<>1}
v:${c<L>A1}+$
h:${c<R>A2}+$
c:$_?(#_)+#?$

Kết thúc cuốn sách những con rắn thích hợp với biểu tượng ngoài giới hạn $là một cách để làm cho chương trình chỉ khớp với toàn bộ đầu vào.

Bài toán 3 - Phát hiện hình chữ nhật của chữ số

m:{c<R>A1}%{2,}
c:[0-9]%{2,}

Con mrắn di chuyển sang phải, sinh sản tối thiểu 2 con rắn ( %{2,}là cách đóng có nghĩa là "2 đến vô cùng") sử dụng định nghĩa c ( c) và di chuyển sang phải ( <R>), hoặc đúng hơn là trong trường hợp này, bởi vì tất cả các hướng đều liên quan đến con rắn hiện tại. Thông số Alà đường chỉ xác định rằng rắn sinh sản sẽ di chuyển sau cuộc gọi. Các 1tham số là cách chúng ta hạn chế các trận đấu để hình chữ nhật - thông số dạng số đặt rắn trong "nhóm". Một trận đấu không được tính trừ khi tất cả các con rắn trong cùng một nhóm di chuyển chính xác cùng một khoảng cách.

Vấn đề 4 - Tìm một từ trong Tìm kiếm từ

m:<*>GOLF

Lệnh direction <*>xác định rằng con rắn nên quay theo bất kỳ hướng chéo hoặc trực giao nào. Sau đó, nó tìm kiếm regex đơn giản.

Vấn đề 5 - Phát hiện đầu vào hình vuông

m:{v<R>1}{h<>1}
v:${c<L>A1}+$
h:${c<R>A1}+$
c:$.+$

Chìa khóa ở đây là ký tự đặc biệt $, chỉ phù hợp nếu con rắn nằm ngoài giới hạn. Chúng tôi sinh ra một con rắn ngang và một con thẳng đứng; mỗi con sinh ra nhiều con rắn hơn khi nó chạy dọc theo rìa và tất cả những con đó nằm trong cùng một nhóm và phải có cùng chiều dài.

Vấn đề 6 - Tìm tàu ​​lượn trong trò chơi cuộc sống

m:<+>[({l1<R>A}{l2<R>A}{l3<R>})({l1<L>A}{l2<L>A}{l3<L>})]
l1:##\.
l2:[(#\.)(\.#)]#
l3:#\.\.

mbắt đầu theo bất kỳ hướng nào trong bốn hướng trực giao ( <+>), đạt được phép quay. Sau đó, nó nhìn sang trái hoặc phải cho ba hàng theo thứ tự, đạt được sự phản chiếu.

(Lưu ý rằng tôi đã thay thế các khoảng trắng bằng dấu chấm chỉ vì các textareas HTML được sử dụng trong trình thông dịch của tôi dường như làm những điều ngu ngốc nếu chúng có nhiều khoảng trắng liên tiếp)

Bài 7 - Ghép cổng Nether

m:{e<R>A1}{d<R>A1}%{2,22}{e<R>1}
e:~.X%{3,22}~.
d:X\.+X

Con mrắn di chuyển sang phải, sinh ra một con rắn để kiểm tra cạnh trái, 2-22 con rắn để kiểm tra các cột giữa và cuối cùng là một con rắn để kiểm tra cạnh phải. Các ~nhà điều hành chỉ ra rằng bất cứ điều gì sau nên được kiểm tra nhưng không nên được đánh dấu như là một phần của giải pháp.

Đóng cửa giới hạn bây giờ cho phép chúng tôi giải quyết đầy đủ và đúng vấn đề này!

Vấn đề 8 - Vị trí ngực Minecraft

m:~{s<>}~!{d<+>}\.
s:<+>.<BR>([$\.]<R>)%{3}
d:.<+>CC

Ở đây chúng tôi sử dụng một logic không ( !), khớp với khi và chỉ khi mã thông báo sau không khớp với bất cứ thứ gì. Tuyên bố dphát hiện một rương đôi theo một hướng cụ thể, vì vậy !{d<+>}hãy chắc chắn rằng không có rương đôi theo bất kỳ hướng trực giao nào. sdi chuyển trong một viên kim cương nhỏ xung quanh quảng trường hiện tại, xác minh ít nhất 3 trong số các khoảng trống đó là trống hoặc khỏi bảng. Các dấu \.cuối cùng phù hợp với hình vuông, giả sử tất cả các điều kiện trước đã thành công.

Bài 9 - Sắp xếp theo chiều ngang và dọc

m:<R>?#~.*#

Con rắn mtùy ý rẽ phải ( <R>?) trước khi khớp chuỗi. .là một ký tự đại diện, giống như trong regex.

Bài 10 - Điểm Colinear

m:<!>#~.*#~.*#

Với việc bổ sung <!>hướng, chúng ta có thể giải quyết điều này ngay bây giờ! <!>giống như <+>nhưng thay vì phân nhánh theo bốn hướng, nó phân nhánh theo mọi hướng có thể.

Bài 12 - Tránh chữ Q

m:{h<R>A}%{4}
h:[^Qq]%{4}

Chỉ cần sinh ra 4 con rắn mà mỗi con tìm bốn ký tự không phải là chữ Q.

Bài 13 - Khai thác kim cương

m:{tl<RB>1}{tr<RF>1}
tl:X/*{bl<L>1}X
tr:X\\*{br<R>1}X
bl:X\\*X
br:X/*X

Cái này khá gọn gàng. msinh ra hai con rắn, một con đi về phía sau bên phải và một con về phía trước bên phải. Mỗi con đi theo dấu gạch chéo đến chữ X, sau đó sinh ra một con rắn khác theo góc vuông với hướng hiện tại của nó, theo dấu gạch chéo xuống đáy X.

Bài 14 - Ghép chéo

m:{a<R>A}+{b<R>A}+{a<R>A}+
a:{e<>P1}{c<>P2}{e<>P3}
b:{c<>P1}{c<>P2}{c<>P3}
e:\.+
c:#+

Đây là lần đầu tiên tôi sử dụng Ptham số iggyback. Thông thường những con rắn là độc lập, nhưng nếu bạn thực hiện một cuộc gọi với tham số này, con rắn gọi sẽ được di chuyển với callee. Vì vậy, e2có thể kiểm tra một chuỗi '.', Sau đó là một chuỗi '#', sau đó là một chuỗi khác của '.' Và tất cả chúng đều là các cuộc gọi riêng biệt để chúng tôi có thể nhóm chúng với '1,' 2 'và' 3 ' , buộc độ dài của chúng phải khớp với nhau.

Vấn đề 15 - Ghép một từ trong bảng Boggle

m{I}:<*>p<*>a<*>n<*>a<*>m<*>a

Đơn giản, nếu dài dòng. Itham số chỉ định trường hợp không nhạy cảm (chúng ta có thể chỉ định tham số trên các định nghĩa cũng như trong các cuộc gọi). Con rắn quay theo bất kỳ hướng nào, khớp với nhân vật, quay lại, và cứ thế.

m{EI}:<*>p<*>a<*>n<*>a<*>m<*>a

Đây là phiên bản không sử dụng lại nhân vật. Các Etham số Xclusive cấm con rắn từ phù hợp với bất kỳ nhân vật mà đã được đánh dấu, giống như những con đường mòn chất nhờn feersum của.

Bài 16 - Quấn quanh các cạnh

m{W}:{c<R>WA}%{3}
c:###

Các Wtham số cho phép con rắn để quấn khi nó chạy out-of-bounds. Chúng tôi cũng có HVchỉ cho phép gói ngang hoặc dọc.

Thêm - Bộ giải mê cung

m{E}:$(<P>\.)+$

Giải quyết một mê cung ASCII trong đó sàn có thể đi bộ là thời gian. Các <P>phương tiện hướng về phía trước, sang trái hoặc phải (đường cho [<F><L><R>]).

Thêm - Kết hợp Paren

m:\(~{r<>P}\)
r:[^\(\)]*(\({r<>P}\))?[^\(\)]*

Chưa tìm ra cách thực hiện Prelude, nhưng đây là bước đầu tiên! Ở đây tôi sử dụng rcon rắn đệ quy để khớp với dấu ngoặc đơn tương ứng bằng cách kiểm tra rằng không có dấu ngoặc đơn nào giữa chúng.

Bổ sung - Cấu trúc liên kết ASCII: Đếm vòng


Bạn có xem xét việc thêm cú pháp để ngôn ngữ này có thể thay thế thay vì chỉ khớp không? Tôi muốn sử dụng một số giải pháp cho thử thách này để viết một mục cho codegolf.stackexchange.com/questions/51231/, nhưng không phải là một giải pháp duy nhất ở đây tìm và thay thế. (Tôi biết câu trả lời của mình sẽ không hợp lệ do quy tắc thời gian cụ thể của ngôn ngữ)
Sparr

@Sparr. Không phải là một ý tưởng tồi, nó chắc chắn sẽ hữu ích hơn cho mã golf. Không chắc chắn khi nào tôi sẽ có thời gian để làm điều đó một mình, nhưng tôi sẽ ghi nhớ nó.
BMac

3
riêng biệt: cú pháp thay đổi hướng là khó hiểu. bởi vì con rắn tiến triển sau khi khớp một nhân vật, tôi dường như phải làm cho hướng của mình thay đổi một nhân vật trước khi nó có ý nghĩa với tôi. ví dụ: chuỗi "ABC \ nDEF" và tôi muốn khớp với mảnh tetris hình chữ L được xác định bởi ABCF, tôi muốn viết con rắn của mình là "m: ABC <R> F" nhưng tôi phải viết "m: AB <R> CF "thay vào đó. Tôi hiểu rằng điều này phù hợp với thông số kỹ thuật, nhưng tôi thấy nó rất phản trực giác.
Sparr

Tôi có một giải pháp một phần cho cú pháp mở đầu. Vấn đề duy nhất là tôi không thể làm cho nó không khớp nếu nó không khớp với toàn bộ đầu vào: m:{a<>} a:[({n<R>A})({n<R>A}*{l<R>A}{a<>P}{r<R>A})]*{n<R>A}* l:$[^\(\)]*\([^\(\)]*$ r:$[^\(\)]*\)[^\(\)]*$ n:$[^\(\)]+$
TheNumberOne

21

Trượt, Python 3,4 ( Github wiki , trình thông dịch trực tuyến )

Giống như đệ trình của frageum, điều này cũng dựa trên việc truyền tải lưới, nhưng giống như đệ trình của RugPython, điều này dựa trên regex. Bằng cách nào đó, có vẻ như tôi đã xoay sở được.

Có khá nhiều tính năng chưa được thực hiện mà tôi muốn thêm vào, vì vậy khi có liên quan tôi đã lưu ý những gì tôi dự định làm khi có thời gian.


Cập nhật

(Xem trang Github để biết tin tức chi tiết)

  • Ngày 5 tháng 4 năm 2015 : Trượt bây giờ có một thông dịch viên trực tuyến ! Nó vẫn còn ở giai đoạn đầu, vì vậy có thể có một vài lỗi.

  • Ngày 5 tháng 4 năm 2015 : Cập nhật hiệu quả! Bây giờ, cổng thông tin nether đầu vào lớn nhanh hơn rất nhiều (2 giây). Ngoài ra, có một số thay đổi cú pháp, vì vậy hãy chắc chắn kiểm tra wiki. Đánh số nhóm cũng cố định.


Trượt có một con trỏ khớp bắt đầu tại một hình vuông cụ thể và ban đầu hướng về phía bên phải. Khi một char được khớp, con trỏ di chuyển về phía trước theo hướng hiện tại (mặc dù việc triển khai không thực hiện chính xác theo thứ tự đó).

Hướng con trỏ của trận đấu, có thể được thiết lập để một hướng cụ thể với ^<digit>, nơi ^0, ^1, ^2, ..., ^7đặt con trỏ đến N, NE, E, ..., NW tương ứng (đi chiều kim đồng hồ).

Các phím tắt sau đây cũng có sẵn:

  • ^* kiểm tra tất cả 8 hướng trực giao hoặc đường chéo,
  • ^+ kiểm tra tất cả 4 hướng trực giao.

(Kế hoạch tương lai: Cho phép thiết lập các hướng tùy ý, ví dụ như (1, 2)di chuyển của hiệp sĩ)

Ví dụ: ( Bài toán 4 - Tìm một từ trong tìm kiếm từ ),

^*GOLF

thử tất cả 8 hướng trực giao hoặc đường chéo, tìm từ "GOLF". Theo mặc định, Trượt thử tất cả các ô vuông bắt đầu có thể và trả về một kết quả từ mỗi ô, lọc ra các bản sao, do đó, một lưới như

GOLF
O
L
FLOG

chỉ trả về hàng trên cùng và hàng dưới cùng dưới dạng khớp (vì hàng trên cùng và cột bên trái "GOLF" bắt đầu từ cùng một hình vuông). Để có được tất cả các trận đấu, ochế độ khớp chồng chéo có thể được sử dụng.

Tương tự ( Bài toán 15 - Ghép một từ trong bảng Boggle ),

p^*a^*n^*a^*m^*a

phù hợp panamabằng cách thử một hướng khác nhau mỗi lần. Sử dụng icờ cho trường hợp không nhạy cảm. Trượt sử dụng lại ký tự theo mặc định, nhưng điều này có thể được bật với rcờ không lặp lại.

(Gói tương lai: công cụ sửa đổi chế độ tìm kiếm tự động kiểm tra các bộ chỉ đường sau mỗi lần di chuyển để việc lặp lại ^*là không cần thiết)

Hướng của con trỏ khớp cũng có thể được xoay 90 độ sang trái hoặc phải tương ứng với <hoặc >tương ứng. Ví dụ,

 `#`#< `#<  <`#<`#

tìm mẫu

  #
## 
 ##

bằng cách tìm theo thứ tự sau:

765
894
123

Điều này cho phép chúng tôi giải quyết vấn đề 6 - Tìm tàu ​​lượn với

^+(`#`# >`# > `#>`#> |`#`# <`# < `#<`#< | `#`#> `#>  >`#>`#| `#`#< `#<  <`#<`#)

trong đó phần 1 và 2 mã hóa các hình dạng tàu lượn và phần 3 và 4 mã hóa các đối tác phản xạ của chúng.

Lưu ý rằng Trượt sử dụng backtick `để thoát. Điều này là do Trượt có một hình thức chuyển động khác mang tên ngôn ngữ của nó - lệnh trượt. /trượt con trỏ khớp trực giao sang trái, trong khi \trượt con trỏ khớp trực giao sang phải.

Ví dụ,

abc   ghi
   def

có thể được kết hợp bởi abc\def/ghi.

Mặc dù không đặc biệt hữu ích, nhưng việc trượt trở nên quan trọng hơn khi kết hợp với (?| <regex> )nhóm đứng yên, hoạt động giống như một cái nhìn phù hợp. Regex bên trong được khớp, sau đó ở cuối của nó, vị trí và hướng của con trỏ khớp được đặt lại về trạng thái trước nhóm đứng yên.

Ví dụ,

abc
def
ghi

có thể được kết hợp với (?|abc)\(?|def)\(?|ghi).

Tương tự, Bài toán 12 - Tránh chữ Q có thể được giải bằng

%(\(?|[^qQ]{4})){4}

trong đó %một lệnh không trượt để ngăn người đầu tiên \kích hoạt.

Trượt cũng có một xác nhận độ dài (?_(<group num>) <regex> ), chỉ khớp với biểu thức chính bên trong nếu độ dài khớp của nó có cùng độ dài với độ dài của nhóm đã cho.

Ví dụ: Bài toán 13 - Khai thác kim cương có thể được giải quyết dễ dàng với

^1X(`/*)X>(?_(1)`\*)X>(?_(1)`/*)X>(?_(1)`\*)

đầu tiên cố gắng khớp với cạnh trên cùng bên trái của viên kim cương, sau đó khẳng định rằng ba cạnh còn lại có cùng chiều dài.

(Chạy với vcờ cho đầu ra dài dòng)

Match found in rectangle: (8, 0), (12, 4)
  X
 / \
X   X
 \ /
  X

Match found in rectangle: (0, 0), (6, 6)
   X
  / \
 /   \
X     X
 \   /
  \ /
   X

Match found in rectangle: (2, 2), (4, 4)
 X
X X
 X

Match found in rectangle: (10, 2), (14, 6)
  X
 / \
X   X
 \ /
  X

Match found in rectangle: (5, 3), (9, 7)
  X
 / \
X   X
 \ /
  X

Match found in rectangle: (0, 6), (2, 8)
 X
X X
 X

Một thay thế golf là

^1X(`/*)(X>(?_(1)`\*)X>(?_(1)`/*)){2}

mà phù hợp với bên đầu tiên hai lần.

Nhiều vấn đề khác có thể được giải quyết bằng cách sử dụng trượt, nhóm đứng yên và xác nhận độ dài:

Bài 14 - Ghép chéo:

(?|(`.+)(`#+)(`.+))(\(?|(?_(2)`.+)(?_(3)`#+)(?_(4)`.+)))*(\(?|(?_(2)`#+)(?_(3)`#+)(?_(4)`#+)))+(\(?|(?_(2)`.+)(?_(3)`#+)(?_(4)`.+)))+

Khi bạn chụp được chiều rộng của .s và #s ở hàng đầu tiên, nó sẽ trượt xuống hết cỡ.

Đầu ra:

Match found in rectangle: (0, 1), (5, 5)
.###..
######
######
.###..
.###..

Match found in rectangle: (4, 6), (6, 8)
.#.
###
.#.

Điều này có lẽ có thể được chơi golf với một chút đệ quy, một khi tôi nhận được một vài lỗi được sắp xếp.

Bài toán 3 - Phát hiện một hình chữ nhật gồm các chữ số:

(?|`d`d+)(\(?|(?_(1)`d+)))+

Ghép một hàng trên cùng có hai hoặc nhiều chữ số, sau đó đảm bảo mọi dòng bên dưới có cùng độ dài. `dlà một lớp nhân vật được xác định trước tương đương với [0-9].

Lưu ý rằng điều này tìm thấy tất cả các trận đấu .

Vấn đề 7 - Ghép các cổng nether:

(?|.X{2,22}.)\((?|(?_(1)X`.+X))\){3,22}(?_(1).X+.)

mà đầu ra, cho ví dụ hàng đầu trong luồng gốc :

Match found in rectangle: (2, 1), (5, 5)
XXXX
X..X
X..X
X..X
XXXX

Match found in rectangle: (9, 1), (14, 5)
.XXXX.
X....X
X....X
X....X
.XXXX.

Match found in rectangle: (13, 4), (17, 8)
.XXXX
X...X
X...X
X...X
.XXX.

Cuối cùng, một số tính năng khác của Trượt bao gồm:

  • $0, $1, $2, ..., $7neo cạnh phía bắc, góc đông bắc, rìa phía đông, v.v ... $+neo bất kỳ cạnh nào và $*neo bất kỳ góc nào.
  • $theo sau là một ký tự chữ thường đặt một neo ở vị trí hiện tại, sau này có thể được khớp với $ký tự chữ hoa tương ứng, ví dụ $a$A.
  • # bật cờ không di chuyển, ngăn con trỏ di chuyển về phía trước sau trận đấu tiếp theo.
  • ,phù hợp với một char like ., nhưng không thêm nó vào đầu ra, cho phép các kết quả không liền kề trong khi có thể được nhận ra bởi (?_()).

... và nhiều hơn nữa. Có quá nhiều thứ để liệt kê trên trang này.

Các vấn đề khác

Vấn đề 1 - Tìm bàn cờ:

(?|`#?(`_`#)+`_?)(?_(1)(?|...+))(\(?_(1)(?|`#?(`_`#)+`_?$a)))+<(?|`#?(`_`#)+`_?)(?_(9)(?|...+))(\(?_(9)(?|`#?(`_`#)+`_?)))+$A

Hai vấn đề bàn cờ chắc chắn không phải là sở trường của Trượt. Chúng tôi khớp với hàng trên cùng sau đó đảm bảo rằng nó ít nhất là chiều dài 3 và xen kẽ giữa #_sau đó trượt và khớp với các hàng tiếp theo. Cuối cùng, $amỏ neo phải ở dưới cùng bên phải của bàn cờ.

Sau đó chúng tôi rẽ trái và lặp lại cho các cột, đảm bảo chúng tôi khớp $Aở cuối.

Vấn đề 2 - Xác minh bàn cờ:

$7%(\(?|`_?(`#`_)*`#?$2))+$5<%(\(?|`_?(`#`_)*`#?$0))+$3

Giống như vấn đề trước, chúng tôi kiểm tra xem mỗi hàng có đúng không, sau đó xoay trái và làm tương tự cho các cột. Neo được sử dụng để đảm bảo chỉ toàn bộ bảng được khớp.

Bài 9 - Căn chỉnh ngang và dọc:

>?`#,*`#

Chúng tôi áp dụng tùy chọn? bộ định lượng cho >lệnh xoay để chúng ta khớp đúng hoặc hướng xuống. Chúng tôi tìm thấy tất cả 5 trong ví dụ với ochế độ chồng lấp, nhưng chỉ có 4 mà không có nó kể từ đó #.,###.,#bắt đầu từ cùng một vị trí.

Bài 10 - Điểm cộng

^+`#(?|(,*)<(,*))(((?_(2),*)<(?_(3),*),>)+#`#){2}

Ghép nối một #số ký tự ngang và một số ký tự dọc, sau đó lặp lại cho đến lần thứ hai #và lặp lại cho đến lần thứ ba #.

Bài toán 5 - Phát hiện đầu vào vuông:

$7.(.*)>(?_(1).*)$3>((?|.*)\)*

Neo góc trên cùng bên trái và kiểm tra xem cạnh trên có cùng chiều dài với cạnh phải không, trước khi neo góc dưới bên phải. Nếu đầu vào vượt qua điều này, thì chúng ta sẽ đi ngược lại để khớp với toàn bộ đầu vào.

Vấn đề 8 - Vị trí ngực Minecraft:

`.^+(($^|(?|`.))>){3}($^|`.|C<(($^|(?|`.))>){3})

Chạy với pcờ để có được vị trí của mỗi trận đấu. $^là một mỏ neo phù hợp nếu bước tiếp theo sẽ đưa con trỏ khớp ra khỏi giới hạn.

Đầu tiên chúng ta khớp a ., sau đó kiểm tra xem chúng ta được bao quanh bởi ba .s / ranh giới, sau đó đảm bảo rằng hình vuông xung quanh thứ tư cũng là một ./ ranh giới hoặc là một rương (bằng cách kiểm tra các ô vuông xung quanh).

Vấn đề 11 - Xác minh cú pháp mở đầu :

$7>%(/(?|[^()]+$4)(?1)?|/(?|[^()]*`([^()]*$4)(?1)?/(?|[^()]*`)[^()]*$4)(?1)?)$1

Đã thử một vài lần, nhưng tôi nghĩ điều này đúng. Ở đây chúng tôi sử dụng đệ quy, có cú pháp giống như PCRE.

Cách tiếp cận này yêu cầu đầu vào là hình chữ nhật, nhưng một khi tôi đã thực hiện khớp không phải hình chữ nhật thì giả định đó sẽ không cần thiết.

Đây là cách tiếp cận tương tự, được chơi với nhiều đệ quy hơn:

$7>%((/(?|([^()]*)$4)|/(?|(?4)`((?3))(?1)?/(?|(?4)`)(?3)))*)$1

Bài 16 - Quấn quanh các cạnh:

%(\(?|`#{3})){3}

(Lưu ý: Gói chưa được đẩy đến trình thông dịch trực tuyến)

Điều này đòi hỏi cờ gói w. Về mặt kỹ thuật ban đầu %cho việc không trượt là không cần thiết, nhưng sau đó trận đấu sẽ được tính là bắt đầu từ một hình vuông cao hơn.

Vấn đề EX 1 - Người giải mê cung:

S(^+`.)*^+E

Vấn đề từ bình luận của BMac trong trò chuyện . Sử dụng rcờ không có chế độ lặp lại để con trỏ khớp không bị kẹt khi qua lại.

Vấn đề EX 2 - Nhận dạng khuôn mặt :

(?|O(,*),(?_(2),*)O)(?_(2)(\(?|,))*)\(?|,(?_(2),*)O)(?_(2)(\(?|,))*)\`\(?_(2)`_*)`_(?_(2)`_*)`/

Lưu ý rằng tôi chỉ phù hợp với khuôn mặt, không thực hiện bất kỳ xóa. Lưu ý rằng câu hỏi có chứa các ký hiệu euro, sẽ cần được thay thế bằng một số ASCII có thể in để hoạt động.


Mẫu băm đó là tàu lượn Conway
Heimdall

17

PMA / Ốc sên (C ++)

Tôi hình dung ngôn ngữ là những con ốc di chuyển xung quanh lưới và thực hiện các lệnh. Những con ốc để lại một vệt chất nhờn trên mỗi hình vuông mà chúng di chuyển lên, điều này theo mặc định làm cho hình vuông sau đó không thể so sánh được. Một trận đấu thành công nếu kết thúc danh sách các lệnh.

Hiện tại có đủ các nhà khai thác mà chúng ta sẽ cần một danh sách ưu tiên để theo dõi chúng. Các hoạt động được giải quyết theo thứ tự sau:

  1. Bên trong các nhóm ( ) [ ]
  2. Chia theo nhân vật xen kẽ |
  3. Đánh giá mọi thứ ở bên trái của `một nhóm
  4. Định lượng [m],[n]n
  5. Khẳng định = !
  6. Ghép

Trình thông dịch được viết bằng C ++. Mã nguồn sâu thẳm có thể được tìm thấy ở đây .

Vấn đề 4: Tìm kiếm từ

Chương trình

z\G\O\L\F

là đủ để có được một giá trị trung thực hoặc falsey cho dù từ được tìm thấy. z(một trong 15 lệnh định hướng tuyệt đối hoặc tương đối) khớp với bất kỳ hướng bát giác nào. Nhiều lệnh hướng liên tiếp được ORed với nhau. Ví dụ, ruldygần như tương đương với z, vì đó là các lệnh cho phải, lên, trái, xuống và bất kỳ hướng chéo nào. Tuy nhiên, các hướng sẽ được kiểm tra theo một thứ tự khác. Ký tự đầu tiên phù hợp luôn là ký tự bắt đầu, bất kể hướng nào. \<character> khớp với một ký tự theo nghĩa đen.

Chiến lược mặc định là thử mẫu ở mọi ô vuông trong hộp giới hạn của đầu vào bên trái và xuất số lượng khớp. Nếu giá trị boolean 1hoặc 0được yêu cầu, chương trình sau có thể được sử dụng:

?
z\G\O\L\F

Nếu có ít nhất một dòng mới trong tệp nguồn, dòng đầu tiên được coi là các tùy chọn cho việc chuyển đổi ban đầu của đầu vào thành dạng hình chữ nhật. Các ?tùy chọn in 0 hoặc 1 tùy thuộc vào việc có một bất cứ nơi nào phù hợp.

Bài 15:

Sau khi thực hiện xen kẽ, bây giờ có thể giải quyết Boggle. Sẽ tốt hơn nếu sử dụng kết hợp không phân biệt chữ hoa chữ thường cho trường hợp này, nhưng thực hiện đó không phải là ưu tiên cao nhất của tôi.

\p|\P)z(\a|\A)z{\n|\N)z{\a|\A}z(\m|\M)z(\a|\A

|hoạt động chính xác giống như regex 1 chiều. Có hai cặp dấu phân cách phù hợp để phân nhóm, cụ thể là (){}. Một khung đóng sẽ đóng bất kỳ nhóm mở nào thuộc loại đối diện đứng giữa nó và nhóm gần nhất cùng loại. Ví dụ, sau đây {({{), chỉ nhóm ngoài cùng bên trái vẫn mở. Như bạn có thể thấy, các biểu tượng nhóm chưa từng có ở các cạnh được đóng hoàn toàn. Có một lệnh nhóm khác `mà tôi sẽ không đi vào bây giờ.

Vấn đề 8: Rương Minecraft

Chương trình in số lượng vị trí ngực hợp lệ. Đây là lần đầu tiên tôi thực sự phải chơi golf và giảm số byte của tôi (17) một vài lần.

\.!(o\C)2o(!\Cw)3
  • \. khớp với một dấu chấm theo nghĩa đen, tại điểm bắt đầu của trận đấu.
  • !(o\C)2tương đương với !((o\C)2)định lượng là ưu tiên cao hơn khẳng định. <atom> <number>có nghĩa là lặp lại <atom>chính xác <number>lần. oxoay ốc theo bất kỳ hướng trực giao nào. !là một khẳng định tiêu cực. Do đó, phần này kiểm tra sự vắng mặt của một rương đôi liền kề.
  • o quay theo một số hướng trực giao.
    • (!\Cw)3khẳng định rằng không có Ccon ốc phía trước, rồi quay ngược chiều kim đồng hồ, 3 lần.

Vấn đề 2: Xác minh bàn cờ

&
\#!(o^_)|\_!(o^#

Các &tùy chọn bộ đầu ra của chương trình là 1nếu trận đấu thành công ở tất cả các vị trí, và 0ngược lại. ^cphù hợp với một nhân vật không c, tương đương với [^c]trong regex. Nhìn chung, chương trình có nghĩa là: In 1 nếu ở mọi vị trí trong hình chữ nhật giới hạn của đầu vào, có một #cái không liền kề trực tiếp với một ký tự không _hoặc _không liền kề trực tiếp với một ký tự không #; mặt khác 0


Ý tưởng về chất nhờn là một ý tưởng tốt để đối phó với boggle, tôi đã gặp một số rắc rối với điều đó
BMac

Đó là một giải pháp tốt đẹp cho vấn đề Boggle. Tôi không thể giải quyết điều đó bằng cách tiếp cận của tôi.
Hiệp sĩ logic

14

Lớp Re2d, Python 2

Cập nhật: thêm vấn đề "9. Căn chỉnh".

Cách tiếp cận của tôi là sử dụng mô-đun Python để thực hiện tìm kiếm và khớp. Lớp Re2d chuẩn bị văn bản để xử lý, thực thi các hàm re và định dạng kết quả cho đầu ra.

Lưu ý rằng đây không phải là một ngôn ngữ hoàn toàn mới - đó là ngôn ngữ biểu thức chính quy tiêu chuẩn được chiếu thành 2 chiều với các cờ được thêm cho các chế độ 2D bổ sung.

Lớp học có cách sử dụng sau:

re2dobject = Re2d(<horizontal pattern>, [<vertical pattern>], [<flags>])

Cả hai mẫu đều là mẫu RE văn bản tuyến tính tiêu chuẩn. Nếu một mẫu dọc không được cung cấp, lớp cũng sẽ sử dụng mẫu ngang để khớp theo chiều dọc. Các cờ là các cờ RE tiêu chuẩn với một số phần mở rộng 2D.

Kiểm tra

1. Finding chessboards
Chessboard pattern at (2, 1, 4, 3)

print '\n1. Finding chessboards'
reob1 = Re2d('#(_#)+_?|_(#_)+#?')
found = reob1.search('~______~\n~##_#_#~\n~#_#_##~\n~##_#_#~\n~______~')
print 'Chessboard pattern at', found
assert not reob1.search('#_##\n_#_#\n__#_\n#_#_\n#_#_')

Phương pháp tìm kiếm đã tìm thấy một mẫu bàn cờ và trả về vị trí 4 tuple. Bộ dữ liệu có x,yvị trí của nhân vật đầu tiên của trận đấu và width, heightkhu vực phù hợp. Chỉ có một mẫu được đưa ra để nó sẽ được sử dụng cho khớp ngang dọc.

2. Verifying chessboards
Is chess? True

print '\n2. Verifying chessboards'
reob2 = Re2d('^#(_#)*_?|_(#_)*#?$')
print 'Is chess?', reob2.match('_#_#_#_#\n#_#_#_#_\n_#_#_#_#')
assert not reob2.match('_#_#_#__\n__#_#_#_\n_#_#_#__')

Bàn cờ đã được xác minh bằng phương thức khớp sẽ trả về giá trị boolean. Lưu ý rằng ^$bắt đầu và ký tự cuối được yêu cầu để phù hợp với toàn bộ văn bản.

3. Rectangle of digits
Found: [(0, 1, 5, 3), (1, 1, 4, 3), (2, 1, 3, 3), (3, 1, 2, 3), (0, 2, 5, 2), (1, 2, 4, 2), (2, 2, 3, 2), (3, 2, 2, 2), (6, 3, 2, 2)]
Not found: None

print '\n3. Rectangle of digits'
reob3 = Re2d(r'\d\d+', flags=MULTIFIND)
print 'Found:', reob3.search('hbrewvgr\n18774gwe\n84502vgv\n19844f22\ncrfegc77')
print 'Not found:', reob3.search('uv88wn000\nvgr88vg0w\nv888wrvg7\nvvg88wv77')

Bây giờ chúng tôi sử dụng MULTIFINDcờ để trả về tất cả các kết quả khớp có thể có cho khối 2+ chữ số. Phương pháp tìm thấy 9 kết quả khớp có thể. Lưu ý rằng chúng có thể được chồng chéo.

4. Word search (orthogonal only)
Words: [(0, 0, 4, 1), (0, 3, 4, 1), (3, 3, -4, -1), (3, 2, -4, -1), (3, 0, -4, -1)] [(0, 0, 1, 4), (3, 0, 1, 4), (3, 3, -1, -4), (0, 3, -1, -4)]
Words: ['SNUG', 'WOLF', 'FLOW', 'LORE', 'GUNS'] ['S\nT\nE\nW', 'G\nO\nL\nF', 'F\nL\nO\nG', 'W\nE\nT\nS']
No words: [] []

print '\n4. Word search (orthogonal only)'
words = 'GOLF|GUNS|WOLF|FLOW|LORE|WETS|STEW|FLOG|SNUG'
flags = HORFLIP | VERFLIP | MULTIFIND
reob4a, reob4b = Re2d(words, '.', flags), Re2d('.', words, flags)
matching = 'SNUG\nTEQO\nEROL\nWOLF'
nomatch = 'ABCD\nEFGH\nIJKL\nMNOP'
print 'Words:', reob4a.search(matching), reob4b.search(matching)
print 'Words:', reob4a.findall(matching), reob4b.findall(matching)
print 'No words:', reob4a.findall(nomatch), reob4b.findall(nomatch)

Thử nghiệm này cho thấy việc sử dụng lật dọc và ngang. Điều này cho phép kết hợp các từ được đảo ngược. Từ chéo không được hỗ trợ. Các MULTIFINDlá cờ cho phép nhiều trận đấu chồng chéo trong tất cả 4 hướng. Phương thức findall sử dụng tìm kiếm để tìm các hộp phù hợp sau đó trích xuất các khối văn bản phù hợp. Lưu ý cách tìm kiếm sử dụng chiều rộng và / hoặc chiều cao âm cho khớp theo hướng ngược lại. Các từ theo hướng dọc có các ký tự dòng mới - điều này phù hợp với khái niệm về các khối ký tự 2D.

7. Calvins portals
Portals found: [(3, 1, 5, 6)]
Portal not found None

print '\n7. Calvins portals'
reob7 = Re2d(r'X\.{2,22}X|.X{2,22}.', r'X\.{3,22}X|.X{3,22}.', MULTIFIND)
yes = '....X......\n.XXXXXX.XX.\n...X...X...\n.X.X...XXX.\n...X...X.X.\n.XXX...X.X.\nX..XXXXX.X.'
no = 'XX..XXXX\nXX..X..X\nXX..X..X\n..X.X..X\n.X..X.XX'
print 'Portals found:', reob7.search(yes)
print 'Portal not found', reob7.search(no)

Tìm kiếm này cần các mẫu riêng biệt cho mỗi thứ nguyên vì kích thước tối thiểu là khác nhau cho mỗi thứ nguyên.

9. Alignment
Found: ['#.,##', '##'] ['#\n.\n,\n.\n#', '#\n,\n.\n#']
Found: [(3, 4, 5, 1), (6, 4, 2, 1)] [(7, 0, 1, 5), (3, 1, 1, 4)]
Not found: None None

print '\n9. Alignment'
reob9a = Re2d(r'#.*#', r'.', MULTIFIND)
reob9b = Re2d(r'.', r'#.*#', MULTIFIND)
matching = '.,.,.,.#.,\n,.,#,.,.,.\n.,.,.,.,.,\n,.,.,.,.,.\n.,.#.,##.,\n,.,.,.,.,.'
nomatch = '.,.#.,.,\n,.,.,.#.\n.,#,.,.,\n,.,.,.,#\n.#.,.,.,\n,.,.#.,.\n#,.,.,.,\n,.,.,#,.'
print 'Found:', reob9a.findall(matching), reob9b.findall(matching)
print 'Found:', reob9a.search(matching), reob9b.search(matching)
print 'Not found:', reob9a.search(nomatch), reob9b.search(nomatch)

Bộ 2 tìm kiếm này tìm thấy 2 kết quả dọc và 2 khớp ngang, nhưng không thể tìm thấy #.,#chuỗi nhúng .

10. Collinear Points (orthogonal only)
Found: [(0, 1, 7, 1)] [(3, 1, 1, 4)]
Not found: None None

print '\n10. Collinear Points (orthogonal only)'
matching = '........\n#..#..#.\n...#....\n#.......\n...#....'
nomatch = '.#..#\n#..#.\n#....\n..#.#'
reob10h = Re2d(r'#.*#.*#', '.')
reob10v = Re2d('.', r'#.*#.*#')
flags = MULTIFIND
print 'Found:', reob10h.search(matching, flags), reob10v.search(matching, flags)
print 'Not found:', reob10h.search(nomatch, flags), reob10v.search(nomatch, flags)

Ở đây chúng tôi sử dụng 2 tìm kiếm để tìm trận đấu theo cả hai hướng. Nó có thể tìm thấy nhiều trận đấu trực giao nhưng cách tiếp cận này không hỗ trợ các đường chéo.

12. Avoid qQ
Found: (2, 2, 4, 4)
Not found: None

print '\n12. Avoid qQ'
reob12 = Re2d('[^qQ]{4,4}')
print 'Found:', reob12.search('bhtklkwt\nqlwQklqw\nvtvlwktv\nkQtwkvkl\nvtwlkvQk\nvnvevwvx')
print 'Not found:', reob12.search('zxvcmn\nxcvncn\nmnQxcv\nxcvmnx\nazvmne')

Tìm kiếm này tìm thấy trận đấu đầu tiên.

13. Diamond Mining
.X.
X.X
.X.

.X.
X.X
.X.

..X..
./.\.
X...X
.\./.
\.X..

..X..
./.\.
X...X
.\./.
..X..

.XX.\
//.\.
X...X
.\./.
..X..

...X...
../.\..
./.X.\.
X.X.X.X
.\.X.//
..\./X.
.X.X..\

Diamonds: [(2, 2, 3, 3), (0, 6, 3, 3)] [(8, 0, 5, 5), (10, 2, 5, 5), (5, 3, 5, 5)] [(0, 0, 7, 7)]
Not found: None None None

print '\n13. Diamond Mining'
reob13a = Re2d(r'.X.|X.X', flags=MULTIFIND)
reob13b = Re2d(r'..X..|./.\\.|X...X|.\\./.', flags=MULTIFIND)
reob13c = Re2d(r'...X...|../.\\..|./...\\.|X.....X|.\\.../.|..\\./..', flags=MULTIFIND)
match = '''
...X......X....
../.\..../.\...
./.X.\..X...X..
X.X.X.XX.\./.\.
.\.X.//.\.X...X
..\./X...X.\./.
.X.X..\./...X..
X.X....X.......
.X.............
'''.strip().replace(' ', '')
nomatch = '''
.X......./....
.\....X.......
...X.\.\...X..
..X.\...\.X.\.
...X.X...X.\.X
../X\...\...X.
.X...\.\..X...
..\./.X....X..
...X..../.....
'''.strip().replace(' ', '')
for diamond in reob13a.findall(match)+reob13b.findall(match)+reob13c.findall(match):
    print diamond+'\n'
print 'Diamonds:', reob13a.search(match), reob13b.search(match), reob13c.search(match)
print 'Not found:', reob13a.search(nomatch), reob13b.search(nomatch), reob13c.search(nomatch)

Vấn đề kim cương là khó khăn hơn. Ba đối tượng tìm kiếm là cần thiết cho ba kích cỡ. Nó có thể tìm thấy sáu viên kim cương trong bộ thử nghiệm, nhưng nó không mở rộng thành những viên kim cương có kích thước thay đổi. Đây chỉ là một giải pháp một phần cho vấn đề kim cương.

Mã Python 2

import sys
import re

DEBUG = re.DEBUG
IGNORECASE = re.IGNORECASE
LOCALE = re.LOCALE
UNICODE = re.UNICODE
VERBOSE = re.VERBOSE
MULTIFIND = 1<<11
ROTATED = 1<<12     # not implemented
HORFLIP = 1<<13
VERFLIP = 1<<14
WRAPAROUND = 1<<15  # not implemented

class Re2d(object):
    def __init__(self, horpattern, verpattern=None, flags=0):
        self.horpattern = horpattern
        self.verpattern = verpattern if verpattern != None else horpattern
        self.flags = flags

    def checkblock(self, block, flags):
        'Return a position if block matches H and V patterns'
        length = []
        for y in range(len(block)):
            match = re.match(self.horpattern, block[y], flags)
            if match:
                length.append(len(match.group(0)))
            else:
                break
        if not length:
            return None
        width = min(length)
        height = len(length)
        length = []
        for x in range(width):
            column = ''.join(row[x] for row in block[:height])
            match = re.match(self.verpattern, column, flags)
            if match:
                matchlen = len(match.group(0))
                length.append(matchlen)
            else:
                break
        if not length:
            return None
        height = min(length)
        width = len(length)
        # if smaller, verify with RECURSIVE checkblock call:
        if height != len(block) or width != len(block[0]):
            newblock = [row[:width] for row in block[:height]]
            newsize = self.checkblock(newblock, flags)
            return newsize
        return width, height

    def mkviews(self, text, flags):
        'Return views of text block from flip/rotate flags, inc inverse f()'
        # TODO add ROTATED to generate more views
        width = len(text[0])
        height = len(text)
        views = [(text, lambda x,y,w,h: (x,y,w,h))]
        if flags & HORFLIP and flags & VERFLIP:
            flip2text = [row[::-1] for row in text[::-1]]
            flip2func = lambda x,y,w,h: (width-1-x, height-1-y, -w, -h)
            views.append( (flip2text, flip2func) )
        elif flags & HORFLIP:
            hortext = [row[::-1] for row in text]
            horfunc = lambda x,y,w,h: (width-1-x, y, -w, h)
            views.append( (hortext, horfunc) )
        elif flags & VERFLIP:
            vertext = text[::-1]
            verfunc = lambda x,y,w,h: (x, height-1-y, w, -h)
            views.append( (vertext, verfunc) )
        return views

    def searchview(self, textview, flags=0):
        'Return matching textview positions or None'
        result = []
        for y in range(len(textview)):
            testtext = textview[y:]
            for x in range(len(testtext[0])):
                size = self.checkblock([row[x:] for row in testtext], flags)
                if size:
                    found = (x, y, size[0], size[1])
                    if flags & MULTIFIND:
                        result.append(found)
                    else:
                        return found
        return result if result else None

    def search(self, text, flags=0):
        'Return matching text positions or None'
        flags = self.flags | flags
        text = text.split('\n') if type(text) == str else text
        result = []
        for textview, invview in self.mkviews(text, flags):
            found = self.searchview(textview, flags)
            if found:
                if flags & MULTIFIND:
                    result.extend(invview(*f) for f in found)
                else:
                    return invview(*found)
        return result if result else None

    def findall(self, text, flags=0):
        'Return matching text blocks or None'
        flags = self.flags | flags
        strmode = (type(text) == str)
        text = text.split('\n') if type(text) == str else text
        result = []
        positions = self.search(text, flags)
        if not positions:
            return [] if flags & MULTIFIND else None
        if not flags & MULTIFIND:
            positions = [positions]
        for x0,y0,w,h in positions:
            if y0+h >= 0:
                lines = text[y0 : y0+h : cmp(h,0)]
            else:
                lines = text[y0 : : cmp(h,0)]
            if x0+w >= 0:
                block = [row[x0 : x0+w : cmp(w,0)] for row in lines]
            else:
                block = [row[x0 : : cmp(w,0)] for row in lines]
            result.append(block)
        if strmode:
            result = ['\n'.join(rows) for rows in result]
        if flags & MULTIFIND:
            return result
        else:
            return result[0]

    def match(self, text, flags=0):
        'Return True if whole text matches the patterns'
        flags = self.flags | flags
        text = text.split('\n') if type(text) == str else text
        for textview, invview in self.mkviews(text, flags):
            size = self.checkblock(textview, flags)
            if size:
                return True
        return False

Nếu vấn đề kim cương không rõ ràng, kim cương có thể có kích thước bất kỳ, không chỉ 0, 1 hoặc 2. Chỉnh sửa: Tôi đã chỉnh sửa thông số kỹ thuật để làm cho điều này rõ ràng hơn.
PhiNotPi 6/03/2015

Hiểu rồi. Tôi sẽ ghi chú trong câu trả lời rằng Re2d chỉ có một giải pháp một phần cho vấn đề này. Nó không thể mở rộng theo kích cỡ thay đổi. Ổn chứ?
Logic Knight

Vâng, điều đó tốt.
PhiNotPi 6/03/2015

14

Bụi bẩn , Haskell

Giới thiệu

Grime dựa trên ngữ pháp Boolean . Ý tưởng cơ bản là xây dựng các mẫu hình chữ nhật từ các thành phần nhỏ hơn và kiểm tra xem chúng có được tìm thấy trong ma trận đầu vào không. Cho đến nay, Grime chỉ hỗ trợ các trận đấu hình chữ nhật và giải quyết ít nhất 11 vấn đề ít nhiều một cách thanh lịch.

EDIT: Đã sửa lỗi các dấu thập (nhờ DLosc để phát hiện lỗi) và thêm khai thác kim cương.

EDIT2: Đã thêm các lớp nhân vật, lấy cảm hứng từ những người của Trượt. Đồng thời thay đổi cú pháp của các cờ tùy chọn, cải thiện trình phân tích cú pháp biểu thức và thêm vấn đề no-Q.

EDIT3: Đã thực hiện các ràng buộc kích thước và thêm vấn đề về cổng Nether.

Sử dụng

Một chương trình Grime được gọi là một ngữ pháp và phần mở rộng tệp chính xác cho một ngữ pháp là .gr, mặc dù điều này không được thi hành. Ngữ pháp được đánh giá là

runhaskell grime.hs [options] grammarfile matrixfile

trong đó matrixfilemột tập tin chứa ma trận ký tự. Ví dụ, ngữ pháp chữ số sẽ được đánh giá là

runhaskell grime.hs digits.gr digit-matrix

Để có thêm tốc độ, tôi khuyên bạn nên biên dịch tệp với tối ưu hóa:

ghc -O2 grime.hs
./grime digits.gr digit-matrix

Theo mặc định, trình thông dịch in kết quả khớp đầu tiên mà nó tìm thấy, nhưng điều này có thể được kiểm soát bằng các cờ tùy chọn:

  • -e: chỉ khớp toàn bộ ma trận, in 1cho khớp và 0không khớp.
  • -n: in số lượng trận đấu hoặc toàn bộ ma trận nếu -ecũng được đưa ra.
  • -a: in tất cả các trận đấu.
  • -p: in cũng các vị trí của các trận đấu, trong định dạng (x,y,w,h).
  • -s: không tự in các trận đấu.
  • -d: in thông tin gỡ lỗi.

Các tùy chọn cũng có thể được chỉ định trong ngữ pháp, bằng cách chèn chúng trước bất kỳ dòng nào và thêm dấu phẩy ,(xem ví dụ bên dưới).

Cú pháp và ngữ nghĩa

Một ngữ pháp Grime bao gồm một hoặc nhiều định nghĩa , mỗi định nghĩa trên một dòng riêng biệt. Mỗi người trong số họ xác định giá trị của một nonterminal , và một trong số họ phải xác định noplem nonterminal ẩn danh . Cú pháp của một định nghĩa là N=Ehoặc E, trong đó Nlà một chữ cái viết hoa và Elà một biểu thức .

Biểu thức được xây dựng như sau.

  • Bất kỳ ký tự nào thoát với \khớp với bất kỳ 1x1hình chữ nhật có chứa ký tự đó.
  • . phù hợp với bất kỳ nhân vật duy nhất.
  • $khớp với một 1x1hình chữ nhật bên ngoài ma trận ký tự.
  • _ phù hợp với bất kỳ hình chữ nhật có chiều rộng hoặc chiều cao bằng không.
  • Các nhóm nhân vật được xác định trước là digit, uppercase, lowercase, alphabetic, alpha numeric và symbol.
  • Các lớp ký tự mới có thể được xác định theo cú pháp [a-prt-w,d-gu]. Các chữ cái bên trái được bao gồm và những chữ cái bên phải được loại trừ, vì vậy chữ này khớp chính xác với các chữ cái abchijklmnoprtvw. Nếu bên trái trống, nó được lấy để chứa tất cả các ký tự. Dấu phẩy có thể được bỏ qua nếu phía bên phải trống. Các nhân vật [],-\phải được trốn thoát với \.
  • Một chữ cái viết hoa không có dấu là một ký tự đại diện và phù hợp với biểu thức được gán.
  • Nếu PQlà các biểu thức, thì đó PQchỉ là cách ghép ngang của chúng, và P/Qlà phép nối dọc của chúng, với Ptrên cùng.
  • P+là một hoặc nhiều Ps được căn chỉnh theo chiều ngang và P/+được căn chỉnh theo chiều dọc.
  • Các hoạt động Boolean được ký hiệu P|Q, P&QP!.
  • P?là tốc ký cho P|_, P*cho P+|_P/*cho P/+|_.
  • P#phù hợp với bất kỳ hình chữ nhật có chứa một trận đấu của P.
  • P{a-b,c-d}, trong đó abcdcác số nguyên không âm, là một ràng buộc kích thước trên P. Nếu Plà một lớp ký tự, thì biểu thức khớp với bất kỳ mxnhình chữ nhật nào chỉ chứa các ký tự đó, miễn mlà nằm giữa abbao gồm, và nnằm giữa cdbao gồm. Trong các trường hợp khác, biểu thức khớp với bất kỳ hình chữ nhật nào có kích thước chính xác và Pcũng khớp. Nếu ahoặc cbị bỏ qua, chúng được coi là 0và nếu bhoặc dbị bỏ qua, chúng là vô hạn. Nếu dấu gạch nối giữa abđược bỏ qua, thì chúng ta sử dụng cùng một số cho cả hai đầu của khoảng. Nếu toàn bộc-dmột phần bị bỏ qua, cả hai trục bị hạn chế. Để làm rõ, {-b}tương đương với {0-b,0-b}, và {a-,c}tương đương với {a-infinity,c-c}.

Ghi chú

Grime không cho phép các định nghĩa nghịch lý như A=A!với hành vi không xác định. Tuy nhiên, chúng sẽ không gây ra sự cố hoặc vòng lặp vô hạn.

Grime hỗ trợ đầu vào không phải hình chữ nhật; các hàng được căn chỉnh đơn giản ở bên trái và các khoảng trống có thể được khớp với nhau bằng cách sử dụng $.

Trong tương lai, tôi muốn thực hiện như sau:

  • Phù hợp nhanh hơn. Hiện tại, trình thông dịch không tính đến thực tế là, ví dụ, .chỉ có thể khớp với 1x1hình chữ nhật. Cho đến khi tìm thấy kết quả khớp, nó sẽ thử tất cả các hình chữ nhật ở mọi kích thước theo thứ tự, ngay lập tức không thành công cho mỗi hình.
  • Hoạt động xoay và phản xạ, cho các thách thức tìm kiếm từ và tàu lượn.
  • Các trận đấu không phải hình chữ nhật sử dụng bối cảnh , sẽ hữu ích trong thử thách bảng Boggle. Ví dụ: Pv(Q>R)có nghĩa là Pvới bối cảnh dưới cùng ( Qvới bối cảnh bên phải R). Nó sẽ phù hợp với các mẫu hình chữ L

    PPP
    PPP
    QQQRRRR
    QQQRRRR
    QQQRRRR
    

Nhiệm vụ

Đưa ra đại khái theo thứ tự phức tạp.

Hình chữ nhật của chữ số

d{2-}

Điều này rất đơn giản: ít nhất là một hình chữ nhật có kích thước 2x2.

Không có q hoặc Q

[,qQ]{4}

Điều này gần như đơn giản như cái đầu tiên; bây giờ chúng ta có kích thước hạn chế hơn và một lớp ký tự tùy chỉnh.

Căn ngang và dọc

\#.*\#|\#/./*/\#

Bây giờ chúng tôi có một số nhân vật thoát. Về cơ bản, cái này khớp với một #, sau đó là bất kỳ số lượng ký tự nào, sau đó #, theo chiều ngang hoặc chiều dọc.

Phát hiện đầu vào vuông

S=.|S./+/.+
e,S

Ngữ pháp này rất đơn giản, về cơ bản nó xác định rằng một hình vuông là 1x1hình chữ nhật hoặc hình vuông nhỏ hơn với một cột được đặt ở cạnh phải của nó và một hàng được đặt ở dưới cùng của hình đó. Cũng lưu ý etùy chọn trước toplevel nonterminal, để tắt toàn bộ xác minh đầu vào.

Tìm một từ trong tìm kiếm từ

G=\G
O=\O
L=\L
F=\F
GOLF|FLOG|G/O/L/F|F/L/O/G|G.../.O../..L./...F|...G/..O./.L../F...|F.../.L../..O./...G|...F/..L./.O../G...

Điều này thật kinh khủng, vì Grime không có hoạt động để xoay hoặc phản xạ. Nó cũng cực kỳ chậm, vì Grime không biết rằng các trận đấu chỉ có thể có kích cỡ 4x1, 1x4hoặc 4x4.

Vấn đề tàu lượn có thể được giải quyết tương tự, nhưng tôi quá lười để viết nó xuống.

Cổng Nether

.\X+./\X/+\.{2-22,3-22}\X/+/.\X+.

Với toán tử giới hạn kích thước, cái này không khó lắm. Phần giữa \.{2-22,3-22}khớp với bất kỳ hình chữ nhật nào có .kích thước chính xác, và sau đó chúng ta chỉ cần thêm các cột của Xs ở cả hai bên và giải quyết các hàng Xs với các đầu bị bỏ qua ở trên cùng và dưới cùng.

Phù hợp chéo

E=\.+/+
F=\#+/+
EFE/F/EFE&(E/F/E)F(E/F/E)

Những gì chúng ta có ở đây là sự kết hợp (logic AND) của hai biểu thức. Nonterminal Ekhớp với một hình chữ nhật không trống của .s và Fmột hình chữ nhật không trống của #s. Phía bên trái của kết hợp khớp với hình chữ nhật của loại

...####..
...####..
...####..
#########
#########
.....##..
.....##..

nơi chúng ta có EFEtrên đỉnh, sau đó F, và sau đó EFEmột lần nữa. Phía bên phải khớp với các chuyển vị của những điều này, vì vậy chúng ta có được chính xác các đường chéo.

Khai thác kim cương

C=./+
T=\X|CTC/\/.+\\
B=\X|\\.+\//CBC
CTC/\X.+\X/CBC

Các nonterminal Clà một tốc ký cho bất kỳ 1xncột. Nửa trên của một viên kim cương được khớp bởi T: nó là mộtX hoặc một cái khác được Tbao quanh bởi một cột ở cả hai bên và một hàng /[something]\bên dưới đó. Bkhớp với đáy của một viên kim cương theo cùng một cách, và toplevel nonterminal chỉ là hàng có dạng X[something]Xgiữa nửa trên và nửa dưới.

Tìm bàn cờ

(\#\#|\#/\#|\_\_|\_/\_)#!&[#_]{3-}

Phía bên tay phải [#_]{3-}khớp với bất kỳ 3x3hoặc hình chữ nhật lớn hơn của #s và_ s, trong khi phía bên trái đảm bảo rằng nó không chứa hai #s hoặc s liền kề _.

Xác minh bàn cờ

e,(\#\#|\#/\#|\_\_|\_/\_)#!&[#_]+/+

Điều này về cơ bản giống như trên, ngoại trừ việc chúng ta có thể khớp với bất kỳ hình chữ nhật không trống nào, nhưng cần sử dụng ecờ cho toàn bộ xác minh đầu vào.

Xác minh cú pháp mở đầu

A=[,()]/*
P=A*|P(A/\(/A)P(A/\)/A)P
e,P

Đây có lẽ là ngữ pháp thú vị nhất cho đến nay. Nonterminal Akhớp với bất kỳ cột nào không chứa (hoặc ), và Pkhớp với một số số As hoặc hai dấu ngoặc phù hợp, giữa và bên ngoài có nhiều Ps hơn .


@DLosc Đã sửa, cảm ơn vì đã tìm ra lỗi!
Zgarb 30/03/2015

Sẽ \#(.*|./*)\#làm việc?
xem

@Sieg Cho căn chỉnh? Thật không may, bởi vì điều đó sẽ được phân tích thành "một #bên trái, sau đó một hàng hoặc cột của bất cứ điều gì, sau đó một #bên phải". Tôi cần xác định rằng các #s được nối thẳng đứng với cột bằng cách sử dụng dấu gạch chéo /.
Zgarb

10

TMARL

Ngôn ngữ đối sánh và nhận dạng mẫu

Sự miêu tả

Trình thông dịch của tôi chiếm 24K ký tự ( đoạn mã chiếm ký tự? ), Vì vậy mô tả đầy đủ có thể được tìm thấy ở đây .

Phần tốt nhất: trình thông dịch là trong Javascript, có nghĩa là bạn có thể thử nó ngay tại đây!

Và cho các vấn đề:

# 1 - Tìm bàn cờ

$#_#
a
$_#_
bvacvbS5&(avcS5)G0G2P

&nối thêm các tìm kiếm. G2 ở cuối lấy phần tử thứ 3 trong phần tử khớp, khớp thực tế. 2 phần tử đầu tiên là tọa độ x và y (dựa trên 1, không phải 0).

# 3 - Phát hiện hình chữ nhật của chữ số

$DD
$DD
S1G2P

Tôi nghĩ rằng điều này là khá đơn giản.

# 4 - Tìm từ trong Tìm kiếm từ

$GO\LF
a
$G
$*O
$**\L
$***F
S6&(aS6)G0G2P

Đối Ssố thậm chí là để nó sẽ tìm kiếm tất cả các phép quay. Nó lớn hơn 4 vì sau đó nó có thể được thêm vào tìm kiếm tiếp theo (các trận đấu riêng lẻ không thể được thêm vào).

# 5 - Phát hiện đầu vào hình vuông

IL-(IG0L)!P

Không chắc chắn nếu điều này là hoàn toàn hợp pháp, vì nó chỉ xác định chính xác độ vuông nếu đầu vào là một hình chữ nhật. Nó so sánh độ dài của đầu vào ILvới chiều dài của hàng đầu tiên IG0Lvà đảo ngược nó.

# 6 - Tìm tàu ​​lượn trong trò chơi cuộc sống

$## 
$# #
$# 
a
$ ##
$## 
$  #
bS6&(bMS6)&(aS6)&(aMS6)G0G2P

Cuối cùng, sử dụng cho gương!

# 12 - Tránh chữ Q

$[^Qq]
~4*4S1G2P

S1 vì chỉ cần 1 trận đấu.

Tôi sẽ làm một số trong những cái khó hơn sau này.

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.