Phát hiện Cổng thông tin Nether


53

Trò chơi video Minecraft là tất cả về việc đặt và loại bỏ các loại khối khác nhau trong mạng số nguyên 3D tạo nên thế giới ảo. Mỗi điểm mạng có thể chứa chính xác một khối hoặc trống (một khối " không khí " chính thức). Trong thử thách này, chúng ta sẽ chỉ quan tâm đến một mặt phẳng 2D dọc của thế giới 3D và một loại khối: obsidian .

Khi obsidian tạo thành đường viền của hình chữ nhật trống trong mặt phẳng thẳng đứng, cổng thông tin nether có thể được tạo. Hình chữ nhật trống có thể có kích thước bất kỳ từ 2 đơn vị rộng 3 đơn vị cao đến 22 đơn vị rộng 22 đơn vị cao. Các góc của hình chữ nhật không cần phải được viền trong obsidian, chỉ cần các cạnh.

Ví dụ: giả sử Xlà obsidian và .là sự trống rỗng: (Các số chỉ dành cho mục đích nhận dạng và cũng trống rỗng.)

...................................
..XXXX....XXXX....XXXXXXXXX........
..X..X...X....X..X.........X..XXXX.
..X.1X...X.2..X..X...3...X.X..X....
..X..X...X....XXXX.........X..X.6X.
..XXXX....XXXX...XXXXXXXXXXX..X..X.
.............X.4.X....X.5.X...XXXX.
.............X...X....X...X........
..............XXX......XXX.........
...................................

Lưới này chứa 3 cổng hợp lệ:

  • Cổng thông tin 1 là 2 của 3 đơn vị, hoàn toàn trống rỗng và được bao bọc trong obsidian. Vì vậy, nó hợp lệ.
  • Portal 2 là 4 by 3, hoàn toàn trống rỗng và được bao bọc trong obsidian. Vì vậy, nó hợp lệ.
  • Cổng 3 không hoàn toàn trống. Do đó, nó không hợp lệ.
  • Portal 4 là 3 by 3, hoàn toàn trống rỗng và được bao bọc trong obsidian. Vì vậy, nó hợp lệ.
  • Cổng 5 là 3 của 2 đơn vị, quá nhỏ. Do đó, nó không hợp lệ.
  • Cổng 6 bị thiếu một phần của biên giới. Do đó, nó không hợp lệ.

Thử thách

Viết một chương trình hoặc hàm có các biểu diễn chuỗi này của các lưới của obsidian và trống rỗng, và in hoặc trả về số lượng cổng thông tin hợp lệ hiện có.

  • Đầu vào có thể từ stdin hoặc tệp hoặc đối số chức năng.
  • Bạn có thể giả sử đầu vào luôn được định dạng tốt - tức là một lưới văn bản hình chữ nhật hoàn hảo, rộng ít nhất 1 ký tự, chỉ chứa X.. Bạn có thể tùy ý cho rằng có một dòng mới sau hàng cuối cùng.

  • Nếu muốn, bạn có thể sử dụng bất kỳ hai ký tự ASCII có thể in riêng biệt nào thay cho X..

  • Obsidian có thể nằm trên đường viền của lưới. Bất cứ điều gì ngoài biên giới được coi là trống rỗng.

Ví dụ đầu vào - đầu ra phải là 4:

................................................................
...................................XXXXXXXXXXXXXXXXXXXXXXXXX....
..XXXX....XXXX....XXXXXXXXX........X.......................X....
..X..X...X....X..X.........X..XXXX.X.......................X....
..X..X...X....X..X.......X.X..X....X.......................X....
..X..X...X....XXXX.........X..X..X..XXXXXXXXXXXXXXXXXXXXXXXX....
..XXXX....XXXX...XXXXXXXXXXX..X..X.X......................X..XXX
.............X...X....X...X...XXXX.X......................X..X..
.............X...X....X...X........X......................X..X..
..............XXX......XXX........XXXXXXXXXXXXXXXXXXXXXXXX...X..
..................................XX.........................XXX

Chấm điểm

Việc gửi với ít byte nhất sẽ thắng.


Tôi có thể sử dụng một ký tự ASCII khác thay cho các dòng mới không?
Zgarb 8/2/2015

@Zgarb Không, tôi vẫn muốn đầu vào trông giống như một lưới.
Sở thích của Calvin

4
Khi nào kích thước của cổng nether thay đổi từ kích thước tĩnh 2x3 sang kích thước lớn hơn tùy chọn?
Sparr

5
@Sparr SInce 1.7.2 (xem lịch sử cập nhật ). Tôi không chắc liệu họ có thể làm điều này trong phiên bản console hay không.
Sở thích của Calvin

