Zrób trochę śniegu!


18

Twoje zadanie: wygeneruj płatek śniegu Kocha na n-tej głębokości. Nie musisz tworzyć pełnego płatka śniegu Kocha, tylko jedną stronę trójkąta początkowego. Wikipedia na temat płatków Kocha: https://en.wikipedia.org/wiki/Koch_snowflake .

Zasady:

  • Program musi wygenerować jedną stronę płatka śniegu Kocha na n-tej głębokości.
  • Wyjściem musi być ASCII.
  • Państwo może generować cały płatek śniegu; nie jest to wymagane.
  • Obowiązują standardowe zasady dotyczące wejścia / wyjścia oraz luki i inne rzeczy.
  • Biała spacja nie ma znaczenia, o ile wszystkie znaki znajdują się we właściwym miejscu względem siebie.
  • Najkrótszy kod wygrywa!

Przypadki testowe:

n = 0:

__

n = 1:

__/\__

n = 2:

      __/\__
      \    /
__/\__/    \__/\__

n = 3:

                        __/\__
                        \    /
                  __/\__/    \__/\__
                  \                /
                  /_              _\
                    \            /
      __/\__      __/            \__      __/\__
      \    /      \                /      \    /
__/\__/    \__/\__/                \__/\__/    \__/\__

Mam nadzieję, że to ma sens. Zauważ, że w każdym przypadku testowym fraktal można podzielić na trzy części o równej długości. Zauważ również, że szerokość każdego płatka śniegu jest trzy razy większa niż szerokość poprzedniej generacji płatka śniegu.


FYI, uznano, że nie jest to dupe od tego .
Towarzysz SparklePony

Nie sądzę, żebyś właściwie zdefiniował, jaka jest właściwa reprezentacja ASCII n-tej krzywej Kocha.
orlp

Nie jestem pewien, czy proporcje mają sens. W trybie bez duplikatu zastosowano __/\__dwa podkreślenia, dzięki którym każda iteracja była 3 razy większa niż poprzednia. Używanie tylko jednego podkreślenia wydaje się dawać sprzeczności, które zaczynają być naprawdę niezręczne w n = 3. Np. Zewnętrzne części mają szerokość 12, podczas gdy środkowa część ma tylko szerokość 10, w wyniku czego /_i _\ które są zbyt ciasne. A nawet wcześniej _rozszerzasz do dwukrotnej szerokości /i \ .
Ørjan Johansen

Myślę, że /_i _\ to jedyny naprawdę krytyczny część - podkreślenia trzeba iść, ponieważ muszą być w tej samej pozycji jak /i \ . Gdy to się stanie, rzeczy mogą wzrosnąć 3 razy od n = 1 (ale n = 0 nie pasuje.)
Ørjan Johansen

Niestety, nie, środkowa część nadal ma szerokość niepasującą do zewnętrznych części, o czym świadczy n = 3 o szerokości 52 zamiast 54 = 2 * 3 ^ 3. Wypróbuj jedną z nich . Dołączyłem wersje do góry nogami z częściami wyświetlanymi tylko od n = 4 lub n = 5 - różnią się one od tych w górę, w których upuszczane są podkreślenia.
Ørjan Johansen

Odpowiedzi:


10

Haskell , 308 300 299 bajtów

Edycje:

  • -4 bajtów: Zmieniające zipWith(+)się zipWith(-)i regulacja kodowania i korekcje pozbył każdego znaku negacji.
  • -1 bajt: Dalsze dopracowanie kodowania pozwoliło na usunięcie kilku nazw zmiennych #przy użyciu r=reversezamiast bezpośredniego dopasowania wzorca.
  • -2 bajty: Użycie operatora zamiast alfanum dla zipWith(-).
  • -1 bajt: Definiowanie w o=[0,0]celu skrócenia stałych listy.
  • -1 bajt: Scalenie dwóch gałęzi ?.
