Napisz program, który generuje poziom lustrzany

31

Istnieje 95 znaków ASCII do wydrukowania :

 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~

W czcionce Consolas (domyślnie blok kodu Stack Exchange) niektóre znaki mają odbicia lustrzane wokół pionowej osi symetrii:

  • Te pary znaków są wzajemnie zwierciadłami: () [] {} <> /\
  • Te postacie są zwierciadłami samych siebie: ! "'*+-.8:=AHIMOTUVWXY^_ovwx|(Zwróć uwagę, że spacja to jeden).
  • Nie mają kopii lustrzanych: #$%&,012345679;?@BCDEFGJKLNPQRSZ`abcdefghijklmnpqrstuyz~

( i, l, 0, #, I prawdopodobnie inne znaki są ich własne lusterka w niektórych czcionek, ale będziemy trzymać się kształtów Consolas).

Mówi się, że łańcuch jest zwierciadłem samym w sobie, jeśli składa się tylko z 39 znaków zwierciadlanych , ułożonych w taki sposób, że łańcuch ma środkową pionową linię symetrii. Tak samo ](A--A)[jest zwierciadłem, ale nim ](A--A(]nie jest.

Napisz jednoliniowy program o parzystej długości, który jest zwierciadłem samego siebie. Kiedy N kopii jego lewej połowy zostało do niego dołączonych, a N kopii jego prawej połowy zostało do niego dołączonych, powinno wyprowadzać N + 1. N jest nieujemną liczbą całkowitą.

Na przykład, jeśli program był ](A--A)[(lewa połowa:, ](A-prawa połowa:) -A)[, to:

  • Uruchomienie ](A--A)[powinno dać wynik 1. (N = 0)
  • Uruchomienie ](A-](A--A)[-A)[powinno dać wynik 2. (N = 1)
  • Uruchomienie ](A-](A-](A--A)[-A)[-A)[powinno dać wynik 3. (N = 2)
  • Uruchomienie ](A-](A-](A-](A--A)[-A)[-A)[-A)[powinno dać wynik 4. (N = 3)
  • . . .
  • Uruchomienie ](A-](A-](A-](A-](A-](A-](A-](A-](A-](A--A)[-A)[-A)[-A)[-A)[-A)[-A)[-A)[-A)[-A)[powinno dać wynik 10. (N = 9)
  • itp.

Zasady

  • Wyjście na standardowe wyjście lub najbliższą alternatywę dla twojego języka. Może występować opcjonalny znak nowej linii. Nie należy pobierać żadnych danych wejściowych.
  • Proces powinien teoretycznie działać dla N do 2 15 -1 lub więcej, biorąc pod uwagę wystarczającą pamięć i moc obliczeniową.
  • Wymagany jest pełny program, a nie tylko polecenie REPL .

Najkrótszy program początkowy (przypadek N = 0) w bajtach wygrywa.

Hobby Calvina
źródło
W niektórych czcionkach #jest to również jego własna relacja, ale masz rację, nie w konsolach.
SuperJedi224
1
Korzystanie z replik jest dozwolone? Innymi słowy: czy powinniśmy napisać kompletny poprawny program, czy wystarczy wyrażenie? Myślę o wpisie Haskell, który działałby podczas uruchamiania w ghci, ale nie jest poprawnym kompletnym programem.
Bakuriu
@ Bakuriu Wymagany jest pełny program. Odpowiedź Haskella jest nieprawidłowa.
Calvin's Hobbies
4
Dlaczego lustra „b” i „d” nie są sobą nawzajem? To uniemożliwia mój plan: P
Thijs ter Haar
1
@ThijsterHaar Właściwie nie brałem tego pod uwagę, ale wygląda na to, że ich kształty Consoli są nieco inne, przepraszam: P
Hobby Calvina

Odpowiedzi:

20

Pip, 12 8 4 bajtów

Teraz z 66% mniej bajtów!

x++x
  • xjest zmienną, zainicjalizowaną do "". W kontekście numerycznym staje się to 0.
  • Pierwsza połowa, bez finału +, wyraża formę x+x+...+x. To prawidłowe stwierdzenie, które nic nie robi.
  • Druga połowa, w tym finał +z pierwszej połowy, stanowi wyraz formy ++x+x+...+x. ++xPrzyrosty xsię 1, a resztę dodaje go do siebie n razy. Ponieważ wyrażenia są oceniane od lewej do prawej w Pip, przyrost jest gwarantowany jako pierwszy, a wynik jest równy liczbie poziomów lustrzanych.
  • Na koniec wartość tego wyrażenia jest drukowana automatycznie.

Niestety, Pip nie radzi sobie dobrze z przetwarzaniem dużych wyrażeń: to rozwiązanie powoduje maximum recursion depth exceededbłąd dla N powyżej około 500. Oto poprzednie rozwiązanie, które nie obejmuje 8 bajtów :

x++oo++x

Więcej na Pip

DLosc
źródło
OK, chyba że ktoś opublikuje odpowiedź 2-bajtową, wygląda na to, że masz ją w torbie. Nawiasem mówiąc, nie wiem, czy uruchomiłeś go z N = 32767 , ale rzeczywiste wyjście to Fatal error: maximum recursion depth exceeded while calling a Python object.
Dennis
@Dennis Tak, trafiłem na to - zaczyna się dość wcześnie, około 600, jeśli nie wcześniej. Powodem jest to, że wyrażenia są oceniane przez rekurencyjną ocenę wszystkich podwyrażeń najpierw, więc x+x+...+xgeneruje głębokość rekurencji O (N). Może to unieważnia tę odpowiedź. Dodam notatkę.
DLosc
Limit rekurencji jest łatwo regulowany w Pythonie, prawda?
Dennis
@Dennis Tak, chociaż istnieją straszne ostrzeżenia o tym, co zrobi z twoim systemem, jeśli ustawisz go zbyt wysoko, więc nigdy tego nie próbowałem. ;) Poza tym konfiguracja nie jest możliwa z poziomu Pipa , więc wydaje mi się, że to oszustwo. Jeśli jednak chcesz tego spróbować, byłbym zainteresowany usłyszeniem wyników.
DLosc
Próbowałem. Na moim komputerze zwiększenie limitu rekurencji do 20000 już powoduje awarie. Ale ponieważ odpowiedź musi działać tylko przy wystarczającej ilości pamięci i mocy obliczeniowej , nie powinno to stanowić problemu.
Dennis
34