4
Chắc chắn là +1 vì Minecraft.
Alex A.

Câu trả lời:


24

Perl, 81 86

Sử dụng nhiều hơn một regrec.

#!perl -p0
$_=map{/.
/;$n="@-"-++$.;/(?=X{$.}..{$n}(X\.{$.}X.{$n}){3,22}.X{$.})/gs}($_)x21

Các regexp cho chiều rộng cụ thể của một cổng thông tin là đơn giản hơn nhiều so với một generic: X{$m}..{$n}(X\.{$m}X.{$n}){3,22}.X{$m}nơi mlà chiều rộng của cổng thông tin và ntotal width - 1 - m. Các biểu thức chính quy phải được đặt trong xác nhận chuyển tiếp có chiều rộng bằng 0 (?=...)vì các kết quả khớp có thể trùng nhau. Sau đó, tôi lặp lại 21 lần trong cài đặt regrec này $n$.. "@-"ước tính vị trí bắt đầu của kết quả khớp cuối cùng ( /.\n/) có tổng chiều rộng - 1. $.được sử dụng làm biến khác khi được khởi tạo 1khi được sử dụng với -p0.


2
Bạn có thể lưu một byte nếu bạn sử dụng một ký tự khác với .các ô trống (vì vậy bạn không phải thoát nó).
Martin Ender

62

Regex (hương vị .NET), 182 181 145 132 126 114 104 100 98 97 96 byte

Nhận dạng mẫu nghệ thuật 2D ASCII? Âm thanh như một công việc cho regex! (Nó không.)

Tôi biết điều này sẽ tiếp tục thảo luận vô tận một lần nữa về việc liệu đệ trình regex có phải là chương trình hợp lệ hay không, nhưng tôi nghi ngờ điều này sẽ đánh bại APL hoặc CJam, vì vậy tôi không thấy có hại gì. (Nói như vậy, họ làm vượt qua khảo nghiệm chết cứng của chúng tôi đối với "một ngôn ngữ lập trình là gì?" .)

Điều này lấy đầu vào là chuỗi được khớp và kết quả là số lượng khớp được tìm thấy. Nó sử dụng _thay thế ., bởi vì tôi phải thoát cái thứ hai. Nó cũng đòi hỏi một dòng mới.

(X(X){1,21})(?=\D+((?>(?<-2>_)+)_))(?=.((?!\7)(.)*
.*(X\3X|()\1.)(?=(?<-5>.)*(?(5)!)
)){4,23}\7)

Bạn có thể kiểm tra trực tiếp tại RegexHero hoặc RegexStorm ). Các trận đấu sẽ là các hàng obsidian hàng đầu của các cổng. Nếu bạn có thể tìm thấy một trường hợp thử nghiệm thất bại, xin vui lòng cho tôi biết!

Đây là yêu thuật gì?

Giải thích sau đây giả định hiểu biết cơ bản về các nhóm cân bằng của .NET . Điểm chính là các ảnh chụp là các ngăn xếp trong .NET regex - mọi thao tác chụp mới có cùng tên được đẩy lên ngăn xếp, nhưng cũng có cú pháp bật lại các ảnh chụp từ các ngăn xếp đó, cũng như cú pháp để chụp các ảnh chụp từ một ngăn xếp và đẩy các ảnh chụp lên cái khác cùng một lúc. Để có bức ảnh hoàn chỉnh hơn, bạn có thể xem câu trả lời của tôi về Stack Overflow sẽ bao gồm tất cả các chi tiết.

Ý tưởng cơ bản là khớp một mẫu như:

 X{n}..{m}
X_{n}X.{m} |
X_{n}X.{m} |  3 to 22 times
X_{n}X.{m} |
 X{n}..{m} 

Trường hợp nlà từ 2 đến 22 (bao gồm). Điều khó khăn là làm cho tất cả các ns và tất cả các đều mgiống nhau. Vì các nhân vật thực tế sẽ không giống nhau, chúng tôi không thể sử dụng phản hồi.

Lưu ý rằng regex phải nhúng các dòng mới, mà tôi sẽ viết như \nsau.

