Suggerimenti per giocare a golf in CJam


43

CJam è un linguaggio di golf basato su stack ispirato a GolfScript, creato dall'utente aditsu PPCG .

Quindi, sulla scia di altre domande sui suggerimenti specifici della lingua:

Quali consigli generali hai per giocare a golf in CJam? Si prega di inviare un suggerimento per risposta.


4
Vedi anche Suggerimenti per giocare a golf in GolfScript ; le lingue sono abbastanza simili che molti dei trucchi possono essere adattati in entrambi i modi.
Ilmari Karonen,

2
@IlmariKaronen Dopo aver esaminato le risposte a questa domanda, direi che solo circa la metà di esse si applica a CJam, a causa delle differenze sintattiche o logiche nelle lingue.
Ottimizzatore

Risposte:


23

Modulo corretto per numeri negativi

È spesso fastidioso che il risultato dell'operazione modulo dia lo stesso segno del primo operando. Ad esempio, -5 3%-2al posto di 1. Più spesso vuoi quest'ultimo. La soluzione ingenua è applicare modulo, aggiungere il divisore una volta e applicare di nuovo modulo:

3%3+3%

Ma è lungo e brutto. Invece, possiamo usare il fatto che matrice indicizzazione è sempre modulare e fa correttamente lavoro con indici negativi. Quindi trasformiamo il divisore in un intervallo e accediamo a:

3,=

Applicato a -5, questo dà 1come previsto. Ed è solo un byte più lungo di quello incorporato %!

Se il modulo ha una potenza di 2, puoi salvare un altro byte usando l'arihmetica bit a bit (che è anche molto più veloce). Confrontare:

32,=
31&

Per il caso speciale di 65536 == 2^16un altro byte può essere salvato facendo uso del comportamento a capo del tipo di carattere:

ci

13

