Намалюйте випадковий гексагліф


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 має бути впізнаваним до тих пір, поки кожен край зображений і розміщений у невиразному правильному місці?
Джон Дворак

@JanDvorak Я усунув варіант виклику ASCII (наприклад, протягом 2 хвилин після публікації), оскільки програми, що створюють ASCII-графічні та графічні виходи, не легко порівняти.
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 серій:

введіть тут опис зображення

Пояснення

Це рішення взагалі не використовує зовнішні зіркові точки. Натомість він працює безпосередньо з точками, що входять до складу гексагліфа, та лініями, які охоплюють три з них одночасно.

Давайте позначимо точки:

введіть тут опис зображення

1починається з трохи дивного кута, але це пов'язано з (також дещо дивною) поведінкою за замовчуванням CirclePoints. Почати шестикутник звідти вийшло найдешевше.

Тепер ми хочемо знайти відповідні лінії через три з тих точок, які відповідають з’єднаним точкам зовнішньої зірки. Звичайно навколо шестикутника - це лише 3 сусідні точки (модуль 12), починаючи з непарного числа. Ті , через центр складається з парного числа n, 13і n+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 Я не думаю, що це працює, тому що мені потрібно мати можливість перезаписати окремі значення згодом.
Мартін Ендер

Гарне використання 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)}}

Взуття (Ruby) 205 ... Rev B 196 байт

Взуття - це рубіновий інструмент для побудови графічного інтерфейсу тощо. Це я вперше застосував це. mothereff.in/byte-counter вважає моє подання 196 байтами, але чомусь взуття вважає це 202.

Крім того, Ruby дозволяє робити такі речі, як, t[a=i.ord]але дивно, здається, це не працює так, як очікувалося взуття.

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, а шкала умножується на 14, що є дуже близьким раціональним наближенням до правильного співвідношення: 14/8 = 1,75 проти 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 Zhang

Hehe Я не можу перемогти ім'я Ruby with Shoes XD
Beta Decay

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 байти. Гольф 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

Ungolfing:

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
Тім Час
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.