ASCII topology pt 1: ฉันไว้ใจคุณได้ไหม?


28

ฉันมีปัญหาร้ายแรง ฉันมีไฟล์ข้อความที่ฉันเก็บหมายเลขที่สำคัญของฉัน - ทั้งหมดที่สำคัญ! และสองและสาม ..

ตัวเลขเหล่านี้สำคัญมากที่ฉันไม่สามารถมอบความไว้วางใจให้กับระบบทศนิยมหรือไบนารีเลขใหม่ ฉันเก็บรหัสแต่ละหมายเลขไว้ด้วยกันโดยไม่ระมัดระวังดังนี้:

            +--+
            |  |
+---+  +----+  |
|   |  |       |
+---+  +-------+
   ~/two.txt

ง่ายและน่าเชื่อถือ: ASCII สองลูปสำหรับหมายเลข 2 โชคไม่ดีสิ่งเหล่านี้มักจะยุ่งเหยิงเมื่อเวลาผ่านไปและตอนนี้ฉันมีเวลายากที่จะทราบว่ามีกี่ลูปในแต่ละไฟล์ นี่คือตัวอย่างบางส่วนที่ฉันทำงานด้วยมือ:

หนึ่ง:

   +---+
   |   |
+--+   |
|      |
+--+   |
   |   |
   |   |
   |   |
+--+   +--+
|         |
+---------+

สาม:

+---------+
| +-----+ |
| | +-+ | |
| | | | | |
| | +-+ | |
| +-----+ |
+---------+

ที่สี่:

  +--------------+
  |  +--+  +--+  |
  |  |  |  |  |  |
+-|-----|-----|----+
| |  |  |  |  |  | |
| +--+  +--+  +--+ |
+------------------+

              +------------+
              |            |
        +-----+  +-----+   |
        |        |     |   |
  +-----|-----------+  |   |
  |     |  +--+  |  |  |   |
  +-+   +--|--|--+  +---------+
    |      |  +-+      |   |  |
    +------+    |      |   |  |
                +-------+  |  |
                       ||  |  |
                       |+-----+
                       |   |
                       +---+

ห้า:

+--------+  +--------+  +--------+
|        |  |        |  |        |
|     +--|-----+  +--|-----+     |
|     |  |  |  |  |  |  |  |     |
+-----|--+  +-----|--+  +--------+
      |        |  |        |
      +--------+  +--------+

คุณช่วยฉันนับลูปของฉันได้ไหม

นี่คือกฎ:

  • เนื่องจากฉันเก็บทุกอย่างไว้ในระบบเข้ารหัส ASCII ดังนั้นประสิทธิภาพของพื้นที่จึงเป็นสิ่งสำคัญสำหรับฉัน ดังนั้นนี่คือรหัสกอล์ฟ โปรแกรมที่เล็กที่สุดเป็นไบต์ชนะ
  • ลูปถูกวาดด้วยอักขระ +, -, | ทุกมุมในวงถูกวาดอย่างไม่น่าเชื่อ: หนึ่งในอักขระด้านบนและด้านล่าง + จะเป็น | และอีกหนึ่งทางขวาหรือซ้ายจะเป็น - เครื่องหมายสองเครื่องหมาย + ไม่เคยอยู่ติดกัน
  • เส้นอาจผ่านไปมาและอยู่ใต้กันและกัน เมื่อข้ามเส้นคุณจะสามารถเห็นเส้น "ใต้" ได้ทันทีบนทั้งสองด้านของเส้น "เกิน"
  • โปรแกรมของคุณควรเป็นตัวแทนสตริงของลูป (จาก stdin หรือเป็นพารามิเตอร์ฟังก์ชั่น) และผลิตจำนวน (เพื่อ stdout หรือเป็นค่าตอบแทน)
  • ความยาวบรรทัดอาจไม่เหมือนกันในการวาดลูปและอาจมีช่องว่างต่อท้ายในแต่ละบรรทัด
  • คุณอาจคิดว่ามีอินพุตอย่างน้อยหนึ่งลูป

