Wskazówki dotyczące gry w golfa w APL

28

Niedawno rozpocząłem jedno wyzwanie golfowe i wydaje się, że zwycięzcą jest GolfScript (niespodzianka, niespodzianka!). Co ciekawe, był jeszcze jeden bardzo silny konkurent, który miał wszelkie szanse wygrać z GolfScript. Nazywa się APL. Widzę tu wiele odpowiedzi napisanych w APL. Wygląda na to, że ten język jest dość wydajny do gry w golfa kodowego, więc postanowiłem poprosić o wszelkie wskazówki dotyczące gry w golfa, które znasz dla programów APL. Opublikuj kilka przykładów kodu. Zwykle bardzo interesujący jest widok języka w akcji.

gthacoder
źródło

Odpowiedzi:

23

Edycja : dla osób czytających to, którzy w ogóle nie znają APL, ale chcą je podjąć, Mastering Dyalog APL jest bardzo dobrym źródłem.

  1. Ocena jest ściśle od prawej do lewej. Obejmuje to ustawianie zmiennych, więc skorzystaj z niego.

    2+a, 1+a←1 -> 3 4

    ajest ustawiony na 1, 1+aocenia 2, a,2ocenia 1 2i 2+1 2ocenia 3 4.

  2. Podobnie jak C, można łączyć z funkcją, tj a +← 3. W przeciwieństwie do C jest to rodzajowe: foo F← barustawia foona F bar. Nieco unintuitively, jako wyrażenie to zwraca bar, nie F bar.

    Działa również z anonimowymi funkcjami:

          a←0
          a+←3 ⋄ a
    3
          a+←3 ⋄ a
    6
          a { ⍵/'!' } ←4 ⋄ a
    !!!!
    
  3. Możesz przypisać do tablicy: A[3]←8tak jak byś się spodziewał. Ale możesz także przypisać wiele elementów jednocześnie: A[3 5 6]←9 1 4lub nawet A[3 5 6]←9ustawić je wszystkie na ten sam element. Możesz oczywiście dodać tutaj także funkcję . Funkcja zostanie następnie zastosowana do każdego elementu osobno, tak jakbyś to zrobił .

  4. jest twoim przyjacielem, nawet jeśli nie wygląda na zbyt szczęśliwego z tego powodu.

    1. Jeśli Fjest dyadyczne, dyadic przełącza argumenty: a F b<-> b F⍨ a. Jest to przydatne podczas gry w golfa, ponieważ może uchronić Cię przed użyciem aparatów ortodontycznych:

      (F G H x) K y      <->     y K⍨ F G H x
      

      To zmienia kolejność oceny, ponieważ prawa ręka jest zawsze oceniana przed lewą ręką.

    2. Jeśli Fjest dynamiczne, monadyczne stosuje ten sam argument do obu stron funkcji:

            5⍴5
      5 5 5 5 5
            ⍴⍨5
      5 5 5 5 5
      

      Argument jest oceniany tylko raz. Jest to szczególnie przydatne w przypadku produktów zewnętrznych, tzn. Aby porównać każdą wartość w tablicy z innymi wartościami w tej samej tablicy, możesz użyć ∘.=⍨zamiast tego robić x∘.=x←(whatever).

    3. Jeśli Fjest monadyczny, nie robi nic, ale oddziela funkcję od argumentu. Więc może nadal oszczędzać ci nawiasy klamrowe, jeśli funkcja jest złożona:

            {⍵+3}⍣5 6
            ∇{⍵+3}              
           ∇ ⍣ 5 6              
            ({⍵+3}⍣5)6
      21
            {⍵+3}⍣5⍨6
      21
      
  5. Naucz się idiomów! Następnie golf idiomy. Na przykład:

    ((((1↑⍴X),⍴Y)↑X)^.=Y)⌿X
    

    można mechanicznie przekształcić w:

    X⌿⍨Y^.=⍨X↑⍨(1↑⍴X),⍴Y
    

    a następnie dalej:

    X⌿⍨Y^.=⍨X↑⍨(⊃⍴X),⍴Y
    

    (pierwszy) jest równoważny 1↑(weź jeden) w tym przypadku. I ewentualnie:

    X⌿⍨Y^.=⍨X↑⍨(≢X),⍴Y
    

    (suma) jest równoważna ⊃⍴(pierwszemu elementowi kształtu) dla wszystkich oprócz skalarów.