(                     # Open capturing group 1. This will contain the top of a portal, which
                      # I can reuse later to match the bottom (being of the same length).
  X                   # Match a single X.
  (X){1,21}           # Match 1 to 21 X's, and push each separately on the <2> stack. Let's
                      # Call the number of X's captured N-1 (so N is the inner width of the
                      # portal).
)                     # End of group 1. This now contains N X's.
(?=                   # Start a lookahead. The purpose of this lookahead is to capture a 
                      # string of N underscores in group 2, so I can easily use this to match 
                      # the inside rows of the portal later on. I can be sure that such a 
                      # string can always be found for a valid portal (since it cannot have 0 
                      # inner height).
  \D+                 # Skip past a bunch of non-digits - i.e. *any* of the vaild characters
                      # of the input (_, X, \n). This to make sure I search for my N 
                      # underscores anywhere in the remainder of the input.
  (                   # Open capturing group 3. This will contain a portal row.
    (?>               # This is an atomic group. Once the engine hass successfully matched the
                      # contents of this group, it will not go back into the group and try to
                      # backtrack other possible matches for the subpattern.
      (?<-2>_)+       # Match underscores while popping from the <2> stack. This will match as
                      # many underscores as possible (but not more than N-1).
    )                 # End of the atomic group. There are two possible reasons for the
                      # subpattern stopping to match: either the <2> stack is empty, and we've
                      # matched N-1 underscores; or we've run out of underscores, in which 
                      # case we don't know how many underscores we matched (which is not 
                      # good).
    _                 # We simply try to match one more underscore. This ensures that we 
                      # stopped because the <2> stack was empty and that group 3 will contain
                      # exactly N underscores.
  )                   # End of group 3.
)                     # End of the lookahead. We've got what we want in group 2 now, but the
                      # regex engine's "cursor" is still at the end of the portal's top.
(?=                   # Start another lookahead. This ensures that there's actually a valid
                      # portal beneath the top. In theory, this doesn't need to be a 
                      # lookahead - I could just match the entire portal (including the lines
                      # it covers). But matches cannot overlap, so if there were multiple
                      # portals next to each other, this wouldn't return all of them. By 
                      # putting the remainder of the check in a lookahead the actual matches
                      # won't overlap (because the top cannot be shared by two portals).
  .                   # Match either _ or X. This is the character above the portal side.

  (                   # This group (4) is where the real magic happens. It's purpose is to to
                      # count the length of the rest of the current line. Then find a portal
                      # row in the next line, and ensure that it's the same distance from the
                      # end of the line. Rinse and repeat. The tricky thing is that this is a
                      # single loop which matches both inner portal rows, as well as the 
                      # bottom, while making sure that the bottom pattern comes last.

    (?!\7)            # We didn't have a group 7 yet... group 7 is further down the pattern.
                      # It will capture an empty string once the bottom row has been matched.
                      # While the bottom row has not been matched, and nothing has been
                      # captured, the backreference will fail, so the negative lookahead will
                      # pass. But once we have found the bottom row, the backreference will
                      # always match (since it's just an empty string) and so the lookahead
                      # will fail. This means, we cannot repeat group 4 any more after the
                      # bottom has been matched.
    (.)*              # Match all characters until the end of the line, and push each onto
                      # stack <5>.
    \n                # Match a newline to go to the next line.
    .*                # Match as many characters as necessary to search for the next portal
                      # row. This conditions afterwards will ensure that this backtracks to
                      # the right position (if one exists).
    (                 # This group (6) will match either an inner portal row, or the bottom
                      # of the portal.
      X\3X            # Match X, then N underscores, then X - a valid inner portal row.
    |                 # OR
      ()              # Capture an empty string into group 7 to prevent matching further rows.
      \1.             # Use the captured top to match the bottom and another character.
    )
    (?=               # This lookahead makes sure that the row was found at the same 
                      # horizontal position as the top, by checking that the remaining line
                      # is the same length.
      (?<-5>.)*       # Match characters while popping from the <5> stack.
      (?(5)!)\n       # Make sure we've hit end of the line, *and* the <5> stack is empty.
    )
  ){4,23}             # Repeat this 4 to 23 times, to ensure an admissible portal height.
                      # Note that this is one more than the allowed inner height, to account
                      # for the bottom row.
  \7                  # Now in the above repetition there is nothing requiring that we have
                      # actually matched any bottom row - it just ensured we didn't continue
                      # if we had found one. This backreference takes care of that. If no
                      # bottom row was found, nothing was captured into group 7 and this
                      # backreference fails. Otherwise, this backreference contains an empty
                      # string which always matches.
)

C #, 185 byte

Đây là một hàm C # đầy đủ, chỉ để làm cho mục này hợp lệ. Đã đến lúc tôi viết một "trình thông dịch" dòng lệnh cho các biểu thức chính quy .NET ...

static int f(string p){return System.Text.RegularExpressions.Regex.Matches(p,@"(X(X){1,21})(?=\D+((?>(?<-2>_)+)_))(?=.((?!\7)(.)*
.*(X\3X|()\1.)(?=(?<-5>.)*(?(5)!)
)){4,23}\7)").Count;}