ฉันไว้ใจคุณ!


ด้านใดด้านหนึ่งของ 'ภายใต้สาระ' เป็นได้+หรือไม่?
feersum

@feersum: ไม่ขอบทั้งสองที่ติดกับ + จะมองเห็นได้เสมอ
Matt Noonan

1
@ มาร์ติน: ฉันไม่กลัว พื้นที่เก็บข้อมูลของฉันอยู่ในระดับพรีเมี่ยมดังนั้นฉันจึงไม่สามารถสำรองพื้นที่พิเศษเหล่านั้นทั้งหมด
Matt Noonan

ฉันคิดว่าคุณควรเพิ่ม ( pastebin ) เป็นกรณีทดสอบเว้นแต่ว่าฉันทำอะไรหายไปและไม่มีการป้อนข้อมูลที่ถูกต้อง มี 6 ห่วงคือ ฉันทดสอบทางออนไลน์ด้วยโซลูชัน SnakeEx เท่านั้นและมันส่งออก 12
blutorange

1
บางทีคุณควรห้ามอย่างชัดแจ้งหรืออนุญาตให้มีการวนซ้ำข้ามตัวเอง (เช่นpastebin.com/5RLZuULG ) ในปัจจุบันพวกเขาถูกตรวจพบโดยวิธีการแก้ปัญหาทับทิม แต่ไม่ได้แก้ปัญหาโดย SnakeEx
blutorange

คำตอบ:


19

SnakeEx - 98 ไบต์ด้วย Javascript, 44 ไม่มี

นี่เป็นปัญหาที่ดีในการลองใช้ภาษาของฉันจากการท้าทายรายปักษ์เมื่อ:

m:({e<>PE}\-[|\-]*<T>\+|[|\-]*<T>)+`\+
e:\+

สถานที่ที่ดีที่สุดที่จะลองของฉันนี้เป็นล่ามออนไลน์

SnakeEx จับคู่รูปแบบในข้อความโดยใช้ "งู" ที่เคลื่อนที่ไปรอบ ๆ ข้อความที่ตรงกับ regexes รหัสอ่านชนิดของ regex ยกเว้น:

  • การ<T>เรียนการสอน นั่นคือคำสั่งทิศทางที่แยกงูซ้ายและขวาจากทิศทางปัจจุบัน
  • {e<>PE}เป็นเหมือนการเรียกรูทีนย่อย มันวางไข่งูที่มีคำจำกัดความeก้าวไปข้างหน้า ( <>) และด้วยพารามิเตอร์P(piggyback - งูวางไข่ตามงูใหม่) และE(พิเศษ - ไม่ตรงกับสิ่งที่จับคู่ไว้แล้ว) การตรวจสอบพิเศษนี้เป็นสิ่งเดียวที่หยุดงูจากการวนซ้ำไม่สิ้นสุด
  • คำนำหน้า`ในตอนท้ายระบุว่าสิ่งต่อไปนี้ควรจับคู่ก็ต่อเมื่อมันได้รับการจับคู่แล้วซึ่งเราสามารถใช้เพื่อบังคับให้วงปิด

เนื่องจาก SnakeEx เป็นเหมือน regex และไม่มีผลลัพธ์ทางเทคนิคตามที่ต้องการด้วยตัวเองฉันเดาว่าเราจำเป็นต้องรวมไว้ใน Javascript บางตัวที่เรียกล่าม:

function e(s){return snakeEx.run('m:({e<>PE}\\-[|\\-]*<T>\\+|[|\\-]*<T>)+`\\+\ne:\\+',s,1).length}

แก้ไข : แก้ไขให้ทำงานได้กับกรณีทดสอบเพิ่มเติมของ blutorange


1
+1 ฉันชอบสิ่งนี้มากอาจเป็นเพราะฉันสามารถลองออนไลน์และรับการเน้นลูป แต่คุณอาจต้องการตรวจสอบกรณีทดสอบทั้งสองนี้: 1 , 2
blutorange