marinus
źródło
Czy istnieje sposób na uzyskanie bezpłatnej licencji oprócz wersji Raspberry Pi?
Fabinout
Oczywiście legalny sposób na zdobycie go.
Fabinout
2
@Fabinout: Na stronie dyalog.com możesz pobrać bezpłatną wersję systemu Windows. Kliknij „Strefa pobierania”, a następnie „Pobieranie niezarejestrowane”. Będzie to wymagało rejestracji, ale poza tym jest w pełni funkcjonalne, bezpłatne i legalne. Jeśli jesteś studentem, możesz uzyskać normalną wersję za darmo, wypełniając formularz. Jeśli nie mieszkasz w kraju, w którym zrujnują ci życie za piractwo, wiesz, co robić.
marinus
Istnieje również Nars2000, implementacja typu open source, która ma o wiele więcej funkcji niż Dyalog (i kilka błędów). Niektóre z tych funkcji są przydatne do gry w golfa, takie jak funkcje liczb pierwszych lub multisety.
Tobia,
1
Istnieje GNU APL.
M. Alaggan
14

Pociągi

A(f g h)B      ←→  (A f B)g A h B  ⍝ fork
 (f g h)B      ←→  (  f B)g   h B  ⍝ fork
A(  g h)B      ←→         g A h B  ⍝ atop
 (  g h)B      ←→         g   h B  ⍝ atop
 (A g h)       ←→  ({A} g h)       ⍝ "Agh" fork
 (f g h k)     ←→  (f (g h k))     ⍝ 4-train
 (f g h k l)   ←→  (f g (h k l))   ⍝ 5-train, etc
 (f g h k l m) ←→  (f(g h(k l m))) ⍝ groups of 3 from the right, last could be 2
  f∘g B        ←→    f g B         ⍝ "compose" operator, useful in trains
A f∘g B        ←→  A f g B
ngn
źródło
Czy to oznacza, że ​​ze względu na przyszłych czytelników nie powinniśmy mówić Oberonowi, jak to skrócić?
Adám
Nie, rób jak zwykle w PPCG. Usunę tę linię, gdy wyrażenie osiągnie (moim zdaniem) najkrótszą. To łatwe ćwiczenie - nie sądzę, żebyś osobiście na tym skorzystał.
ngn
Mogę obniżyć do 16, ale nie używam żadnych twoich wskazówek, więc może jestem daleko.
Adám
@ Adám cóż, używasz pociągu :) moja była podobna, ale dłużej, ponieważ nie myślałem o ⎕ML
ngn
Czy to nie „grupy 3 z prawej ”?
Adám
7

Sztuczki do radzenia sobie z pociągami /i w pociągach

Przy korzystaniu z pociągów może chcesz użyć redukcji f/takich jak sumy +/, a nawet zmniejszenie replikacji //. Jeśli jednak twój pociąg ma więcej części po lewej stronie redukcji, potrzebujesz nawiasów, aby utworzyć szczyt. Oto kilka sztuczek, aby zaoszczędzić bajty.

Użyj 1∊zamiast tablic monadycznych ∨/lub ∨⌿na tablicach boolowskich

Zadanie: Biorąc pod uwagę dwa ciągi A i B o równej długości, zwróć 2, jeśli dowolne odpowiadające znaki A i B są równe, w przeciwnym razie 0. Np A←'abc'i B←'def'daje 0a A←'abc'i B←'dec'daje 2.

Rozwiązanie dfn może być, A{2×∨/⍺=⍵}Bale chcesz je skrócić, przechodząc milczenie. A(2×∨/=)Bnie zadziała, ponieważ zasady formowania pociągów parsują to tak, jak 2 (× ∨/ =)chcesz 2 × (∨/=).

Zauważ, że ∨/lub ∨⌿na wektorze boolowskim ( ∨/,lub w ∨⌿,przypadku tablic wyższej rangi) pyta, czy jest jakikolwiek 1, tzn. Czy 1∊możemy napisać nasz pociąg jako 2×1∊=.

Zwróć uwagę, że zachowuje właściwy argument, więc nie można go użyć do zmniejszenia każdego wiersza lub kolumny osobno.

Użyj 1⊥zamiast monadycznego +/lub+⌿

Zadanie: Biorąc pod uwagę listę list L i indeks N, zwróć trzykrotnie sumę N-tej listy. Np. L←(3 1 4)(2 7)I N←1daje 24.

Rozwiązanie dfn może być, N{3×+/⍺⊃⍵}Lale chcesz je skrócić, przechodząc milczenie. N(3×+/⊃)Lnie zadziała, ponieważ zasady formowania pociągów parsują to tak, jak 3(× +/ ⊃)chcesz 3 × (+/⊃).

Zauważ, że ocena listy liczb w jednostkowej (podstawa-1) jest równoważna zsumowaniem listy, ponieważ ∑ { a , b , c , d } =  a + b + c + d  = ( a × 1³) + ( b × 1² ) + ( c × 1¹) + ( d × 1⁰). Dlatego +/a b c djest taki sam jak 1⊥a b c di możemy napisać nasz pociąg jako 3×1⊥⊃.

Zauważ, że w argumentach wyższej rangi 1⊥jest to równoważne z +⌿.

