画一个随机的六字形


23

在此处输入图片说明

上面的图像称为六字形。六字形是我在DiffEq课堂上涂鸦时制作的一些很酷的图案。制作方法如下:

  1. 考虑以下点集,它们的形状像规则六边形。内部的六边形将包含最终的字形,而外部的6个点将形成星形,这是我们开始绘制线条的地方。

在此处输入图片说明

  1. 从外部的六个点中,随机选择一对。为了提高效率,两个选定的点之间应该至少有一个其他点(否则,它将对最终图形没有影响)。然后,从两个点中的每个点向另一个方向投射射线。该光线前几行遮挡了。

在此处输入图片说明

  1. 重复此过程,直到形成所有9个边缘,如以下几幅图像所示。

在此处输入图片说明

  1. 这是光线被遮挡的示例。射线段的末端仍然可见,但是中间部分被我们绘制的前两个段所遮挡。

在此处输入图片说明

  1. 这两条光线也被“阻挡”,但这不会造成任何可见的差异,因为它们被同一条其他线阻挡了。

在此处输入图片说明

  1. 快进直到画完所有9条线。如果您想对这些跳过的步骤进行更详细的说明,我可以进行阐述。

在此处输入图片说明

  1. 最后,删除星星的点。为了使其看起来更漂亮,还将删除粗点。

在此处输入图片说明

挑战

您面临的挑战是输出随机六字形的视觉表示。这是代码高尔夫球,最少的字节获胜。

  1. 所有可能的六字形都应以一定的概率出现。通过更改绘制9条边的顺序来生成不同的六字形。

  2. 此外,程序输出的所有图像都必须是有效的六字形。某些样式(例如内部六边形的完整轮廓)可能无法显示为六字形,因此您编程时不得输出这些样式。

  3. 输出应为图形图像(打印到屏幕或文件)。

  4. 六边形必须是规则的,但可以以任何方向出现。

  5. 反射/旋转不是唯一的。(这可能使要求1易于遵循)。


8
I made up while doodling during my DiffEq class。道路上的一切伟大的发现发生...:P
Rɪᴋᴇʀ

图像的最低要求是什么?只要表示每个边缘并将其模糊地放置在正确的位置,ASCII美术应在多大程度上可识别?
John Dvorak

@JanDvorak我删除了挑战的ASCII art选项(例如在发布后2分钟之内),因为产生ASCII art和图形输出的程序不容易比较。
PhiNotPi '16

那像素艺术呢?PPM标头不太重,之后的唯一区别是使用'01'交错的空间而不是' *'
约翰·德沃夏克

@JanDvorak输出将是正确格式的图像文件,对吗?然后我看不出有什么问题。
PhiNotPi '16

Answers:


18

数学,273个 268 264 242字节