@ blutorange จับดี ฉันเพิ่มการแก้ไขแฮ็กเล็กน้อยสำหรับลูปข้ามตัวเอง ฉันจะต้องคิดเกี่ยวกับกรณีทดสอบ 1 อีกเล็กน้อย
BMac

นั่นเป็นหนึ่งง่ายต่อการแก้ไขเพียงแทนที่[^ ]ด้วย[|\-];)
blutorange

ฮะฉันใช้เวลานานกว่าจะเข้าใจว่าทำไมถึงเป็นเช่นนั้น โทรดีมาก
BMac

นี่มันเจ๋งมาก!
Ingo Bürk

10

C # - 338 388 433ไบต์

บันทึกจำนวนไบต์ด้วยการเปลี่ยนเป็นอาร์เรย์ 1 มิติ

using C=System.Console;using System.Linq;class P{static void Main(){var D=C.In.ReadToEnd().Split('\n');int z,w=D.Max(m=>m.Length)+1,d,c=0;var E=D.SelectMany(l=>l.PadRight(w)).ToList();for(z=E.Count;z-->1;)if(E[z-1]==43)for(d=1,c++;E[z+=d%2<1?w*d-w:d-2]>32;)if(E[z]<44){E[z]=' ';d=d%2>0?z<w||E[z-w]<99?2:0:E[z+1]!=45?1:3;}C.WriteLine(c);}}

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

using C=System.Console;
using System.Linq;

class P
{
    static void Main()
    {
        // read in
        var D=C.In.ReadToEnd().Split('\n');

        int z, // z is position in E
        w=D.Max(m=>m.Length)+1, // w is width
        d, // d is direction of travel (1 == horizontal?, 2 == down/right?)
        c=0; // c is loop count

        // make all the lines the same length
        var E=D.SelectMany(l=>l.PadRight(w)).ToList(); // say no to horizontal bounds checking

        // consume +s
        for(z=E.Count;z-->1;)
            if(E[z-1]==43) // right-most lower-most +
                for(d=1,c++; // go left, increment counter
                    E[z+=d%2<1?w*d-w:d-2]>32 // move z, then check we havn't hit a space (when we do, z is basiclly z - 1)
                    ;)
                    if(E[z]<44) // +
                    {
                        E[z]=' '; // toodles

                        d=
                            d%2>0? // currently horizontal, must go vertical
                                z<w||E[z-w]<99?2 // can't go up, must go down
                                :0 // can go up, go up
                            : // currently vertical, must go horizontal
                                E[z+1]!=45?1 // can't go right, must go left
                                :3 // can go right, go right
                            ;
                    }

        // output result
        C.WriteLine(c);
    }
}

ว้าว. ประทับใจมาก: o
Metoniem

6

สลิป , 51 41 + 2 = 43 ไบต์

$a(`+`-[^ +]*`+(<|>)`|[^ +]*`+#(<|>))+?$A

(อัปเดตตอนนี้ให้ทำงานกับกรณีทดสอบของ @ blutorange ในราคาที่สำคัญ)

เนื่องจาก @BMac ใช้ SnakeEx สำหรับความท้าทายนี้ฉันคิดว่าฉันลองและใช้Slip ภาษาที่ตรงกับรูปแบบ 2Dของฉันนั่นคือ Slip แต่เนื่องจาก Slip ไม่ได้มีคุณสมบัติที่จำเป็นในการแก้ปัญหานี้ฉันจึงได้เพิ่มคุณสมบัติเหล่านี้ในช่วงไม่กี่วันที่ผ่านมา ในคำอื่น ๆ ส่งนี้คือไม่ได้รับสิทธิ์ที่จะชนะ

วิ่งด้วยnธงสำหรับจำนวนการแข่งขันเช่น

py -3 slip.py regex.txt input.txt n

ลองมันออนไลน์


คำอธิบาย

เนื่องจากมีฟีเจอร์ใหม่มากมายในการส่งนี้จึงเป็นโอกาสที่ดีในการแสดง

$a                Set custom anchor at current position
(
  `+`-            Match '+-'
  [^ +]*          Match any number of '|' or '-'
  `+              Match a '+'
  (<|>)           Either turn left or turn right
  `|              Match a '|'
  [^ +]*          Match any number of '|' or '-'
  `+              Match a '+'
  #               Prevent next match from moving the match pointer (doubling up on '+')
  (<|>)           Either turn left or turn right
)
+?                Do the above at least once, matching lazily
$A                Make sure we're back where we started

