Wskazówki dotyczące gry w golfa w CJam


43

CJam to inspirowany golfem język golfowy oparty na stosach, stworzony przez aditsu użytkownika PPCG .

Tak więc, zgodnie z innymi poradami dotyczącymi konkretnych języków:

Jakie masz ogólne wskazówki na temat gry w golfa w CJam? Proszę zamieścić jedną wskazówkę na odpowiedź.


4
Zobacz także Wskazówki dotyczące gry w golfa w GolfScript ; języki są na tyle podobne, że wiele sztuczek można dostosować w obu kierunkach.
Ilmari Karonen

2
@IlmariKaronen Po przejrzeniu odpowiedzi w tym pytaniu powiedziałbym, że tylko około połowa z nich dotyczy CJam, ze względu na różnice składniowe lub logiczne w językach.
Optymalizator

Odpowiedzi:


23

Prawidłowy moduł dla liczb ujemnych

Często denerwujące jest to, że wynik operacji modulo daje ten sam znak, co pierwszy operand. Np. -5 3%Daje -2zamiast 1. Najczęściej nie chcesz tego drugiego. Naiwną poprawką jest zastosowanie modulo, dodanie dzielnika raz i ponowne zastosowanie modulo:

3%3+3%

Ale to jest długie i brzydkie. Zamiast tego, możemy skorzystać z faktu, że indeksowanie tablicy jest zawsze modułowe i robi działać poprawnie z ujemnymi wskaźnikami. Po prostu przekształcamy dzielnik w zakres i uzyskujemy dostęp do tego:

3,=

Stosowane do -5daje to 1zgodnie z oczekiwaniami. I to tylko jeden bajt dłużej niż wbudowany %!

Jeśli moduł ma potęgę 2, możesz zapisać kolejny bajt za pomocą bitowej arytmetyki (która jest również znacznie szybsza). Porównać:

32,=
31&

W specjalnym przypadku 65536 == 2^16innego bajtu można zapisać, wykorzystując zachowanie zawijania typu znaku:

ci

13

Przesuwanie połączonych zakresów znaków

  • Ciąg zawierający wszystkie cyfry "0123456789"można zapisać jako

    A,s
    
  • Wielkie litery ASCII ( A-Z) można wypychać jako

    '[,65>
    

    który generuje ciąg wszystkich znaków do Z , a następnie odrzuca pierwsze 65 (do @ ).

  • Wszystkie litery ASCII ( A-Za-z) można wcisnąć jako

    '[,65>_el+
    

    który działa jak wyżej, a następnie tworzy kopię, konwertuje na małe litery i dołącza.

    Ale jest na to krótszy sposób!

    Wtedy często pomijany ^operator (różnice symetryczne dla list) pozwala tworzyć te same zakresy, oszczędzając trzy bajty:

    '[,_el^
    

    '[,tworzy zakres wszystkich znaków ASCII do Z , _eltworzy małą literę i ^zachowuje tylko znaki obu ciągów, które pojawiają się w jednym, ale nie w obu.

    Ponieważ wszystkie litery w pierwszym ciągu są pisane wielkimi literami, wszystkie w drugim są małe, a wszystkie znaki nieliterowe są w obu ciągach, w wyniku czego powstaje ciąg liter.

  • Alfabet RFC 1642 Base64 ( A-Za-z0-9+/) można wypychać przy użyciu powyższej techniki i dodając inne niż litery:

    '[,_el^A,s+"+/"+
    

    Równie krótki sposób popychania tego sznurka wykorzystuje wyłącznie różnice symetryczne:

    "+,/0:[a{A0":,:^
    

    Jak znaleźć ciąg na początku?

    Wszystkie wykorzystane zakresy znaków ( A-Z, a-z, 0-9, +, /) może zostać przesunięta jako różnicę symetryczną do zakresu, który rozpoczyna się na bajt null, a mianowicie 'A,'[,^, 'a,'{,^, '0,':,^, '+,',,^i '/,'0,^.

    Dlatego wykonanie :,:^dalej "A[a{):+,/0"popchnie pożądane postacie, ale nie we właściwej kolejności.

    Jak znaleźć właściwą kolejność? Brutalna siła na ratunek! Program

    '[,_el^A,s+"+/"+:T;"0:A[a{+,/0"e!{:,:^T=}=
    

    iteruje wszystkie możliwe kombinacje łańcucha, stosuje :,:^i porównuje wynik z pożądanym wyjściem (bezpośredni link ).

  • Alfabet radix-64 użyty np. Przez crypt ( .-9A-Za-z) można wygenerować przy użyciu powyższej metody:

    ".:A[a{":,:^
    

    To najkrótsza metoda, jaką znam.

    Ponieważ wszystkie znaki w żądanym wyjściu mają kolejność ASCII, iteracja po permutacjach nie jest potrzebna.

  • Nie wszystkie łączone zakresy znaków można przesuwać w żądanej kolejności za pomocą :,:^.

    Na przykład zakresu 0-9A-Za-z;-?nie można przesuwać, wykonując :,:^dowolną permutację "0:A[a{;@".

    Możemy jednak znaleźć obróconą odmianę pożądanego ciągu, który może, używając kodu

    A,'[,_el^'@,59>]s2*:T;"0:A[a{;@"e!{:,:^T\#:I)}=Ip
    

    który wydrukuje (bezpośredni link ):

    10
    0:@[a{A;
    

    To znaczy że

    "0:@[a{A;":,:^Am>
    

    ma taki sam efekt jak

    A,'[,_el^'@,59>]s
    

    który może być użyty tylko z pustym stosem bez przygotowania a [.


11

Unikać {…} {…}?

Załóżmy, że masz stos na liczbach całkowitych. Jeśli jest nieparzysty, należy go pomnożyć przez 3 i dodać 1; w przeciwnym razie chcesz podzielić to przez 2.

„Normalna” instrukcja if / else wyglądałaby tak:

_2%{3*)}{2/}?

Jednak korzystanie z bloków zwykle nie jest dobrym rozwiązaniem, ponieważ {}{}dodaje już cztery bajty. ?można również użyć do wybrania jednego z dwóch elementów na stosie:

_2%1$3*)@2/?

Jest to jeden bajt krótszy.


Blok-? z pustą instrukcją if jest zawsze nie do przyjęcia. Na przykład,

{}{2/}?

jest o dwa bajty dłuższy niż

{2/}|

Jeśli zamiast tego masz

{2/}{}?

a rzeczą, którą sprawdzasz, jest nieujemna liczba całkowita, możesz to zrobić

g)/

Nowe {}&i {}|są przydatne, ale czasem problematyczne, jeśli nie możesz zagracać stosu.

Jednak w przypadku

_{…}{;}?

zamiast tego możesz użyć zmiennej tymczasowej:

:T{T…}&

1
!)/i g)/są krótsze w przykładach.
jimmy23013,