GolfScript, 10 bajtów

!:{)::(}:!

Wypróbuj online z Web Golfscript: N = 0 , N = 1 , N = 2 , N = 3 , N = 41

Web GolfScript ma limit 1024 znaków, ale interpreter języka Ruby doskonale radzi sobie z N = 32767 :

$ curl -Ss http://www.golfscript.com/golfscript/golfscript.rb > golfscript.rb
$ echo '"!:{):"32768*":(}:!"32768*' | ruby golfscript.rb > mirror-level-32767.gs
$ ruby golfscript.rb mirror-level-32767.gs
32768

Jak to działa

Bez żadnych danych GolfScript początkowo ma pusty ciąg znaków na stosie.

W pierwszej lewej połowie dzieje się tak:

  • !stosuje logiczne NIE do pustego ciągu. To popycha 1.

  • :{zapisuje liczbę całkowitą na stosie w zmiennej {.

    Tak, jest to prawidłowy identyfikator, chociaż nie ma możliwości odzyskania zapisanej wartości.

  • ) zwiększa liczbę całkowitą na stosie.

  • : jest niepełną instrukcją.

Kolejne lewe połowy następują:

  • :!(gdzie :jest pozostałość po wcześniejszym) zapisuje liczbę całkowitą na stosie w zmiennej !.

    Tak, to także prawidłowy identyfikator. To łamie !polecenie, ale już go nie używamy.

  • :{, )A :praca jak wcześniej.

W pierwszej prawej połowie następują:

  • ::(gdzie :jest pozostałość po wcześniejszym) zapisuje liczbę całkowitą na stosie w zmiennej :.

    Tak, nawet to jest prawidłowy identyfikator. Podobnie jak w przypadku {, nie ma możliwości odzyskania zapisanej wartości.

  • ( zmniejsza liczbę całkowitą na stosie, uzyskując liczbę lewych połówek.

  • }, ponieważ nie ma sobie równych i natychmiast kończy wykonywanie.

    Jest to funkcja nieudokumentowana. Nazywam je przesądami .

Pozostały kod jest po prostu ignorowany.

Dennis
źródło
Wydaje się naprawdę dziwne, że nie ma sobie równych }w drugiej połowie kodu w konkursie lustrzanym.
ballesta25
To powszechna sztuczka w wariantach palindromu. W "\""/"czwartym podwójnym cudzysłowie również byłby nieporównywalny, ponieważ drugi uciekł.
Dennis
27

Kod maszynowy Z80, 8 6 bajtów *

<8ww8> * Przyjmuje określone warunki, wchodząc z Amstrad BASIC

<   INC A         // A=A+1
8w  JR C, #77     ## C is unset unless A has overflowed, does nothing

w   LD (HL), A    // Saves A to memory location in HL (randomly initialised)
8>  JR C, #3E     ## C is still unset, does nothing

Apoczątkowo wynosi 0 po wprowadzeniu z BASIC. Przyrosty A n razy, a następnie zapisuje n razy do tej samej lokalizacji w pamięci (która jest ustawiona przez BASIC na nieco losową lokalizację)! Operacja JRJump Relative nigdy nie robi nic, ponieważ Cflaga jest zawsze rozbrojona, dlatego służy do „komentowania” następującego bajtu! Ta wersja nieco oszukuje, zakładając pewne warunki wejścia, a mianowicie wejście z gwarancji BASIC, która Azawsze wynosi 0. Lokalizacja (HL)nie jest gwarantowana jako bezpieczna, aw rzeczywistości jest to prawdopodobnie niebezpieczne miejsce. Poniższy kod jest znacznie bardziej niezawodny, dlatego jest o wiele dłuższy.

Kod maszynowy Z80, 30 bajtów

Jako ASCII: o!.ww.!>A=o>{))((}<o=A<!.ww.!o

Zasadniczo pierwsza połowa gwarantuje utworzenie wartości zerowej, a druga połowa zwiększa ją i zapisuje w pamięci. W rozszerzonej wersji poniżej ##oznacza kod, który nie służy żadnemu celowi w jego połowie lustra.

o   LD L, A       ## 
!.w LD HL, #772E  // Load specific address to not corrupt random memory!
w   LD (HL), A    ## Save random contents of A to memory
.!  LD L, #21     ## 
>A  LD A, #41     // A=#41
=   DEC A         // A=#40
o   LD L, A       // L=#40
>{  LD A, #7B     ## 
)   ADD HL, HL    // HL=#EE80
)   ADD HL, HL    // HL=#DD00. L=#00 at this point