สลิปพยายามจับคู่เริ่มต้นจากทุกตำแหน่งและส่งคืนการจับคู่ที่ไม่ซ้ำกันเท่านั้น โปรดทราบว่าเราใช้[^ +]- ในขณะที่ใช้[-|]จะช่วยประหยัดสองไบต์ตามหลักวิชาโดยไม่ใช้ค่า Escape -ที่จุดเริ่มต้น / จุดสิ้นสุดของคลาสอักขระในสลิป


1
@blutorange threeยังมี+s ที่ไม่ใช่หนึ่ง-, หนึ่ง|และ 2 ช่องว่างดังนั้นฉันคิดว่ามันไม่ใช่ความผิด
Sp3000

5

ทับทิม 295

F=->i{l=i.lines
g={}
l.size.times{|y|i.size.times{|x|l[y][x]==?+&&g[[y,x]]=[[y,x]]}}
c=->a,b{w=g[b]+g[a];w.map{|x|g[x]=w}}
k=g.keys
k.product(k).map{|n,o|
r,p=n
s,q=o
((r==s&&p<q&&l[r][p...q]=~/^\+-[|-]*$/)||(p==q&&r<s&&l[r...s].map{|l|l[p]||c}.join=~/^\+\|[|-]*$/))&&c[n,o]}
g.values.uniq.size}

ลองมันออนไลน์: http://ideone.com/kIKELi ( I เพิ่ม#to_aโทรในบรรทัดแรกเพราะ ideone.com ใช้ทับทิม 1.9.3 ซึ่งไม่สนับสนุน#sizeสำหรับEnumerableในทับทิม 2.1.5+ รหัสวิ่งตกลง. . )

วิธีการดังต่อไปนี้:

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

นี่คือรุ่นที่อ่านได้มากขึ้น:

def ascii_topology_count(input)
  lines = input.lines
  max_length = lines.map(&:size).max

  # hash in which the keys are corners ("+"s), represented by their [y, x] coords
  # and the values are arrays of corners, representing all corners in that group
  corner_groups = {}

  lines.size.times { |y|
    max_length.times { |x|
      if lines[y][x] == ?+
        corner_groups[[y, x]] = [[y, x]]
      end
    }
  }

  # function that combines the groups of two different corners
  # into only one group
  combine_groups =-> c1, c2 {
    g1 = corner_groups[c1]
    g2 = corner_groups[c2]

    g2 += g1
    corner_groups[c1] = g2
    g2.map{|x| corner_groups[x] = g2}
  }

  corner_groups.keys.product(corner_groups.keys).map{|c1, c2|
    y1,x1=c1
    y2,x2=c2
    if y1 == y2 && x1 < x2
      # test horizontal edge
      t = lines[y1][x1...x2]
      if t =~ /^\+-[|-]*$/
        # p "#{c1}, #{c2}, [H] #{t}"
        combine_groups[c1, c2]

      end
    end

    if x1 == x2 && y1 < y2
      # test vertical edge
      t=lines[y1...y2].map{|l|l[x1]||' '}.join

      if t =~ /^\+\|[|-]*$/
        # p "#{c1}, #{c2}, [V] #{t}"
        combine_groups[c1, c2]
      end
    end
  }

  corner_groups.values.uniq.count