11

Instrukcje zamiany

CJam nie ma instrukcji switch. Zagnieżdżone, jeśli instrukcje działają równie dobrze, ale {{}{}?}{}?mają już 12 bajtów ...

Jeśli uda nam się przekształcić warunek w małą, nieujemną liczbę całkowitą, możemy przekształcić wszystkie instrukcje case w rozdzielany ciąg znaków i ocenić odpowiedni wynik.

Na przykład, jeśli chcemy wykonać, code0jeśli liczba całkowita stosu wynosi 0 , code1jeśli jest to 1 , a code2jeśli jest to 2 , możemy użyć

_{({code2}{code1}?}{;code0}?

lub

[{code0}{code1}{code2}]=~

lub

"code0 code1 code2"S/=~

S/dzieli ciąg na ["code0" "code1" "code2"], =wyodrębnia odpowiedni fragment i ~ocenia kod.

Kliknij tutaj, aby zobaczyć instrukcje przełączników w akcji.

Wreszcie, zgodnie z sugestiami @ jimmy23013 i @RetoKoradi, w niektórych przypadkach możemy jeszcze bardziej skrócić przełącznik. Powiedzmy code0, code1i code2ma długość L 0 , L 1 i L 2 , odpowiednio.

Jeżeli L 0 = L 1 ≥ L 2

"code0code1code2"L/=~

zamiast tego można użyć, gdzie Ljest L 0 . Zamiast dzielić na separator, /dzieli tutaj łańcuch na kawałki o równej długości.

Jeżeli L 0 ≥ L 1 ≥ L 2 ≥ L 0 - 1 ,

"cccooodddeee012">3%~

można zamiast tego użyć. >usuwa 0, 1 lub 2 elementy z początku łańcucha i 3%wyodrębnia co trzeci element (zaczynając od pierwszego).


Czy w ostatnim przykładzie ma to jakąś przewagę "code0code1code2"5/=~? Wydaje mi się to o wiele prostsze i ma tę samą długość.
Reto Koradi,

@RetoKoradi Jeśli wszystkie fragmenty mają tę samą długość, nie ma żadnej przewagi. Dla innej długości, twoja metoda może być zarówno krótsza, jak i dłuższa niż metoda modułu.
Dennis

11

Gra w golfa wspólne wartości tablic i ciągów

Istnieją pewne krótkie tablice lub ciągi znaków, które pojawiają się co jakiś czas, np. W celu inicjowania siatek. Naiwnie mogą one kosztować 4 lub więcej bajtów, więc warto poszukać operacji na wbudowanych wartościach, które dadzą ten sam wynik. Szczególnie przydatna jest konwersja bazy.

  • [0 1]można zapisać jako 2,.
  • [1 0]można zapisać jako YYb(tj. 2 w formacie binarnym).
  • [1 1]można zapisać jako ZYb(tj. 3 w formacie binarnym).
  • Macierz [[0 1] [1 0]]można zapisać jako 2e!.
  • [LL] można zapisać jako SS/(dzielenie pojedynczej spacji przez spacje).
  • "\"\""można zapisać jako L`.
  • "{}"można zapisać jako {}s.

Ten ostatni można rozszerzyć na przypadki, w których wszystkie typy nawiasów mają zapisywać kolejny bajt:

  • "[{<()>}]"można zapisać jako {<()>}a`.
  • "()<>[]{}"można zapisać jako {<()>}a`$.

Zwłaszcza podstawowa sztuczka konwersji może być użyteczna, aby pamiętać o niektórych mniej znanych przypadkach, które pojawiają się co jakiś czas. Np. [3 2]Byłoby E4b(14 w bazie 4).

W jeszcze rzadszych przypadkach może okazać się mfprzydatny operator faktoryzacji . Np . [2 7]Jest Emf.

Rozszerz tę listę, jeśli natkniesz się na inne przykłady.


10

Czyszczenie stosu

Jeśli chcesz po prostu wyczyścić cały stos, zawiń go w tablicę i pop:

];

Trochę trudniejsze jest to, że wykonałeś wiele obliczeń, ale chcesz tylko zachować element najwyższego stosu i odrzucić wszystko pod spodem. Naiwnym podejściem byłoby przechowywanie górnego elementu w zmiennej, czyszczenie stosu, wypychanie zmiennej. Istnieje jednak znacznie krótsza alternatywa: zawiń stos w tablicę i wyodrębnij ostatni element:

]W=

(Dzięki Optimizer, który mi to pokazał pewnego dnia.)

Oczywiście, jeśli na stosie \;są tylko dwa elementy, jest on krótszy.


\;wyskakuje tylko element poniżej warunków. Miałeś na myśli ;;?
CalculatorFeline,

1
@CalculatorFeline druga połowa odpowiedzi dotyczy wyczyszczenia wszystkiego oprócz TOS.
Martin Ender,

9

e i potęgi dziesięciu

Tak jak w wielu innych językach, możesz pisać 1e3zamiast 1000w CJam.

Działa to dla baz niecałkowitych, a nawet dla wykładników niecałkowitych. Na przykład 1.23e2wypycha 123.0 i 1e.5wypycha 3.1622776601683795 (pierwiastek kwadratowy z 10 ).

Co nie jest od razu oczywiste, 1e3to tak naprawdę dwa tokeny:

  • 1wypycha liczbę całkowitą 1 na stosie.

  • e3mnoży to przez 1000 .

Dlaczego to takie ważne?

  • Możesz przywołać e<numeric literal>coś, co już jest na stosie.

    2 3 + e3 e# Pushes 5000.
    
  • Możesz zmapować e<numeric literal>tablicę.

    5 , :e3  e# Pushes [0 1000 2000 3000 4000].
    

9

Normy euklidesowe

Prostym sposobem obliczenia normy euklidesowej wektora, tj. Pierwiastka kwadratowego z sumy kwadratów jego elementów, jest:

2f#:+mq

Istnieje jednak znacznie krótsza droga.

mh, operator przeciwprostokątny, wyrzuca dwie liczby całkowite a i b ze stosu i wypycha sqrt (a 2 + b 2 ) .

Jeśli mamy wektor x: = [x 1 … x n ], n> 1 na stosie :mh(redukcja przez przeciwprostokątną) osiągnie:

  • Pierwsze x 1 i x 2 są wypychane i mhwykonywane, pozostawiając sqrt (x 1 2 + x 2 2 ) na stosie.

  • Następnie x 3 jest wypychane i mhwykonywane ponownie, pozostawiając
    sqrt (sqrt (x 1 2 + x 2 2 ) 2 + x 3 2 ) = sqrt (x 1 2 + x 2 2 + x 3 2 ) na stosie.

  • Po przetworzeniu x n pozostaje nam sqrt (x 1 2 +… x n 2 ) , euklidesowa norma x .

Jeśli n = 1 i x 1 <0 , powyższy kod da niepoprawny wynik. :mhzdziała bezwarunkowo. (Podziękowania dla @ MartinBüttner za zwrócenie na to uwagi.)

Po raz pierwszy użyłem tej sztuczki w tej odpowiedzi .


2
Ma to oczywiście wpływ na analizę numeryczną twojego programu ...
Peter Taylor

8

Konwertuj z bazy n za pomocą listy liczb większej niż n

CJam konwertuje listę na liczbę z tym wzorem: A 0 * n l + A 1 * n l-1 + A 2 * n l-2 + A l * n 0 (z nieujemną wartością n). njest podstawą i ljest długością listy. Oznacza to, że A i może być dowolną liczbą całkowitą, która nie musi znajdować się w zakresie [0,n).

Kilka przykładów:

  • 0bwyodrębnia ostatni element i rzuca go na liczbę całkowitą. Działa jak W=ii zapisuje bajt, jeśli nie był liczbą całkowitą. Ale wszystko inne na liście musi być również zdolne do rzutowania na liczbę całkowitą.
  • 1bzwraca sumę. Działa jak :i:+i zapisuje dwa bajty, jeśli nie były liczbami całkowitymi. Działa również z pustymi listami, podczas gdy :+nie działa.
  • [i{_1&9 32?_@\m2/}16*;]W%:ckonwertuje znak na ciąg zakończeń linii i tabulatorów, które można konwertować z powrotem 2bc. Funkcja kodowania nie jest łatwa do grania w programie golfowym. Ale zwykle tego nie potrzebujesz.
  • Możesz użyć następującego kodu, aby przekonwertować ciąg znaków na znaki Unicode spoza 16 bitów, które można przekonwertować z powrotem 2A#b128b:c. (Wyjaśnienia zostaną dodane później. A może napiszę nową wersję później.)

    128b2A#b         " Convert to base 1024. ";
    W%2/)W%\:+       " Convert to two base 1024 digit groups. ";
    [0X@
    {
      _54+
      @I+_Am>@\-
      _Am<@+ 0@-@1^
    }fI
    ]);)
    @\+[~+]2A#b_2G#<!{2A#b}*
    \W%+:c
    

Podobna metoda działa z dowolnym zestawem nliczb całkowitych, które mają różne wartości mod n, jeśli możesz znaleźć sposób na pozbycie się najbardziej znaczącej cyfry.


8

Używanie $jako trójskładnikowe jeśli

Kiedy nie przeszkadza ci wyciek pamięci, tj. Pozostawienie nieużywanych elementów na stosie, które później wyczyścisz ];, operator kopiowania $może być przydatnym substytutem dla operatora trójskładnikowego ?.

? działa dobrze, jeśli uda ci się obliczyć warunek przed popchnięciem dwóch elementów do wyboru, ale częściej stan nie zależy od tych elementów, a umieszczenie go na nich daje o wiele bardziej naturalny efekt.

Jeśli masz A B Cna stosie, możesz wykonać

!$

zamiast

\@?

kopiować, Bjeśli Cjest to prawdą i Ainaczej.

Jeśli Cjest to wartość logiczna ( 0lub 1), można wykonać

$

zamiast

@@?

kopiować, Ajeśli Cjest to prawdą i Binaczej.


Z perspektywy czasu jest to dość oczywista sztuczka, ale nigdy wcześniej o tym nie myślałem. Użyłem go po raz pierwszy w tej odpowiedzi .
Dennis

7

Mapa list zagnieżdżonych

Załóżmy, że masz zagnieżdżoną listę, na przykład macierz:

[[0 1 2][3 4 5][6 7 8]]

Lub tablica ciągów:

["foo""bar"]

I chcesz zmapować blok na poziom zagnieżdżony (tj. Zastosować go do każdej liczby lub każdego znaku). Naiwnym rozwiązaniem jest zagnieżdżenie %:

{{...}%}%

Możesz jednak wcisnąć blok wewnętrzny na stos, a następnie użyć f%. fjest „mapuj z dodatkowym parametrem”, więc będzie %mapowany na listę zewnętrzną, używając bloku jako drugiego parametru:

{...}f%

Zapisuje dwa bajty.

Kolejną zgrabną sztuczką, aby zrobić coś takiego for (i=0; i<5; ++i) for (j=0; j<5; ++j) {...}jest

5,_f{f{...}}

Zewnętrzne fmapuje na pierwszy zakres, podając drugi zakres jako dodatkowy parametr. Ale teraz, jeśli użyjesz go fponownie, tylko górny element stosu jest tablicą, więc fodwzorowujesz na nim blok wewnętrzny, podając zewnętrzną „zmienną iteracyjną” jako dodatkowy parametr. Oznacza to, że wewnętrzny blok jest uruchamiana z ii jna stos.

Ma taką samą liczbę znaków, jak zwykłe mapowanie bloku na iloczyn kartezjański (chociaż ten drugi staje się krótszy, jeśli potrzebujesz par jako tablic):

5,_m*{~...}%

Różnica polega na tym, że ta wersja daje jedną tablicę wyników dla wszystkich par, podczas gdy podwójna fdaje zagnieżdżoną listę, co może być przydatne, jeśli chcesz zapisać wyniki w siatce, przy czym zmienne iteratora są współrzędnymi.

Dzięki Dennisowi za pokazanie mi tej sztuczki.

0.6.4 Aktualizacja

fi :zostały teraz znacznie ulepszone poprzez włączenie dowolnego innego operatora, w tym siebie. Oznacza to, że możesz teraz zaoszczędzić jeszcze więcej bajtów. Mapowanie operatora na zagnieżdżonej liście jest teraz jeszcze krótsze:

{:x}%
{x}f%
::x

Nie pomaga to jednak w mapowaniu bloków na listy zagnieżdżone.

Jeśli chodzi o stosowanie bloków lub operatorów do produktu kartezjańskiego, teraz również stało się to krótsze, zarówno dla bloków, jak i operatorów:

5,_f{f{...}}
5,_ff{...}

5,_f{fx}
5,_ffx

Fajne jest to, że możesz je teraz zagnieżdżać. Możesz więc równie łatwo zastosować operatora do trzeciego poziomu w dół listy:

:::x

Lub blok z pewnymi sztuczkami:

{...}ff%

Świetna aktualizacja. Ale wciąż nie ma f~...
jimmy23013

@ user23013 foczekuje, że operator binarny, ~jest jednoargumentowy; może chciałeś :~? Możemy również omówić to na czacie
aditsu

Czy brakuje mi czegoś w tej aktualizacji 0.6.4? Nadal dostaję komunikaty o błędach podczas wykonywania tych sztuczek, np. Unhandled char after ':': :( Link )
Runer112,

2
@ Runer112 Działa dla mnie. Upewnij się, że przeładowałeś poprawnie (tj. Nie z pamięci podręcznej). W zależności od przeglądarki Ctrl + F5 powinien działać.
Martin Ender,

@ MartinBüttner To rzeczywiście było spowodowane przez głupie buforowanie. Dzięki.
Runer112

7

Wektoryzowane operatory dla sztuki ASCII

W przypadku wielu wyzwań artystycznych ASCII przydatne jest wygenerowanie dwóch różnych wzorów w celu ich późniejszego nałożenia. Wektoryzowani operatorzy mogą być bardzo pomocni w osiągnięciu różnych rodzajów superpozycji.

Jedną przydatną właściwością wektoryzacji operatora jest to, że operator jest wykonywany tylko raz dla każdego elementu krótszego łańcucha / tablicy, podczas gdy elementy większego, które nie mają odpowiedników, pozostają nietknięte.

  • .e<

    Minimalna e<praca operatora dla par ciągów, znaków, tablic i liczb całkowitych; wyskakuje dwa przedmioty ze stosu i popycha niższy na plecach.

    Ponieważ spacja ma niższy punkt kodowy niż wszystkie inne drukowalne znaki ASCII, .e<można jej użyć do „wymazania” części wygenerowanego wzoru:

    "\/\/\/\/\/" "    " .e<
    
    e# This pushes "    \/\/\/".
    

    Aby zobaczyć pełny przykład, zobacz moją odpowiedź do Me Want Honeycomb .

  • .e>

    Operator maksymalny e>działa jako operator minimalny, z wynikiem odwrotnym.

    Ponownie, z powodu niskiego punktu kodowego spacji, .e>można użyć do wstawienia wzoru znaków do wydruku w bloku spacji:

    [[" " " " " " " "] [" " " " " " " "]][["+" "" "-" ""]["" "*" "" "/"]] ..e>
    
    e# This pushes [["+" " " "-" " "] [" " "*" " " "/"]].
    

    Pełny przykład znajduje się w mojej odpowiedzi na Seven Slash Display .

  • .e&

    Logiczny operator AND e&wypycha lewy argument, jeśli jest fałszem, a prawy argument w przeciwnym razie.

    Jeśli żaden wzorzec nie zawiera elementów fałszywych, można tego użyć do bezwarunkowego nałożenia jednego wzoru na inny:

    "################" " * * * *" .e&
    
    e# This pushes " * * * *########".
    

    Pełny przykład znajduje się w mojej odpowiedzi na Wydrukuj flagę amerykańską! .

  • .e|

    Logicznego operatora OR e|można używać jak wyżej, z odwróconą kolejnością argumentów:

    " * * * *" "################" .e|
    
    e# This pushes " * * * *########".
    

6

Służy &do sprawdzania, czy element znajduje się na liście

Dla

1 [1 2 3] #W>
1 [1 2 3] #)

Możesz użyć

1 [1 2 3] &,
1 [1 2 3] &

zamiast tego zwraca odpowiednio 0/1 i truey / falsey.


6

z i nieprostokątne tablice

Operator zip ztransponuje wiersze i kolumny dwuwymiarowej tablicy 1 A , której elementami mogą być iterowalne.

W przypadku tablic nieprostokątnych - w przeciwieństwie do wbudowanych zipfunkcji, np. Python (obcina wiersze do tej samej długości) lub Ruby ( nilwypełnia rzędy ) - CJam po prostu konwertuje kolumny tablicy na rzędy, ignorując ich długości i luki.

Na przykład spakowanie tablicy

[
  [1]
  [2 4]
  [3 5 6]
]

jest równoważne skompresowaniu tablicy

[
  [1 4 6]
  [2 5]
  [3]
]

lub tablica

[
  [1]
  [2 4 6]
  [3 5]
]

gdy wszystkie trzy działania się przesuwają

[
  [1 2 3]
  [4 5]
  [6]
]

na stosie.

Chociaż oznacza to, że znie jest to inwolucja (co byłoby przydatne w niektórych przypadkach), ma kilka zastosowań.

Na przykład:

  • Możemy wyrównać kolumny tablicy do góry (tj. Zamienić pierwszą tablicę na drugą) poprzez dwukrotne skompresowanie:

    zz
    
  • Drobne modyfikacje powyższej metody można zastosować do podobnych problemów.

    Na przykład, aby wyrównać kolumny tablicy do dołu (tj. Aby zamienić drugą tablicę w pierwszą), możemy dwukrotnie spakować zip z odwróconą kolejnością wierszy:

    W%zzW%
    
  • Biorąc pod uwagę tablicę ciągów, możemy obliczyć długość najdłuższego ciągu w następujący sposób:

    :,:e>
    

    Jednak poprzez skompresowanie i obliczenie liczby wierszy wyniku możemy zapisać trzy bajty:

    z,
    

1 Jeśli którykolwiek z „wierszy” A nie jest iterowalny, ztraktuje je jako singletony, więc zipowanie działa dla dowolnych tablic.


1
Po prostu inny sposób wizualizacji tego samego, ale dla mnie zachowanie jest o wiele bardziej logiczne, jeśli wyobrażam sobie zprzekształcanie kolumn w wiersze, a puste wartości są pomijane. W przykładzie pierwsza kolumna na wejściu to 1, 2, 3, druga kolumna to 4, 5 (pusta pozycja jest pomijana), a trzecia kolumna to 6. To są wówczas wiersze wyniku.
Reto Koradi

@RetoKoradi To o wiele lepszy sposób na opisanie tego.
Dennis

6

Wyjątki

Wszystkie wyjątki są śmiertelne w CJam. Ponieważ dane wyjściowe do STDERR są domyślnie ignorowane , możemy to wykorzystać na naszą korzyść.

Wszyscy operatorzy w CJam pracują, wyrzucając zero lub więcej elementów ze stosu, wykonując jakieś zadanie i pchając zero lub więcej elementów na stosie. Występują wyjątki podczas wykonywania zadania, więc nadal wyskakuje elementy, ale w zamian nic nie jest przesyłane.

Oto kilka przypadków użycia:

  • Czyszczenie małego stosu

    Aby wyczyścić stos zawierający dwa elementy, @można użyć. @próbuje zerwać trzy elementy stosu, ale nie udaje się po pęknięciu drugiego.

    Każdy inny operator, który wyskakuje z trzech elementów, miałby ten sam cel.

    Zobacz to w akcji tutaj .

  • Usuwanie dwóch lub trzech elementów ze stosu

    Dowolny operator, który nie jest zaimplementowany dla tych konkretnych elementów, może zostać użyty do usunięcia dwóch lub trzech elementów ze stosu bezpośrednio przed wyjściem.

    Aby wyskoczyć z dwóch elementów, bdziała, jeśli jeden z nich jest postacią lub żaden z nich nie jest liczbą całkowitą.

    Aby wyskoczyć z trzech elementów, tdziała, jeśli żaden z dwóch najbardziej dolnych elementów nie jest iterowalny, najniższy element iteracyjny jest pusty lub żaden z nich nie jest liczbą całkowitą.

  • Wyjście z pętli

    Czasami musimy wyjść z pętli, gdy liczba całkowita jest równa zero lub łańcuch staje się zbyt krótki. Zamiast testować te warunki, jeśli zaangażowane operacje zakończą się niepowodzeniem dla zera, pustego łańcucha lub singletonów, możemy po prostu pozwolić programowi na naturalny kurs.

    Przykład dotyczący arytmetyki można znaleźć tutaj .

    Przykład dotyczący ciągów znaków znajduje się tutaj .

  • Warunkowa realizacja

    Jeśli kod źródłowy nie powinien być wykonywany dla niektórych typów danych wejściowych, czasami możemy użyć operatora, który zawiedzie tego rodzaju dane wejściowe.

    Na przykład inie powiedzie się w przypadku ciągów, które nie są wartościami całkowitymi, i ewzawiedzie w przypadku ciągów o długości 0 lub 1.

    Zobacz to w akcji tutaj .


5

Max / Min od tablicy

Oto jeden na początek!

Gdy potrzebujesz znaleźć maksymalną lub minimalną liczbę z tablicy, najłatwiejszym i najmniejszym sposobem jest posortowanie tablicy, a następnie wyjęcie pierwszego lub ostatniego elementu.

Więc jeśli tablica jest zmienna A

A$W=

jest maksimum i

A$0=

jest minimum.

Uzyskaj oba w tym samym czasie jest również możliwe

A$)\0=

Może się to wydawać oczywiste po przeczytaniu, ale pierwsza próba każdego dąży do użycia e<lub e>iteracji w tablicy, co wygląda jak

A{e<}*

co jest o 2 bajty dłuższe, a nawet dłuższe, jeśli chcesz zarówno maksimum, jak i min.


Oczywiście, jeśli nie przeszkadza ci reszta tablicy pozostającej na stosie, możesz faktycznie użyć (i )zamiast 0=i W=.
Martin Ender

Teraz jest :e<i:e>
aditsu

@aditsu Chociaż nie są one krótsze niż wskazówka powyżej.
Optymalizator

5

Użyj znacznika czasu dla dużych liczb

Jeśli potrzebujesz bardzo dużej, ale dowolnej liczby, zwykle albo użyjesz notacji naukowej jak, 9e9albo podniesiesz jedną z dużych wbudowanych zmiennych do podobnej mocy, jak KK#. Jeśli jednak nie zależy ci na tym, jaka jest rzeczywista liczba i nie musi ona być taka sama (np. Jako górna granica liczby losowej), możesz to zrobić w dwóch bajtach, używając

es

zamiast. Daje to bieżący znacznik czasu w milisekundach i jest rzędu 10 12


3
Pamiętaj również, że jeśli chcesz mieć dużą dowolną liczbę i chcesz odrzucić liczbę dodatnią razem, możesz użyć e9.
jimmy23013,

5

Sprawdzanie, czy dwa ciągi / tablice nie są równe

Czasami potrzebujesz prawdziwej wartości, gdy dwa łańcuchy lub tablice nie są równe, i wartości fałszowania, jeśli są. Oczywistym rozwiązaniem są dwa bajty:

=!

Sprawdź równość i odwróć wynik. Jednak pod pewnymi warunkami możesz użyć

#

Po #zastosowaniu do dwóch tablic faktycznie szuka drugiej tablicy jako podtablicy pierwszej (i daje indeks, od którego zaczyna się podtablica). Więc jeśli dwa tablice są takie same, podtablica zostanie znaleziona na początku i da 0, co jest fałszem. Ale jeśli nie można znaleźć drugiej tablicy, da -1ona prawdę.

Powodem, dla którego potrzebujemy dodatkowego warunku dla dwóch tablic, jest to, że daje to również wartość fałszowania, jeśli druga tablica jest nietrywialnym przedrostkiem pierwszego, np .:

"abc""ab"#

daje, 0chociaż ciągi nie są takie same. Najprostszym warunkiem wykluczającym ten przypadek jest to, że wiesz, że obie tablice będą tej samej długości - w takim przypadku, jeśli jeden jest przedrostkiem drugiego, wiesz, że są one równe. Ale w szczególnych okolicznościach mogą występować słabsze warunki, które są wystarczające. Na przykład, jeśli wiesz, że ciągi są sortowane, przedrostek zawsze będzie pierwszym ciągiem, a nie drugim.


5

c i 16-bitowe liczby całkowite

Aby dodać (lub odjąć) 16-bitowe liczby całkowite bez znaku z odpowiednim zawijaniem, możesz użyć +65536%lub +2G#%.

Jednak,

+ci

jest znacznie krótszy. Znaki zawijają się wokół 65536 , więc rzut na Character ( c), a następnie Long ( i) ma podobny efekt 65536%, z tą dodatkową korzyścią, że wynik nie będzie ujemny.

Tej samej sztuczki można użyć do przepchnięcia 65535 :

Wci

4

Zestawy mocy

Załóżmy, że masz tablicę i chcesz tablicę ze wszystkimi możliwymi podzestawami tej tablicy. Sztuką jest zacząć od pustej tablicy, a następnie dla każdego elementu zduplikować podzbiory, które już masz, i dodać do nich nowy element (zachowując poprzedni wynik tam, gdzie element nie został dodany ). Zauważ, że musisz zainicjować stos za pomocą przypadku podstawowego, tj. Tablicy zawierającej tylko pustą tablicę: Może to wyglądać tak:

[1 2 3 4 5]La\{1$f++}/

Zaletą tego jest to, że możesz natychmiast uruchomić obliczenia na podzbiorze, potencjalnie bez dodanych znaków. Powiedz, że chcesz produktów wszystkich podzbiorów. W takim przypadku podstawowym przypadkiem jest tablica zawierająca 1i na każdym kroku bierzesz poprzednią listę możliwych produktów, powielasz ją i mnożesz wszystko w duplikacie przez nowy element:

[1 2 3 4 5]1a\{1$f*+}/

4

Sprawdź, czy elementy na liście są takie same

Myślę, że warto o tym wspomnieć. Posługiwać się:

)-

Zwraca prawdę, jeśli nie wszystkie są takie same, lub pustą listę, jeśli wszystkie są takie same. Błędy, jeśli lista jest pusta.

W przypadku, gdy wyodrębniony element może być samą tablicą (lub łańcuchem):

)a-

Użyj !lub, !!aby uzyskać wartości logiczne. W przypadku, gdy wyodrębniony element może być tablicą i istnieją najwyżej dwa rodzaje różnych elementów, a chcesz, aby wynosił 1, jeśli nie wszystkie są takie same, jest to krótsze:

_|,(

4

0= na struny

Aby pobrać pierwszy element tablicy, musisz użyć 0=(lub (, jeśli nie masz nic przeciwko pozostawieniu reszty tablicy na stosie).

Jeśli jednak tablica jest ciągiem, rzutowanie na znak jest wystarczające.

Przykład

"xyz"c e# Pushes 'x.

Nie rozumiem, dlaczego CJam nie pozwala po prostu cwyodrębnić pierwszego elementu dowolnej tablicy, co byłoby bardziej przydatne i spójne.
Esolanging Fruit 16.04.17

4

Obracanie tablicy (lub stosu) o jedną jednostkę w lewo

CJam ma operator obrotu w lewom< , który zwykle jest używany do obracania tablicy o dowolną liczbę jednostek w lewo.

W niektórych przypadkach możesz także użyć (+do zmiany i dołączenia:

[1 2 3]       (+ e# Pushes [2 3 1].
[[1] [2] [3]] (+ e# Pushes [[2] [3] 1].

Drugi przykład nie zadziałał, ponieważ pierwszy element tablic jest także iterowalny, więc jest +łączony zamiast dodawania.

Ponadto, jeśli chcesz zrzucić obróconą tablicę na stosie, możesz :\bezwarunkowo użyć (zmniejszyć poprzez zamianę):

[1 2 3]       :\ e# Pushes 2 3 1.
[[1] [2] [3]] :\ e# Pushes [2] [3] [1].

Tak długo, jak nie masz otwartego [, tej sztuczki można również użyć do obrócenia całego stosu, tj. Do przeniesienia najniższego stosu na górę:

]:\

3

Drukowanie listy i czyszczenie stosu

Powiedzmy, że twój stos ma listę ciągów / liczb / itp. na górze i kilka innych dodatkowych elementów poniżej. to znaczy

123 "waste" ["a" "b" "rty" "print" "me" "please"]

Teraz jesteś zainteresowany wydrukowaniem tylko ostatniej listy, więc robisz to

S*]W=

które wyjścia

a b rty print me please

Co wydaje się bardzo mądre, ponieważ używamy sztuczki polegającej na wyczyszczeniu stosu i drukujemy tylko listę połączoną spacjami (co może nie być pożądanym sposobem drukowania listy).

Można to jeszcze pograć w golfa!

p];

To o 2 bajty krócej !

a jeśli masz tylko 1 przedmiot na stosie innym niż lista, jest jeszcze krótszy!

p;

Piękno ppolega na tym, że usuwa on najwyższy element ze stosu, usztywnia go (dodaje również nowy wiersz na końcu) i drukuje do STDOUT natychmiast, bez czekania na zakończenie kodu.

Tak więc powyższy kod wyświetli

["a" "b" "rty" "print" "me" "please"]

która jest dokładną reprezentacją listy, gdy była na stosie!


3

Produkty kartezjańskie lub wszystkie możliwe kombinacje dwóch lub więcej zestawów

CJam ma wbudowany kalkulator kartezjański, m*który bierze dwie najlepsze tablice / ciągi znaków na stos i tworzy z niego wszystkie możliwe pary. Na przykład

[1 2 3 4]"abc"m*

odchodzi

[[1 'a] [1 'b] [1 'c] [2 'a] [2 'b] [2 'c] [3 'a] [3 'b] [3 'c] [4 'a] [4 'b] [4 'c]]

jako stos

Ale co, jeśli chcesz wszystkie możliwe kombinacje z więcej niż 2 list / ciągów. Używasz m*tego wiele razy? Na przykład

[1 2 3 4][5 6]"abc"m*m*

pozostawi następujące na stosie

[[1 [5 'a]] [1 [5 'b]] [1 [5 'c]] [1 [6 'a]] [1 [6 'b]] [1 [6 'c]] [2 [5 'a]] [2 [5 'b]] [2 [5 'c]] [2 [6 'a]] [2 [6 'b]] [2 [6 'c]] [3 [5 'a]] [3 [5 'b]] [3 [5 'c]] [3 [6 'a]] [3 [6 'b]] [3 [6 'c]] [4 [5 'a]] [4 [5 'b]] [4 [5 'c]] [4 [6 'a]] [4 [6 'b]] [4 [6 'c]]]

Zauważ, że produkty są nadal parami, przy czym jednym z nich jest sama para. Nie jest to oczekiwane i chcemy spłaszczonych kombinacji.

Jest na to łatwy sposób. Po prostu zawiń każdą listę, którą chcesz dla swojego produktu kartezjańskiego, w tablicę, utwórz pary kartezjańskie produkty i spłaszcz je za każdym razem:

[1 2 3 4][5 6]"abc"]{m*{(+}%}*

To opuszcza

[['a 5 1] ['b 5 1] ['c 5 1] ['a 6 1] ['b 6 1] ['c 6 1] ['a 5 2] ['b 5 2] ['c 5 2] ['a 6 2] ['b 6 2] ['c 6 2] ['a 5 3] ['b 5 3] ['c 5 3] ['a 6 3] ['b 6 3] ['c 6 3] ['a 5 4] ['b 5 4] ['c 5 4] ['a 6 4] ['b 6 4] ['c 6 4]]

na stosie.

Chcesz utrzymać zamówienie? , po prostu zamień przed dodaniem wyskakującego elementu z powrotem do tablicy. to znaczy

{m*{(\+}%}*

Chcesz tylko permutacje?

{m*{(+$}%_&}*

Chcesz tylko unikalne elementy w kombinacjach?

{m*{(+_&}%}*

To wszystko ludzie. na razie .


1
Teraz możesz to zrobić ]:m*:e_z dowolną liczbą tablic
aditsu

3

Operowanie na ciągach

Czasami, jeśli pracujesz ze złożoną strukturą danych, podczas gdy elementy w niej są proste, konwersja na ciągi może pomóc.

Na przykład, jeśli chcesz uzyskać pierwsze lub ostatnie kilka elementów w tablicy 2D bitów i nie przejmujesz się zwróconym typem, sA<zapisujesz bajt z 0=A<lub :+A<.

Lub jeśli chcesz zmodyfikować niektóre bity na wejściu, możesz zmodyfikować ciąg przed dokonaniem jego oceny.

Lub jeśli masz tę strukturę i chcesz przekonwertować ją na prostą listę:

[[[[[[[[[1]2]3]4]5]6]7]8]9]

Możesz to zrobić z wieloma postaciami na inne sposoby:

[a{~)\}h;]W%

Ale może być znacznie krótszy z łańcuchami:

s:~

Jest krótszy, nawet jeśli może zawierać liczby zawierające więcej niż jedną cyfrę:

[`La`-~]

Lub:

`']-~]

Jeśli nie potrzebujesz innej tablicy zawierającej wiele takich tablic.


e_Teraz jest
aditsu

@aditsu Zobacz tę odpowiedź i komentarz . Czasami snadal działa lepiej.
jimmy23013

Jasne, że gdy możesz bezpośrednio pracować z łańcuchem, jest on krótszy.
aditsu

3

Używanie NzamiastLa

W wielu przypadkach potrzebujesz czegoś zainicjowanego do tablicy zawierającej pustą tablicę jako jej jedyny element, który Lawydaje się niepotrzebnie o 1 bajt dłuższy.

W wielu przypadkach przed drukowaniem należy również dodać nowy wiersz po każdym elemencie, co może wyglądać podobnie do Nolub N*.

Ale jeśli oba są prawdziwe, czasami możesz odkryć, że możesz po prostu zainicjować tablicę N, która ma znak nowej linii jako jedyny element. Upewnij się, że dodajesz tylko elementy do reszty kodu, a pierwszą rzeczą do dodania jest zawsze znak lub tablica. Lub dołącz tylko, jeśli wiodący nowy wiersz jest akceptowalny, a to czyni go krótszym.

Czasami Sdziała również, jeśli trzeba oddzielić dane wyjściowe spacjami.

W rzadszych przypadkach początkowym elementem musi być ciąg. Ale nadal możesz użyć, Naktóry może być krótszy niż dodanie nowej linii później.


2

Podział na jedno lub więcej wystąpień

Powiedz, że masz ciąg znaków "abbcdbbfghbdbb"i chcesz go podzielićb

"abbcdbbfghbdbb"'b/

To pozostawia na stosie:

["a" "" "cd" "" "fgh" "d" "" ""]

Zauważ puste ciągi? Są tam, ponieważ dwie bbyły razem i nic nie było między nimi. Czasami chcesz tego uniknąć. Możesz to zrobić przez

"abbcdbbfghbdbb"'b/La-

lub odfiltrowując puste ciągi

"abbcdbbfghbdbb"'b/{},

ale to 3 dodatkowe bajty.

Nieco mniej znany operator dla tego konkretnego przypadku użycia to %. Oprócz robienia modów i mapowania oraz dzielenia na podstawie liczby ( "abcd"2%= "ac"), %można także dzielić na ciągi / tablice. W powyższym przypadku użycia:

"abbcdbbfghbdbb"'b%

zostawi

["a" "cd" "fgh" "d"]

na stosie.

Dziękuję @ user23013 za wskazanie tego w jednej z moich dzisiejszych odpowiedzi.


Myślę, że należy to nazwać „także uczyć się GolfScript”, który ma lepsze przykłady w dokumentacji.
jimmy23013

@ user23013, ale nigdy nie jesteśmy pewni, co jest podobne do GS, a co nie.
Optymalizator

2

Użyj fold / zmniejsz jako infix foreach

Mamy :xjako skrót dla {x}%i lub {x}*(w zależności od tego, czy xjest jednoargumentowy czy binarny). Niestety nie ma równoważnego operatora infix do skrócenia {x}/. Jednak bardzo często, gdy to robimy {x}/, xjest w rzeczywistości operatorem binarnym, który wielokrotnie modyfikuje przedmiot leżący na stosie. Jeśli tak jest, a wspomniany element nie jest tablicą, możemy zapisać bajt, nadużywając fold / zmniejsz jako foreach:

5 [1 2 3 4]{-}/  e# Gives -5
5 [1 2 3 4]+:-

Działa to, ponieważ fold zawsze pozostawia pierwszy element nietknięty. Niestety nie zapisuje bajtu, gdy zmodyfikowany element jest tablicą, ponieważ dodanie go rozpakuje. Jednak czasami masz szczęście tyle , że tablica zawiera już tego elementu na przodzie, w którym to przypadku skrócenie należy pamiętać (zamiast ręcznego usuwania elementu przed użyciem {}/na resztę).


2

drukuj i drukuj

CJam ma printoperatora: o. Działa, ale stos jest drukowany natychmiast po wykonaniu całego kodu. Możesz go zatrzymać, jeśli wyczyścisz stos na końcu programu. Po prostu umieść to na końcu:

];

Aby wydrukować, możesz użyć oNolub p(działa jako `oNo)


3
Jest większa różnica między oi p. pzaczyna się od przekształcenia drukowanego elementu w jednoznaczną reprezentację ciągu. pjest równoważne z wykonaniem ​`oNo.
Dennis
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.