การตรวจสอบ Nether Portal


53

วิดีโอเกมMinecraftนั้นเกี่ยวกับการวางและลบบล็อกประเภทต่าง ๆ ในโครงร่างจำนวนเต็ม 3 มิติที่ประกอบขึ้นเป็นโลกเสมือนจริง จุดขัดแตะแต่ละจุดสามารถมีหนึ่งบล็อกแน่นอนหรือว่างเปล่า ( บล็อก " อากาศ " อย่างเป็นทางการ) ในการท้าทายนี้เราจะเกี่ยวข้องกับระนาบ 2D แนวดิ่งเดียวของโลก 3 มิติและบล็อกประเภทหนึ่ง: ออบซิเดีย

เมื่อ obsidian สร้างโครงร่างของสี่เหลี่ยมผืนผ้าว่างในระนาบแนวตั้งพอร์ทัล netherสามารถสร้างขึ้นได้ สี่เหลี่ยมผืนผ้าที่ว่างเปล่าอาจมีขนาดใดก็ได้ตั้งแต่ 2 หน่วยกว้าง 3 หน่วยสูงถึง 22 หน่วยกว้าง 22 สูง มุมของรูปสี่เหลี่ยมผืนผ้าไม่จำเป็นต้องล้อมรอบด้วยรัคเพียงด้านข้าง

ตัวอย่างเช่นสมมติว่าXเป็น obsidian และ.ว่างเปล่า: (ตัวเลขเหล่านี้มีวัตถุประสงค์เพื่อระบุตัวตนและยังว่างเปล่า)

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

ตารางนี้มี 3 พอร์ทัลที่ถูกต้อง:

  • พอร์ทัล 1 คือ 2 โดย 3 หน่วยว่างเปล่าทั้งหมดและล้อมรอบด้วยรัค ดังนั้นมันจึงถูกต้อง
  • พอร์ทัล 2 คือ 4 คูณ 3 ว่างทั้งหมดและล้อมรอบด้วยรัค ดังนั้นมันจึงถูกต้อง
  • พอร์ทัล 3 ไม่ว่างเปล่าทั้งหมด ดังนั้นมันจึงไม่ถูกต้อง
  • พอร์ทัล 4 คือ 3 คูณ 3 ว่างทั้งหมดและล้อมรอบด้วยรัค ดังนั้นมันจึงถูกต้อง
  • พอร์ทัล 5 คือ 3 คูณ 2 ยูนิตซึ่งเล็กเกินไป ดังนั้นมันจึงไม่ถูกต้อง
  • พอร์ทัล 6 หายไปส่วนหนึ่งของชายแดน ดังนั้นมันจึงไม่ถูกต้อง

ท้าทาย

เขียนโปรแกรมหรือฟังก์ชั่นที่ใช้ในการเป็นตัวแทนสตริงของกริดของ obsidian และความว่างเปล่าและพิมพ์หรือส่งคืนจำนวนของพอร์ทัล nether ที่ถูกต้องที่มีอยู่

  • อินพุตอาจมาจาก stdin หรือไฟล์หรืออาร์กิวเมนต์ของฟังก์ชัน
  • คุณอาจจะสมมติป้อนข้อมูลอยู่เสมอดีขึ้น - เช่นตารางสี่เหลี่ยมอย่างสมบูรณ์แบบของข้อความอย่างน้อย 1 ตัวกว้างและสูงเท่านั้นที่มีและX .คุณอาจเลือกที่จะสันนิษฐานว่ามีการขึ้นบรรทัดใหม่ต่อท้ายแถวสุดท้าย

  • หากต้องการคุณอาจจะใช้ที่แตกต่างกันสองASCII พิมพ์ตัวอักษรในสถานที่และX.

  • Obsidian อาจอยู่บนเส้นขอบของกริด สิ่งใดก็ตามที่เกินขอบเขตจะถือว่าว่างเปล่า

ตัวอย่างอินพุต - เอาต์พุตควรเป็น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

เกณฑ์การให้คะแนน

การส่งที่มีจำนวนไบต์น้อยที่สุดจะเป็นผู้ชนะ


ฉันสามารถใช้อักขระ ASCII อื่นแทนการขึ้นบรรทัดใหม่ได้หรือไม่
Zgarb

@Zgarb ไม่ฉันยังต้องการให้อินพุตดูเหมือนกริด
งานอดิเรกของ Calvin

4
เมื่อใดขนาดของพอร์ทัลเมื่อเปลี่ยนจากสแตติก 2x3 เป็นขนาดที่ใหญ่ขึ้นเป็นทางเลือก
Sparr

5
@Sparr SInce 1.7.2 (ดูประวัติการอัปเดต ) ฉันไม่แน่ใจว่าพวกเขาสามารถทำได้ในรุ่นคอนโซลหรือไม่
งานอดิเรกของ Calvin

4
+1 อย่างแน่นอนเพราะ Minecraft
Alex A.

คำตอบ:


24

Perl, 81 86

ใช้มากกว่าหนึ่ง regexp

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

regexp สำหรับความกว้างที่เฉพาะเจาะจงของพอร์ทัลง่ายกว่าทั่วไปหนึ่งX{$m}..{$n}(X\.{$m}X.{$n}){3,22}.X{$m}ที่mเป็นความกว้างของพอร์ทัลและเป็นn total width - 1 - mregexp จะต้องใส่ในการยืนยันไปข้างหน้าเป็นศูนย์กว้าง(?=...)เพราะการแข่งขันอาจทับซ้อน จากนั้นผมก็ย้ำ 21 ครั้งในช่วงการตั้งค่า regexp นี้และ$n ประเมินตำแหน่งเริ่มต้นของการแข่งขันที่ผ่านมา ( ) ซึ่งจะเกิดขึ้นจะกว้างทั้งหมด - 1. ใช้เป็นตัวแปรอื่น ๆ เช่นมันจะเริ่มต้นได้เมื่อใช้กับ$."@-"/.\n/$.1-p0