end

5

JavaScript (ES6) 190 197 202 215 235 289 570

แก้ไขอาร์เรย์มิติเดียวแทน 2 มิติขนาดแถวสูงสุด 999 ตัวอักษร (แต่สามารถเพิ่มได้โดยไม่มีค่าใช้จ่ายเช่น 1e5 แทน 999)

แก้ไขข้อมูลโค้ดเคลื่อนไหวที่เพิ่มเข้ามาดูด้านล่าง

F=s=>[...s.replace(/.+/g,r=>r+Array(e-r.length),e=999)]
  .map((c,x,z,d=1,f='-',g='|')=>{
    if(c=='+')
      for(++n;z[x+=d]!='+'||([f,g,e,d]=[g,f,d,z[x-e]==g?-e:z[x+e]==g&&e],d);)
        z[x]=z[x]==g&&g
  },n=0)|n

พยายามครั้งแรกที่Ungolfed

f=s=>
{
  cnt=0
  s = (1+s+1).split(/[1\n]/)

  for(;x=-1, y=s.findIndex(r=>~(x=r.indexOf('+-'))), x>=0;++cnt)
  {
    //console.log(y+' '+x+' '+s.join('\n'))
    dx = 1
    for(;dx;)
    {
      a=s[y-1],b=s[y+1],
      r=[...s[y]]
      for(r[x]=' ';(c=r[x+=dx])!='+';)
      {
        if (c=='-')
          if((a[x]||b[x])=='|')r[x]='|';
          else r[x]=' ';
      }  

      if(a[x]=='|')dy=-1;
      else if(b[x]=='|')dy=1;
      else dy=0
      r[x]=' '
      s[y]=r.join('')
      if (dy) {
        for(;y+=dy,r=[...s[y]],(c=r[x])!='+'&c!=' ';)
        {
          if (c=='|') 
            if((r[x-1]||r[x+1])=='-')r[x]='-';
            else r[x]=' ';
          s[y]=r.join('')
        }  
        if(r[x-1]=='-')dx=-1;
        else if(r[x+1]=='-')dx=1;
        else dx=0;
      }
    }  
  }
  return cnt
}

ตัวอย่างภาพเคลื่อนไหว

ทดสอบในคอนโซล Firefox / FireBug

F('\
  +--------------+\n\
  |  +--+  +--+  |\n\
  |  |  |  |  |  |\n\
+-|-----|-----|----+\n\
| |  |  |  |  |  | |\n\
| +--+  +--+  +--+ |\n\
+------------------+\n\
\n\
              +------------+\n\
              |            |\n\
        +-----+  +-----+   |\n\
        |        |     |   |\n\
  +-----|-----------+  |   |\n\
  |     |  +--+  |  |  |   |\n\
  +-+   +--|--|--+  +---------+\n\
    |      |  +-+      |   |  |\n\
    +------+    |      |   |  |\n\
                +-------+  |  |\n\
                       ||  |  |\n\
                       |+-----+\n\
                       |   |\n\
                       +---+')

4

F('\
+--------+  +--------+  +--------+\n\
|        |  |        |  |        |\n\
|     +--|-----+  +--|-----+     |\n\
|     |  |  |  |  |  |  |  |     |\n\
+-----|--+  +-----|--+  +--------+\n\
      |        |  |        |\n\
      +--------+  +--------+')

5


แน่นอนคุณต้องการบันทึกไบต์โดยซับในรุ่น golfed เดียวหรือไม่ คุณสามารถสร้างฟังก์ชั่นนิรนามได้ (ฉันคิดว่ามันอยู่ในกฎของ codegolf)
theonlygusti

@ theonlygusti รุ่น golfed ถูกนับเป็นบรรทัดเดียว (ไม่มีการขึ้นบรรทัดใหม่และเว้นวรรคการเยื้อง) ด้วยฟังก์ชั่นที่ไม่ระบุชื่อฉันบันทึก 2 ไบต์ประหยัดเล็กน้อย ...
edc65