((  JR Z, #28     ## 
}   LD A, L       // A=L
<   INC A         // A=L+1
o   LD L, A       // L=L+1
=   DEC A         // A=L
A   LD B, C       ## 
<   INC A         // A=L+1
!.w LD HL, #772E  // Load address back into HL
w   LD (HL), A    // Save contents of A to memory
.!  LD L, #21     ## 
o   LD L, A       // L=A

Podział dozwolonych instrukcji:

n   op    description
--  ----  -----------
28  LD    LoaD 8-bit or 16-bit register
3   DEC   DECrement 8-bit or 16-bit register
1   INC   INCrement 8-bit or 16-bit register
1   ADD   ADD 8-bit or 16-bit register

Available but useless instructions:
3   JR    Jump Relative to signed 8-bit offset
1   DAA   Decimal Adjust Accumulator (treats the A register as two decimal digits
          instead of two hexadecimal digits and adjusts it if necessary)
1   CPL   1s ComPLement A
1   HALT  HALT the CPU until an interrupt is received

Spośród 39 dozwolonych instrukcji 28 to operacje ładowania (blok od 0x40 do 0x7F to LDinstrukcje jednobajtowe ), z których większość tutaj nie pomaga! Jedyne dozwolone ładowanie do pamięci jest nadal dozwolone, LD (HL), Aco oznacza, że ​​muszę zapisać wartość w A. Ponieważ Ajest to jedyny rejestr z dozwoloną INCinstrukcją, jest to całkiem przydatne!

Nie mogę załadować Az 0x00, ponieważ ASCII 0x00 nie jest dozwolonym znakiem! Wszystkie dostępne wartości są dalekie od 0, a wszystkie instrukcje matematyczne i logiczne zostały niedozwolone! Z wyjątkiem ... Nadal mogę ADD HL, HL, dodaj 16-bit HLdo siebie! Oprócz bezpośredniego ładowania wartości (tutaj nie ma zastosowania!), INKrementacji Ai DECrementacji A, Llub HLto jest jedyny sposób na zmianę wartości rejestru! W rzeczywistości jest jedna specjalistyczna instrukcja, która może być pomocna w pierwszej połowie, ale kłopot z obejściem w drugiej połowie, i instrukcja uzupełniająca, która jest prawie bezużyteczna tutaj i zajmuje tylko miejsce.

Znalazłem więc najbliższą wartość 0, którą mogłem: 0x41. Jak to jest bliskie zeru? W systemie binarnym jest to 0x01000001. Więc zmniejszam, ładuję Li robię ADD HL, HLdwa razy! Lma teraz zero, do którego ładuję ponownie A! Niestety kod ASCII dla ADD HL, HLjest, )więc muszę teraz użyć (dwa razy. Na szczęście (jest JR Z, e, gdzie ejest następny bajt. Więc pożera drugi bajt i muszę tylko upewnić się, że nic nie zrobi, uważając na Zflagę! Ostatnią instrukcją, która wpłynęła na Zflagę, była DEC A(sprzeczna z intuicją, ADD HL, HLnie zmienia jej), a ponieważ wiem, że Aw tym momencie była to 0x40, jest pewna, że Znie jest ustawiona.

Pierwsza instrukcja w drugiej połowie JR Z, #28nic nie zrobi przez pierwsze 255 razy, ponieważ flagę Z można ustawić tylko wtedy, gdy A przepełniło się z 255 do 0. Następnie dane wyjściowe będą błędne, jednak ponieważ i tak zapisuje tylko wartości 8-bitowe nie powinno mieć znaczenia. Kod nie powinien być rozszerzany więcej niż 255 razy.

Kod musi zostać wykonany jako fragment kodu, ponieważ wszystkie dostępne sposoby czystego powrotu zostały niedozwolone. Wszystkie instrukcje RETurn są powyżej 0x80, a kilka dozwolonych operacji Jump może przeskoczyć tylko do dodatniego przesunięcia, ponieważ wszystkie 8-bitowe wartości ujemne zostały również niedozwolone!

CJ Dennis
źródło
6
CO. CO TO JEST.
cloudfeet
4
Teraz widziałem tę odpowiedź, używając GolfScript / J / etc. po prostu wygląda na oszustwo. : p
cloudfeet
Czy istnieją procesory kompatybilne z Z80 z 16-bitowym rejestrem A? Pytam, ponieważ pytanie wymaga, aby kod działał dla N = 32767 .
Dennis
1
@Dennis Aby program działał dla N = 32767 , musi mieć co najmniej 2 x 32767 lub 65534 bajtów. Z80 może adresować tylko 65536 bajtów pamięci, co czyni to niemożliwym zadaniem, ponieważ nie sądzę, żebym mógł uczynić program mniejszym niż 6 bajtów! ARejestr jest zawsze 8 bitów, w przeciwnym razie nie byłoby procesor kompatybilny z Z80. Powiedziałbym, że biorąc pod uwagę wystarczającą pamięć i moc obliczeniową , zostało to tutaj pokryte!
CJ Dennis
1
@ Dennis Rozumiesz, dlaczego żaden procesor zgodny z Z80 nie będzie miał Arejestru innego niż 8 bitów? Zmiana na 16-bitową złamałaby kod polegający na przykład na 255 + 1 = 0. Trzeba wymyślić procesor, nazwijmy go Z160, który używa domyślnego rejestru 16-bitowego, ale nadal używa tego samego zestawu instrukcji 8-bitowych z Z80. Dziwne!
CJ Dennis
19

J, 16 14 bajtów

(_=_)]++[(_=_)

Zastosowania:

   (_=_)]++[(_=_)
1
   (_=_)]+(_=_)]++[(_=_)+[(_=_)
2
   (_=_)]+(_=_)]+(_=_)]++[(_=_)+[(_=_)+[(_=_)
3

Wyjaśnienie:

  • J ocenia od prawej do lewej.

  • (_=_)jest inf equals infprawdą, ma wartość 1, więc wyrażenie staje się 1+]...[+1. ( (8=8)również by działało, ale wygląda to fajniej. :))

  • [i ]zwracają odpowiednio lewy i prawy argument, jeśli mają 2 argumenty. Jeśli otrzymają tylko 1, zwracają to.

  • +dodaje 2 argumenty. Jeśli otrzyma tylko 1, zwraca to.

Teraz oceńmy wyrażenie poziomu 3 (od prawej do lewej):

(_=_)]+(_=_)]++[(_=_)+[(_=_)  NB. (_=_) is 1

1]+1]+1]++[1+[1+[1  NB. unary [, binary +

1]+1]+1]++[1+[2  NB. unary [, binary +

1]+1]+1]++[3  NB. unary [, unary +

1]+1]+1]+3  NB. unary +, binary ]

