O serii
Po pierwsze, możesz potraktować to jak każde inne wyzwanie związane z golfem i odpowiedzieć na nie, nie martwiąc się w ogóle serią. Istnieje jednak tabela wyników dla wszystkich wyzwań. Możesz znaleźć tabelę liderów wraz z kilkoma więcej informacji o serii w pierwszym poście .
Chociaż mam szereg pomysłów w szeregu, przyszłe wyzwania nie są jeszcze ustalone. Jeśli masz jakieś sugestie, daj mi znać w odpowiednim poście z piaskownicą .
Dziura 6: Rzuć k20
Bardzo popularną kością w stołowych grach RPG jest matryca dwustronna ( dwudziestościan , powszechnie znany jako d20 ). Twoim zadaniem jest rzucić taką kostką. Jeśli jednak zwracasz losową liczbę od 1 do 20, byłoby to trochę trywialne. Twoim zadaniem jest wygenerowanie losowej sieci dla danej kości.
Wykorzystamy następującą sieć:
Jest to pasek trójkąta, dzięki czemu można go łatwo przedstawić jako listę liczb całkowitych. Np. Jeśli otrzymasz dane wejściowe:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
Odpowiadałoby to następującej kości (fajny fakt: to sieć używana przez Magic: liczniki życia Gathering / kości spin-down).
Nie jest to jednak jedyna sieć reprezentująca tę kostkę. W zależności od tego, jak rozwijamy twarze, istnieje 60 różnych sieci. Oto dwa kolejne:
[1, 8, 9, 10, 2, 3, 4, 5, 6, 7, 17, 18, 19, 11, 12, 13, 14, 15, 16, 20]
[10, 9, 18, 19, 11, 12, 3, 2, 1, 8, 7, 17, 16, 20, 13, 14, 4, 5, 6, 15]
Lub graficznie (nie obracałem etykiet twarzy dla uproszczenia):
Wyzwanie
Biorąc pod uwagę listę liczb całkowitych reprezentujących matrycę (jak opisano powyżej) i liczbę całkowitą N
, wyprowadzane N
niezależnie, równomiernie losowe sieci d20 odpowiadające danej matrycy. (Oznacza to, że każda z 60 możliwych sieci powinna mieć takie samo prawdopodobieństwo wygenerowania.)
Oczywiście, ze względu na ograniczenia techniczne PRNG, idealna jednolitość będzie niemożliwa. W celu oceny jednolitości przesłanych danych następujące operacje zostaną uznane za zapewniające idealnie jednolite rozkłady:
- Uzyskiwanie numeru z PRNG (w dowolnym zakresie), który jest udokumentowany jako (w przybliżeniu) jednolity.
- Mapowanie równomiernego rozkładu większego zbioru liczb na mniejszy zbiór poprzez modulo lub mnożenie (lub inną operację, która równomiernie rozprowadza wartości). Większy zestaw musi zawierać co najmniej 1024 razy więcej możliwych wartości niż mniejszy zestaw.
Biorąc pod uwagę te założenia, algorytm musi dawać idealnie jednolity rozkład.
Twój program powinien być w stanie wygenerować 100 sieci w mniej niż sekundę (więc nie próbuj generować losowych sieci, dopóki nie odpowiada to kości podanej powyżej).
Możesz napisać program lub funkcję, pobierając dane wejściowe przez STDIN (lub najbliższą alternatywę), argument wiersza poleceń lub argument funkcji i wypisując wynik przez STDOUT (lub najbliższą alternatywę), wartość zwracaną funkcji lub parametr funkcji (wyjściowej).
Dane wejściowe i wyjściowe mogą być w dowolnym wygodnym, jednoznacznym, płaskim formacie listy. Możesz założyć, że wartości nominalne d20 są odrębnymi dodatnimi liczbami całkowitymi, które pasują do naturalnego typu liczb całkowitych twojego języka.
To jest kod golfowy, więc wygrywa najkrótsze przesłanie (w bajtach). I oczywiście najkrótsze zgłoszenie na użytkownika wejdzie również do ogólnej tabeli liderów serii.
Przykładowe dane wyjściowe
Dla danych wejściowych
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
60 możliwych sieci (o ile nie popełniłem błędu), w żadnej określonej kolejności, to:
[11, 10, 9, 18, 19, 20, 13, 12, 3, 2, 1, 8, 7, 17, 16, 15, 14, 4, 5, 6]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
[8, 7, 17, 18, 9, 10, 2, 1, 5, 6, 15, 16, 20, 19, 11, 12, 3, 4, 14, 13]
[3, 12, 13, 14, 4, 5, 1, 2, 10, 11, 19, 20, 16, 15, 6, 7, 8, 9, 18, 17]
[3, 4, 5, 1, 2, 10, 11, 12, 13, 14, 15, 6, 7, 8, 9, 18, 19, 20, 16, 17]
[11, 19, 20, 13, 12, 3, 2, 10, 9, 18, 17, 16, 15, 14, 4, 5, 1, 8, 7, 6]
[4, 14, 15, 6, 5, 1, 2, 3, 12, 13, 20, 16, 17, 7, 8, 9, 10, 11, 19, 18]
[2, 10, 11, 12, 3, 4, 5, 1, 8, 9, 18, 19, 20, 13, 14, 15, 6, 7, 17, 16]
[4, 5, 1, 2, 3, 12, 13, 14, 15, 6, 7, 8, 9, 10, 11, 19, 20, 16, 17, 18]
[10, 2, 1, 8, 9, 18, 19, 11, 12, 3, 4, 5, 6, 7, 17, 16, 20, 13, 14, 15]
[3, 2, 10, 11, 12, 13, 14, 4, 5, 1, 8, 9, 18, 19, 20, 16, 15, 6, 7, 17]
[7, 8, 1, 5, 6, 15, 16, 17, 18, 9, 10, 2, 3, 4, 14, 13, 20, 19, 11, 12]
[13, 12, 11, 19, 20, 16, 15, 14, 4, 3, 2, 10, 9, 18, 17, 7, 6, 5, 1, 8]
[16, 15, 14, 13, 20, 19, 18, 17, 7, 6, 5, 4, 3, 12, 11, 10, 9, 8, 1, 2]
[15, 16, 17, 7, 6, 5, 4, 14, 13, 20, 19, 18, 9, 8, 1, 2, 3, 12, 11, 10]
[20, 13, 12, 11, 19, 18, 17, 16, 15, 14, 4, 3, 2, 10, 9, 8, 7, 6, 5, 1]
[5, 4, 14, 15, 6, 7, 8, 1, 2, 3, 12, 13, 20, 16, 17, 18, 9, 10, 11, 19]
[10, 11, 12, 3, 2, 1, 8, 9, 18, 19, 20, 13, 14, 4, 5, 6, 7, 17, 16, 15]
[4, 3, 12, 13, 14, 15, 6, 5, 1, 2, 10, 11, 19, 20, 16, 17, 7, 8, 9, 18]
[19, 20, 13, 12, 11, 10, 9, 18, 17, 16, 15, 14, 4, 3, 2, 1, 8, 7, 6, 5]
[1, 8, 9, 10, 2, 3, 4, 5, 6, 7, 17, 18, 19, 11, 12, 13, 14, 15, 16, 20]
[8, 1, 5, 6, 7, 17, 18, 9, 10, 2, 3, 4, 14, 15, 16, 20, 19, 11, 12, 13]
[18, 9, 8, 7, 17, 16, 20, 19, 11, 10, 2, 1, 5, 6, 15, 14, 13, 12, 3, 4]
[12, 3, 2, 10, 11, 19, 20, 13, 14, 4, 5, 1, 8, 9, 18, 17, 16, 15, 6, 7]
[2, 3, 4, 5, 1, 8, 9, 10, 11, 12, 13, 14, 15, 6, 7, 17, 18, 19, 20, 16]
[10, 9, 18, 19, 11, 12, 3, 2, 1, 8, 7, 17, 16, 20, 13, 14, 4, 5, 6, 15]
[9, 8, 7, 17, 18, 19, 11, 10, 2, 1, 5, 6, 15, 16, 20, 13, 12, 3, 4, 14]
[16, 17, 7, 6, 15, 14, 13, 20, 19, 18, 9, 8, 1, 5, 4, 3, 12, 11, 10, 2]
[17, 7, 6, 15, 16, 20, 19, 18, 9, 8, 1, 5, 4, 14, 13, 12, 11, 10, 2, 3]
[1, 5, 6, 7, 8, 9, 10, 2, 3, 4, 14, 15, 16, 17, 18, 19, 11, 12, 13, 20]
[9, 18, 19, 11, 10, 2, 1, 8, 7, 17, 16, 20, 13, 12, 3, 4, 5, 6, 15, 14]
[16, 20, 19, 18, 17, 7, 6, 15, 14, 13, 12, 11, 10, 9, 8, 1, 5, 4, 3, 2]
[5, 1, 2, 3, 4, 14, 15, 6, 7, 8, 9, 10, 11, 12, 13, 20, 16, 17, 18, 19]
[8, 9, 10, 2, 1, 5, 6, 7, 17, 18, 19, 11, 12, 3, 4, 14, 15, 16, 20, 13]
[13, 20, 16, 15, 14, 4, 3, 12, 11, 19, 18, 17, 7, 6, 5, 1, 2, 10, 9, 8]
[6, 15, 16, 17, 7, 8, 1, 5, 4, 14, 13, 20, 19, 18, 9, 10, 2, 3, 12, 11]
[6, 5, 4, 14, 15, 16, 17, 7, 8, 1, 2, 3, 12, 13, 20, 19, 18, 9, 10, 11]
[7, 6, 15, 16, 17, 18, 9, 8, 1, 5, 4, 14, 13, 20, 19, 11, 10, 2, 3, 12]
[19, 18, 17, 16, 20, 13, 12, 11, 10, 9, 8, 7, 6, 15, 14, 4, 3, 2, 1, 5]
[14, 15, 6, 5, 4, 3, 12, 13, 20, 16, 17, 7, 8, 1, 2, 10, 11, 19, 18, 9]
[17, 18, 9, 8, 7, 6, 15, 16, 20, 19, 11, 10, 2, 1, 5, 4, 14, 13, 12, 3]
[6, 7, 8, 1, 5, 4, 14, 15, 16, 17, 18, 9, 10, 2, 3, 12, 13, 20, 19, 11]
[14, 13, 20, 16, 15, 6, 5, 4, 3, 12, 11, 19, 18, 17, 7, 8, 1, 2, 10, 9]
[20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
[7, 17, 18, 9, 8, 1, 5, 6, 15, 16, 20, 19, 11, 10, 2, 3, 4, 14, 13, 12]
[15, 6, 5, 4, 14, 13, 20, 16, 17, 7, 8, 1, 2, 3, 12, 11, 19, 18, 9, 10]
[9, 10, 2, 1, 8, 7, 17, 18, 19, 11, 12, 3, 4, 5, 6, 15, 16, 20, 13, 14]
[2, 1, 8, 9, 10, 11, 12, 3, 4, 5, 6, 7, 17, 18, 19, 20, 13, 14, 15, 16]
[12, 13, 14, 4, 3, 2, 10, 11, 19, 20, 16, 15, 6, 5, 1, 8, 9, 18, 17, 7]
[17, 16, 20, 19, 18, 9, 8, 7, 6, 15, 14, 13, 12, 11, 10, 2, 1, 5, 4, 3]
[18, 17, 16, 20, 19, 11, 10, 9, 8, 7, 6, 15, 14, 13, 12, 3, 2, 1, 5, 4]
[18, 19, 11, 10, 9, 8, 7, 17, 16, 20, 13, 12, 3, 2, 1, 5, 6, 15, 14, 4]
[11, 12, 3, 2, 10, 9, 18, 19, 20, 13, 14, 4, 5, 1, 8, 7, 17, 16, 15, 6]
[15, 14, 13, 20, 16, 17, 7, 6, 5, 4, 3, 12, 11, 19, 18, 9, 8, 1, 2, 10]
[19, 11, 10, 9, 18, 17, 16, 20, 13, 12, 3, 2, 1, 8, 7, 6, 15, 14, 4, 5]
[12, 11, 19, 20, 13, 14, 4, 3, 2, 10, 9, 18, 17, 16, 15, 6, 5, 1, 8, 7]
[20, 16, 15, 14, 13, 12, 11, 19, 18, 17, 7, 6, 5, 4, 3, 2, 10, 9, 8, 1]
[13, 14, 4, 3, 12, 11, 19, 20, 16, 15, 6, 5, 1, 2, 10, 9, 18, 17, 7, 8]
[5, 6, 7, 8, 1, 2, 3, 4, 14, 15, 16, 17, 18, 9, 10, 11, 12, 13, 20, 19]
[14, 4, 3, 12, 13, 20, 16, 15, 6, 5, 1, 2, 10, 11, 19, 18, 17, 7, 8, 9]
W przypadku każdej innej sieci po prostu zamień każde wystąpienie i
na i
liczbę th na wejściu (gdzie i
jest oparta na 1).
Powiązane wyzwania
Tabela liderów
Pierwszy post z serii generuje tabelę wyników.
Aby upewnić się, że Twoje odpowiedzi się pojawią, zacznij każdą odpowiedź od nagłówka, używając następującego szablonu Markdown:
## Language Name, N bytes
gdzie N
jest rozmiar twojego zgłoszenia. Jeśli poprawić swój wynik, to może zachować stare porachunki w nagłówku, uderzając je przez. Na przykład:
## Ruby, <s>104</s> <s>101</s> 96 bytes
(Język nie jest obecnie wyświetlany, ale fragment go wymaga i analizuje, a w przyszłości mogę dodać tabelę wyników według języków).
źródło
Odpowiedzi:
Rubinowy, 160 bajtów (rev B)
17 bajtów zapisanych dzięki sugestiom Martina Büttnera.
Rubinowy, 177 bajtów (rev A)
Wyjaśnienie
Możliwe jest wygenerowanie wszystkich możliwych orientacji poprzez obrót wokół jednej powierzchni (3-krotnie), jednego wierzchołka (5-krotnie) i dwóch krawędzi (2-krotnie). Ale nie tylko twarz i krawędzie. Osie muszą mieć prawidłową relację, a obroty muszą być wykonywane we właściwej kolejności, inaczej mogą się zdarzyć dziwne rzeczy.
Tak to zrobiłem (choć rozumiem, że Martin zrobił to inaczej).
Wszystkie orientacje czworościanu mogą być generowane przez kombinacje następujących trzech operacji symetrii:
a) Obrót wokół dwóch 2-krotnych osi w prawo przez punkty środkowe krawędzi (są one ustawione pod kątem prostym do siebie. Jeśli pomnożymy je razem, odkryjemy trzecią 2-krotną oś przez pozostałą parę krawędzi.)
b) Obrót wokół 3-krotnej osi ukośnej do 2-krotnej osi, przechodzący przez wierzchołek i powierzchnię.
Symetria dwudziestościanu jest nadzbiorem symetrii czworościanu. Na poniższym obrazku z https://en.wikipedia.org/wiki/Icosahedron żółte i czerwone twarze definiują dwie różne czworościany (lub alternatywnie pojedynczy ośmiościan), podczas gdy krawędzie wspólne dla dwóch niebieskich ścian są w trzech parach po kąty proste (i leżą na powierzchniach sześcianu).
Wszystkie orientacje dwudziestościanu mogą być generowane przez te operacje symetrii wspomniane powyżej plus dodatkowa 5-krotna operacja.
Obroty wokół trzech z czterech wyżej wymienionych osi są reprezentowane przez magiczne sznurki między
''
znakami. Obrót wokół drugiej 2-krotnej osi jest inny i można to zrobić po prostu przez odwrócenie tablicya[]
.Ungolfed w programie testowym:
Alternatywne rozwiązanie 131 bajtów (niepoprawne ze względu na binarne podejście losowe, daje jedynie przybliżony prawidłowy rozkład).
Jest to szyfrowanie (podobnie jak programy używane do szyfrowania kostki Rubika).
Specyficzne rotacje, których używam, to dwie z najbardziej oczywistych:
-Obrót o 120 stopni (około powierzchni 1 i 20 na pierwszym schemacie)
-Obrót o 72 stopnie (około wierzchołków wspólnych dla 1,2,3,4,5 i 16,17,18,19,20 na pierwszym schemacie).
rzucamy monetą 99 razy i za każdym razem wykonujemy jedną z tych dwóch rotacji w zależności od tego, czy jest to główka czy reszka.
Zauważ, że naprzemienne ich deterministycznie prowadzi do dość krótkich sekwencji. Na przykład przy prawidłowych zmysłach obrotu można uzyskać obrót o 180 stopni z okresem zaledwie 2.
źródło
b.map
nie działa bezpośrednio, muszęb.chars.map
go uruchomić (BTW, który nie działa na moim komputerze, ponieważ mam Ruby 1.9.3, ale działa na Ideone.) To uczciwa oszczędność. Nie sądzę, aby zmiana magicznych ciągów znaków niedrukowalnych w celu zapisania-64
testamentu działała:%w{}
interpretuje\n
(jak również spację) jako separator między ciągami w wygenerowanej tablicy. Nie mam pojęcia, co zrobi z innymi niedrukowalnymi znakami ASCII.Kod maszynowy IA-32, 118 bajtów
Hexdump:
Jest trochę długi, więc niektóre wyjaśnienia są najważniejsze. Kiedyś niemal ten sam algorytm jak istniejącego Odpowiedź poziom rzeki św . Aby moja odpowiedź była inna, wziąłem inne podstawowe permutacje, które niekoniecznie mają intuicyjne znaczenie geometryczne, ale są w jakiś sposób wygodniejsze.
Kod musi generować permutację, która jest sekwencyjnym zastosowaniem następujących elementów:
p3
, zastosowała 0 ... 2 razyq2
, zastosowała 0 lub 1 razyp5
, zastosowała 0 ... 4 razyp2
, zastosowała 0 lub 1 razyIstnieje wiele możliwych wyborów dla tych permutacji. Jednym z nich jest:
Ten wybór jest lepszy niż inne, ponieważ tutaj permutacje mają długie serie indeksów sekwencyjnych, które można skompresować za pomocą kodowania długości przebiegu - tylko 29 bajtów dla 4 permutacji.
Aby uprościć generowanie liczb losowych, wybrałem moce (ile razy stosuje się każdą permutację) z zakresu 1 ... 30 dla wszystkich. Prowadzi to do znacznie dodatkowej pracy w kodzie, ponieważ np.
p3
Staje się permutacją tożsamości za każdym razem, gdy jest ona mnożona 3 razy. Jednak kod jest w ten sposób mniejszy i dopóki zakres jest podzielny przez 30, wynik będzie miał jednolity rozkład.Ponadto moce powinny być dodatnie, aby operacja dekodowania przebiegała co najmniej raz.
Kod ma 4 zagnieżdżone pętle; zarys wygląda następująco:
Mam nadzieję, że ten pseudo-kod jest wyraźniejszy niż poniższy kod asemblera.
Niektóre zabawne szczegóły implementacji:
call
i kolejnepop
dostęp do danych (zakodowanych permutacji) przechowywanych w kodziejecxz
Instrukcja wygodnie pozwala mi użyć zerowy bajt jako zakończenie procesu dekodowania run-lengthNa szczęście liczba 30 (2 * 3 * 5) jest prawie potęgą 2. Pozwala mi to użyć krótkiego kodu do wygenerowania liczby z zakresu 1 ... 30:
Korzystam z instrukcji „podziału ogólnego” (
aam
), aby oddzielić bajt na pola bitowe (długość 3-bitowa i indeks 5-bitowy); na szczęście w tej pozycji w kodziecl = 0
, więc korzystam z obu „stron”xchg
źródło