ランダムなヘキサグリフを描く


23

ここに画像の説明を入力してください

上記の画像はヘキサグリフと呼ばれます。ヘキサグリフは、DiffEqクラスでだらだらしている間に作成したクールなパターンです。作成方法は次のとおりです。

  1. 通常の六角形のような形をした次の一連のポイントを考えてみましょう。内側の六角形は最終的なグリフを含むものであり、外側の6つの点は星を形成し、線の描画を開始する場所です。

ここに画像の説明を入力してください

  1. 外側の6つのポイントから、ランダムにペアを選択します。効率を上げるには、選択した2つのポイントの間に少なくとも1つの他のポイントが必要です(そうでない場合、最終的な数値には影響しません)。次に、2つのポイントのそれぞれから、もう一方に向かって光線を投射します。この光線は前の行によってブロックされています。

ここに画像の説明を入力してください

  1. 次のいくつかの画像に示すように、9つのエッジがすべて形成されるまで、このプロセスを繰り返します。

ここに画像の説明を入力してください

  1. ブロックされている光線の例を次に示します。光線セグメントの端はまだ表示されていますが、中央部分は最初に描いた2つのセグメントによって隠されています。

ここに画像の説明を入力してください

  1. これらの2つの光線も「ブロック」されますが、同じ他のラインによってブロックされるため、目に見える違いは生じません。

ここに画像の説明を入力してください

  1. 9行すべてが描画されるまで早送りします。これらのスキップされた手順の詳細な説明が必要な場合は、説明できます。

ここに画像の説明を入力してください

  1. 最後に、星のポイントを削除します。見栄えを良くするために、太いドットも削除されます。

ここに画像の説明を入力してください

チャレンジ

あなたが挑戦するのは、ランダムなヘキサグリフの視覚的表現を出力することです。これはコードゴルフであり、バイト数が最も少なくなります。

  1. 可能性のあるすべてのヘキサグリフは、何らかの正の確率で表示されるはずです。9つのエッジが描画される順序を変更することにより、異なるヘキサグリフが生成されます。

  2. さらに、プログラムによって出力されるすべての画像は有効なヘキサグリフでなければなりません。特定のパターン(内側の六角形の完全な輪郭など)は、六角形のグリフとして表示されることはないため、プログラムでこれらを出力してはなりません。

  3. 出力は、グラフィカルイメージ(画面またはファイルに印刷)である必要があります。

  4. 六角形は規則的である必要がありますが、任意の方向に表示できます。

  5. 反射/回転は一意と見なされません。(これにより、要件1が従いやすくなる場合があります)。


8
I made up while doodling during my DiffEq class。すべての偉大な発見が起こるの道...:P
Rɪᴋᴇʀ

画像の最小要件は何ですか?ASCIIのアートは、各エッジが曖昧に適切な場所に表され、配置されている限り、どの程度認識できる必要がありますか?
ジョンドヴォルザーク

@JanDvorak ASCIIアートとグラフィック出力を生成するプログラムは簡単に比較できないため、チャレンジのASCIIアートオプションを削除しました(投稿から2分以内など)。
-PhiNotPi

ではピクセルアートはどうですか?PPMヘッダーはそれほど重くなく、その後の唯一の違いはの'01'代わりにスペースをインターリーブして使用することです' *'
ジョンドヴォルザーク

@JanDvorak出力は、適切にフォーマットされた画像ファイルになりますよね?それから私はそれで何も悪いことを見ない。
PhiNotPi

回答:


18

Mathematicaの、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の中と後置転置演算子です。

これのバグを整理することは永遠にかかりました...最後に向かって、私はそれを機能させるためにいくつかのことを一緒にハックしました。また、外側の六角形を横切る線を介して文字どおり仕様を実装し、Mathematicaのジオメトリ関数に交差を処理させる方が全体的に良いのではないかと思います。

これは完全なプログラムであり、単一のREPLセッション内でコードを複数回実行する場合は、先頭にを付ける必要がありClear[b]ます。

20回の実行の結果は次のとおりです。

ここに画像の説明を入力してください

説明

この解決策は、外側の星の点をまったく使用しません。代わりに、ヘキサグリフの一部であるポイントと、一度に3つをカバーするラインで直接動作します。

ポイントにラベルを付けましょう:

ここに画像の説明を入力してください

1は少し奇妙なコーナーから始まりますが、これはの(これもやや奇妙な)デフォルトの動作によるものCirclePointsです。そこから六角形を開始すると、最も安価になりました。

次に、外側の星の接続された点に対応する3つの点を通る関連線を見つけたいと思います。六角形の周りの点は、奇数から始まる3つの隣接する点(モジュロ12)です。センター全体のものが偶数で構成されn13そしてn+6

これらの行の表現(次のコードによって3つのポイントのリストの形式で生成されます):

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

Partition六角形の周りに線を生成Array中心を通るライン。両方のビームを処理するには、この関数を行のリストにマッピングします:

{#,Reverse@#}&

次に、これらをシャッフルRandomSampleして、ランダムな順序で処理します。Join @@ペアのリストをフラット化して、ビームのリストを作成します。

短い休憩:どのポイントが既にブロックされているかを追跡するために、ルックアップ関数を使用します。この関数はbTrueによってすべての値に対して初期化されますb@_=k=1>0;。ビームを処理するときに我々がした第1時点までのすべてのポイントを維持b[n] == False含む 1つ)。

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

今、これが最もゴルフに適した部分だと感じています... Mastermindプレイするために2つの一時変数を使用するのは、本当に高価なようです。とにかく、この結果は、私たちが描くことを許されている線の点を私たちに与えます。現在、この関数はこれらの各ポイントにマッピングされています。

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

最初の部分は、2つの呼び出しのインターリーブされた結果を使用して、13のポイントすべてのリストを生成しますCirclePoints(エッジの中心と六角形のコーナーの半径が異なる)。b@#=!kこれにより、現在のポイントのルックアップテーブルの値がに設定され、Falseそれ以上ビームが通過できなくなることに注意してください。最後に、値は座標のリストへのインデックスとして使用され、正しい2Dポイントを取得します。

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

これは、個々の(および表示される)ポイントとしてレンダリングされるため、すべての単一要素リストを破棄します。最後に結果をレンダリングします。

Graphics[Line/@...]

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

@CatsAreFluffy個々の値を後で上書きできるようにする必要があるので、それが機能するとは思わない。
マーティンエンダー

CirclePointsの素晴らしい使用法。
DavidC

Youtubeリンクに感謝します。
DanTheMan

8

(ルビー)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 ... Rev B 196バイト

Shoesは、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)}}

説明

六角形の外側の線の部分は考慮しません。描画する必要がある部分のみを描画します。重要なのは、線が交差点を横切るかどうかです(描画する必要がある部分のみを描画する場合、これは交差点で開始/終了することを意味します)。

基本的なルールは、線の両方のエンドポイントにアクセスした場合、その線はブロックされ、描画されないことです。線は2分割されて描画されるため、それぞれの半分を描画する必要があるかどうかを確認するために、中間点にアクセスしたかどうかも確認する必要があります。

配列内でどのポイントが訪問されたかを追跡し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がコードを196ではなく202バイトとしてカウントしたのは、改行が実際には2文字のシーケンス「\ r \ n」だからだと思います。これにより、すべての改行が2回カウントされます。\ rおよび\ nに関するスタックオーバーフローの回答を次に示します。
Kチャン

Hehe私は XDでルビーの名前を克服することはできません
ベータ崩壊

3

パイソン、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バイトのバグ修正とゴルフ。L1バイトのゴルフ。

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
ティムČ16年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.