import Data.List
k n=0?sort(o#(f=<<scanl1(+)(iterate(>>=(:[1,4,1]))[6]!!n)))
x?l@(([_,w],c):r)|x>w='\n':0?l|0<1=([2..w-x]>>" ")++[c|w>x]++w?r
_?_=""
w#((c,l):m)=(l&w,c):r l&(l&w)#m
_#_=[]
f x=zip"_/\\_/\\"([id,r]<*>[0:1:o,[0,1,0,1],o++[1,1]])!!mod x 6<$[1,3..gcd 3x]
(&)=zipWith(-)
r=reverse
o=[0,0]

Wypróbuj online! (Niestety, wszystko większe niż n = 3 zostaje okropnie opakowane i nieczytelne, ale możesz skopiować to do innego programu, aby to zobaczyć.)

Wariacje

Jak to działa

  • kjest główną funkcją, pobiera Int ni zwraca a String.
  • iterate(>>=(:[1,4,1]))[6]generuje nieskończoną listę zawierającą, dla każdego n, zwoje między kolejnymi liniami w tej iteracji krzywej, styl grafiki żółwia, jako liczby nominalnie między 0a 5. Każda iteracja jest tylko poprzednia z 1,4,1przeplotem zwojów . Jedynym powodem, dla którego podlisty zaczynają, 6zamiast 0robić gcdsztuczkę, fjest unikanie f 0.
  • scanl1(+)zamienia zwoje w kierunki „absolutne”, aż do modułu 6. A 0oznacza w prawo, a następnie każda wyższa liczba wynosi 60 stopni w kierunku przeciwnym do ruchu wskazówek zegara w stosunku do poprzedniego. (Cóż, byłoby to 60 stopni, gdyby był to właściwy rysunek, a nie ASCII.)
  • f konwertuje kierunek bezwzględny na listę par (znak, kodowanie offsetowe), która koduje znaki, które należy dodać do krzywej (dla kierunków poziomych generuje dwie pary, w przeciwnym razie jedną), oraz sposób zmiany położenia względnego.
  • Że #iteracje przez operatora poprzedniej listy (znak offsetowy, kodowanie), generowanie par rzeczywistych (współrzędnych par znaków).
  • Zasady kodowania:
    • Znak z _/\nominalnie reprezentuje linię od narożnika początkowego przez prostokątną komórkę do innego narożnika końcowego.
    • Współrzędne komórki mają postać [y,x], od góry do dołu, od lewej do prawej, dzięki czemu sortują się w kolejności, w jakiej chcemy je wydrukować. Kolumny są oparte na 1. Listy są używane zamiast krotek dla krótszej arytmetyki wektorowej z (&)=zipWith(-).
    • Narożnik jest oznaczony tymi samymi współrzędnymi, [y,x]co komórka w lewym górnym rogu. Zapewnia to, że wszystkie przesunięcia od rogu do sąsiednich komórek są nieujemne, unikając stałych ujemnych.
    • Jednak współrzędne narożnika są przekazywane dookoła zanegowane, aby wszystkie operacje wektorowe mogły być odejmowane zamiast dodawania, co pozwala uniknąć wszystkich innych wyraźnych znaków.
    • Lista kodowania przesunięć to miejsce, w [y1,x1,x2,y2]którym [y1,x1]znajduje się przesunięcie współrzędnych od narożnika początkowego do komórki znakowej i [y2,x2]jest przesunięciem od narożnika końcowego do komórki znakowej. To znaczy:
      • Listy kodowania dla kierunków 3.. 5są tylko odwrotnością list dla 02, pozwalając na ich generowanie [id,r]<*>.
      • Wszystkie niezbędne arytmetyki wektorowej można dokonać za pomocą (&)=zipWith(-)listy kodowania lub jej odwrotności.
  • Po posortowaniu listy par (współrzędnych, znaków) są one przekazywane do ?, co generuje Stringz nich finał .
    • In x?l@(([_,w],c):r) xjest współrzędną x poprzedniego znaku pokazanego w tym wierszu lub 0jeśli jest na początku wiersza; ljest całą bieżącą listą, wjest współrzędną x następnego znaku do dodania, cjest znakiem i rjest pozostałą listą.
    • Na tym etapie współrzędne Y nie są już potrzebne. Ponieważ każda linia zawiera znaki, a pierwszy znak każdej linii znajduje się daleko na lewo od końca poprzedniej, początek nowych linii jest wykrywany przez sprawdzenie, czy współrzędna x zmniejszyła się.
    • Podkreślenie ma większą wartość ASCII niż \i /, więc jest sortowane jako ostatnie, jeśli nakłada się z innym znakiem na tej samej pozycji. W ten sposób wykrywany jest nadmiarowy znak podkreślenia, sprawdzając, czy współrzędna X została powtórzona.

Ładny! Zaakceptuję to, jeśli dzisiaj nie będzie już więcej aktywności w tym pytaniu.
Towarzysz SparklePony,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.