1]+1]+3  NB. unary +, binary ]

1]+3  NB. unary +, binary ]

3

Jak widzimy, dodaje się prawą połowę z nich 1, a lewą stronę z nich 1pomija się, co daje pożądaną liczbę całkowitą N, poziom lustra.

Wypróbuj online tutaj.

randomra
źródło
12

Haskell, 42 bajty

(8-8)-(-(8-8)^(8-8))--((8-8)^(8-8)-)-(8-8)

Na szczęście komentarz liniowy w Haskell (-> --) jest dublowany, a połowa (-> -) jest prawidłową funkcją. Reszta to trochę matematyki, aby uzyskać liczby 0i 1. Zasadniczo mamy (0)-(-1)komentarz N=0i dopisujemy (0)-(-1)-na każdym etapie.

W przypadku liczb zmiennoprzecinkowych są dopuszczone do produkcji, możemy budować 1od 8/8i dostać się z 26 bajtów:

Haskell, 26 bajtów

(8-8)-(-8/8)--(8\8-)-(8-8)

Wyjścia 1.0, 2.0itp

nimi
źródło
2
Jest to technicznie nieprawidłowe, ponieważ musi to być pełny program.
Hobby Calvina
@ Calvin'sHobbies: Rozumiem. Czy mamy konsensus w sprawie minimalnych wymagań dla pełnego programu? Przeszukałem meta, ale znalazłem tylko dyskusję na temat funkcji, a nie programów. W zależności od definicji pełnego programu może być w stanie naprawić moje rozwiązanie.
nimi
Nazwałbym go pełnym programem, jeśli możesz zapisać go w pliku, program.hsa następnie uruchomić $ runhaskell program.hsz wiersza poleceń i zobaczyć wynik. Nie znam Haskella, więc nie mogę powiedzieć dokładnie, co należy zmienić.
Calvin's Hobbies
2
@ Calvin'sHobbies: runhaskellto skrypt powłoki, który konfiguruje środowisko i wreszcie wywołuje ghckompilator Haskell. Można uruchomić bezpośrednio z mojego kodu ghc: ghc -e "(8-8)-(-8/8)--(8\8-)-(8-8)". Uruchamia się, ghcktóre ocenia kod podany jako argument, drukuje wynik i kończy działanie. Bez REPL, bez interakcji. Oczywiście dodałoby to +1 do liczby bajtów dla -e.
nimi
@nimi: -ew tym przypadku nie wpływa na wynik. Nie liczymy bajtów perl -Eani gcc -std=c99żadnego z nich.
Dennis
11

