Dicas para jogar golfe em CJam


43

CJam é uma linguagem de golfe baseada em pilha, inspirada no GolfScript, criada pelo usuário do PPCG aditsu .

Assim, na linha de outras perguntas de dicas específicas de idiomas:

Que dicas gerais você tem para jogar golfe no CJam? Poste uma dica por resposta.


4
Veja também Dicas para jogar golfe no GolfScript ; os idiomas são semelhantes o suficiente para que muitos dos truques possam ser adaptados de qualquer maneira.
Ilmari Karonen

2
@IlmariKaronen Depois de analisar as respostas dessa pergunta, eu diria que apenas metade delas se aplica ao CJam, devido a diferenças lógicas ou sintáticas nos idiomas.
Optimizer

Respostas:


23

Módulo correto para números negativos

Muitas vezes é irritante que o resultado da operação do módulo dê o mesmo sinal que o primeiro operando. Por exemplo, -5 3%dá em -2vez de 1. Na maioria das vezes você quer o último. A solução ingênua é aplicar o módulo, adicionar o divisor uma vez e aplicar o módulo novamente:

3%3+3%

Mas isso é longo e feio. Em vez disso, podemos usar o fato de que a indexação de matriz é sempre modular e faz trabalho corretamente com índices negativos. Então, transformamos o divisor em um intervalo e acessamos:

3,=

Aplicado a -5, isso dá 1como esperado. E é apenas um byte a mais que o embutido %!

Se o módulo for uma potência de 2, você poderá salvar outro byte usando a aritmética bit a bit (que também é muito mais rápida). Comparar:

32,=
31&

Para o caso especial de 65536 == 2^16outro byte, pode ser salvo usando o comportamento de quebra automática do tipo de caractere:

ci

13