5
Hmm, không chắc tôi cảm thấy thế nào về một câu trả lời regex thuần túy. Khớp ngọn không giống như in số. Tất nhiên sẽ ổn khi sử dụng regex trong một chương trình và in số lượng trận đấu. Tuy nhiên, như bạn nói, nó có thể sẽ bị đánh, vì vậy tôi cũng quá lo lắng.
Sở thích của Calvin

1
Bạn có thể sử dụng ^(hoặc bất kỳ ký tự không sử dụng) cho (?!).
jimmy23013

@ user23013 Ồ, điểm tốt, cảm ơn bạn.
Martin Ender


@ user23013 Tôi nhận được 114 chỉ bằng cách sử dụng nhóm không tên, nhưng không kết hợp kiểm tra dòng thành một.
Martin Ender

11

Python, 219 byte

def f(s):s=s.split();L=len;R=range;return L([r for r in R(L(s))for a in R(L(s[0]))for w in R(2,23)for h in R(3,min(L(s)+~r,23))if(s[r][a:a+w]==s[r-~h][a:a+w]==w*"X")*all(s[r-~k][a-1:a+w+1]=="X"+"."*w+"X"for k in R(h))])

Tốt hơn Java, nhưng cậu bé quintuple lồng vào nhau bị tổn thương. Nó for/incó thể hơi nén khi sử dụng %sthay thế, nhưng nó sẽ không tiết kiệm nhiều.

Mở rộng:

def f(s):
  s=s.split()
  L=len
  R=range
  return L([r for r in R(L(s))
              for a in R(L(s[0]))
              for w in R(2,23)
              for h in R(3,min(L(s)+~r,23))
              if(s[r][a:a+w]==s[r-~h][a:a+w]==w*"X")* 
                 all(s[r-~k][a-1:a+w+1]=="X"+"."*w+"X"for k in R(h))])

1
Bản năng của tôi là thử các phép thuật tạo vòng lặp lồng nhau.
imallett

7

Java, 304 byte

Điều này dài hơn rất nhiều so với một biểu thức thông thường. Nó chỉ đơn giản lặp đi lặp lại trên mỗi ô vuông có thể có trong đầu vào. Nếu đó là một cổng thông tin hợp lệ, nó sẽ tăng một bộ đếm lên 1. Sau đó nó trả về bộ đếm. Điều này có thể có thể được chơi golf hơn nữa. Mọi góp ý đều được chào đón.

int a(String...a){a=a[0].split("\n");int b=0,c=0,d,e,f,g,h,i=a.length,j=a[0].length();for(;c<j;c++)for(d=0;d<i;d++)for(e=c+2;++e<j&e<c+24;)a:for(f=d+3;++f<i&f<d+24;){for(g=c;g<=e;g++)for(h=d;h<=f;h++){if(g==c|g==e&&h==d|h==f)continue;if((g==c|g==e|h==d|h==f)^a[h].charAt(g)>60)continue a;}b++;}return b;}

Thụt lề:

int a(String...a){
    a=a[0].split("\n");
    int b=0,c=0,d,e,f,g,h,i=a.length,j=a[0].length();
    for(;c<j;c++)
        for(d=0;d<i;d++)
            for(e=c+2;++e<j&e<c+24;)
                a:for(f=d+3;++f<i&f<d+24;){
                    for(g=c;g<=e;g++)
                        for(h=d;h<=f;h++){
                            if(g==c|g==e&&h==d|h==f)
                                continue;
                            if((g==c|g==e|h==d|h==f)^a[h].charAt(g)>60)
                                continue a;
                        }
                    b++;
                }
    return b;
}

Chương trình đầy đủ:

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;

public class B {

    public static void main(String[] args) throws FileNotFoundException {
        String blocks = new BufferedReader(new FileReader(args[0])).lines().reduce((a,b)->a+"\n"+b).get();
        System.out.println(new B().a(blocks));
    }

    int a(String...a){
        a=a[0].split("\n");
        int b=0,c=0,d,e,f,g,h,i=a.length,j=a[0].length();
        for(;c<j;c++)
            for(d=0;d<i;d++)
                for(e=c+2;++e<j&e<c+24;)
                    a:for(f=d+3;++f<i&f<d+24;){
                        for(g=c;g<=e;g++)
                            for(h=d;h<=f;h++){
                                if(g==c|g==e&&h==d|h==f)
                                    continue;
                                if((g==c|g==e|h==d|h==f)^a[h].charAt(g)>60)
                                    continue a;
                            }
                        b++;
                    }
        return b;
    }

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