Użyj f.gzamiast f/gz argumentami skalarnymi i / lub wektorowymi

Zadanie: Biorąc pod uwagę listę L i liczbę N, zwróć zakres 1 dokładnie liczbę resztek minimalnego podziału, gdy elementy L zostaną podzielone przez NEg L←31 41 59i N←7daje 1 2 3.

Rozwiązanie dfn może być, N{⍳⌊/⍺|⍵}Lale chcesz je skrócić, przechodząc milczenie. N(⍳⌊/|)Lnie zadziała, ponieważ zasady formowania pociągów parsują to tak, jak ⍳ (⌊/) |chcesz ⍳ (⌊/|).

Wewnętrzny iloczyn A f.g Bdwóch funkcji skalarnych, gdy argumentami są skalary i / lub wektory, jest taki sam, f/ A g Bponieważ oba są (A[1] g B[1]) f (A[2] g B[2]) f (A[3] g B[3])itp., Więc możemy napisać nasz ciąg jako ⍳⌊.|.

Zauważ, że to nie działa w przypadku tablic wyższego rzędu.

Użyj ∊⊆zamiast /z logicznymi argumentami lewej i prostej wektorowej prawej

Zadanie: biorąc pod uwagę listę L i liczbę N, przefiltruj listę, aby pozostały tylko liczby większe niż N. Np. L←3 1 4I N←1daje 3 4.

Rozwiązanie dfn może być, N{(⍺<⍵)/⍵}Lale chcesz je skrócić, przechodząc milczenie. N(</⊢)Lnie zadziała, ponieważ reguły wiązania to przeanalizują, ponieważ (</) ⊢chcesz /być replikacją funkcji, a nie operatorem zmniejszania .

Dyadic z logicznym lewym argumentem dzieli prawy argument zgodnie z przebiegiem 1s w lewym argumencie, usuwając elementy wskazane przez 0s. To jest prawie to, czego chcemy, z wyjątkiem niechcianego partycjonowania. Możemy jednak pozbyć się partycjonowania, stosując monadic . W ten sposób {(⍺<⍵)/⍵}możemy się stać {∊(⍺<⍵)⊆⍵}i w ten sposób możemy napisać nasz pociąg jako ∊<⊆⊢.

Zauważ, że to nie działa w przypadku tablic wyższego rzędu.

Użyj 0⊥zamiast ⊢/lub ⊢⌿z argumentami numerycznymi

Zadanie: Biorąc pod uwagę listę L i liczbę N, pomnóż N przez najbardziej prawy element LEg L←3 1 4i N←2daje 8.

Rozwiązanie dfn może być, N{⍺×⊢/⍵}Lale chcesz je skrócić, przechodząc milczenie. N(⊣×⊢/⊢)Lnie zadziała, ponieważ zasady formowania pociągów parsują to tak, jak ⊣ (× ⊢/ ⊢)chcesz ⊣ × (⊢/⊢).

Zauważ, że 0⊥na tablicy liczbowej jest to samo ⊢⌿, więc możemy napisać nasz pociąg jako ⊣×0⊥⊢.

Zauważ, że wybiera to ostatnią główną komórkę tablic wyższego rzędu.

Adám
źródło
1
Może mógłbyś dodać tę odpowiedź do czatu ?
J. Sallé,
1
@ J.Sallé Dodano.
Adám
7

Służy do łączenia mnożenia z dodawaniem

(a×b)+C  ->  a⊥b,C
(C)+a×b  ->  a⊥b,C
(a×b)-C  ->  a⊥b,-C

Założenia:

  • ai bsą warunkami, które nie wymagają dalszych nawiasów, gdy są używane jako lewy argument

  • C jest wyrażeniem, które może wymagać nawiasów, gdy jest używane jako lewy argument

  • a b C oceniać na skalary numeryczne

ngn
źródło
5

Liczby zespolone

Często pomijane, stwarzają wspaniałe możliwości skrócenia wyrażeń dotyczących siatek, labiryntów, fraktali lub geometrii.

0j1⊥¨    0j1⊥   ⍝ pair(s) of reals -> complex
11 9∘○¨  11 9○  ⍝ complex -> pair(s) of reals
|z0-z1          ⍝ distance between two points
0j1×z   0j¯1×z  ⍝ rotate by ±90° around (0,0)
0j1*⍳4          ⍝ the four cardinal directions
+z       -+z    ⍝ reflect across x or y axis
+\0,z           ⍝ sequence of steps -> path
2-/z            ⍝ path -> sequence of steps
0j1⊥¨n-⍳2⍴1+2×n ⍝ lattice centred on (0,0)
ngn
źródło
4

Indeksowanie długości wektora modulo