Empurrando intervalos de caracteres concatenados

  • A cadeia que contém todos os dígitos "0123456789"pode ser escrita como

    A,s
    
  • As letras ASCII maiúsculas ( A-Z) podem ser pressionadas como

    '[,65>
    

    que gera a sequência de todos os caracteres até Z e descarta os primeiros 65 (até @ ).

  • Todas as letras ASCII ( A-Za-z) podem ser pressionadas como

    '[,65>_el+
    

    que funciona como acima, cria uma cópia, converte para minúsculas e acrescenta.

    Mas há uma maneira mais curta de fazer isso!

    O ^operador geralmente esquecido (diferenças simétricas para listas) permite criar os mesmos intervalos enquanto economiza três bytes:

    '[,_el^
    

    '[,cria o intervalo de todos os caracteres ASCII até Z , _elcria uma cópia em minúscula e ^mantém apenas os caracteres das duas seqüências que aparecem em uma, mas não nas duas.

    Como todas as letras da primeira string estão em maiúsculas, todas na segunda estão em minúsculas e todos os caracteres que não são da letra estão nas duas strings, o resultado na string de letras.

  • O alfabeto RFC 1642 Base64 ( A-Za-z0-9+/) pode ser pressionado usando a técnica acima e acrescentando as não letras:

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

    Uma maneira igualmente curta de empurrar essa string utiliza apenas diferenças simétricas:

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

    Como podemos encontrar a corda no começo?

    Todos os intervalos de caracteres usados ( A-Z, a-z, 0-9, +, /) pode ser empurrado como a diferença simétrica de gama para que começam no byte nulo, ou seja 'A,'[,^, 'a,'{,^, '0,':,^, '+,',,^e '/,'0,^.

    Portanto, a execução :,:^em "A[a{):+,/0"vão empurrar os caracteres desejados, mas não na ordem certa.

    Como encontramos a ordem certa? Força bruta para o resgate! O programa

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

    itera sobre todas as permutações possíveis da string, aplica :,:^e compara o resultado à saída desejada ( link permanente ).

  • O alfabeto radix-64 usado, por exemplo, por crypt ( .-9A-Za-z) pode ser gerado usando o método acima:

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

    Este é o método mais curto que eu conheço.

    Como todos os caracteres na saída desejada estão na ordem ASCII, a iteração sobre permutações não é necessária.

  • Nem todos os intervalos de caracteres concatenados podem ser enviados na ordem desejada usando :,:^.

    Por exemplo, o intervalo 0-9A-Za-z;-?não pode ser pressionado executando :,:^qualquer permutação de "0:A[a{;@".

    No entanto, podemos encontrar uma variação girada da string desejada que pode, usando o código

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

    que imprimirá ( permalink ) o seguinte:

    10
    0:@[a{A;
    

    Isso significa que

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

    tem o mesmo efeito que

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

    que só pode ser usado com uma pilha vazia sem anexar a [.


11

Evitar {…} {…}?

Suponha que você tenha um número inteiro na pilha. Se for ímpar, você deseja multiplicá-lo por 3 e adicionar 1; caso contrário, você deseja dividi-lo por 2.

Uma declaração if / else "normal" seria assim:

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

No entanto, o uso de blocos geralmente não é o caminho a seguir, pois {}{}já adiciona quatro bytes. ?também pode ser usado para selecionar um dos dois itens na pilha:

_2%1$3*)@2/?

Este é um byte mais curto.


Quadra-? com uma declaração if vazia é sempre um impedimento. Por exemplo,

{}{2/}?

tem dois bytes a mais que

{2/}|

Se você tiver

{2/}{}?

e o que você está verificando é um número inteiro não negativo, você pode fazer

g)/

O novo {}&e {}|é útil, mas às vezes problemático se você não pode desordenar a pilha.

Ainda assim, no caso de

_{…}{;}?

você pode usar uma variável temporária:

:T{T…}&

1
!)/e g)/são mais curtos nos exemplos.
jimmy23013

11

Instruções de troca

CJam não possui instruções de opção. As instruções aninhadas if funcionam da mesma maneira, mas {{}{}?}{}?já têm 12 bytes de comprimento ...

Se pudermos transformar a condição em um número inteiro pequeno e não negativo, podemos transformar todas as instruções de caso em uma sequência delimitada e avaliar o resultado correspondente.

Por exemplo, se queremos executar code0se o número inteiro da pilha for 0 , code1se for 1 e code2se for 2 , poderemos usar

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

ou

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

ou

"code0 code1 code2"S/=~

S/divide a string em ["code0" "code1" "code2"], =extrai o pedaço correspondente e ~avalia o código.

Clique aqui para ver as instruções do switch em ação.

Por fim, conforme sugerido por @ jimmy23013 e @RetoKoradi, podemos reduzir ainda mais a opção em alguns casos. Digamos code0, code1e code2tenham comprimentos L 0 , L 1 e L 2 , respectivamente.

Se L 0 = L 1 ≥ L 2

"code0code1code2"L/=~

Em vez disso, pode ser usado, onde Lé L 0 . Em vez de dividir em um delimitador, /divida a cadeia em pedaços de comprimento igual aqui.

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

"cccooodddeee012">3%~

pode ser usado em seu lugar. >remove 0, 1 ou 2 elementos do início da string e 3%extrai cada terceiro elemento (começando com o primeiro).


Para o último exemplo, isso tem alguma vantagem "code0code1code2"5/=~? Parece muito mais direto para mim, e tem o mesmo comprimento.
Reto Koradi

@RetoKoradi Se todos os snippets tiverem o mesmo comprimento, não haverá vantagem. Para comprimentos diferentes, seu método pode ser mais curto e mais longo que o método de módulo.
Dennis

11

Valores comuns de array e string de golfe

Existem certas matrizes ou strings curtas que surgem de vez em quando, por exemplo, para inicializar grades. Ingenuamente, estes podem custar 4 ou mais bytes, por isso vale a pena procurar operações com valores internos que fornecerão o mesmo resultado. Especialmente a conversão de base geralmente é útil.

  • [0 1]pode ser escrito como 2,.
  • [1 0]pode ser escrito como YYb(ou seja, 2 em binário).
  • [1 1]pode ser escrito como ZYb(ou seja, 3 em binário).
  • A matriz [[0 1] [1 0]]pode ser escrita como 2e!.
  • [LL] pode ser escrito como SS/(dividir um único espaço por espaços).
  • "\"\""pode ser escrito como L`.
  • "{}"pode ser escrito como {}s.

O último pode ser estendido aos casos em que você deseja que todos os tipos de colchetes salvem outro byte:

  • "[{<()>}]"pode ser escrito como {<()>}a`.
  • "()<>[]{}"pode ser escrito como {<()>}a`$.

Especialmente, o truque de conversão de base pode ser útil para alguns casos obscuros que aparecem de vez em quando. Por exemplo, [3 2]seria E4b(14 na base 4).

Em casos ainda mais raros, você pode até achar o operador de fatoração mfútil. Por exemplo, [2 7]é Emf.

Fique à vontade para estender esta lista se você encontrar outros exemplos.


10

Limpando a pilha

Se você quiser limpar toda a pilha, envolva-a em uma matriz e solte-a:

];

O que é um pouco mais complicado é que, se você fez muitos cálculos, mas apenas deseja manter o elemento da pilha superior e descartar tudo o que está embaixo. A abordagem ingênua seria armazenar o elemento superior em uma variável, limpar a pilha, pressionar a variável. Mas há uma alternativa muito mais curta: agrupar a pilha em uma matriz e extrair o último elemento:

]W=

(Obrigado ao Optimizer, que me mostrou isso outro dia.)

Obviamente, se houver apenas dois elementos na pilha, \;é mais curto.


\;exibirá apenas o elemento abaixo dos Termos de Serviço. Você quis dizer ;;?
CalculatorFeline

1
@CalculatorFeline a segunda metade da resposta é sobre limpar tudo, menos os Termos de Serviço.
Martin Ender

9

e e poderes de dez

Como em muitas outras línguas, você pode escrever em 1e3vez de 1000em CJam.

Isso funciona para bases não inteiras e também para expoentes não inteiros. Por exemplo, 1.23e2empurra 123,0 e 1e.5empurra 3,1622776601683795 (raiz quadrada de 10 ).

O que não é imediatamente óbvio é que 1e3na verdade existem dois tokens:

  • 1empurra o número inteiro 1 na pilha.

  • e3multiplica por 1000 .

Por que isso é importante?

  • Você pode chamar e<numeric literal>algo que já está na pilha.

    2 3 + e3 e# Pushes 5000.
    
  • Você pode mapear e<numeric literal>sobre uma matriz.

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

9

Normas euclidianas

A maneira direta de calcular a norma euclidiana de um vetor, isto é, a raiz quadrada da soma dos quadrados dos seus elementos, é

2f#:+mq

No entanto, há uma maneira muito mais curta.

mh, O operador hipotenusa, aparece dois inteiros um e b a partir da pilha e empurra sqrt (a 2 + b 2 ) .

Se tivermos um vetor x: = [x 1 … x n ], n> 1 na pilha, :mh(reduzir por hipotenusa) obterá o seguinte:

  • Primeiro x 1 e x 2 são pressionados e mhsão executados, deixando sqrt (x 1 2 + x 2 2 ) na pilha.

  • Em seguida, x 3 é pressionado e mhé executado novamente, deixando
    sqrt (sqrt (x 1 2 + x 2 2 ) 2 + x 3 2 ) = sqrt (x 1 2 + x 2 2 + x 3 2 ) na pilha.

  • Após o processamento de x n , ficamos com sqrt (x 1 2 +… x n 2 ) , a norma euclidiana de x .

Se n = 1 e x 1 <0 , o código acima produzirá um resultado incorreto. :mhzfunciona incondicionalmente. (Obrigado a @ MartinBüttner por apontar isso.)

Eu usei esse truque pela primeira vez nesta resposta .


2
Claro, isso tem implicações para a análise numérica de seu programa ...
Peter Taylor

8

Converta da base n com uma lista de números maior que n

CJam converte uma lista em um número com esta fórmula: A 0 * n l + A 1 * n l-1 + A 2 * n l-2 + A l * n 0 (com não negativo n). né a base e lé o comprimento da lista. Isso significa que A i pode ser qualquer número inteiro, que não precisa estar no intervalo de [0,n).

Alguns exemplos:

  • 0bextrai o último item e o converte em número inteiro. Funciona como W=ie salva um byte se não fosse um número inteiro. Mas todo o resto da lista também deve ser capaz de converter em número inteiro.
  • 1bretorna a soma. Funciona como :i:+e salva dois bytes se não fossem números inteiros. Também funciona com listas vazias, enquanto :+não.
  • [i{_1&9 32?_@\m2/}16*;]W%:cconverte um caractere em uma sequência de linhas e tabulações, que podem ser convertidas novamente 2bc. A função de codificação não é fácil de jogar em um programa de código-golfe. Mas você geralmente não precisa disso.
  • Você pode usar o código a seguir para converter uma seqüência de caracteres em caracteres Unicode não em 16 bits, que podem ser convertidos novamente 2A#b128b:c. (As explicações serão adicionadas mais tarde. Ou talvez eu escreva uma nova versão mais tarde.)

    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
    

O método semelhante funciona com qualquer conjunto de nnúmeros inteiros com valores diferentes mod n, se você puder encontrar uma maneira de se livrar do dígito mais significativo.


8

Usando $como ternário se

Quando você não se importa de vazar memória, ou seja, deixando elementos não utilizados na pilha com os quais você limpará mais tarde ];, o operador de cópia $pode ser um substituto útil para o operador ternário ?.

? funciona bem se você conseguir calcular a condição antes de pressionar os dois itens para escolher, mas, na maioria das vezes, a condição realmente depende desses itens, e tê-la em cima deles resulta muito mais natural.

Se você tiver A B Cna pilha, poderá executar

!$

ao invés de

\@?

para copiar Bse Cé verdade ou Anão.

Se Cfor um booleano ( 0ou 1) real , você pode executar

$

ao invés de

@@?

para copiar Ase Cé verdade ou Bnão.


Em retrospectiva, esse é um truque bastante óbvio, mas eu nunca havia pensado nisso antes. Eu o usei pela primeira vez nesta resposta .
214 Dennis

7

Mapa para listas aninhadas

Digamos que você tenha uma lista aninhada, como uma matriz:

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

Ou uma matriz de strings:

["foo""bar"]

E você deseja mapear um bloco no nível aninhado (ou seja, aplicá-lo a cada número ou cada caractere). A solução ingênua é aninhada %:

{{...}%}%

No entanto, você pode realmente empurrar o bloco interno para a pilha e usá-lo f%. fé "map com parâmetro adicional", portanto, ele será mapeado %para a lista externa, usando o bloco como o segundo parâmetro:

{...}f%

Salva dois bytes.

Outro truque interessante para fazer algo como for (i=0; i<5; ++i) for (j=0; j<5; ++j) {...}é

5,_f{f{...}}

O externo fserá mapeado para o primeiro intervalo, fornecendo o segundo intervalo como um parâmetro adicional. Mas agora, se você usar fnovamente, apenas o elemento superior da pilha é uma matriz, então você fmapeia o bloco interno para isso, fornecendo a "variável de iteração" externa como um parâmetro adicional. Isso significa que o bloco interno é executado com ie jna pilha.

Isso tem o mesmo número de caracteres do que apenas mapear um bloco em um produto cartesiano (embora o último fique mais curto se você precisar dos pares como matrizes):

5,_m*{~...}%

A diferença é que esta versão gera uma única matriz de resultados para todos os pares, enquanto a dupla fproduz uma lista aninhada, que pode ser útil se você deseja armazenar os resultados em uma grade, com as variáveis ​​do iterador sendo as coordenadas.

Agradeço ao Dennis por me mostrar esse truque.

0.6.4 Atualizar

fe :agora foram imensamente aprimorados com a utilização de qualquer outro operador, inclusive eles próprios. Isso significa que você pode salvar ainda mais bytes agora. O mapeamento de um operador em uma lista aninhada ficou ainda mais curto agora:

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

Isso realmente não ajuda no mapeamento de blocos para listas aninhadas.

Quanto à aplicação de blocos ou operadores ao produto cartesiano, isso também ficou mais curto agora, tanto para blocos quanto para operadores:

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

5,_f{fx}
5,_ffx

O legal é que agora você pode aninhar isso. Assim, você pode aplicar um operador com a mesma facilidade ao terceiro nível de uma lista:

:::x

Ou um bloco com alguns truques:

{...}ff%

Ótima atualização. Mas ainda não há f~...
jimmy23013 13/02/2015

@ user23013 fespera que um operador binário ~seja unário; você talvez quisesse :~? Além disso, podemos discutir isso no chat
aditsu 13/02/2015

Estou perdendo algo sobre esta atualização 0.6.4? Eu ainda receber mensagens de erro fazendo aqueles truques, como Unhandled char after ':': :( ligação )
Runer112

2
@ Runer112 Funciona para mim. Certifique-se de recarregar corretamente (ou seja, não do cache). Dependendo do seu navegador, Ctrl + F5 deve funcionar.
Martin Ender

@ MartinBüttner Foi realmente causado por armazenamento em cache bobo. Obrigado.
Runer112

7

Operadores vetorizados para arte ASCII

Para muitos desafios de arte ASCII, é útil gerar dois padrões diferentes para superpor mais tarde. Operadores vetorizados podem ser muito úteis para obter diferentes tipos de superposições.

Uma propriedade útil da vetorização do operador é que o operador é executado apenas uma vez para cada elemento da string / matriz mais curta, enquanto os elementos da maior que não possuem contrapartes permanecem intocados.

  • .e<

    O operador mínimo e<trabalha para pares de cadeias, caracteres, matrizes e números inteiros; ele solta dois itens da pilha e empurra a parte de baixo para trás.

    Como um espaço tem um ponto de código mais baixo do que todos os outros caracteres ASCII imprimíveis, .e<pode ser usado para "apagar" partes de um padrão gerado:

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

    Para um exemplo completo, consulte minha resposta para Me Want Honeycomb .

  • .e>

    O operador máximo e>funciona como o operador mínimo, com o resultado oposto.

    Novamente, devido ao baixo ponto de código do espaço, .e>pode ser usado para inserir um padrão de caracteres imprimíveis em um bloco de espaços:

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

    Para um exemplo completo, consulte minha resposta para o Seven Slash Display .

  • .e&

    O operador AND lógico e&pressiona seu argumento esquerdo, se for falso e, caso contrário, seu argumento correto.

    Se nenhum dos padrões contiver elementos falsos, isso poderá ser usado para impor incondicionalmente um padrão sobre outro:

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

    Para um exemplo completo, veja minha resposta para Imprimir a bandeira americana! .

  • .e|

    O operador OR lógico e|pode ser usado como acima, com ordem de argumento invertida:

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

6

Use &para verificar se um item está em uma lista

Para

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

Você pode usar

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

em vez disso, que retorna 0/1 e truthy / falsey, respectivamente.


6

z e matrizes não retangulares

O operador postal ztranspõe as linhas e colunas de um bidimensional uma matriz A , cujos elementos também pode ser iterables.

Para matrizes não retangulares - diferentemente das zipfunções nilinternas em, por exemplo, Python (trunca as linhas com o mesmo comprimento) ou Ruby ( preenche as linhas ) - o CJam simplesmente converte as colunas da matriz em linhas, ignorando seus comprimentos e lacunas.

Por exemplo, compactando a matriz

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

é equivalente a fechar o array

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

ou a matriz

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

como todas as três ações pressionam

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

na pilha.

Embora isso signifique que znão é uma involução (o que seria útil em algumas ocasiões), ele tem alguns aplicativos.

Por exemplo:

  • Podemos alinhar as colunas de uma matriz ao topo (ou seja, transformar a primeira matriz na segunda) fechando duas vezes:

    zz
    
  • Modificações menores do método acima podem ser usadas para problemas semelhantes.

    Por exemplo, para alinhar as colunas de uma matriz com a parte inferior (ou seja, para transformar a segunda matriz na primeira), podemos compactar duas vezes com a ordem inversa das linhas:

    W%zzW%
    
  • Dada uma matriz de cadeias, podemos calcular o comprimento da cadeia mais longa assim:

    :,:e>
    

    No entanto, compactando e calculando o número de linhas do resultado, podemos salvar três bytes:

    z,
    

1 Se qualquer uma das "linhas" de A não for iterável, ztratá-las como singletons, portanto, compactar funciona para matrizes arbitrárias.


1
Apenas uma maneira diferente de visualizar a mesma coisa, mas para mim o comportamento é muito mais lógico se eu imaginar a zconversão de colunas em linhas, enquanto os valores vazios são ignorados. No exemplo, a primeira coluna na entrada é 1, 2, 3, a segunda coluna é 4, 5 (a posição vazia é ignorada) e a terceira coluna é 6. Essas são as linhas do resultado.
Reto Koradi 28/08/2015

@RetoKoradi Essa é uma maneira muito melhor de descrevê-lo.
Dennis

6

Exceções

Todas as exceções são fatais no CJam. Como a saída para STDERR é ignorada por padrão , podemos usar isso para nossa vantagem.

Todos os operadores no CJam trabalham inserindo zero ou mais elementos da pilha, realizando alguma tarefa e pressionando zero ou mais elementos na pilha. Exceções ocorrem enquanto a tarefa é executada, portanto, ainda aparece os elementos, mas nada é enviado em retorno.

Aqui estão alguns casos de uso:

  • Limpando uma pequena pilha

    Para limpar uma pilha que contém dois elementos, @pode ser usado. @tenta exibir três elementos da pilha, mas falha depois de exibir o segundo.

    Qualquer outro operador que exibir três elementos serviria ao mesmo propósito.

    Veja em ação aqui .

  • Removendo dois ou três elementos da pilha

    Qualquer operador que não esteja implementado para esses elementos em particular pode ser usado para exibir dois ou três elementos da pilha antes de sair.

    Para exibir dois elementos, bfunciona se um deles é um caractere ou nenhum deles é um número inteiro.

    Para exibir três elementos, tfunciona se nenhum dos dois inferiores for iterável, o iterável inferior estiver vazio ou nenhum deles for um número inteiro.

  • Saindo de um loop

    Em algumas ocasiões, precisamos sair de um loop quando um número inteiro se torna zero ou uma string se torna muito curta. Em vez de testar essas condições, se as operações envolvidas falharem com zero, a sequência vazia ou os singletons, podemos simplesmente deixar o programa seguir seu curso natural.

    Para um exemplo envolvendo aritmética, veja aqui .

    Para um exemplo envolvendo seqüências de caracteres, veja aqui .

  • Execução condicional

    Se o código-fonte não deve ser executado para certos tipos de entrada, às vezes podemos usar um operador que falha nesse tipo de entrada.

    Por exemplo, ifalhará para cadeias que não são avaliadas como um número inteiro e ewfalhará para cadeias de comprimento 0 ou 1.

    Veja em ação aqui .


5

Max / Min de uma matriz

Aqui está um para iniciantes!

Quando você precisa encontrar o número máximo ou mínimo de uma matriz, a maneira mais fácil e menor é classificar a matriz e remover o primeiro ou o último elemento.

Portanto, se a matriz estiver na variável A

A$W=

é o máximo e

A$0=

é o mínimo.

Obter os dois ao mesmo tempo também é possível

A$)\0=

Isso pode parecer óbvio após a leitura, mas a primeira tentativa de qualquer pessoa tende a ir para o uso e<ou a e>iteração da matriz, que ocorre como

A{e<}*

que é 2 bytes mais longo e ainda mais se você deseja max e min.


Obviamente, se você não se importa com o restante da matriz restante na pilha, pode usar (e, em )vez de 0=e W=.
Martin Ender

Agora existe :e<e:e>
aditsu

@aditsu No entanto, eles não são mais curtos que a dica acima.
Optimizer

5

Use um carimbo de data / hora para grandes números

Se você precisa de um número muito grande, mas arbitrário, geralmente usa notação científica como 9e9ou eleva uma das grandes variáveis ​​incorporadas a um poder semelhante, como KK#. No entanto, se você não se importa qual é o número real e não precisa ser consistentemente o mesmo (por exemplo, o limite superior de um número aleatório), é possível fazê-lo em dois bytes usando

es

em vez de. Isso fornece o registro de data e hora atual em milissegundos e está na ordem de 10 12


3
Observe também que se você deseja um número arbitrário grande e deseja descartar um número positivo juntos, pode usar e9.
jimmy23013

5

Verificando se duas strings / matrizes não são iguais

Às vezes, você deseja um valor verdadeiro quando duas cadeias ou matrizes não são iguais e um valor falso, se forem. A solução óbvia é dois bytes:

=!

Verifique a igualdade e inverta o resultado. No entanto, sob algumas condições, você pode usar

#

Quando #aplicado a duas matrizes, na verdade, procura a segunda matriz como uma sub-matriz da primeira (e fornece o índice onde a sub-matriz inicia). Portanto, se as duas matrizes forem iguais, o sub-arranjo será encontrado logo no início e 0doado, o que é falso. Mas se a segunda matriz não puder ser encontrada, ela dará o -1que é verdadeiro.

A razão pela qual precisamos de alguma condição adicional nas duas matrizes é que isso também gera um valor falso se a segunda matriz for um prefixo não trivial da primeira, por exemplo:

"abc""ab"#

0embora as cordas não sejam as mesmas. A condição mais simples que exclui esse caso é se você souber que as duas matrizes terão o mesmo comprimento - nesse caso, se uma for um prefixo da outra, você saberá que elas são iguais. Mas, em circunstâncias específicas, pode haver condições mais fracas que também sejam suficientes. Por exemplo, se você souber que as strings são classificadas, um prefixo sempre será a primeira, não a segunda.


5

c e inteiros de 16 bits

Para adicionar (ou subtrair) números inteiros de 16 bits não assinados com quebra automática, você pode usar +65536%ou +2G#%.

Contudo,

+ci

é muito mais curto. Os caracteres são agrupados em 65536 , portanto, a conversão para Character ( c) e Long ( i) tem um efeito semelhante a 65536%, com o benefício adicional de que o resultado não será negativo.

O mesmo truque pode ser usado para enviar 65535 :

Wci

4

Conjuntos de potência

Digamos que você tenha uma matriz e deseje uma matriz com todos os subconjuntos possíveis dessa matriz. O truque é começar com uma matriz vazia e, em seguida, para cada elemento, duplicar os subconjuntos que você já possui e adicionar o novo elemento a eles (mantendo o resultado anterior onde o elemento não foi adicionado ). Observe que você precisa inicializar a pilha com o caso base, ou seja, uma matriz que contenha apenas uma matriz vazia: Isso pode ser assim:

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

O bom disso é que você pode executar imediatamente alguns cálculos no subconjunto, potencialmente sem caracteres adicionados. Digamos que você queira os produtos de todos os subconjuntos. Nesse caso, o caso base é uma matriz que contém 1, e a cada etapa, você pega a lista anterior de produtos possíveis, a duplica e multiplica tudo na duplicata pelo novo elemento:

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

4

Verifique se os itens de uma lista são iguais

Eu acho que isso também vale a pena mencionar. Usar:

)-

Retorna verdade se não for a mesma coisa ou lista vazia se for a mesma coisa. Erros se a lista estiver vazia.

Caso o item extraído possa ser uma matriz (ou sequência):

)a-

Use !ou !!para obter valores booleanos. Caso o item extraído possa ser uma matriz e haja no máximo dois tipos de itens diferentes, e você deseja que seja 1 se não for o mesmo, isso é mais curto:

_|,(

4

0= para cordas

Para recuperar o primeiro elemento de uma matriz, você precisa usar 0=(ou (, se não se importa em deixar o resto da matriz na pilha).

No entanto, se essa matriz for uma sequência, a conversão para caractere é suficiente.

Exemplo

"xyz"c e# Pushes 'x.

Não vejo por que o CJam não permite apenas cextrair o primeiro elemento de qualquer matriz, o que seria mais útil e consistente.
Esolanging Fruit

4

Girando uma matriz (ou a pilha) uma unidade para a esquerda

O CJam possui o operador girar para a esquerdam< , que normalmente é o que você deve usar para girar uma matriz com um número arbitrário de unidades para a esquerda.

Em alguns casos, você também pode usar (+para mudar e acrescentar:

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

O segundo exemplo não funcionou porque o primeiro elemento das matrizes também é iterável, portanto +concatenado em vez de anexar.

Além disso, se você quiser despejar a matriz rotacionada na pilha, poderá usar :\(reduzir ao trocar) incondicionalmente:

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

Contanto que você não tenha uma abertura [, esse truque também pode ser usado para girar a pilha inteira, ou seja, para trazer o item da pilha mais inferior para o topo:

]:\

3

Imprimindo uma lista e limpando a pilha

Digamos que sua pilha tenha uma lista de strings / números / etc. na parte superior e alguns outros itens extras abaixo dela. ie

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

Agora você está interessado em imprimir apenas a última lista, para

S*]W=

quais saídas

a b rty print me please

O que parece realmente inteligente, pois usamos o truque de limpar a pilha e imprimimos apenas a lista unida com espaços (que pode não ser a maneira desejada de imprimir uma lista às vezes).

Isso pode ser jogado ainda mais!

p];

Isso é 2 bytes mais curto !

e se você tiver apenas 1 item na pilha que não seja a lista, é ainda mais curto!

p;

A pvantagem é que ele remove o item mais importante da pilha, o especifica (também adiciona uma nova linha no final) e imprime no STDOUT instantaneamente, sem aguardar a conclusão do código.

Portanto, o código acima irá gerar

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

qual é a representação exata de uma lista quando estava na pilha!


3

Produtos cartesianos ou todas as combinações possíveis de dois ou mais conjuntos

O CJam possui uma calculadora cartesiana embutida do produto, m*que pega as duas listas / cadeias de caracteres da pilha e cria todos os pares possíveis. Por exemplo

[1 2 3 4]"abc"m*

sai

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

como a pilha

Mas e se você quiser todas as combinações possíveis de mais de 2 listas / strings. Você usa m*isso muitas vezes? Por exemplo

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

deixará o seguinte na pilha

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

Observe que os produtos ainda são pares, onde um dos itens é o próprio par. Isso não é esperado e queremos combinações achatadas.

Existe uma maneira fácil de fazer isso. Basta agrupar todas as listas que você deseja para o seu produto cartesiano em uma matriz, criar aos pares produtos cartesianos e achatá-lo sempre:

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

Isso deixa

[['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 pilha.

Deseja que o pedido seja mantido? , basta trocar o antes de adicionar o item pop-up novamente à matriz. ie

{m*{(\+}%}*

Deseja apenas permutações?

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

Deseja apenas elementos exclusivos nas combinações?

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

Isso é tudo, pessoal. por agora .


1
Agora você também pode fazer ]:m*:e_, com qualquer número de matrizes
aditsu

3

Operando em strings

Às vezes, se você estiver trabalhando com uma estrutura de dados complexa, enquanto os itens nela forem simples, a conversão em seqüências de caracteres pode ajudar.

Por exemplo, se você deseja obter o primeiro ou o último item em uma matriz 2D de bits e não se importa com o tipo retornado, sA<salva um byte de 0=A<ou :+A<.

Ou, se você quiser modificar alguns bits na entrada, poderá modificar a sequência antes de avaliá-la.

Ou se você conseguiu essa estrutura e deseja convertê-la em uma lista simples:

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

Você pode fazer isso com muitos caracteres de outras maneiras:

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

Mas pode ser muito mais curto com seqüências de caracteres:

s:~

É mais curto, mesmo que possa ter números com mais de um dígito:

[`La`-~]

Ou:

`']-~]

Se você não precisar de outra matriz contendo muitas dessas matrizes.


e_agora
aditsu

@aditsu Veja esta resposta e comentário . Às vezes sainda funciona melhor.
jimmy23013

Claro, quando você pode trabalhar com uma string diretamente, é mais curto.
Aditsu

3

Usando em Nvez deLa

Em muitos casos, você precisa de algo inicializado em uma matriz que contenha uma matriz vazia como seu único elemento, que é Laaparentemente desnecessariamente 1 byte a mais.

Em muitos casos, você também precisa adicionar uma nova linha após cada elemento antes da impressão, o que seria algo como Noou N*.

Mas se os dois forem verdadeiros, às vezes você pode descobrir que pode apenas inicializar a matriz com N, que tem o caractere de nova linha como seu único elemento. Certifique-se de anexar apenas itens aos elementos no restante do código, e a primeira coisa a acrescentar sempre é um caractere ou uma matriz. Ou apenas acrescente, se uma nova linha principal for aceitável e a diminuir.

Às vezes, Stambém funciona se você precisar separar a saída com espaços.

Em casos mais raros, o elemento inicial deve ser uma string. Mas você ainda pode usar o Naque pode ser menor do que acrescentar a nova linha posteriormente.


2

Divisão em uma ou mais ocorrências

Digamos que você tenha uma string "abbcdbbfghbdbb"e queira dividi-lab

"abbcdbbfghbdbb"'b/

Isso deixa na pilha:

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

Observe as cadeias vazias? Aqueles estão lá porque doisb estavam juntas e não havia nada entre elas. Às vezes, você deseja evitar isso. Você pode fazer isso

"abbcdbbfghbdbb"'b/La-

ou filtrando cadeias vazias

"abbcdbbfghbdbb"'b/{},

mas são 3 bytes extras.

Um operador pouco menos conhecido para esse caso de uso específico é %. Além de fazer mod e mapear e dividir com base no número ( "abcd"2%= "ac"), %também pode dividir em strings / matrizes. Portanto, para o caso de uso acima:

"abbcdbbfghbdbb"'b%

vai deixar

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

na pilha.

Obrigado por @ user23013 por apontar isso em uma das minhas respostas hoje.


Eu acho que isso deve ser chamado de "also learn GolfScript", que tem melhores exemplos na documentação.
Jimmy23013

@ user23013 mas nunca sabemos ao certo o que é semelhante ao GS e o que não é.
Optimizer

2

Use fold / reduza como infix foreach

Temos :xcomo abreviação de {x}%e ou {x}*(dependendo se xé unário ou binário). Infelizmente, não há um operador de infixo equivalente para encurtar {x}/. No entanto, muitas vezes quando o fazemos {x}/, xé realmente um operador binário que modifica repetidamente o item que está embaixo da pilha. Se for esse o caso, e o referido item não for uma matriz, podemos salvar um byte abusando da dobra / redução como foreach:

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

Isso funciona porque a dobra sempre deixa o primeiro elemento intocado. Infelizmente, ele não salva um byte, quando o elemento modificado é uma matriz, porque adicioná-lo o desembrulharia. No entanto, às vezes você tem sorte o suficiente para que sua matriz já contenha esse elemento na frente; nesse caso, a redução deve ser lembrada (em vez de remover manualmente o elemento antes de usá-lo {}/no restante).


2

print e println

CJam tem printoperador: o. Funciona, mas a pilha está sendo impressa imediatamente após a execução de todo o código. Você pode pará-lo se limpar a pilha no final do programa. Basta colocar isso no final:

];

Para imprimir, você pode usar oNoou p(funciona como `oNo)


3
Há uma diferença maior entre oe p. pcomeça convertendo o item a ser impresso em uma representação de seqüência inequívoca. pé equivalente à execução ​`oNo.
1111 Dennis
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.