Spingendo intervalli di caratteri concatenati

  • La stringa contenente tutte le cifre "0123456789"può essere scritta come

    A,s
    
  • Le lettere ASCII maiuscole ( A-Z) possono essere inserite come

    '[,65>
    

    che genera la stringa di tutti i caratteri fino a Z , quindi scarta i primi 65 (fino a @ ).

  • Tutte le lettere ASCII ( A-Za-z) possono essere inserite come

    '[,65>_el+
    

    che funziona come sopra, quindi crea una copia, si converte in minuscolo e si aggiunge.

    Ma c'è un modo più breve per farlo!

    Quindi l' ^operatore spesso trascurato (differenze simmetriche per gli elenchi) consente di creare gli stessi intervalli salvando tre byte:

    '[,_el^
    

    '[,crea l'intervallo di tutti i caratteri ASCII fino a Z , _elcrea una copia minuscola e ^mantiene solo i caratteri di entrambe le stringhe che compaiono in una, ma non entrambe.

    Poiché tutte le lettere nella prima stringa sono maiuscole, tutte nella seconda sono minuscole e tutti i caratteri non lettera sono in entrambe le stringhe, il risultato nella stringa di lettere.

  • L'alfabeto RFC 1642 Base64 ( A-Za-z0-9+/) può essere spinto usando la tecnica sopra e aggiungendo le non lettere:

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

    Un modo altrettanto breve di spingere questa stringa utilizza esclusivamente differenze simmetriche:

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

    Come possiamo trovare la stringa all'inizio?

    Tutti i campi di carattere utilizzato ( A-Z, a-z, 0-9, +, /) possono essere spinti come differenza simmetrica alla gamma che si aprono in byte nullo, vale a dire 'A,'[,^, 'a,'{,^, '0,':,^, '+,',,^e '/,'0,^.

    Pertanto, l'esecuzione :,:^su "A[a{):+,/0"spingerà i caratteri desiderati, ma non nel giusto ordine.

    Come troviamo l'ordine giusto? Forza bruta in soccorso! Il programma

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

    scorre su tutte le possibili permutazioni della stringa, applica :,:^e confronta il risultato con l'output desiderato ( permalink ).

  • L'alfabeto radix-64 usato, ad esempio, da crypt ( .-9A-Za-z) può essere generato usando il metodo sopra:

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

    Questo è il metodo più breve che conosco.

    Poiché tutti i caratteri nell'output desiderato sono in ordine ASCII, non è necessario ripetere le permutazioni.

  • Non tutti gli intervalli di caratteri concatenati possono essere inseriti nell'ordine desiderato usando :,:^.

    Ad esempio, l'intervallo 0-9A-Za-z;-?non può essere spinto eseguendo :,:^una permutazione di "0:A[a{;@".

    Tuttavia, possiamo trovare una variazione ruotata della stringa desiderata che può, usando il codice

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

    che stamperà ( permalink ) quanto segue:

    10
    0:@[a{A;
    

    Ciò significa che

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

    ha lo stesso effetto di

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

    che può essere utilizzato solo con uno stack vuoto senza anteporre a [.


11

Evita {...} {...}?

Supponiamo di avere un numero intero nello stack. Se è dispari, si desidera moltiplicarlo per 3 e aggiungere 1; altrimenti vuoi dividerlo per 2.

Un'istruzione if / else "normale" sarebbe simile a questa:

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

Tuttavia, l'utilizzo dei blocchi non è generalmente la strada da percorrere, poiché {}{}aggiunge già quattro byte. ?può anche essere usato per selezionare uno dei due oggetti in pila:

_2%1$3*)@2/?

Questo è un byte più breve.


Bloccare-? con un'istruzione if vuota è sempre un no-go. Per esempio,

{}{2/}?

è due byte più lungo di

{2/}|

Se invece hai

{2/}{}?

e la cosa su cui stai verificando è un numero intero non negativo, puoi farlo

g)/

I nuovi {}&e {}|sono utili, ma a volte problematici se non riesci a ingombrare la pila.

Tuttavia, nel caso di

_{…}{;}?

puoi invece usare una variabile temporanea:

:T{T…}&

1
!)/e g)/sono più brevi negli esempi.
jimmy23013,

11

Istruzioni switch

CJam non ha istruzioni switch. Nidificato se le istruzioni funzionano altrettanto bene, ma {{}{}?}{}?sono già lunghe 12 byte ...

Se riusciamo a trasformare la condizione in un intero piccolo, non negativo, possiamo trasformare tutte le istruzioni del caso in una stringa delimitata e valutare il risultato corrispondente.

Ad esempio, se vogliamo eseguire code0se il numero intero dello stack è 0 , code1se è 1 e code2se è 2 , possiamo usare

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

o

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

o

"code0 code1 code2"S/=~

S/divide la stringa in ["code0" "code1" "code2"], =estrae il blocco corrispondente e ~valuta il codice.

Fai clic qui per vedere le istruzioni switch in azione.

Infine, come suggerito da @ jimmy23013 e @RetoKoradi, in alcuni casi possiamo accorciare ulteriormente il passaggio. Di ' code0, code1e code2hanno lunghezze L 0 , L 1 e L 2 , rispettivamente.

Se L 0 = L 1 ≥ L 2

"code0code1code2"L/=~

può essere usato invece, dove Lè L 0 . Invece di dividere un delimitatore, /divide la stringa in blocchi di uguale lunghezza qui.

Se L 0 ≥ L 1 ≥ L 2 ≥ L 0 - 1 ,

"cccooodddeee012">3%~

può essere usato invece. >rimuove 0, 1 o 2 elementi dall'inizio della stringa ed 3%estrae ogni terzo elemento (a partire dal primo).


Per l'ultimo esempio, ha qualche vantaggio rispetto "code0code1code2"5/=~? Sembra molto più semplice per me, ed è della stessa lunghezza.
Reto Koradi,

@RetoKoradi Se tutti gli snippet hanno la stessa lunghezza, non ci sono vantaggi. Per lunghezze diverse, il metodo può essere sia più breve che più lungo del metodo del modulo.
Dennis,

11

Golfare valori comuni di array e stringhe

Ci sono alcuni array o stringhe brevi che spuntano di tanto in tanto, ad esempio per inizializzare le griglie. Ingenuamente, questi possono costare 4 o più byte, quindi vale la pena cercare operazioni su valori incorporati che daranno lo stesso risultato. Soprattutto la conversione di base è spesso utile.

  • [0 1]può essere scritto come 2,.
  • [1 0]può essere scritto come YYb(cioè 2 in binario).
  • [1 1]può essere scritto come ZYb(cioè 3 in binario).
  • La matrice [[0 1] [1 0]]può essere scritta come 2e!.
  • [LL] può essere scritto come SS/(suddividere un singolo spazio per spazi).
  • "\"\""può essere scritto come L`.
  • "{}"può essere scritto come {}s.

Quest'ultimo può essere esteso ai casi in cui si desidera che tutti i tipi di parentesi salvino un altro byte:

  • "[{<()>}]"può essere scritto come {<()>}a`.
  • "()<>[]{}"può essere scritto come {<()>}a`$.

Soprattutto il trucco di conversione di base può essere utile da tenere a mente per alcuni casi oscuri che compaiono di tanto in tanto. Ad esempio [3 2]sarebbe E4b(14 in base 4).

In casi ancora più rari potresti trovare mfutile l' operatore di fattorizzazione . Ad esempio, [2 7]è Emf.

Non esitare a estendere questo elenco se trovi altri esempi.


10

Svuotare la pila

Se vuoi solo cancellare l'intero stack, avvolgilo in un array e pop:

];

La cosa un po 'più complicata è, se hai fatto molti calcoli, ma vuoi solo mantenere l'elemento superiore dello stack e scartare tutto quello che c'è sotto. L'approccio ingenuo sarebbe quello di memorizzare l'elemento superiore in una variabile, cancellare lo stack, spingere la variabile. Ma c'è un'alternativa molto più breve: avvolgere lo stack in un array ed estrarre l'ultimo elemento:

]W=

(Grazie a Optimizer che me lo ha mostrato l'altro giorno.)

Naturalmente, se ci sono solo due elementi nello stack, \;è più breve.


\;pop solo l'elemento sotto il TOS. Volevi dire ;;?
Calcolatrice

1
@CalculatorFeline la seconda metà della risposta riguarda la cancellazione di tutto tranne il TOS.
Martin Ender,

9

e e poteri di dieci

Come in molte altre lingue, puoi scrivere 1e3invece che 1000in CJam.

Funziona con basi non intere e anche con esponenti non interi. Ad esempio, 1.23e2spinge 123.0 e 1e.5spinge 3.1622776601683795 (radice quadrata di 10 ).

Ciò che non è immediatamente ovvio è che in 1e3realtà sono due token:

  • 1spinge l'intero 1 sullo stack.

  • e3lo moltiplica per 1000 .

Perché è importante?

  • Puoi chiamare e<numeric literal>qualcosa che è già in pila.

    2 3 + e3 e# Pushes 5000.
    
  • Puoi mappare e<numeric literal>su un array.

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

9

Norme euclidee

Il modo semplice per calcolare la norma euclidea di un vettore, cioè la radice quadrata della somma dei quadrati dei suoi elementi, è

2f#:+mq

Tuttavia, c'è un modo molto più breve.

mh, L'operatore ipotenusa, apre due interi a e b dalla pila e spinte sqrt (a 2 + b 2 ) .

Se abbiamo un vettore x: = [x 1 … x n ], n> 1 nello stack, :mh(riduci per ipotenusa) otterremo quanto segue:

  • I primi x 1 e x 2 vengono spinti e mhvengono eseguiti, lasciando sqrt (x 1 2 + x 2 2 ) , nello stack.

  • Quindi, viene premuto x 3 ed mheseguito nuovamente, lasciando nello stack
    sqrt (sqrt (x 1 2 + x 2 2 ) 2 + x 3 2 ) = sqrt (x 1 2 + x 2 2 + x 3 2 ) .

  • Dopo che x n è stato elaborato, restiamo con sqrt (x 1 2 +… x n 2 ) , la norma euclidea di x .

Se n = 1 e x 1 <0 , il codice sopra riportato produrrà un risultato errato. :mhzfunziona incondizionatamente. (Grazie a @ MartinBüttner per averlo sottolineato.)

Ho usato questo trucco per la prima volta in questa risposta .


2
Naturalmente, questo ha implicazioni per l'analisi numerica del tuo programma ...
Peter Taylor,

8

Converti dalla base n con un elenco di numeri maggiore di n

CJam converte un elenco in un numero con questa formula: A 0 * n l + A 1 * n l-1 + A 2 * n l-2 + A l * n 0 (con non negativo n). nè la base ed lè la lunghezza dell'elenco. Questo significa che A i può essere qualsiasi numero intero, che non deve essere compreso nell'intervallo di [0,n).

Qualche esempio:

  • 0bestrae l'ultimo elemento e lo converte in numero intero. Funziona come W=ie salva un byte se non era intero. Ma anche tutto il resto nell'elenco deve essere in grado di eseguire il cast in numero intero.
  • 1brestituisce la somma. Funziona come :i:+e salva due byte se non fossero numeri interi. Funziona anche con elenchi vuoti mentre :+non lo fa.
  • [i{_1&9 32?_@\m2/}16*;]W%:cconverte un carattere in una stringa di terminazioni e tabulazioni, che può essere riconvertito con 2bc. Tuttavia, la funzione di codifica non è facile da giocare a golf in un programma di code-golf. Ma di solito non ne hai bisogno.
  • È possibile utilizzare il seguente codice per convertire una stringa in caratteri Unicode non a 16 bit, che possono essere riconvertiti con 2A#b128b:c. (Le spiegazioni verranno aggiunte in seguito. O forse scriverò una nuova versione in seguito.)

    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
    

Il metodo simile funziona con qualsiasi set di nnumeri interi che hanno valori diversi mod n, se riesci a trovare un modo per sbarazzarsi della cifra più significativa.


8

Usando $come ternario se

Quando non ti dispiace perdere la memoria, vale a dire, lasciando sulla pila elementi inutilizzati che eliminerai in seguito ];, l'operatore di copia $può essere un comodo sostituto dell'operatore ternario ?.

? funziona bene se riesci a calcolare la condizione prima di spingere i due elementi tra cui scegliere, ma il più delle volte, la condizione dipende in realtà da tali elementi e avere sopra di essi risulta molto più naturale.

Se hai A B Cin pila, puoi eseguire

!$

invece di

\@?

per copiare Bse Cè vero e Aaltrimenti.

Se Cè un vero booleano ( 0o 1), è possibile eseguire

$

invece di

@@?

per copiare Ase Cè vero e Baltrimenti.


Col senno di poi, questo è un trucco piuttosto ovvio, ma non ci avevo mai pensato prima. L'ho usato per la prima volta in questa risposta .
Dennis,

7

Mappa per elenchi nidificati

Supponi di avere un elenco nidificato, come una matrice:

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

O una serie di stringhe:

["foo""bar"]

E vuoi mappare un blocco sul livello nidificato (cioè applicarlo a ciascun numero o ciascun personaggio). La soluzione ingenua è un nidificato %:

{{...}%}%

Tuttavia, puoi effettivamente spingere il blocco interno sulla pila e quindi utilizzare f%. fè "mappa con parametro aggiuntivo", quindi verrà mappata %sull'elenco esterno, usando il blocco come secondo parametro:

{...}f%

Salva due byte.

Un altro trucco per fare qualcosa del genere for (i=0; i<5; ++i) for (j=0; j<5; ++j) {...}è

5,_f{f{...}}

L'esterno fverrà mappato sul primo intervallo, fornendo il secondo intervallo come parametro aggiuntivo. Ma ora, se lo usi di fnuovo, solo l'elemento stack superiore è un array, quindi fmappi il blocco interno su quello, fornendo la "variabile di iterazione" esterna come parametro aggiuntivo. Ciò significa che il blocco interno viene eseguito con ie jsullo stack.

Questo ha lo stesso numero di caratteri della semplice mappatura di un blocco su un prodotto cartesiano (sebbene quest'ultimo si accorcia se si necessitano le coppie come matrici):

5,_m*{~...}%

La differenza è che questa versione produce un singolo array di risultati per tutte le coppie, mentre il doppio fproduce un elenco nidificato, che può essere utile se si desidera archiviare i risultati in una griglia, con le variabili iteratore come coordinate.

Grazie a Dennis per avermi mostrato questo trucco.

0.6.4 Aggiornamento

fe :ora sono stati immensamente migliorati prendendo qualsiasi altro operatore incluso se stessi. Ciò significa che ora puoi salvare ancora più byte. La mappatura di un operatore su un elenco nidificato è diventata ancora più breve ora:

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

Questo non aiuta molto a mappare i blocchi su elenchi nidificati.

Per quanto riguarda l'applicazione di blocchi o operatori al prodotto cartesiano, anche questo è diventato più breve ora, sia per i blocchi che per gli operatori:

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

5,_f{fx}
5,_ffx

La cosa bella è che ora puoi nidificarli. Quindi puoi applicare un operatore altrettanto facilmente al terzo livello in fondo a un elenco:

:::x

O un blocco con qualche trucco:

{...}ff%

Ottimo aggiornamento. Ma non c'è ancora f~...
jimmy23013,

@ user23013 si faspetta un operatore binario, ~è unario; forse volevi :~? Inoltre, possiamo discuterne in chat
aditsu,

Mi sto perdendo qualcosa su questo aggiornamento 0.6.4? Ricevo ancora messaggi di errore che fanno questi trucchi, come Unhandled char after ':': :( link )
Runer112,

2
@ Runer112 Funziona per me. Assicurati di ricaricare correttamente (cioè non dalla cache). A seconda del browser, Ctrl + F5 dovrebbe funzionare.
Martin Ender,

@ MartinBüttner È stato effettivamente causato dalla stupida memorizzazione nella cache. Grazie.
Runer112,

7

Operatori vettorizzati per l'arte ASCII

Per molte sfide di arte ASCII, è utile generare due diversi modelli per sovrapporli in un secondo momento. Gli operatori vettorizzati possono essere molto utili per ottenere diversi tipi di sovrapposizioni.

Una proprietà utile della vettorializzazione dell'operatore è che l'operatore viene eseguito una sola volta per ciascun elemento della stringa / matrice più corta, mentre gli elementi di quella più grande che non hanno controparti rimangono intatti.

  • .e<

    L'operatore minimo e<lavora per coppie di stringhe, caratteri, matrici e numeri interi; estrae due oggetti dalla pila e spinge la parte inferiore su e indietro.

    Poiché uno spazio ha un punto di codice inferiore rispetto a tutti gli altri caratteri ASCII stampabili, è .e<possibile utilizzare per "cancellare" parti di un modello generato:

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

    Per un esempio completo, vedere la mia risposta a Me Want Honeycomb .

  • .e>

    L'operatore massimo e>funziona come l'operatore minimo, con il risultato opposto.

    Ancora una volta, a causa del punto di codice basso dello spazio, .e>può essere utilizzato per inserire un modello di caratteri stampabili in un blocco di spazi:

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

    Per un esempio completo, vedere la mia risposta a Seven Slash Display .

  • .e&

    L'operatore logico AND e&spinge il suo argomento a sinistra se è falso e il suo argomento a destra altrimenti.

    Se nessuno dei due pattern contiene elementi falsi, questo può essere usato per imporre incondizionatamente un pattern su un altro:

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

    Per un esempio completo, vedi la mia risposta a Stampa la bandiera americana! .

  • .e|

    L'operatore logico OR e|può essere utilizzato come sopra, con ordine degli argomenti invertito:

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

6

Utilizzare &per verificare se un elemento è in un elenco

Per

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

Puoi usare

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

invece, che restituisce rispettivamente 0/1 e verità / falsità.


6

z e matrici non rettangolari

L'operatore zip ztraspone le righe e le colonne di un 1 bidimensionale array A , i cui elementi possono anche essere iterabili.

Per matrici non rettangolari, a differenza di quelle integrate zip funzioni integrate in, ad esempio, Python (tronca le righe della stessa lunghezza) o Ruby ( nilriempie le righe con ) - CJam converte semplicemente le colonne dell'array in righe, ignorandone le lunghezze e lacune.

Ad esempio, zippare l'array

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

equivale a zippare l'array

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

o l'array

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

come tutte e tre le azioni spingono

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

sullo stack.

Mentre questo significa che z non si tratta di un'involuzione (che sarebbe utile in alcune occasioni), ha alcune applicazioni.

Per esempio:

  • Possiamo allineare le colonne di un array verso l'alto (ovvero, trasformare il primo array nel secondo) zippando due volte:

    zz
    
  • Modifiche minori del metodo sopra possono essere utilizzate per problemi simili.

    Ad esempio, per allineare le colonne di un array nella parte inferiore (ovvero, per trasformare il secondo array nel primo), possiamo comprimere due volte con l'ordine delle righe invertito:

    W%zzW%
    
  • Data una matrice di stringhe, possiamo calcolare la lunghezza della stringa più lunga in questo modo:

    :,:e>
    

    Tuttavia, comprimendo e calcolando il numero di righe del risultato, possiamo salvare tre byte:

    z,
    

1 Se una qualsiasi delle "righe" di A non è iterabile, le ztratta come singoli, quindi zippare funziona per array arbitrari.


1
Solo un modo diverso di visualizzare la stessa cosa, ma per me il comportamento è molto più logico se immagino di zconvertire le colonne in righe, mentre i valori vuoti vengono saltati. Nell'esempio, la prima colonna nell'input è 1, 2, 3, la seconda colonna è 4, 5 (la posizione vuota viene ignorata) e la terza colonna è 6. Queste sono quindi le righe del risultato.
Reto Koradi,

@RetoKoradi Questo è un modo molto migliore per descriverlo.
Dennis,

6

eccezioni

Tutte le eccezioni sono fatali in CJam. Poiché l' output su STDERR è ignorato per impostazione predefinita , possiamo utilizzarlo a nostro vantaggio.

Tutti gli operatori in CJam lavorano estraendo zero o più elementi dallo stack, eseguendo alcune attività e spingendo zero o più elementi nello stack. Si verificano eccezioni durante l'esecuzione dell'attività, quindi questo fa ancora apparire gli elementi, ma nulla viene spinto in cambio.

Ecco alcuni casi d'uso:

  • Svuotare una piccola pila

    Per cancellare una pila che contiene due elementi, è @possibile utilizzare. @tenta di far apparire tre elementi dello stack, ma non riesce dopo aver fatto scattare il secondo.

    Qualsiasi altro operatore che apre tre elementi avrebbe lo stesso scopo.

    Guardalo in azione qui .

  • Rimozione di due o tre elementi dalla pila

    Qualsiasi operatore non implementato per questi elementi particolari può essere utilizzato per estrarre due o tre elementi dallo stack prima di uscire.

    Per far apparire due elementi, b funziona se uno di essi è un carattere o nessuno di essi è un numero intero.

    Per far apparire tre elementi, tfunziona se nessuno dei due più in basso è un iterabile, il più in basso più iterabile è vuoto o nessuno di essi è un numero intero.

  • Uscita da un ciclo

    A volte, dobbiamo uscire da un ciclo quando un numero intero diventa zero o una stringa diventa troppo corta. Invece di testare queste condizioni, se le operazioni coinvolte falliscono per zero, la stringa vuota o i singleton, possiamo semplicemente lasciare che il programma faccia il suo corso naturale.

    Per un esempio di aritmetica, vedi qui .

    Per un esempio di stringhe, vedere qui .

  • Esecuzione condizionale

    Se il codice sorgente non deve essere eseguito per determinati tipi di input, a volte possiamo usare un operatore che fallisce quel tipo di input.

    Ad esempio, inon riuscirà per le stringhe che non valutano un numero intero e ewnon riuscirà per le stringhe di lunghezza 0 o 1.

    Guardalo in azione qui .


5

Max / Min da un array

Eccone uno per cominciare!

Quando è necessario trovare il numero massimo o minimo da un array, il modo più semplice e più piccolo è ordinare l'array e quindi eliminare il primo o l'ultimo elemento.

Quindi se l'array è in variabile A

A$W=

è il massimo e

A$0=

è il minimo.

Ottenere entrambi allo stesso tempo è anche possibile

A$)\0=

Questo potrebbe sembrare ovvio dopo aver letto, ma il primo tentativo di chiunque tende ad andare verso l'uso e<o e>tramite iterazione attraverso l'array, che va come

A{e<}*

che è più lungo di 2 byte e anche più lungo se si desidera sia il massimo che il minimo.


Naturalmente, se non ti dispiace che il resto dell'array rimanga nello stack, puoi effettivamente usare (e )invece di 0=e W=.
Martin Ender,

Ora c'è :e<e:e>
aditsu, il

@aditsu Tuttavia, non sono più brevi del suggerimento sopra.
Ottimizzatore

5

Utilizzare un timestamp per numeri grandi

Se hai bisogno di un numero molto grande, ma arbitrario, di solito utilizzerai la notazione scientifica come 9e9o aumenti una delle grandi variabili incorporate a un potere simile, come KK#. Tuttavia, se non ti interessa quale sia il numero effettivo e non è necessario che sia sempre lo stesso (ad esempio il limite superiore per un numero casuale), puoi farlo in due byte usando

es

anziché. Ciò fornisce il timestamp corrente in millisecondi ed è dell'ordine di 10 12


3
Si noti inoltre che se si desidera un numero arbitrario di grandi dimensioni e si desidera eliminare insieme un numero positivo, è possibile utilizzare e9.
jimmy23013,

5

Verifica che due stringhe / array non siano uguali

A volte vuoi un valore veritiero quando due stringhe o array non sono uguali e un valore falso se lo sono. La soluzione ovvia è di due byte:

=!

Controlla l'uguaglianza e inverti il ​​risultato. Tuttavia, in alcune condizioni è possibile utilizzare

#

Quando #viene applicato a due array, in realtà cerca il secondo array come un subarray del primo (e fornisce l'indice da cui inizia il subarray). Quindi, se i due array sono uguali, il subarray si troverà all'inizio e darà 0, il che è falso. Ma se il secondo array non può essere trovato, darà -1quale è la verità.

Il motivo per cui abbiamo bisogno di qualche condizione aggiuntiva sui due array è che questo produce anche un valore falso se il secondo array è un prefisso non banale del primo, ad esempio:

"abc""ab"#

0anche se le stringhe non sono uguali. La condizione più semplice che esclude questo caso è se sai che entrambi gli array avranno la stessa lunghezza - in quel caso se uno è un prefisso dell'altro, sai che sono uguali. Ma in circostanze specifiche possono esserci condizioni più deboli che sono anche sufficienti. Ad esempio, se sai che le stringhe sono ordinate, un prefisso sarebbe sempre la prima stringa, non la seconda.


5

c e numeri interi a 16 bit

Per aggiungere (o sottrarre) numeri interi a 16 bit senza segno con il wrapping corretto, è possibile utilizzare +65536%o +2G#%.

Tuttavia,

+ci

è molto più breve. I personaggi si avvolgono intorno a 65536 , quindi il lancio su Character ( c) quindi su Long ( i) ha un effetto simile a 65536%, con l'ulteriore vantaggio che il risultato non sarà negativo.

Lo stesso trucco può essere utilizzato per spingere 65535 :

Wci

4

Set di alimentazione

Supponi di avere un array e desideri un array con tutti i possibili sottoinsiemi di tale array. Il trucco è iniziare con un array vuoto, quindi, per ogni elemento, duplicare i sottoinsiemi che già possiedi e aggiungere il nuovo elemento ad essi (mantenendo il risultato precedente in cui l'elemento non è stato aggiunto ). Si noti che è necessario inizializzare lo stack con il case base, ovvero un array contenente solo un array vuoto: Potrebbe apparire così:

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

La cosa bella è che puoi eseguire immediatamente un calcolo sul sottoinsieme, potenzialmente senza caratteri aggiunti. Di 'che vuoi i prodotti di tutti i sottoinsiemi. In tal caso, il caso di base è un array che contiene 1e ad ogni passaggio si prende l'elenco precedente di possibili prodotti, lo si duplica e si moltiplica tutto nel duplicato per il nuovo elemento:

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

4

Controlla se gli elementi in un elenco sono tutti uguali

Penso che valga la pena menzionare anche questo. Uso:

)-

Restituisce verità se non tutti uguali o lista vuota se tutti uguali. Errori se l'elenco è vuoto.

Nel caso in cui l'elemento estratto potrebbe essere un array (o stringa) stesso:

)a-

Utilizzare !o !!per ottenere valori booleani. Nel caso in cui l'elemento estratto possa essere un array e ci siano al massimo due tipi di elementi diversi e si desidera che sia 1 se non tutti uguali, questo è più breve:

_|,(

4

0= per archi

Per recuperare il primo elemento di un array, devi usare 0=(o (, se non ti dispiace lasciare il resto dell'array nello stack).

Tuttavia, se tale matrice è una stringa, è sufficiente eseguire il cast su carattere.

Esempio

"xyz"c e# Pushes 'x.

Non vedo perché CJam non lasci semplicemente cestrarre il primo elemento di qualsiasi array, il che sarebbe più utile e coerente.
Esolanging Fruit

4

Rotazione di un array (o dello stack) di un'unità a sinistra

CJam ha l' operatore di rotazione a sinistram< , che è normalmente quello che dovresti usare per ruotare un array di un numero arbitrario di unità a sinistra.

In alcuni casi, puoi anche usare (+per spostare e aggiungere:

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

Il secondo esempio non ha funzionato perché anche il primo elemento array è iterabile, quindi +concatenato invece di aggiungere.

Inoltre, se si desidera scaricare l'array ruotato nello stack, è possibile utilizzare :\(ridurre mediante scambio) incondizionatamente:

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

Finché non hai un'apertura [, questo trucco può anche essere usato per ruotare l'intero stack, cioè per portare in cima l'elemento stack più in basso:

]:\

3

Stampa un elenco e svuota la pila

Supponiamo che il tuo stack abbia un elenco di stringhe / numeri / ecc. sopra e alcuni altri oggetti extra sotto di esso. vale a dire

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

Ora sei interessato a stampare solo l'ultimo elenco, quindi lo fai

S*]W=

quali uscite

a b rty print me please

Il che sembra davvero intelligente quando usiamo il trucco di eliminazione dello stack e stampiamo solo l'elenco unito con spazi (che a volte potrebbe non essere il modo desiderato di stampare un elenco).

Questo può essere ulteriormente giocato a golf!

p];

Sono 2 byte più brevi !

e se hai solo 1 oggetto in pila diverso dall'elenco, è ancora più breve!

p;

La bellezza di p è che rimuove la maggior parte degli oggetti dallo stack, lo stringe (aggiunge anche una nuova riga alla fine) e stampa istantaneamente su STDOUT, senza attendere il completamento del codice.

Quindi verrà emesso il codice sopra

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

che è l'esatta rappresentazione di un elenco quando era nello stack!


3

Prodotti cartesiani o tutte le possibili combinazioni di due o più set

CJam ha un calcolatore di prodotti cartesiano incorporato m*che prende in pila i primi due arrailisti / stringhe e crea tutte le possibili coppie da esso. Per esempio

[1 2 3 4]"abc"m*

le foglie

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

come la pila

E se volessi tutte le possibili combinazioni da più di 2 liste / stringhe. Lo usi m*molte volte? Per esempio

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

lascerà quanto segue nello stack

[[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]]]

Si noti che i prodotti sono ancora coppie, dove uno dell'articolo è una coppia stessa. Questo non è previsto e vogliamo combinazioni appiattite.

C'è un modo semplice per farlo. Basta racchiudere in un array ogni elenco desiderato per il tuo prodotto cartesiano, creare in coppia prodotti cartesiani e appiattirlo ogni volta:

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

Questo lascia

[['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]]

in pila.

Vuoi che l'ordine venga mantenuto? , è sufficiente scambiare prima di aggiungere nuovamente l'elemento spuntato alla matrice. vale a dire

{m*{(\+}%}*

Vuoi solo permutazioni?

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

Vuoi solo elementi unici nelle combinazioni?

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

È tutto gente. per ora .


1
Ora puoi anche fare ]:m*:e_, con qualsiasi numero di array
aditsu,

3

Operando su stringhe

A volte se si lavora con una struttura di dati complessa, mentre gli elementi in essa contenuti sono semplici, può essere utile la conversione in stringhe.

Ad esempio, se si desidera ottenere il primo o l'ultimo elemento in un array 2D di bit e non si preoccupa del tipo restituito, sA<salva un byte da 0=A<o :+A<.

Oppure, se si desidera modificare alcuni bit nell'input, è possibile modificare la stringa prima di valutarla.

O se hai questa struttura e vuoi convertirla in un semplice elenco:

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

Puoi farlo con molti personaggi in altri modi:

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

Ma può essere molto più breve con le stringhe:

s:~

È più breve anche se può contenere numeri con più di una cifra:

[`La`-~]

O:

`']-~]

Se non è necessario un altro array contenente molti di tali array.


V'è e_ora
aditsu

@aditsu Vedi questa risposta e commento . A volte sfunziona ancora meglio.
jimmy23013,

Certo, quando puoi lavorare direttamente con una stringa, è più breve.
aditsu,

3

Usando Ninvece diLa

In molti casi è necessario inizializzare qualcosa su un array contenente un array vuoto come unico elemento, che è Laapparentemente inutilmente più lungo di 1 byte.

In molti casi è inoltre necessario aggiungere una nuova riga dopo ogni elemento prima della stampa, che sarebbe qualcosa di simile Noo N*.

Ma se entrambi sono veri, a volte potresti scoprire che puoi semplicemente inizializzare l'array con N , che ha il carattere newline come unico elemento. Assicurati di anteporre elementi agli elementi nel resto del codice e la prima cosa da anteporre è sempre un carattere o un array. O solo aggiungere, se una nuova riga iniziale è accettabile e ciò la rende più breve.

A volte Sfunziona anche se è necessario separare l'output con spazi.

In casi più rari, l'elemento iniziale deve essere una stringa. Ma puoi ancora usareNa quale potrebbe essere più breve di aggiungere successivamente la nuova riga.


2

Suddivisione su una o più occorrenze

Supponi di avere una stringa "abbcdbbfghbdbb"e che desideri dividerlab

"abbcdbbfghbdbb"'b/

Questo lascia in pila:

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

Notare le stringhe vuote? Quelli sono lì perché due berano insieme e non c'era nulla tra loro. A volte, vuoi evitarlo. Puoi farlo entro

"abbcdbbfghbdbb"'b/La-

o filtrando stringhe vuote

"abbcdbbfghbdbb"'b/{},

ma sono 3 byte extra.

Un operatore un po 'meno conosciuto per questo particolare caso d'uso è %. Oltre a fare mod e mappa e dividere in base al numero ( "abcd"2%= "ac"), %può anche dividere su stringhe / array. Quindi per il caso d'uso sopra riportato:

"abbcdbbfghbdbb"'b%

lascerà

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

in pila.

Grazie per @ user23013 per averlo segnalato oggi in una delle mie risposte.


Penso che questo dovrebbe essere chiamato "impara anche GolfScript", che ha esempi migliori nella documentazione.
jimmy23013,

@utente23013 ma non siamo mai sicuri di cosa sia simile a GS e cosa no.
Ottimizzatore

2

Usa piega / riduci come infix foreach

Abbiamo :xuna scorciatoia per {x}%e o {x}*(a seconda che xsia unario o binario). Sfortunatamente, non esiste un operatore infix equivalente da abbreviare {x}/. Tuttavia, molto spesso quando lo facciamo {x}/, in xrealtà è un operatore binario che modifica ripetutamente l'oggetto che giace sotto lo stack. In tal caso, e detto articolo non è un array, possiamo salvare un byte abusando di fold / ridurre come foreach:

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

Questo funziona perché fold lascia sempre intatto il primo elemento. Sfortunatamente, non salva un byte, quando l'elemento modificato è un array, perché aggiungendolo lo scarterebbe. Tuttavia, a volte sei abbastanza fortunato che l'array contenga già quell'elemento nella parte anteriore, nel qual caso il riduttore dovrebbe essere tenuto presente (invece di rimuovere manualmente l'elemento prima di usarlo {}/sul resto).


2

stampa e stampa

CJam ha printoperator: o. Funziona ma lo stack viene stampato immediatamente dopo l'esecuzione di tutto il codice. Puoi fermarlo se cancelli lo stack alla fine del programma. Metti semplicemente questo alla fine:

];

Per stampare puoi usare oNoo p(funziona come `oNo)


3
C'è una differenza più grande tra oe p. pinizia convertendo l'elemento da stampare in una rappresentazione di stringa non ambigua. pè equivalente all'esecuzione ​`oNo.
Dennis,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.