每日随机ASCII艺术#5:钻石拼贴


21

混搭时间!

这是我的每日随机高尔夫和Optimizer的ASCII每日艺术系列的第5期。您在此挑战中提交的作品将计入两个排行榜(您可以在其中找到链接的帖子)。当然,您可以像对待其他任何代码高尔夫挑战赛一样对待它,并回答它而不必担心任何一个系列。

第5洞:钻石拼贴

正六边形始终可以用钻石平铺,如下所示:

我们将使用这些拼贴的ASCII艺术表示形式。对于边长为2的六边形,有20个此类平铺:

   ____     ____     ____     ____     ____     ____     ____     ____     ____     ____  
  /\_\_\   /\_\_\   /\_\_\   /\_\_\   /_/\_\   /_/\_\   /\_\_\   /_/\_\   /_/\_\   /_/\_\ 
 /\/\_\_\ /\/_/\_\ /\/_/_/\ /\/_/\_\ /\_\/\_\ /\_\/_/\ /\/_/_/\ /\_\/\_\ /\_\/_/\ /_/\/\_\
 \/\/_/_/ \/\_\/_/ \/\_\_\/ \/_/\/_/ \/\_\/_/ \/\_\_\/ \/_/\_\/ \/_/\/_/ \/_/\_\/ \_\/\/_/
  \/_/_/   \/_/_/   \/_/_/   \_\/_/   \/_/_/   \/_/_/   \_\/_/   \_\/_/   \_\/_/   \_\/_/ 
   ____     ____     ____     ____     ____     ____     ____     ____     ____     ____  
  /_/_/\   /\_\_\   /_/\_\   /_/_/\   /_/\_\   /_/\_\   /_/_/\   /_/_/\   /_/_/\   /_/_/\ 
 /\_\_\/\ /\/_/_/\ /_/\/_/\ /\_\_\/\ /\_\/_/\ /_/\/_/\ /_/\_\/\ /\_\_\/\ /_/\_\/\ /_/_/\/\
 \/\_\_\/ \/_/_/\/ \_\/\_\/ \/_/\_\/ \/_/_/\/ \_\/_/\/ \_\/\_\/ \/_/_/\/ \_\/_/\/ \_\_\/\/
  \/_/_/   \_\_\/   \_\/_/   \_\/_/   \_\_\/   \_\_\/   \_\/_/   \_\_\/   \_\_\/   \_\_\/ 

给定边长N,您应该为边长的六边形N随机生成这样的切片。确切的分布无关紧要,但是每个拼贴必须以非零概率返回。

对于N ≤ 4,您的提交必须至少在80%的时间内在1分钟内生成平铺,并且至少有80%的平铺必须在1分钟内生成。大多数方法都不必担心该规则(这很宽容)-只是为了排除非常幼稚的基于拒绝的算法,该算法会生成任意字符串,直到碰巧是一个平铺。

您可能想知道,可以在OEIS A008793中找到给定N的可能拼接的总数

您可以编写完整的程序或函数,并通过STDIN(或最接近的替代方案),命令行自变量或函数自变量接受输入,并通过STDOUT(或最接近的替代方案),函数返回值或函数(out)参数产生输出。

您输出的前导空格不得超过对齐六边形所需的多余空格(也就是说,六边形的左上角不应在其前面有空格)。每行最多可以包含N尾随空格(不一定一致),因此,例如,您可以使用矩形输出,打印六边形的边界框。

这是代码高尔夫球,因此最短的提交(以字节为单位)获胜。当然,每位用户最短的提交时间也将进入该系列的整体排行榜。

排行榜

每个系列的第一篇文章都会生成一个排行榜。

为确保您的答案显示出来,请使用以下Markdown模板以标题开头每个答案:

# Language Name, N bytes

N您提交的文件大小在哪里。如果您提高了分数,则可以将旧分数保留在标题中,方法是将它们打掉。例如:

# Ruby, <s>104</s> <s>101</s> 96 bytes

(目前未显示该语言,但是该代码段确实需要并对其进行解析,并且将来我可能会添加一个语言排行榜。)


3
只是我一直在看3D示例图像吗?
LegionMammal978

3
@ LegionMammal978不,那是完全正常的。;)(而且可能也是应对挑战的好方法。)
Martin Ender 2015年

For N ≤ 4, your submission must produce a tiling within 1 minute at least 80% of the time.太容易了:80%的时间是相同的,基本的平铺,否则我会在想要的任何时间找到另一个平铺
edc65

@ edc65好点,让我改一下。
Martin Ender 2015年

Answers:


10

CJam,105个字节