2
คุณสามารถบันทึกไบต์ได้หากคุณใช้อักขระที่แตกต่างจาก.เซลล์ว่างเปล่า (ดังนั้นคุณจึงไม่ต้องหลบหนี)
Martin Ender

62

Regex (. NET รส), 182 181 145 132 126 114 104 100 98 97 96 ไบต์

การจดจำรูปแบบศิลปะ ASCII 2D? ดูเหมือนงาน regex! (ไม่เช่นนั้น)

ฉันรู้ว่าสิ่งนี้กำลังจะเริ่มการสนทนาที่ไม่มีที่สิ้นสุดอีกครั้งว่าการส่ง regex เป็นโปรแกรมที่ถูกต้องหรือไม่ แต่ฉันสงสัยว่ามันจะเอาชนะ APL หรือ CJam ต่อไปดังนั้นฉันจึงไม่เห็นอันตรายใด ๆ (ที่ถูกกล่าวว่าพวกเขาจะทำผ่านการทดสอบตายแข็งของเราสำหรับ"เป็นภาษาโปรแกรมอะไร?" .)

การดำเนินการนี้ใช้อินพุตเป็นสตริงที่จะจับคู่และผลลัพธ์คือจำนวนการจับคู่ที่พบ มันใช้_แทน.เพราะฉันต้องหลบหนีหลัง นอกจากนี้ยังต้องขึ้นบรรทัดใหม่ต่อท้าย

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

คุณสามารถทดสอบมันได้ที่RegexHeroหรือRegexStorm ) การแข่งขันจะเป็นแถวออบซิเดียนอันดับต้น ๆ ของพอร์ทัล หากคุณสามารถหากรณีทดสอบที่ล้มเหลวได้โปรดแจ้งให้เราทราบ!

คาถานี้คืออะไร?

คำอธิบายต่อไปนี้อนุมานความเข้าใจพื้นฐานของ .NET ของกลุ่มสมดุล แก่นสำคัญคือการจับภาพเป็นกองใน. NET regex - ทุกการจับภาพใหม่สำหรับชื่อเดียวกันจะถูกผลักลงบนสแต็ก แต่ยังมีไวยากรณ์ที่จะป๊อปอัพการจับจากกองเหล่านั้นอีกครั้ง ไปยังอีกในเวลาเดียวกัน สำหรับภาพที่สมบูรณ์มากขึ้นคุณสามารถดูคำตอบของฉันใน Stack Overflowซึ่งควรครอบคลุมรายละเอียดทั้งหมด

แนวคิดพื้นฐานคือการจับคู่รูปแบบที่ชอบ:

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

อยู่nระหว่าง 2 และ 22 (รวม) สิ่งที่ยุ่งยากคือทำให้ทุกอย่างnและทุกอย่างmเหมือนกัน เนื่องจากตัวละครที่เกิดขึ้นจริงจะไม่เหมือนกันเราจึงไม่สามารถใช้การอ้างอิงย้อนกลับได้

โปรดทราบว่า regex จะต้องฝังตัวขึ้นบรรทัดใหม่ซึ่งฉันจะเขียน\nดังต่อไปนี้

(                     # 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 ไบต์

นี่คือฟังก์ชัน C # เต็มรูปแบบเพียงเพื่อให้รายการนี้ถูกต้อง ถึงเวลาที่ฉันเขียน "interpreter" บรรทัดคำสั่งสำหรับนิพจน์ปกติ. 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
อืมไม่แน่ใจว่าฉันรู้สึกอย่างไรกับคำตอบของ regex อย่างแท้จริง การจับคู่เสื้อไม่เหมือนกับการพิมพ์ตัวเลข แน่นอนว่าน่าจะใช้ regex ในโปรแกรมและพิมพ์จำนวนการแข่งขัน ถึงอย่างที่คุณพูดมันอาจจะถูกตีดังนั้นฉันก็กังวลเหมือนกัน
งานอดิเรกของ Calvin

1
คุณสามารถใช้^(หรือตัวละครที่ไม่ได้ใช้) (?!)สำหรับ
jimmy23013

@ user23013 โอ้จุดดีขอบคุณ
Martin Ender

118 ไบต์
jimmy23013

@ user23013 ผมได้ 114 มีเพียงแค่ใช้ชื่อกลุ่ม แต่ไม่รวมการตรวจสอบสายเป็นหนึ่ง
Martin Ender

11

Python ขนาด 219 ไบต์

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

ดีกว่า Java แต่ให้ห่วงที่ซ้อนกันเป็นห้าเท่าได้รับบาดเจ็บ for/inอาจจะอัดเล็กน้อยใช้%sทดแทน แต่มันจะไม่ช่วยมาก

ขยาย:

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
สัญชาตญาณของฉันคือการลองใช้เวทมนตร์เวทซ้อนในรุ่น itertools
imallett

7

Java, 304 ไบต์

นี่นานกว่านิพจน์ทั่วไป มันวนซ้ำทุกตารางที่เป็นไปได้ในอินพุต ถ้ามันเป็นพอร์ทัลที่ถูกต้องก็จะเพิ่มเคาน์เตอร์โดย 1 จากนั้นส่งกลับเคาน์เตอร์ นี่อาจเป็นเรื่องที่ต้องทำต่อไป ข้อเสนอแนะใด ๆ ยินดีต้อนรับ

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

เยื้อง:

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

โปรแกรมเต็มรูปแบบ:

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

}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.