CJam, 14 bajtów

]X+:+OooO+:+X[

Wypróbuj online w interpretatorze CJam: N = 0 , N = 1 , N = 2 , N = 3 , N = 41

Pamiętaj, że ten kod kończy się komunikatem o błędzie. Za pomocą interpretera Java ten komunikat o błędzie można ukryć, zamykając lub przekierowując STDERR. 1

Jak to działa

W lewej połowie dzieje się:

  • ] otacza cały stos w tablicę.

  • Xdołącza się 1do tej tablicy.

  • :+ oblicza sumę wszystkich elementów tablicy.

  • Oo wypisuje zawartość pustej tablicy (tzn. nic).

W pierwszej prawej połowie następują:

  • o wypisuje liczbę całkowitą na stosie, która jest pożądanym wyjściem.

  • O+ próbuje dołączyć pustą tablicę do najwyższego elementu stosu.

    Jednak stos był pusty przed wypchnięciem O. To kończy się niepowodzeniem i kończy działanie programu.

Pozostały kod jest po prostu ignorowany.

1 Według meta-ankiety Czy należy zezwolić na przesyłanie zgłoszeń z błędem? jest to dozwolone.

Dennis
źródło
Byłbym sceptycznie nastawiony do zaakceptowania tego z powodu błędu, ale ponieważ nie wygrywa, nie martwię się zbytnio.
Calvin's Hobbies
Takie zadania są zaskakująco trudne w CJam, biorąc pod uwagę, że jest to język golfowy. Nawet błąd składniowy (np. Niezdefiniowany operator) w niewykonanym bloku uniemożliwi wykonanie całego programu. Nadal próbuję pozbyć się błędu.
Dennis