c=CirclePoints;b@_=k=1>0;Graphics[Line/@Cases[Append[Join@@({c@6,{3^.5/2,-Pi/6}~c~6}),{0,0}][[b@#=!k;#]]&/@TakeWhile[#,t=k;(r=t;t=b@#;r)&]&/@Join@@RandomSample[{#,Reverse@#}&/@Partition[Range@12,3,2,1]~Join~Array[{2#,13,2#+6}&,3]],{_,__}]]

呈现为一个标T在数学,是一个后缀置运算符。

整理其中的错误花了很长时间……直到最后,我一起砍了几件事才能使它起作用,所以这绝对不是最佳选择。我还想知道,通过外部六边形上的线更确切地实现该规范并让Mathematica的几何函数处理交点,是否可能整体上更好地实现规范。

请注意,这是一个完整的程序,如果要在单个REPL会话中多次运行代码,则必须在前缀上加上Clear[b]

这是20次运行的结果:

在此处输入图片说明

说明

该解决方案根本不利用外部星点。取而代之的是,它直接与属于字形的点和一次覆盖其中三个的线一起工作。

让我们标记要点:

在此处输入图片说明

1从一个有点怪异的角开始,但这是由于的默认行为(也有些怪异)引起的CirclePoints。从那里开始六角形最便宜。

现在,我们要通过与外星体的连接点相对应的三个点找到相关的线。六边形周围的那些当然只是3个相邻点(取模12),从奇数开始。整个中心的那些由一个偶数n13n+6

这些行的表示形式(由以下代码生成三点列表的形式):

Partition[Range@12,3,2,1]~Join~Array[{2#,13,2#+6}&,3]

Partition产生围绕六边形的线与Array通过中心的线。为了处理两个光束,我们将此功能映射到线列表上:

{#,Reverse@#}&

现在,我们将RandomSample它们随机组合以随机处理它们。Join @@展平线对列表,以便我们有一个光束列表。

短暂中断:为了跟踪哪些点已经被阻塞,我们使用了查找功能b,该功能True针对初始化为所有值b@_=k=1>0;。处理光束时,我们保留所有点,直到具有b[n] == False包括该点)的第一个点为止:

TakeWhile[#,t=k;(r=t;t=b@#;r)&]&

我觉得这是目前最容易打高尔夫球的部分。使用两个临时变量玩Mastermind似乎真的很昂贵。无论如何,这样做的结果是使我们可以绘制一条直线上的点。现在,此函数映射到这些点的每一个上:

Append[Join@@({c@6,{3^.5/2,-Pi/6}~c~6}),{0,0}][[b@#=!k;#]]&

第一部分使用两次调用的交错结果生成所有13个点的列表CirclePoints(边缘中心和六边形的拐角半径不同)。请注意,b@#=!k该工具现在将当前点的查找表的值设置为,False以便没有其他光束可以通过它。最后,该值用作坐标列表的索引,以获得正确的2D点。

Cases[...,{_,__}]

这将丢弃所有单元素列表,因为它们将呈现为单个(可见)点。最后,我们渲染结果:

Graphics[Line/@...]

b@_=1>0=b=1>0&
CalculatorFeline

@CatsAreFluffy我认为这不起作用,因为稍后我需要能够覆盖单个值。
Martin Ender

很好地使用CirclePoints。
DavidC

我感谢Youtube链接。
DanTheMan

8

鞋子(Ruby)Rev C 184字节

通过转移责任来节省12个字节,以检查是否应从主程序向绘制方法绘制特定的半行。但是,主程序仍然必须检查整个行是否被完全阻塞。

Shoes.app{t=[]
d=->p,q{t[p]&&t[q]||line(p/6*8,p%6*14,q/6*8,q%6*14)}
%w{1I IW WM M5 5' '1 =A P. R,}.shuffle.map{|i|b=i.sum/2
c=b*2-a=i.ord
t[a]&&t[c]||(d[a,b]
d[b,c]
t[a]=t[b]=t[c]=1)}}

鞋子(红宝石) 205 ...版本B 196字节

鞋子是用于构建GUI等的基于红宝石的工具。这是我第一次使用它。mothereff.in/byte-counter将我提交的内容计为196字节,但出于某种原因,Shoes将其计为202。

另外,Ruby使您可以做类似的事情,t[a=i.ord]但奇怪的是,它似乎不能与Shoes一起使用。

Shoes.app{t=[]
d=->p,q{line(p/6*8,p%6*14,q/6*8,q%6*14)}
%w{1I IW WM M5 5' '1 =A P. R,}.shuffle.map{|i|b=i.sum/2
c=b*2-a=i.ord
t[a]&&t[c]||(t[a]&&t[b]||d[a,b]
t[b]&&t[c]||d[b,c]
t[a]=t[b]=t[c]=1)}}

说明

我不考虑六边形之外的直线部分。我只绘制需要绘制的部分。重要的是线是否与相交相交(如果我们仅绘制需要绘制的部分,则意味着它们在相交处开始/结束。)

基本规则是,如果已访问线的两个端点,则该线将被阻塞并且不应绘制。由于将线分为两半,因此我们还必须检查是否已访问中点,以查看是否应绘制每一半。

我跟踪在数组中访问过哪些点t[]。最终包含下面网格上每个物理坐标的条目。没有单独的13元素逻辑数组。到最后,t[]可能包含87个元素,尽管最多只有13个元素包含有用的数据。

在内部,直线端点的坐标由单个数字z给出,其中z%6是y坐标,z / 6是x坐标。在此系统中,六角形被展平。绘制线时,x比例乘以8,y比例乘以14,这是对正确比率的非常接近的有理近似值:14/8 = 1.75 vs sqrt(3)= 1.732。

内部坐标系如下所示,并带有一些示例输出。

在此处输入图片说明

不打高尔夫球

Shoes.app{
  t=[]                                          #Empty array for status tracking
  d=->p,q{line(p/6*8,p%6*14,q/6*8,q%6*14)}      #Drawing method. Convert p and q into x,y pairs, scale and draw line.
  %w{1I IW WM M5 5' '1 =A P. R,}.shuffle.map{|i|#take an array of the coordinates of the endpoints of each line, shuffle, then for each line
    b=i.sum/2                                   #b = midpoint of line, convert ASCII sum to number (average of the two coordinates)
    a=i.ord                                     #a = first endpoint of line, convert ASCII to number (no need to write i[0].ord)
    c=b*2-a                                     #c = second endpoint of line (calculating is shorter than writing i[1].ord)
    t[a]&&t[c]||(                               #if both endpoints have already been visited, line is completely blocked, do nothing. ELSE
      t[a]&&t[b]||d[a,b]                        #if first endpoint and midpoint have not both been visited, draw first half of line
      t[b]&&t[c]||d[b,c]                        #if second endpoint and midpoint have not both been visited, draw second half of line
      t[a]=t[b]=t[c]=1                          #mark all three points of the line as visited
    )
  }
}

更多样本输出

这些是通过较旧版本的程序完成的。唯一的区别是,六边形在窗口中的位置现在略有不同。

在此处输入图片说明


mothereff.in/byte-counter counts my submission as 196 bytes, but for some reason Shoes counts it as 202.我不是100%知道这是否正确,但是我认为Shoes将您的代码计算为202字节而不是196的原因是因为换行符实际上是两个字符序列“ \ r \ n”。这使得每个换行符都会被计数两次。这是关于\ r和\ n的堆栈溢出答案。
K张

呵呵我无法忘记的名字红宝石鞋 XD
β衰变

3

Python中,604 591 574 561 538 531 536 534 528 493 483 452 431 420 419 415 388 385 384字节

我采用了Level River St的想法,即通过检查线路的两个端点是否已经被访问过来检查线路是否被阻塞。这样可以节省27个字节。欢迎打高尔夫球。

编辑:错误修复和高尔夫g(p,q)3字节。打L了一个字节。

from turtle import*
from random import*
R=range
G=goto
*L,=R(9)
shuffle(L)
a=[0]*13
ht()
T=12
c=[(j.imag,j.real)for j in(1j**(i/3)*T*.75**(i%2/2)for i in R(T))]+[(0,0)]
def g(p,q):pu();G(c[p]);a[p]*a[q]or pd();G(c[q])
for m in L:
 p=2*m;x,y,z=R(p,p+3)
 if m<6:
  if a[x]*a[z%T]<1:g(x,y);g(y,z%T);a[x]=a[y]=a[z%T]=1
 else:
  if a[p-11]*a[p-5]<1:g(p-11,T);g(p-5,T);a[p-11]=a[p-5]=a[T]=1

开球:

from turtle import*
from random import*

def draw_line(points, p_1, p_2):
    penup()
    goto(points[p_1])
    if not (a[p] and a[q]):
        pendown()
    goto(points[p_2])

def draw_glyph():
    ht()
    nine_lines = list(range(9))
    shuffle(nine_lines)
    size = 12
    center = [0,0]

    points = []
    for i in range(12):      # put in a point of a dodecagon
                             # if i is even, keep as hexagon point
                             # else, convert to hexagon midpoint
        d = 1j**(i/3) * 12   # dodecagon point
        if i%2:
            d *= .75**.5     # divide by sqrt(3/4) to get midpoint
        points += (d.imag, d.real)
    points.append(center)

    a = [0]*13
    for m in nine_lines:
        p = 2*m
        if m<6:
            x, y, z = p, p+1, p+2
            if not (a[x] and a[z%12]):
                draw_line(points, x, y)
                draw_line(points, y, z%12)
                a[x] = a[y] = a[z%12] = 1
        else:
            if not (a[p-11] and a[p-5]):
                draw_line(p-11, 12)
                draw_line(p-5, 12)
                a[p-11] = a[p-5] = a[12] = 1

六字形本身很小,因为我们使用12像素的六边形作为基础(出于打高尔夫球的原因)。以下是一些六字形示例(歉收歉意):

六字形示例 六字形示例 六字形示例 六字形示例 六字形示例 六字形示例


可以节省一些字节:R=range;G=goto
TimČas16年
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.