ri:A" __"e*A,2f*:B,[W1]{J+B:):B,{N1$S*"\/"J%A2*4$-:D*
0{;B{_1&!2mr+J*m1e>D(2*e<}%__:)&}g:B{'_t}/+@J+}*}fJ;

添加了换行符以避免滚动。在线尝试

说明:

此解决方案以锯齿形开始每行,然后根据它们在前一行的位置和一些规则在其上放置N个下划线。我从一系列观察中得到了这一点,同时将输出视为字符的普通2D矩阵:

  • 每行正好有N个下划线
  • 下划线可以用/或\代替,以形成完美重复的锯齿形图案(/\上半部分,\/下半部分)
  • 下划线不能碰到侧面,也不能与另一个下划线相邻
  • 转到下一行时,每个下划线的位置都会改变-1、0或1
  • 不仅如此,/_/只能更改-1或0,并且\_\只能更改0或1
  • 用于初始下划线位置我们可以使用一个"_ "图案或" _"图案,二者都是优良
  • 以上规则足以获取所有切片

因此,我决定通过保留以前的下划线位置,使用随机因子修改它们(每个下划线有2个选择)并重复执行直到满足规则来实现它。在优化过程中,我切换到相对于六边形左侧(不包括空格)的下划线位置。

ri:A" __"e*       read the input (A) and generate the top line
A,2f*:B           make an array [0 2 4 ... 2A-2] and store in B
                  these are the initial positions for the underscores
,                 B's length = A, used as the initial number of leading spaces
                  let's call it C
[W1]{…}fJ         for J in [-1 1] (top half, bottom half)
  J+              add J to C
  B:):B           increment the underscore positions (adjustment before each half)
  ,{…}*           repeat A times
    N1$S*         add a newline and C spaces
    "\/"J%        take "\/" and reverse it if J=-1 (zigzag pattern)
    A2*4$-:D*     calculate D=A*2-C and repeat the pattern
    0             dummy value (for the next loop)
    {…}g          do-while
      ;B          pop last value and push B
      {…}%        apply block to each item (say x)
        _1&!      duplicate x and calculate !(x&1) (for /_/ vs \_\)
        2mr+      randomly add 0 or 1
        J*m       multiply by J and subtract from x
        1e>       limit the minimum value to 1
        D(2*e<    and the maximum value to 2*(D-1)
      __:)&       check if the modified array has any adjacent values
    :B            store the new positions in B
    {'_t}/        place underscores over the zigzag pattern
    +@J+          bring C to the top and add J to it
;                 pop C

旧的“ 3D”版本,189个字节:

ri:A" __"e*aA4*S*aA2**+[0-2XXW1]:C;"/\_\\\/_/":D;A3m*{{C2/.f*:.+~
A(2*+:V;A+:U;2{UI+1$1$=4{_V+D4/I=@=t}/t}fI}:F~}/[0Y1WWW]:C;
"/_/\\\_\/":D;AaA*:B;A{A[_{_BI=e<)mr}fI]:B;{BQ={[PQR]F}fR}fQ}fPN*

在线尝试


+1代表出色的工作,还因为多投一票即可使您获得10k代表,但主要是为出色的工作。(哦,嘿,看看。恭喜10k :))
Alex A.

对模式进行了很好的分析!我将用它来回答。
anatolyg 2015年

6

Python 2中,337个 335 324 318 311 300 296字节

from random import*
n=input()
R=range(n*2)
b=[]
l=[]
for i in R:o=abs(i-n)-(i<n);b+=[o];l+=[list(' '*o+'\//\\'[i<n::2]*(n*2-o))]
for i in R[:n]:
 o=1;p=n+i*2
 for j in R:r=randint(0,p<n*3+i*2-j);p+=(r or-1)*(o==r);q=p<=b[j];o=r|q;p+=q;l[j][p]='_';b[j]=p+1
for s in[' '*n+'__'*n]+l:print''.join(s)

这个想法是首先创建一个六边形的钻石,如下所示:

  ____
 /\/\/\
/\/\/\/\
\/\/\/\/
 \/\/\/

然后用下划线的向下路径填充它,如下所示:

  ____                          ____
 /_/\/\                        /\_\/\
/_/\/\/\    or maybe this:    /\/_/\/\
\_\/\/\/                      \/_/\/\/
 \_\/\/                        \_\/\/

添加了所有路径的最终结果将如下所示:

  ____                          ____  
 /_/\_\                        /\_\_\ 
/_/\/_/\    or maybe this:    /\/_/\_\
\_\/_/\/                      \/_/\/_/
 \_\_\/                        \_\/_/ 

要确保这些路径不会越界或彼此交叉,需要花费大量代码。

取消编码:

# Initialize l with all diamonds
blocked = []
l = [[] for _ in range(n*2)]
for i in range(n*2):
    offset = n-i-1 if i<n else i-n
    blocked.append(offset)
    l[i] += ' '*offset + ('/\\' if i<n else '\/')*(2*n - offset)

# Generate the random _'s
for i in range(n):
    oldright = True
    pos = n + i*2
    for j in range(n*2):
        # Go randomly right (true) or left (false), except when you out of bounds on the right side
        right = randint(0, 1) and pos < n*3 + i*2 - j
        if right == oldright:
            pos += 1 if right else -1
        if pos <= blocked[j]:
            right = True
            pos += 1
        l[j][pos] = '_'
        blocked[j] = pos + 1
        oldright = right

# Print the result
print ' '*n + '__'*n
for s in l:
    print ''.join(s)

1
我只是注意到您的输出似乎有问题。您的两个示例结果(右上和右下)中都有三角形。
Martin Ender

1
@MartinEnder示例仅显示一个“下划线”,以说明算法的思想。最终输出具有所有路径(在本例中为2),这消除了三角形。我还添加了最终输出的示例。
马蒂

哦,我明白了,这很有意义。感谢您的澄清。
Martin Ender

2
我认为您可以缩短randint(0,1)*(p<n*3+i*2-j)randint(0,p<n*3+i*2-j)
18Me21年

哦,是的,谢谢!
马蒂

4

Perl中,174 168 166 161

#!perl -n
for$l(-$_..$_){$t=/_/?join'',map'/_'x($%=rand
1+(@z=/__?/g)).'/\\'.'_\\'x(@z-$%),split/\/\\/:__
x$_;$l>0&&$t!~s!^.(\\.*/).$!$1!?redo:print$"x abs$l-.5,$_=$t.$/}

试试


它似乎总是产生相同的平铺(至少在ideone上)
aditsu

@aditsu,如果您仅单击链接,则Ideone将显示缓存的结果。您需要分叉才能再次实际运行它。
nutki 2015年

2

JavaScript(ES6),376416494

只是在那里...

这将构建所有拼贴,然后选择一个随机拼贴。在我的笔记本电脑上,N = 4的232848拼接时间为〜45秒。我没有尝试N = 5。

作为EcmaScript 6,它只能在Firefox上运行。

F=n=>{
  for(i=s=r=b='';i<n;i++)
    s='\n'+b+'/\\'[R='repeat'](n-i)+'_\\'[R](n)+s,
    r+='\n'+b+'\\/'[R](n-i)+'_/'[R](n),
    b+=' ';
  for(h=[t=0],x=[s+r];s=x[t];t++)
    for(d='';!d[n*3];d+='.')
      if(l=s.match(r=RegExp("(\n"+d+"/)\\\\_(.*\n"+d+"\\\\)/_","g")))
        for(j=2<<l.length;j-=2;h[z]||(h[z]=x.push(z)))
          z=s.replace(r,(r,g,h)=>(k+=k)&j?g+'_/'+h+'_\\':r,k=1);
  return b+'__'[R](n)+x[Math.random()*t|0]
}


function go()
{
  var n = N.value | 0,
  t0 = performance.now(),
  r = F(n),
  t1 = performance.now();
  
  O.innerHTML = r+'\n\nTime (msec): '+(t1-t0)
}
N: <input id=N value=3><button onclick="go()">GO</button>
<pre id=O></pre>


在Chromium 42中,我得到“未捕获的SyntaxError:意外令牌=>”和“未捕获的ReferenceError:未定义”
aditsu

1
@aditsu是ES6,Chrome:否Firefox:是。这不是众所周知的事实吗?
edc65 2015年

我不知道,我希望Chromium使用最新和最好的工具-所谓的-显然不是JavaScript。感谢您的解释。
aditsu

我现在在firefox(31.5.3)中运行它,它适用于N = 1、2或3,但是对于N = 4,它可以运行约10秒,完成并且不显示任何内容(并且控制台中没有错误) )
aditsu 2015年

@aditsu不确定... 超过时间限制时,沙盒中的javascript可能会被悄悄杀死dom.max_script_run_time。它是在对全球的偏好:配置,矿山设置为30
edc65

1

SmileBASIC,241个字节

INPUT N
T=N*2CLS?" "*N;"__"*N
DIM B[T]FOR I=-1TO N-1O=1P=N+I*2FOR J=0TO T-1IF I<0THEN O=ABS(J0N+.5)<<0B[J]=O?" "*O;MID$("\/\",J<N,2)*(T-O)ELSE R=P<N*3+I*2-J&&RND(2)P=P+(R*2-1)*(O==R)A=P<=B[J]R=R||A:P=P+A:LOCATE P,J+1?"_"B[J]=P+1O=R
NEXT
NEXT

很大程度上基于Matty的答案

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.