⊃i⌽ajest często krótszy niż naiwny ⊃a[(≢a)|i]lub a⊃⍨i|⍨≢a(gdzie ajest wektorem i ijest liczbą całkowitą i ⎕iowynosi 0)

użyteczną odmianą tego (dzięki EriktheOutgolfer za wskazanie) jest: I↑Y⌽⍨I×Xgdzie Yjest konkatenacja niektórych Iwektorów długości i Xjest indeksem tego, który chcemy wybrać, na przykład:3↑'JanFeb...Dec'⌽⍨3×month

ngn
źródło
3

Funkcje stałe

=⍨i ≠⍨dzięki ngn.

Czasami potrzebujesz tylko jednej wartości dla każdego elementu listy. Chociaż możesz ulec pokusie użycia {value}¨, jest on krótszy, value⊣¨ ale w przypadku niektórych typowych wartości możesz stać się jeszcze krótszy (używając ⎕IO←0):

¯1s z ⍬⍸list

0s z ⍬⍳list

1s z ⍬⍷list

Pamiętaj, że działają one tylko na listach (choć mogą być zagnieżdżone). W przypadku tablic wyższego rzędu możesz użyć następujących elementów, aby uzyskać wszystkie 0 i wszystkie 1:

1s z =⍨

0s z ≠⍨

Jeśli ustawisz ⎕ML←0, wszystkie liczby mogą być przekształcone w zera (jak gdyby ) za pomocą:

Jeśli potrzebujesz tylko jednego numeru, możesz użyć monadycznego, aby uzyskać 1 lub 0 zamiast używania 1⊣lub 0⊣.

Adám
źródło
Czasami potrzebujesz tylko jednej wartości dla każdego elementu listy. ” - To może być godne uwagi: gdy ta wartość jest pierwszym elementem listy, możesz użyć⊣\
ngn
@ngn Powiedziałbym, że i ze /i zasługa stanowisko własne.
Adám
2

Posługiwać się

Unikaj nawiasów

(Dojazdy) może zaoszczędzić bajty, unikając nawiasów. Ilekroć masz funkcję, w której lewy argument musi być nawiasowany, a prawy argument nie, możesz zapisać bajt, np . (A<B)÷CC÷⍨A<B.

Podwójne tablice

Aby dołączyć kopię tablicy do jej końca, użyj ,⍨Alub ⍪⍨A.

Podwójne liczby

Zamiast 2∘×podwójnego możesz użyć, +⍨ponieważ dodaje on argument do siebie: 1+2∘×1++⍨.

Liczby kwadratowe

Zamiast 2*⍨Ykwadratu można użyć, ×⍨Yponieważ mnoży argument z samym sobą: 2*⍨A+B×⍨A+B.

Losowa permutacja

?⍨Nda ci losową permutację długości N.

Samoklasyfikuj się

Znajdź wskaźniki pierwszego wystąpienia każdej głównej komórki za pomocą ⍳⍨A

Policz końcowe 1s w wektorze boolowskim

Zamiast +/∧\⌽Bpoliczyć, ile końcowych jedynek jest w środku N, możesz użyć ⊥⍨.

Odwrotna kompozycja

A f∘g Bjest A f g B, ale jeśli chcesz (g A) f B, użyj f⍨∘g⍨.

Odwróć redukcję

f/ a1 a2 a3jest a1 f (a2 f a3). Jeśli chcesz (a1 f a2) f a3, użyj f⍨/⌽.

Skanowanie do tyłu

f\ A B Cjest
A (A f B) (A f (B f C)).

f⍨/∘⌽¨,\ A B Cjest
A (A f B) ((A f B) f C).

f⍨\⌽ A B Cjest
((A f B) f C) (B f C) C.

⌽f/∘⌽¨,\⌽ A B C. jest
(A f (B f C)) (B f C) C.

Adám
źródło
2

Wymień znaki w ciągu bez ⍳≢

Zadanie: Biorąc pod uwagę dwa łańcuchy, S i T, wymień wskaźniki ich konkatenacji. Np. S←'abcd'I T←'xyz'daje 1 2 3 4 5 6 7.

Rozwiązanie dfn może być, S{⍳≢⍺,⍵}Tale chcesz je skrócić, przechodząc milczenie. ⍳≢,nie zadziała, ponieważ reguły analizy składni parsują to tak, jak (⍳)≢(,)chcesz (⍳≢),.

Dyadic z pustym lewym argumentem ocenia proste tablice znaków zgodnie z ich bieżącą kolejnością, która jest taka sama jak ⍳≢. Tak {⍳≢⍺,⍵} może się stać {⍬⍋⍺,⍵}, abyśmy mogli napisać nasz pociąg jako ⍬⍋,.

Pamiętaj, że nie działa to w przypadku tablic numerycznych lub mieszanych.

Adám
źródło
Wow, nie wiedziałem, że to była rzecz.
Zacharý