ASCII拓扑pt 1:我可以指望您吗?


28

我有一个严重的问题。我有一些文本文件,其中保存着我非常重要的数字-所有重要的数字!还有二三。

这些数字是如此重要,以至于我无法将它们委托给那些新奇的十进制或二进制数字系统。我将每个数字保持一元编码,如下所示:

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

简单可靠:数字2的两个ASCII循环。不幸的是,随着时间的流逝,这些事情会变得一团糟,现在我很难确定每个文件中有多少个循环。以下是我手工制作的一些示例:

一:

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

三:

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

四:

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

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

五:

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

你能帮我数一下我的循环吗?

规则如下:

  • 由于我将所有内容都存储为ASCII编码的一进制,因此空间效率对我来说非常重要。因此,这就是代码高尔夫。以字节为单位的最小程序获胜。
  • 用字符+,-,|绘制循环。循环中的每个角都是清楚地绘制的:+上方和下方的字符之一将是|,而右侧或左侧的字符将是-。两个+标记永不相邻。
  • 股线可能会相互上下穿过。股线交叉时,您将能够在“上方”股线的两侧立即看到“下方”股线。
  • 您的程序应采用循环的字符串表示形式(从stdin或作为函数参数)并产生一个数字(以stdout或作为返回值)。
  • 回路图中的线长可能不一致,并且每条线上可能会有尾随空格。
  • 您可以假设输入中至少有一个循环。

我指望你!


“下线”的一侧可以是+吗?
feersum

@feersum:不,附加到+的两个边缘将始终可见。
马特·努南

1
@马丁:恐怕不是。我的存储空间确实非常宝贵,所以我无法保留所有这些多余的空间。
马特·诺南

我认为您应该将此(pastebin)添加为测试用例,除非我遗漏了某些东西并且它不是有效的输入。有6个循环;我仅使用SnakeEx解决方案在线对其进行了测试,并且其输出为
12。– blutorange

1
也许您应该明确禁止或允许自身交叉的循环(例如pastebin.com/5RLZuULG)当前,它们被红宝石溶液检测到,但未被SnakeEx解决方案检测到。
blutorange

Answers:


19

SnakeEx-使用Javascript读取98个字节,不使用Java读取44个字节

尝试在“ 双周挑战赛”上尝试我的语言时,这似乎是一个好问题:

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我真的很喜欢,也许是因为我可以在线尝试并突出显示循环。但你可能要检查这两个测试用例:12
blutorange

@blutorange好收获。我为自交叉循环添加了一些小技巧。不过,我将不得不再考虑一下测试用例1。
BMac 2015年

那是容易解决的问题,只需替换[^ ][|\-];)
blutorange

嗯,我花了很长时间才弄清楚为什么会这样。好决定。
BMac

这太棒了!
IngoBürk'15

10

C# - 338个388 433字节

通过更改为一维数组,节省了一堆字节。

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 '17

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

滑动尝试从每个位置开始进行匹配,并且仅返回唯一的匹配项。请注意,我们使用了[^ +]-尽管使用[-|]会理论上节省两个字节,-但在Slip中尚未实现在字符类的开头/结尾未转义。


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我加了#to_a第一线的呼叫,因为ideone.com使用了Ruby 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

编辑一维数组而不是二维数组,最大行大小为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

不打高尔夫球的第一次尝试

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的规则之内)
theonlygusti 2015年

@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从任何地方开始+,递归地遍历循环,将全部设置+u。因此,每次b调用都会删除一个循环。函数F只是尝试我们需要调用的频率,b直到没有剩余的循环为止。


2

Python 2-390

从标准输入取一个带有换行符的字符串。这是一个相当简单的方法,但我敢肯定它考虑的时间不会那么长。

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.