4

ทับทิม, 178 187 199 212

ทับทิมรุ่นที่ดีกว่าสร้างฟังก์ชั่น F ตอนนี้พร้อมคำเตือนล่ามแสนอร่อยอย่างต่อเนื่อง

b=->n{Q[I]=?~
d=Q[I+n]==(n>1??|:?-)?1:-1
loop{I+=d*n
b[n>1?1:N]if Q[I]==?+
Q[I]<?~?4:break}}
F=->s{N=s.size;Q=s+?\n
Q.gsub!(/^.*$/){$&.ljust N-1}
(0..N).find{!(I=Q=~/\+/)||b[1]}}

ทดสอบออนไลน์: ideone

โดยทั่วไปฟังก์ชั่นbเริ่มต้นที่ใด+, ซ้ำไปผ่านห่วง, การตั้งค่าทั้งหมดไป+ uดังนั้นหนึ่งวงจะถูกลบออกในแต่ละครั้งbเรียกว่า ฟังก์ชั่นFเพียงแค่พยายามความถี่ที่เราต้องโทรbจนกว่าจะไม่มีลูปเหลืออยู่


2

Python 2 - 390

รับสตริงที่มีการขึ้นบรรทัดใหม่จาก stdin มันเป็นวิธีการที่เรียบง่ายค่อนข้างเล่นกอล์ฟได้ดี แต่ฉันแน่ใจว่าไม่มากเท่าที่ควรพิจารณานานเท่าไหร่

s=raw_input().split('\n');L=len
def R(x,y):
 b=p,q=x,y;u=v=f=0
 while b!=(p,q)or not f:
    p+=u;q+=v;f=u+v;c=s[q][p]
    if'+'==c:u,v=[(i,j)for i,j in{(-1,0),(1,0),(0,-1),(0,1)}-{(-u,-v)}if 0<=q+j<L(s)and 0<=p+i<L(s[q+j])and s[q+j][p+i]in['-+','|+'][j]][0];s[q]=s[q][:p]+' '+s[q][p+1:]
    if c+s[q+v][p+u]in'-|-':p+=u;q+=v
print L([R(x,y)for y in range(L(s))for x in range(L(s[y]))if'+'==s[y][x]])

1

Python 2 - 346 ไบต์

ใช้งานเป็นฟังก์ชั่นcที่รับข้อมูลไฟล์เป็นอินพุตและส่งคืนจำนวนลูป

ก่อนอื่นฟังก์ชันจะแยกข้อมูลออกเป็นการแมปของตำแหน่งองค์ประกอบลูปกับประเภทองค์ประกอบที่ตำแหน่งนั้น (เช่น{(0,0): '+'}) จากนั้นจะใช้สองฟังก์ชั่นภายในซ้ำกันซ้ำ วิธีแรกจะลบเซกเมนต์ลูปออกจากการแมปและตัดสินใจว่าจะเลือกที่ตั้งใดเพื่อตรวจสอบเซกเมนต์ถัดไป ที่สองตรวจสอบชนิดขององค์ประกอบวงอยู่ในสถานที่ที่เลือกและถ้าเข้ากันได้กับสิ่งที่คาดว่าจะเรียกสายแรกเพื่อลบส่วนที่เพิ่งพบ

e=enumerate
def c(d):
 D={(i,j):k for i,l in e(d.split('\n'))for j,k in e(l)if k in'+-|'}
 def f(r,c,R,C,t):
  if D.get((r,c),t)!=t:g(r,c)
  elif D.get((R,C),t)!=t:g(R,C)
 def g(r,c):
  t=D.pop((r,c))
  if t!='|':f(r,c-1,r,c-2,'|');f(r,c+1,r,c+2,'|')
  if t!='-':f(r-1,c,r-2,c,'-');f(r+1,c,r+2,c,'-')
 n=0
 while D:g(*D.keys()[0]);n+=1
 return n
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.