Dicas para jogar golfe no GolfScript

35

O que, este post ainda não existe?

Obviamente, o GolfScript é feito para o golfe, então você pode pensar que não são realmente necessárias dicas específicas. Mas, para fazer pleno uso dos recursos do GolfScript, você precisa aprender alguns truques não óbvios. Este post é para coletar dicas e truques úteis.

Para começar, aqui estão as páginas de referência oficiais do GolfScript. Você realmente deve se familiarizar com estes primeiro:

Em particular, eu sugeriria a leitura das páginas nesta ordem - a referência rápida é de pouca utilidade até que você já esteja razoavelmente familiarizado com os built-ins, e o tutorial inclui alguns detalhes importantes que não são explicados nas outras páginas .


Ps. Por uma questão de inspiração e interesse pessoal, aqui estão algumas perguntas que eu gostaria de ver respostas legais para:

  • Como fazer transliteração limitada no GolfScript? {FROM?TO=}%funciona se você pode ter certeza de que todas as entradas são encontradas FROM(ou não se importa de todas elas serem mapeadas para o último elemento de TO), mas todas as maneiras que vi para deixar inalterados os valores não mapeados foram mais ou menos klugey.

  • Como converter melhor uma string em uma matriz de códigos ASCII e vice-versa? Quais operações fazem isso como um efeito colateral? Qual é a melhor maneira de despejar os caracteres em uma string na pilha (como ~faz para matrizes)?

Ilmari Karonen
fonte
Outra pergunta: existe uma boa maneira de transformar ... xem ... [x]? O melhor que posso ver é [.;].
Peter Taylor
@ Peter: Se xé um número, []+funciona e é um caractere mais curto. E, xé claro, se é a única coisa na pilha, então ]será suficiente .
Ilmari Karonen
Gostaria de perguntar as melhores maneiras de fazer: valor mínimo, máximo e absoluto. Todas as minhas soluções parecem ter muito mais caracteres do que deveriam.
Cláudio
Qual é a melhor maneira de modificar uma matriz em um determinado índice?
precisa saber é o seguinte
@ user1502040: Respondida abaixo. (Se alguém souber de uma maneira melhor, por favor, compartilhe!)
Ilmari Karonen

Respostas:

29

Racional / flutuante / complexo

Eu li tantas vezes que o GolfScript tem apenas números inteiros que comecei a acreditar. Bem, não é verdade.

2-1? # Raise 2 to the power of -1. Result: 0.5
4-1? # Raise 4 to the power of -1. Result: 0.25
+    # Add. Result: 0.75

A saída é

3/4

com o intérprete GolfScript padrão e

0.75

no Web GolfScript .

Hackes semelhantes permitem transmitir para o Rational, Float ou mesmo Complex:

