ASCII 토폴로지 pt 1 : 믿을 수 있습니까?


28

심각한 문제가 있습니다. 매우 중요한 숫자를 유지하는 텍스트 파일이 있습니다. 모든 중요한 숫자가 있습니다! 그리고 둘, 셋 ..

이 숫자는 너무 중요해서 새로운 십진수 또는 이진수 시스템에 맡길 수 없었습니다. 각 숫자를 단항으로 인코딩하여 유지했습니다.

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

간단하고 신뢰할 수 있음 : 숫자 2에 대한 두 개의 ASCII 루프 다음은 손으로 직접 만든 예제입니다.

하나:

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

세:

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

네 :

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

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

다섯:

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

루프 계산에 도움을 줄 수 있습니까?

규칙은 다음과 같습니다.

  • ASCII로 인코딩 된 단항으로 모든 것을 저장하기 때문에 공간 효율성이 매우 중요합니다. 따라서 이것은 코드 골프입니다. 바이트 단위의 가장 작은 프로그램이 이깁니다.
  • 루프는 +,-, | 문자로 그려집니다. 루프의 모든 모서리는 명확하게 그려집니다. + 위와 아래의 문자 중 정확히 하나가 |가되고 오른쪽 또는 왼쪽이 정확히 하나가-가됩니다. 두 개의 + 마크는 절대 인접하지 않습니다.
  • 가닥이 서로 위아래로 지나갈 수 있습니다. 스트랜드가 교차하면 "오버"스트랜드의 양쪽에서 "언더"스트랜드를 즉시 볼 수 있습니다.
  • 프로그램은 루프의 문자열 표현 (stdin 또는 함수 매개 변수)을 가져 와서 숫자 (stdout 또는 리턴 값)를 생성해야합니다.
  • 루프 드로잉에서 선 길이가 균일하지 않을 수 있으며 각 선에 후행 공백이있을 수 있습니다.
  • 입력에 하나 이상의 루프가 있다고 가정 할 수 있습니다.

나는 너를 믿는다!


'언더 스트랜드'의 측면 중 하나가 +?
feersum

@feersum : 아니요, +에 연결된 두 개의 모서리가 항상 보입니다.
Matt Noonan

1
@ 마틴 : 나는 두렵지 않다. 내 스토리지 공간은 정말 프리미엄이므로 추가 공간을 모두 확보 할 수는 없습니다.
매트 누난

뭔가 빠졌거나 입력이 유효하지 않은 경우이 테스트를 pastebin으로 추가해야한다고 생각합니다 . 6 개의 루프가 있습니다. SnakeEx 솔루션으로 온라인에서만 테스트했으며 12를 출력했습니다.
blutorange

1
아마도 스스로 교차하는 루프 (예 : pastebin.com/5RLZuULG )를 명시 적으로 금지하거나 허용해야합니다. 현재 SnakeEx 솔루션이 아니라 루비 솔루션에 의해 감지됩니다.
blutorange

답변:


19

SnakeEx-Javascript가있는 98 바이트,없는 44 바이트

Fortnightly Challenge 에서 내 언어를 시험해 보는 것이 좋은 문제인 것 같습니다.

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

이것을 시도하기 가장 좋은 곳은 온라인 통역사 입니다.

SnakeEx는 텍스트 일치 정규 표현식을 따라 이동하는 "뱀"을 사용하여 텍스트의 패턴을 일치시킵니다. 코드는 다음을 제외하고는 정규식과 비슷합니다.

  • <T>명령. 그것은 뱀을 현재 방향에서 왼쪽과 오른쪽으로 분기하는 방향 명령입니다.
  • {e<>PE}서브 루틴 호출과 같습니다. 정의 e가 앞으로 이동 하는 뱀 ( <>)과 매개 변수 P(피기 백-산란 뱀이 새로운 뱀을 따릅니다)와 E(독점-이미 일치하는 항목과 일치하지 않는 ) 뱀을 생성합니다 . 이 독점적 인 검사는 뱀이 무한 반복되는 것을 막는 유일한 것입니다.
  • `끝에 있는 접두사 는 다음과 일치하는 항목이 이미 일치 된 경우에만 일치해야한다는 것을 나타내며,이를 통해 루프를 강제로 닫을 수 있습니다.

SnakeEx는 정규 표현식과 비슷하고 기술적으로 원하는 결과를 출력하지 않기 때문에 인터프리터를 호출하는 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);}}

먼저 입력에서 읽은 다음 ""테두리를 사용하여 멋지고 직사각형으로 만듭니다. 따라서 가로에 대한 경계 검사를 수행 할 필요가 없습니다. . 그런 다음 사각형을 다시 보면서 항상 오른쪽 아래 모서리에 닿습니다. 이 중 하나에 도달하면 +를 따라 가고 (공백으로) 지워집니다. 공간을 만날 때 따라가는 것을 멈 춥니 다. 주어진 다섯 가지 예에서 테스트되었습니다.

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를 사용했기 때문에 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

슬립은 모든 위치에서 시작하여 일치를 시도하고 고유 한 일치 만 반환합니다. 우리가 사용하는 [^ +]— 문자 클래스의 시작 / 끝에서 [-|]이스케이프되지 않은 이론적으로 2 바이트를 절약 -하는 것은 Slip에서 아직 구현되지 않았습니다.


1
@blutorange three또한이 +일하지의 -하나 |는 실수가 아니라 내가 있으리라 믿고있어, 그래서 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를 ( 내가 추가 한 #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

자바 스크립트 (ES6) 190 197 202 215 235 289 570

2 차원 대신 단일 차원 배열을 편집 합니다. 최대 행 크기는 999 자입니다 (하지만 999 대신 1e5).

추가 된 애니메이션 코드 스 니펫 편집 , 아래 참조

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


확실히 당신은 골프 버전을 한 줄로 줄임으로써 바이트를 절약 할 수 있습니까? 익명 함수를 만들 수도 있습니다 (codegolf의 규칙에 있다고 생각합니다)
onlygusti

@theonlygusti 골프 버전은 한 줄로 계산됩니다 (개행 및 들여 쓰기 공간은 계산되지 않습니다). 익명 함수를 사용하면 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는 any +에서 시작 하고 루프를 반복적으로 통과하여 모두 +로 설정합니다 u. 따라서 b호출 될 때마다 하나의 루프가 제거됩니다 . 함수 는 루프가 남아 있지 않을 때까지 F얼마나 자주 호출해야 하는지를 시도합니다 b.


2

파이썬 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

파이썬 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.