{-2.?./*}:rational
{2.-1??./*}:float
{-2.-1??./*}:complex
Dennis
fonte
9
OMGWTFHAX o_O !!!
Ilmari Karonen
3
WAT! Tenho certeza que isso é um bug no intérprete, mas uau #
Maçaneta da porta
3
Linha 82 do intérprete mais recente: Gint.new(@val**b.val). Parece que o Gintconstrutor está faltando um elenco int ...
primo
10

Negando um número

Uma coisa que falta ao GolfScript é um operador de negação embutido. As maneiras óbvias de converter um número na pilha para negativo, como -1*ou 0\-, precisam de três caracteres. No entanto, há uma maneira de fazer isso em dois:

~)

Isso funciona porque o GolfScript usa a aritmética de complemento de dois , de modo que ~ x seja igual a - x −1.

Obviamente, a variante (~também funciona; escolher entre eles geralmente é uma questão de gosto.

Ilmari Karonen
fonte
9

Baralhar uma matriz

A maneira mais fácil de embaralhar uma matriz no GolfScript é classificá-la por uma chave de classificação aleatória. Se você precisar alterar aleatoriamente apenas alguns valores, o seguinte código fará:

{;9rand}$

Observe que, mesmo para listas curtas, isso não dará um shuffle muito bom. Devido ao paradoxo do aniversário , para obter um embaralhamento razoavelmente uniforme, o argumento para randprecisa ser significativamente maior que o quadrado do comprimento da lista que está sendo embaralhada.

Substituir o 9exposto acima 99fornece resultados razoavelmente bons para listas de até dez elementos, mas exibe viés perceptível para listas mais longas.

O código a seguir, que usa 9 9 = 387.420.489 valores possíveis, é bom para até cerca de 1.000 itens (e aceitável para até 20.000):

{;9.?rand}$

Para listas realmente longas, adicione mais 9 para valores de 99 99 × 3,7 × 10197 :

{;99.?rand}$

Teste:

Aqui está a distribuição do primeiro elemento em uma lista de 10 elementos embaralhada usando as diferentes variantes mostradas acima, amostradas em mais de 10.000 tentativas:

  • A saída de 10,{;9rand}$0=mostra um viés muito claro, com 0três vezes mais chances de terminar na primeira posição do que 1:

    0 16537 #######################################################
    1 5444  ##################
    2 7510  #########################
    3 8840  #############################
    4 9124  ##############################
    5 12875 ##########################################
    6 9534  ###############################
    7 8203  ###########################
    8 7300  ########################
    9 14633 ################################################
    
  • Com 10,{;99rand}$0=, a maior parte do viés se foi, mas ainda resta uma quantidade notável:

    0 10441 ##################################
    1 9670  ################################
    2 9773  ################################
    3 9873  ################################
    4 10134 #################################
    5 10352 ##################################
    6 10076 #################################
    7 9757  ################################
    8 9653  ################################
    9 10271 ##################################
    
  • Com 10,{;9.?rand}$0=, a saída é basicamente indistinguível de uma amostra verdadeiramente aleatória:

    0 9907  #################################
    1 9962  #################################
    2 10141 #################################
    3 10192 #################################
    4 9965  #################################
    5 9971  #################################
    6 9957  #################################
    7 9984  #################################
    8 9927  #################################
    9 9994  #################################
    

Ps. Para um embaralhamento muito ruim de matrizes ou seqüências numéricas, o código a seguir às vezes pode ser aceitável:

{rand}$

Geralmente, é ridiculamente tendencioso, mas desde que todos os elementos da matriz de entrada (ou todos os códigos de caracteres na sequência) sejam maiores que um, há uma probabilidade diferente de zero de produzir qualquer permutação da matriz, que às vezes pode satisfazer requisitos de desafio mal escritos.

Ilmari Karonen
fonte
3
Eu me lembro que uma vez cético fez as contas para o paradoxo do aniversário do meu irmão me falou sobre isso, ele estava certo :(
ajax333221
8

Para abordar uma subquestão específica:

Como converter melhor uma string em uma matriz de códigos ASCII e vice-versa? Quais operações fazem isso como um efeito colateral? Qual é a melhor maneira de despejar os caracteres em uma string na pilha (como ~ faz para matrizes)?

Para quem não entende o problema, o sistema de tipos do GolfScript prioriza os tipos na ordem número inteiro, matriz, string, bloco. Isso significa que as operações comuns de matriz aplicadas a uma string quase sempre fornecem uma string. Por exemplo

'ABC123'{)}%

deixará 'BCD234'na pilha.

Como resultado, a melhor maneira de converter uma string em uma matriz de códigos ASCII é quase certamente despejar os caracteres na pilha e reuni-los em uma matriz.

Qual é a melhor maneira de despejar os caracteres em uma string na pilha? {}/

Qual é a melhor maneira de converter uma string em uma matriz de códigos ASCII? [{}/](com a ressalva usual de que, se não houver mais nada na pilha, você pode pular a [)

Qual é a melhor maneira de converter uma matriz de códigos ASCII em uma string? ''+(Observe que isso também nivela a matriz, por exemplo, [65 [66 67] [[[49] 50] 51]]''+'ABC123')

Peter Taylor
fonte
Qual é a melhor maneira de transformar um único código ASCII em uma string? []+''+? (parece um pouco longo)
Justin
@ Quincunx, é bastante longo, mas não conheço nenhuma maneira melhor. A melhor coisa a fazer é verificar de onde veio o código ASCII e verificar se você já pode chegar em um array.
Peter Taylor
6

Se seu programa interromper misteriosamente, verifique suas variáveis

Passei um tempo depurando um programa aparentemente correto que era usado !como uma variável (alegando que eu não o usaria novamente). Infelizmente eu fiz uso if, e verifica-se que a implementação de ifchamadas !a decidir qual ramo seguir.

Peter Taylor
fonte
6

Quebrando o item superior da pilha em uma matriz

Existe uma boa maneira de transformar ... xem ... [x]?

Para generalidade total, a melhor opção parece ser 4 caracteres. No entanto, em certos casos especiais, é possível reduzir isso.

1 char

]funciona no caso especial que xé a única coisa na pilha.

3 caracteres

[]+funciona no caso especial que xé um número inteiro.

.,/funciona no caso especial que xé uma matriz ou sequência de verdade. Por exemplo, "AB".,/["AB"]; 3,.,/[[0 1 2]]. No entanto, "".,/e [].,/ambos dão [].

4 caracteres

[.;] funciona incondicionalmente.

Peter Taylor
fonte
6

Qual é a melhor maneira de modificar uma matriz em um determinado índice? - usuário1502040

Esta é uma boa pergunta. Não existe uma maneira direta de atribuir um valor a um elemento da matriz no GolfScript; portanto, de uma forma ou de outra, você precisará reconstruir toda a matriz.

A maneira mais curta que conheço para inserir um novo valor xno índice iem uma matriz é dividir a matriz no índice especificado e anexar xà primeira metade antes de juntá-las novamente:

  • .i<[x]+\i>+(11 caracteres) - insira o valor xna matriz no índice (com base em 0)i

Para substituir o valor no índice ipor x, basta encurtar a segunda metade da matriz por um elemento:

  • .i<[x]+\i)>+(12 caracteres) - substitua o elemento no índice ( icom base em 0) pelo valorx

Como alternativa, encurtar a primeira metade fará o mesmo, mas com a indexação baseada em 1, que às vezes pode ser preferível:

  • .i(<[x]+\i>+(12 caracteres) - substitua o elemento no índice ( icom base em 1) pelo valorx

Em todos os exemplos acima, se xfor um número, os colchetes ao redor dele podem ser omitidos para salvar dois caracteres, pois serão coagidos automaticamente em uma matriz de +qualquer maneira:

  • .i<x+\i>+(9 caracteres) - insira o número xna matriz no índice (com base em 0)i
  • .i<x+\i)>+(10 caracteres) - substitua o elemento no índice ( icom base em 0) pelo númerox
  • .i(<x+\i>+(10 caracteres) - substitua o elemento no índice ( icom base em 1) pelo númerox

Os colchetes também podem ser omitidos se uma xou a "matriz" de entrada (ou ambas) forem realmente cadeias; nesse caso, o resultado também será coagido em uma cadeia (usando as regras usuais de conversão de matriz → cadeia).


Ps. Como um caso especial, se soubermos que a matriz possui entre ie 2 × ielementos, podemos inserir um novo elemento xno índice ( baseado em 0) icom i/[x]*(6 caracteres). O que isso realmente faz é dividir a matriz em partes de até ielementos e inserir xentre cada parte. Observe que, nesse caso, os colchetes são necessários, mesmo que xseja um número.


Pps. Uma abordagem alternativa é usar variáveis ​​nomeadas dinamicamente. Por exemplo,

 'foo' 42 ':x'\+~

atribuirá o valor 'foo'à variável x42, enquanto

 42 'x'\+~

irá recuperá-lo.

Você pode otimizar isso ainda mais, omitindo o xprefixo e atribuindo apenas diretamente aos literais numéricos - isso é perfeitamente legal no GolfScript e permite salvar um caractere do código de atribuição e encurtar o código de recuperação para apenas `~(ou nada, se o índice é constante!). O lado negativo, é claro, é que a atribuição a um literal numérico substituirá o valor desse literal em qualquer outro lugar do seu código. Freqüentemente, porém, o uso de literais numéricos pode ser evitado (ou pelo menos restrito ao início do programa, antes que qualquer um deles seja reatribuído); nesse caso, esse truque é perfeitamente adequado.

Ilmari Karonen
fonte
3
Completamente fora de tópico: parabéns por 10k! :-D
Maçaneta da porta
11
Se você souber que a matriz não possui valores duplicados, poderá substituir um valor no índice ipor 9 bytes:.[i=]/[x]*
Martin Ender
5

Manipulação final de saída

Por padrão, quando seu programa termina, o intérprete GolfScript gera tudo na pilha, além de uma nova linha final, exatamente como se o seu programa terminasse com:

]puts

O que a documentação não menciona diretamente é que o intérprete literalmente chama o interno putspara produzir essa saída e que esse interno é literalmente definido como:

{print n print}:puts;

Assim, você pode suprimir ou manipular o resultado final através da redefinição puts, print e / ou n(ou  se você está sentindo realmente torcido). aqui estão alguns exemplos:

Suprimir nova linha final:

'':n;

(É claro que você pode deixar de fora ;se não se importar com uma string extra vazia na pilha.)

Suprima completamente a saída final:

:puts

Isso substitui o que putsquer que esteja no topo da pilha. Se isso for algo que você não deseja executar, você pode usar, por exemplo 0:puts;. Observe que isso também suprime p(que é definido como {`puts}:p;), mas você ainda pode usar printpara saída, se desejar.

Ilmari Karonen
fonte
E nothingvocê quer dizer \n?
CalculadoraFeline
Se você não se importa com a nova linha à direita, também pode usar ];para suprimir a saída final.
Wastl
5

Gostaria de perguntar as melhores maneiras de fazer: valor mínimo, máximo e absoluto. Todas as minhas soluções parecem ter muito mais caracteres do que deveriam. - Claudiu

mínimo máximo

Para encontrar o menor / maior valor em uma matriz, basta classificá-lo e pegar o primeiro / último elemento:

  • $0= (3 caracteres) - elemento mínimo em um arry
  • $-1= (4 caracteres) - elemento máximo em uma matriz

Se você souber o comprimento da matriz e tiver 10 elementos ou menos, poderá encontrar o máximo em três caracteres, substituindo -1pelo índice do último elemento.

Se você tiver os valores na pilha, basta coletá-los em uma matriz primeiro. Para isso, um truque ocasionalmente útil é [\]coletar os dois principais elementos da pilha em uma matriz e [@]coletar os três primeiros. Assim, obtemos:

  • [\]$0= (6 caracteres) - mínimo de dois valores na pilha
  • [@]$0= (6 caracteres) - mínimo de três valores na pilha
  • [\]$1= (6 caracteres) - máximo de dois valores na pilha
  • [@]$2= (6 caracteres) - máximo de três valores na pilha

O mesmo truque também pode ser usado para encontrar a mediana de três valores, que podem ser úteis ocasionalmente:

  • [@]$1= (6 caracteres) - mediana de três valores na pilha

Aqui está outro truque potencialmente útil para encontrar o mínimo / máximo de dois valores e deixar os valores originais na pilha :

  • .2$>$ (5 caracteres) - encontre no mínimo dois valores na pilha, deixando os valores originais intocados
  • .2$<$ (5 caracteres) - encontre no máximo dois valores na pilha, deixando os valores originais intocados

A maneira como funciona é que .2$clona os dois principais elementos da pilha na ordem inversa (ou seja, a ba b b a), </ >compara as cópias e retorna 0 ou 1, e o escalar $copia um dos dois valores de entrada, dependendo do resultado da comparação.


Se você tiver dois números inteiros não negativos na pilha, poderá usar ,\,&,(5 caracteres) para encontrar o mínimo e ,\,|,(5 caracteres) para encontrar o máximo. Esse truque usa interseção e união de conjuntos, respectivamente, nos intervalos. Você pode salvar outro caractere se for possível aplicar ,a cada argumento separadamente sem precisar trocá-los. Como esse método calcula um intervalo para cada argumento, não é muito eficiente para números maiores, mas pode ser muito útil para entradas menores.

Uma maneira ainda mais curta de encontrar o mínimo de dois números inteiros não negativos na pilha é ,<,(3 caracteres). Infelizmente, esse truque não funciona para encontrar o máximo.


valor absoluto

O operador de valor absoluto incorporado do GolfScript é abs(3 caracteres). Embora este seja dois caracteres a mais do que eu preferir, é difícil de bater em geral.

Em alguns casos (por exemplo, para classificar por valor absoluto), você pode encontrar o quadrado de um número como um substituto adequado para seu valor absoluto; isso pode ser calculado em dois caracteres, um 2?ou outro .*. Assim, obtemos:

  • {.*}$0= (7 caracteres) - elemento mínimo por valor absoluto na matriz
  • {.*}$-1= (8 caracteres) - elemento máximo por valor absoluto na matriz

Da mesma forma, em vez de, por exemplo, testar se o valor absoluto de um número é menor que 3 com abs 3<(6 caracteres, incluindo espaço), você pode testar se seu quadrado é menor que 9 com .*9<(4 caracteres, sem espaço necessário).

Ilmari Karonen
fonte
Se você tiver dois números inteiros não negativos na pilha, poderá usar ,\,&,(5 caracteres) para encontrar o mínimo e ,\,|,(5 caracteres) para encontrar o máximo. Esse truque usa interseção e união de conjuntos, respectivamente, nos intervalos. Você pode salvar outro caractere se for possível aplicar ,a cada argumento separadamente sem precisar trocá-los. Como esse método calcula um intervalo para cada argumento, não é muito eficiente para números maiores, mas pode ser muito útil para entradas menores.
precisa saber é o seguinte
@KirarinSnow: Obrigado! Eu adicionei à resposta.
Ilmari Karonen
4

Removendo duplicatas de uma matriz

Os operadores de conjunto |(união), &(interseção) e ^(diferença simétrica) recolherão vários elementos da matriz em um. Portanto, a maneira mais simples de remover elementos duplicados de uma matriz é levar sua união ou interseção consigo mesma:

.|

ou:

.&

Esses operadores tratam as strings como matrizes de caracteres, para que também possam ser usados ​​para remover caracteres duplicados das strings.

Ilmari Karonen
fonte
4

Transliteração limitada

Para abordar uma subquestão específica: dada uma string, qual é a melhor maneira de executar uma tr? Por exemplotr/ABC/abc/

Se todos os caracteres da string forem afetados, isso é bastante fácil: {'ABC'?'abc'=}%(overhead: 9 caracteres).

No entanto, isso será interrompido se alguns dos caracteres não forem transliterados e 'ABC'?der -1.

Se a transliteração não for cíclica, poderá ser feita uma substituição por vez com divisões e junções de strings: 'AaBbCc'1/2/{~@@/\*}/(sobrecarga: 15 caracteres). Isso pode ser improvável, mas há uma abordagem alternativa que atualmente é melhor e funciona para transliterações cíclicas.

Atualmente, as soluções gerais mais curtas têm uma sobrecarga de 14 caracteres:

  • Uma abordagem envolve um caractere de escape:, onde denota um byte nulo literal. (Obviamente, esse método não é completamente{.'ABC'?'abc0'=\or}%0 geral: não pode mapear nenhum outro caractere para um byte nulo.)

  • Como alternativa, {.'ABC'?'abc'@),+=}%possui a mesma sobrecarga, mas usa apenas caracteres ASCII imprimíveis. A @),+é uma maneira complicada (mas, aparentemente, a mais curta) para garantir que a cadeia de substituição sempre termine com o caractere de entrada.

Peter Taylor
fonte
Usando a última abordagem, para a string de entrada 'ABCDEF'eu recebo o resultado 'abc000', mas o resultado correto seria 'abcDEF'. Estou esquecendo de algo?
Cristian Lupascu
11
@ w0lf, que 0 é em negrito porque é o caractere de escape mencionado anteriormente - ou seja, o byte 0.
Peter Taylor
4

Transformar uma string em uma matriz de caracteres

Você pode fazer isso digitando: 1/ depois.

Exemplo: "String"1/empurra para empilhar a matriz['S''t''r''i''n''g'] .

Isso é útil quando você deseja mover caracteres pela string.

user3700847
fonte
11
Você pode dar um exemplo de como isso pode ser útil? As strings já agem como matrizes, então isso não parece tão útil.
23414 Justin justin
@Quincunx é útil quando você quiser pop caracteres para fora e não o seu valor ascii
user3700847
E quando você quer fazer isso?
21714 Justin
5
@ Quincunx: Girando uma string, por exemplo. "abc"1/(+-> "bca", mas "abc"(+-> bc97.
Dennis
4

Atribuindo a números literais

Freqüentemente, em vez de escrever 1:xe usar / atualizar a variável x, você pode apenas usar e atualizar 1diretamente:

1:^;{^.p.+:^;}5*
{1.p.+:1;}5*       (4 bytes shorter)

Obviamente, isso também funciona para outros valores iniciais, mas será interrompido se esse valor ocorrer em qualquer outro lugar do seu código.

Pontuação como nomes de variáveis

Se você tem a variáveis usar, é também muitas vezes aconselhável usar pontuação que não está já em seu código - lotes de programas pode fazer sem &, |,^ , ou ?. Dessa forma, por exemplo, você pode escrever em &nvez de x npressionar sua variável e, em seguida, pressionar uma nova linha.

Lynn
fonte
3
Algumas atribuições podem ter efeitos colaterais inesperados. Em particular, atribuindo a !muitas vezes é uma má idéia, como ele vai quebrar ife do(bem como while, until, and, ore xor). Da mesma forma, oré definido pelo intérprete como um alias para 1$\if, então redefinindo 1, $ou \também o quebrará. Redefinindo `intervalos p.
Ilmari Karonen
3

Filtrando uma matriz

A maneira mais geral de filtrar uma matriz é usar { },, que avalia o bloco de código para cada elemento da matriz e seleciona os elementos para os quais o valor resultante é verdadeiro (ou seja, age comogrep em Perl).

No entanto, o uso do operador de subtração de array -geralmente é mais curto. Esse operador pega duas matrizes e remove todos os elementos que ocorrem na segunda matriz da primeira. Ele não alterar a ordem dos elementos na primeira matriz ou colapso duplicados. Um truque útil é aplicar a operação de subtração duas vezes para gerar um operador de interseção de matriz sem colapso:

  • a b -: remover todos os elementos encontrados na matriz bda matriza
  • a. b --: remova quaisquer elementos não encontrados na matriz bda matriza

Em particular, isso pode ser usado para contar o número de vezes que um elemento ocorre em uma matriz:

  • a.[c]--,: conte o número de vezes que o elemento cocorre na matriza

Em geral, esse método não é o ideal, pois:

  • a[c]/,(: conte o número de vezes que o elemento cocorre na matriza
  • a{c=},,: conte o número de vezes que o elemento cocorre na matriza

é um caractere mais curto (e, se estiver correto para a contagem ser desativada em um, a[c]/,salva um caractere a mais). No entanto, no caso especial em que cé um número e aé uma matriz normal (não uma string), os colchetes ao redor cpodem ser omitidos porque o -operador coage seus argumentos para o mesmo tipo:

  • a.c--,: conte o número de vezes que o número cocorre na matriz (não string!)a

(Se afor uma sequência e cfor um número entre 0 e 9, a.c--contará o número de vezes que o dígito c ocorre a.)


Um truque semelhante pode ser usado para encontrar o elemento mais comum em uma matriz :

:a{a\[.]-,}$0=

Novamente, se a entrada for uma matriz de números, toda a [.]sequência poderá ser omitida. Infelizmente, isso não funciona para seqüências de caracteres sem o [.].

Ilmari Karonen
fonte
Para contar ocorrências (caso geral) a[c]/,(e a{c=},,é um byte mais curto.
Dennis
@ Dennis: Obrigado! Eu editei isso em.
Ilmari Karonen
3

Leia de STDIN

O GolfScript pode ler a partir de stdin:

"#{STDIN.read}"

Isso continuará lendo do STDIN até que o EOF seja alcançado. Alternativamente:

"#{STDIN.gets}"

ou

"#{STDIN.readline}"

Outras coisas disponíveis:

getbyte
getc
gets([sep])
gets(limit)
gets(sep, limit)
inspect # perhaps useful for an underhanded contest
isatty
read([length])
readbyte
readchar
readline([sep])
readline(limit)
readline(sep, limit)
readlines([sep])
readlines(limit)
readlines(sep, limit)
readpartial(maxlen [, outbuf])

Para cada um deles, eles podem ser usados ​​apenas uma vez (e também uma vez para cada alteração do parâmetro, também mais uma vez com parênteses vazios); depois disso, o valor original é o que você obterá, em vez de um novo valor.

Justin
fonte
2
Você pode adicionar uma observação que {"#{STDIN.readline}"p}2*não leia 2 linhas, mas a sequência será avaliada apenas uma vez.
Howard
2
Se você inicializar ipara qualquer número inteiro, '"#{'i):i';STDIN.gets}"'++~fornecerá um resultado diferente toda vez que for avaliado. Também vale a pena mencionar os backticks. Se assumirmos o Linux, podemos usar, por exemplo, em `head -1`vez de STDIN.gets.
Dennis
@Dennis: "#{var'g','gpush Gstring.new(STDIN.gets)'.cc}";também permite definir um novo operador GolfScript g que lê uma linha do stdin e a pressiona na pilha.
Ilmari Karonen
2

Decodificando entrada hexadecimal

O GolfScript não possui literais inteiros hexadecimais, portanto, você não pode simplesmente analisar a entrada hexadecimal com ~ . Em vez disso, se seu código precisar receber entrada hexadecimal, será necessário analisá-lo manualmente.

Esse loop de 8 caracteres, aplicado a uma string, converterá dígitos hexadecimais em minúsculas em seus equivalentes numéricos:

{39%9-}%

Se você precisar (também) aceitar dígitos hexadecimais em maiúsculas, a solução mais fácil (e provavelmente a mais curta) é primeiro minúscula-los com 32|um total de 11 caracteres:

{32|39%9-}%

Observe que tecnicamente a saída ainda será uma string (que consiste nos caracteres ASCII de 0 a 15), mas a maioria das funções da matriz GolfScript também aceitará strings. Se você precisar absolutamente de uma matriz, sempre poderá usar [{39%9-}/](onde a primeira [é opcional se a pilha estiver vazia).

Para converter a saída do código acima em um número inteiro, você pode simplesmente usar 16base(6 caracteres). Se você deseja uma matriz de bytes, a solução mais curta que encontrei foi simplesmente decodificar cada par de dígitos hexadecimais com 2/{16base}%(11 caracteres). Em conjunto, o código mais curto que encontrei para transformar uma sequência hexadecimal em uma matriz de bytes é 8 + 11 = 19 caracteres:

{39%9-}%2/{16base}%

Observe que a saída desse código é de fato uma matriz, não uma string. Se necessário, você pode especificá-lo concatenando-o, por exemplo, com ""+ou, se você não se importa com uma nova linha extra no final n+,.

Ilmari Karonen
fonte
2

Definindo novos operadores internos

O intérprete GolfScript padrão possui um recurso raramente usado que permite o código Ruby interpolado em literais de string com aspas duplas.

Uma razão pela qual esse recurso não é mais comumente usado é que, desajeitadamente, o código interpolado é executado em tempo de compilação e a saída é armazenada em cache pelo intérprete GolfScript, para que a mesma sequência literal sempre produza o mesmo valor, mesmo dentro avaliação de string.

No entanto, uma coisa para a qual esse recurso é bom é definir novos operadores GolfScript implementados no código Ruby. Por exemplo, veja como definir um novo operador de adição binária que funciona exatamente como o +operador interno padrão :

"#{var'add','gpush a+b'.cc2}";

Realmente não importa onde você coloca a definição no seu código; o novo operador é definido assim que a string de aspas duplas que contém o código Ruby é analisada. O addoperador definido acima funciona exatamente como o +operador interno e pode ser usado exatamente da mesma maneira:

1 2 add          # evaluates to 3
"foo" "bar" add  # evaluates to "foobar"

Obviamente, definir um novo operador de adição é inútil, a menos que você tenha feito algo bobo como apagar o +operador interno . Mas você pode usar o mesmo truque para definir novos operadores que fazem coisas que o Golfscript não pode (facilmente) fazer de forma nativa, como, por exemplo, embaralhar uniformemente uma matriz:

"#{var'shuf','gpush a.factory(a.val.shuffle)'.cc1}";

10,shuf          # evaluates to 0,1,2,...,9 in random order

ou imprimir o conteúdo de toda a pilha:

"#{var'debug','puts Garray.new($stack).ginspect'.cc}";

4,) ["foo" debug  # prints ["" [0 1 2] 3 "foo"], leaving the stack untouched

ou entrada interativa:

"#{var'gets','gpush Gstring.new(STDIN.gets)'.cc}";

]; { "> " print gets ~ ]p 1 } do   # simple GolfScript REPL

ou mesmo acesso à web:

"#{
  require 'net/http'
  require 'uri'
  var'get','gpush Gstring.new(Net::HTTP.get_response(URI.parse(a.to_s)).body)'.cc1
}";

"http://example.com" get

Obviamente, uma implementação um pouco mais arriscada (e mais arriscada!) Deste último seria, por exemplo:

"#{var'get','gpush Gstring.new(`curl -s #{a}`)'.cc1}";

Embora não seja particularmente um jogador de golfe, isso permite ampliar os recursos do GolfScript além do que os comandos internos fornecem.


Como funciona?

A referência autorizada sobre como definir novos operadores GolfScript dessa maneira é, obviamente, o código fonte do intérprete . Dito isto, aqui estão algumas dicas rápidas:

  • Para definir um novo operador nameque execute o código Ruby code, use:

    var'name','code'.cc
  • Dentro do código, use gpoppara ler um valor da pilha e gpushempurrá-lo de volta. Você também pode acessar a pilha diretamente através da matriz $stack. Por exemplo, para empurrar ambos ae bpara a pilha, é Golfier para fazer $stack<<a<<bdo que gpush a;gpush b.

    • As posições dos [marcadores de início da matriz são armazenadas na $lbmatriz. A gpopfunção cuida de ajustar esses marcadores para baixo se a pilha encolher abaixo de sua posição, mas manipular a $stackmatriz diretamente não.
  • O .ccmétodo string que compila o código Ruby em uma string em um operador GolfScript é apenas um invólucro de conveniência Gblock.new(). Tem também as variantes .cc1, .cc2e .cc3que fazem o operador automaticamente pop 1, 2 ou 3 argumentos na pilha e atribuí-los às variáveis a, be c. Há também um .ordermétodo que funciona assim .cc2, exceto que ele classifica automaticamente os argumentos por tipo de prioridade .

  • Todos os valores na pilha GolfScript são (e devem ser!) Objetos do tipo Gint, Garray, Gstringou Gblock. O número inteiro nativo ou matriz subjacente, quando necessário, pode ser acessado por meio do .valmétodo

    • No entanto, observe que Gstring.valretorna uma matriz de Gints! Para transformar uma Gstringem uma sequência Ruby nativa, chame .to_s-a (ou use-a em um contexto que faça isso automaticamente, como interpolação de sequência). A chamada .to_gsde qualquer valor de GS o transforma em um Gstring, para que qualquer valor de GS possa ser especificado .to_gs.to_s.
  • A gpushfunção não quebra automaticamente os números, seqüências de caracteres ou matrizes Ruby nativas nos tipos GS correspondentes; portanto, você terá que fazer isso sozinho chamando explicitamente, por exemplo Gstring.new(). Se você colocar algo diferente de um dos tipos de valor GS na pilha, qualquer código que posteriormente tente manipulá-lo provavelmente trava.

  • Os tipos de valor GS também possuem um .factorymétodo que chama o construtor do tipo, que pode ser útil, por exemplo, para reorganizar matrizes / seqüências de caracteres após manipular seu conteúdo. Todos os tipos também têm um .coercemétodo que executa coerção de tipo :a.coerce(b) retorna um par contendo ae bcoagido para o mesmo tipo.

Ilmari Karonen
fonte