Crie um programa "hacker typer" que processe seu próprio código-fonte


25

Se você não conhece o hacker typer, consulte hackertyper.net . Em resumo, é um programa que gera um pedaço de uma base de código por pressionamento de tecla para efeito cômico. MAS, a versão hackertyper.net é muito fácil de implementar. Ele simplesmente gera três caracteres por vez a partir de um trecho de código arbitrário . Para esse desafio, um programa deve gerar seu próprio código-fonte e imprimir um pedaço de código delimitado por espaço por pressionamento de tecla.

Detalhes

  • Não se pode codificar um nome de arquivo para o programa; deve determinar seu nome dinamicamente. Se o programa for compilado em um executável, ele poderá anexar a extensão de arquivo padrão ao nome do executável (excluindo o .exe se estiver usando o Windows) e supor que o arquivo de origem esteja no diretório do executável. Por exemplo, se um executável C é chamado "hacker", ele deve extrair seu código-fonte de um arquivo chamado "hacker.c" no mesmo diretório. Se um programa compilado tiver uma extensão, ele deverá ser descartado antes de determinar o nome do seu código-fonte ("typer.exe" -> "typer.cs").
  • Os programas devem conter pelo menos 5 espaços, com pelo menos um caractere entre cada espaço. Isso significa que o menor tamanho possível para esse desafio é 9 bytes. Os espaços não precisam ser cruciais para o funcionamento do programa.
  • Qualquer formatação (recuo, novas linhas etc.) deve ser mantida na saída. Essa formatação pode ser impressa com o código que a segue ou segue, o que importa é que a formatação seja mantida.
  • Evite usar comentários para satisfazer o requisito de 5 espaços, a menos que não haja outra maneira de implementar os espaços no idioma de sua escolha.

EDIT : Novas linhas podem ser usadas no lugar de, ou além de, espaços como separadores de pedaços.


1
Estou um pouco confuso. O programa deve ser um problema, ou não?
Orby

8
A maneira como você descreveu isso soa como se fosse aceitável ler o código do arquivo de origem original, o que não seria uma solução. Eu acho que seria uma competição melhor se o programa tivesse que ser uma solução real.
Orby

1
@ Orby, eu diria que o programa não é um quine no sentido tradicional, independentemente de se a leitura da fonte é permitida ou não. Quines não tem entrada, mas esses programas claramente têm.
Hobbies de Calvin

@DrJPepper Seu terceiro marcador faz parecer que qualquer sequência de espaço em branco conta como delimitador, mas você diz especificamente que apenas o espaço é. Você pode esclarecer?
Hobbies de Calvin

2
Esse desafio incentiva a leitura do código-fonte do próprio programa, uma prática tipicamente verboten na construção de quines.
feersum 5/09/14

Respostas:


13

festança, 51 58

for w in $(<$0);do read -sn 1;printf -- "$w ";done

2
É do bash, não shell: Isso não vai funcionar sob traço, ( 2: read: Illegal option -s)
F. Hauri

1
Assumindo festa, pode substituir cat $0e tils com$(<$0)

@broslow thx para feedback; rotulado bash, mesmo comprimento
Will

1
@ Will Sem problemas. É IFS=\ realmente necessário se você omitir o shebang? O IFS padrão é algo como IFS=$'\n\t ', e como você não tem mais uma nova linha, não acho que você precise limitá-la a apenas espaço.

1
for w in `<$0`;{ read \-sn1;printf $w\ ;}
precisa saber é o seguinte

21

HTML e JavaScript, 123

<head></head><body onload="s=(a=document.all)[i=0].innerHTML" onkeyup="a[2].textContent += s.split(/(?= )/)[i++%6]"></body>

Isso funciona de maneira semelhante ao hacker typer, mas com seu próprio código-fonte. Deixe-me saber se eu não entendi as regras.

E aqui está uma versão estilizada (170 caracteres):

<head></head>
<body style="background:#000;color:lime" onload="s=(a=document.all)[i=0].innerHTML" onkeyup="a[3].textContent+=s.split(/(?=\s)/)[i++%6]">
<pre></pre></body>

Eu fiz uma demonstração . Foi modificado porque o JS Bin adiciona muito código extra, mas a ideia geral é a mesma.


2
Eu ficaria surpreso se isso não renderizasse corretamente sem as tags <html> e <head> e sem um fechamento </body>. Você ficaria surpreso com o quanto todos os navegadores perdoam a esse respeito.
Will

2
@ Will Obrigado. A razão pela qual incluí <head>foi que o navegador o adicionará se não estiver lá, para que seja sempre exibido. Eu esqueci <html>embora.
grc

12

Perl + Term :: ReadKey, 56 bytes

use
Term'ReadKey;ReadMode
4;open
0;ReadKey,print
for
<0>

Agradecemos a ThisSuitIsBlackNot pela inspiração original e ao primo por sugerir open 0e <0>.

Observe que a nova linha depois foré realmente desnecessária, exceto que eu preciso incluir uma nova linha extra em algum lugar para elevar a contagem de espaços em branco até o mínimo especificado de cinco.

Observe também que, como o envio de ThisSuitIsBlackNot, este programa requer o módulo Term :: ReadKey do CPAN. No Debian / Ubuntu Linux, este módulo, se já não estiver presente, pode ser facilmente instalado com o comando sudo apt-get install libterm-readkey-perl.

Além disso, para salvar alguns caracteres, este programa não restaura o modo de entrada normal na saída, portanto, talvez você não consiga ver o que está digitando posteriormente. A execução do comando shell stty saneou resetdeve corrigir isso. Esse problema pode ser corrigido, ao custo de 10 bytes extras, com:

use
Term'ReadKey;ReadMode
4;open
0;ReadKey,print
for<0>;ReadMode
0

Bônus: Quine puro, 81 bytes

$_=q{use
Term'ReadKey;ReadMode
4;ReadKey,say
for
split$/,
"\$_=q{$_};eval"};eval

Novamente, a nova linha após a vírgula é necessária apenas para atingir o mínimo de cinco espaços em branco.

Ao contrário do programa de 56 bytes acima, esta versão não precisa realmente ler seu próprio código-fonte, pois é baseada em um quine - especificamente, neste quine:

$_=q{say"\$_=q{$_};eval"};eval

O bom desse quine é que ele pode transportar facilmente uma "carga útil" arbitrária dentro do q{ } bloco, sem precisar repeti-lo. Embora não possa bater <0>em pouco, ele chega bem perto.

Nota: Este programa usa o sayrecurso Perl 5.10+ e, portanto, precisa ser chamado com a opção de linha de comando -M5.010(ou -E). Por consenso estabelecido sobre a meta, essas opções usadas para habilitar os recursos modernos de linguagem não contam como caracteres extras . A solução mais curta que posso encontrar sayé de 83 bytes:

$_=q{use
Term'ReadKey;ReadMode
4;ReadKey,print
for
split/^/,
"\$_=q{$_};eval"};eval

Ambos também podem ser mais amigáveis ​​ao terminal (juntando as duas últimas linhas e) inserindo:

;ReadMode
0

antes do último }.


Uau. Apenas Uau. Muito legal.
ThisSuitIsBlackNot

+1, mas eu recomendo ter o hábito de digitar stty saneem vez de reset(o que poderia, em alguns os, por vezes, estar fazendo algo mais do que apenas redefinindo alguns parâmetros terminais ^^)
Olivier Dulac

Solução muito boa. FWIW open F,$0e <F>pode ser substituído por open 0e <0>. Além disso, eu argumentaria que um post na meta não constitui realmente um consenso. A opção "-M5.01 não leva o idioma a um ponto específico" , como sugere o autor, habilita recursos. Não há versão do perl para a qual esses recursos sejam ativados por padrão.
primo

3
@primo: Por favor, poste sua própria resposta no meta thread, se você não concordar com o existente. O fato de ninguém fazer isso em três anos e meio, até agora, sugere um grau razoável de consenso, pelo menos entre os frequentadores locais que visitam ativamente a meta, mas o consenso sempre pode mudar. (De qualquer forma, da forma como vejo, se ruby golfscript.rb foo.gsconta como um comando válido para executar um programa escrito em GolfScript, perl -M5.010 foo.pldeve contar como um comando válido para executar um programa escrito em "Perl 5.10". Mas esses argumentos realmente pertencem à meta, não aqui.)
Ilmari Karonen

5

Python 3 - 124 bytes - 7 espaços


Código:

from curses import*
s=initscr();noecho()
for x in open(__file__).read().split(" "):s.getch();s.addstr(x+" ")
echo();endwin()

Ungolfed:

from curses import*
# init curses
screen=initscr()
noecho()
# split code into spaces
code = open(__file__).read().split(" ")
for x in code:
    # wait for keypress
    screen.getch()
    # print a bit
    screen.addstr(x+" ")
# deactivate curses
echo()
endwin()

Versão com estilo:

from curses import*
s=initscr();noecho();start_color();init_pair(2,COLOR_GREEN,COLOR_BLACK)
for x in open(__file__).read().split(" "):s.getch();s.addstr(x+" ",color_pair(2))
echo();endwin()

4

Ruby, 85 , 71

require"io/console";f=File.open __FILE__;loop{STDIN.raw &:getc;print f.read(3)||exit}

Pena que IO#rawnão faz parte da biblioteca padrão.

Melhoria

require"io/console";24.times{|q|STDIN.raw &:getc;$><<IO.read($0,3,q*3)}

Este elimina a chamada para saída do Kernel # e usa variáveis ​​globais para encurtar o código.


4

Befunge - 21

~ $ g , 1 +:54*`#@_:0

Estou bastante satisfeito com isso, pois acabei de descobrir sobre o Befunge. Se você não se importa em "digitar" em uma janela pop-up, pode executá-la aqui ou aqui até encontrar um melhor intérprete online.


2

Powershell, 89

(gc $MyInvocation.MyCommand.Path).split(" ")|%{$l+="$_ ";write-host "$l";read-host ;cls}

2

Python 3 - 299

a="""from curses import*
s=initscr()
raw()
noecho()
for x in e:
 s.getch()
 s.addstr(x+' ')
nocbreak()
echo()
endwin()
""";b="""e=(a+'a=#%s#;b=#%s#;%s'%(a,b,b.replace('#','""''"',4))+'exec(a)').split(' ')
""";e=('a="""%s""";b="""%s""";%s'%(a,b,b.replace('#','""''"',4))+'exec(a)').split(' ')
exec(a)

É uma solução. Encurtado de 507 usando exece movendo algumas instruções.


2

C, 211 186 bytes

Minha solução em C usando a biblioteca de maldições. Pode ser mais longo que a outra solução C, mas é um problema. Embora não seja exigido pela pergunta, ainda é muito bom. Também funciona muito bem:

#define R(x)#x
#define T(x)R(x)
#define S(p)char*s="#define R(x)#x\n#define T(x)R(x)\n#define S(p)"p"\nS(T(S(p)))";main(){initscr();noecho();while(*s)if(~getch())addch(*s++);}
S(T(S(p)))

Uma versão mais legível com alguns comentários e outras coisas:

#define R(x)#x /* macros to convert the source code in S into a C-string */
#define T(x)R(x)
#define S(p) char*s="#define R(x)#x\n" \
                    "#define T(x)R(x)\n" \
                    "#define S(p) " p "\n" \
                    "S(T(S(p)))";\
    main(){\
        initscr();\
        noecho(); /* don't echo input */ \
        while(*s)\
            if(~getch()) /*true if character has been typed */ \
                addch(*s++);\
}
S(T(S(p)))

ajuntar com:

gcc -o h h.c -lncurses

2

C - 136 135 132 bytes (somente Windows)

*fopen();**v;b[ 1<<20];main(p,q){v=q; strcpy(b,*v);strcat(b,".c") ;for(*v=fopen(b,"r");~fscanf(*v,"%s",b);printf("%s ",b))getch();} 

Nota: existe um espaço no final do programa que provavelmente não aparecerá.

Não posso garantir que este programa funcione em um único computador que não seja o meu, pois é incrivelmente hacky. As coisas teriam sido muito mais simples quando todos tinham apenas máquinas de 32 bits. Então eu não precisaria me preocupar em sizeof(int*)ter 8 anos (o que definitivamente é; eu imprimi para ter certeza) enquantosizeof(int) é 4.

Felizmente, o nome do executável é armazenado na primeira string em argv. No entanto, colocar um ponteiro como argumento em uma função significa que eu tenho que especificar explicitamente o tipo de TODOS os argumentos para a função - o que significa que eu precisaria digitar intduas vezes - um enorme desperdício de caracteres. Felizmente, encontrei uma solução alternativa. Eu tive o segundo argumento para main q,, ser apenas mais um int. Em seguida, atribuir qa uma variável do tipo int**conseguiu, de alguma forma, capturar todos os bytes necessários da pilha.

Não consegui encontrar nenhum truque para interpretar o tipo de retorno fopencomo um ponteiro sem declarar a função.

Edit: Notei que devo usar em ~fscanf(*v,"%s",b)vez de, fscanf(*v,"%s",b)>0pois o retorno é -1 quando o EOF é atingido.


Isso falha para mim, então não posso testá-lo, mas você deve poder declarar um ponteiro nulo ( void **v;) em vez de prototipar fopen().
Comintern

@ Internin essa alteração não me ajudou a armazenar corretamente o resultado de fopen. Não vejo por que substituir void por int deve fazer a diferença, pois todos os ponteiros têm o mesmo tamanho.
feersum 6/09/14

Bom ponto. Ainda mais curto e mais estável para apenas declarar um ponteiro - isso realmente funciona para mim: b[1<<20];main(int *c,char **v){strcpy(b,*v);strcat(b,".c");c=fopen(b,"r");for(;fscanf(c,"%s",b)>0;printf("%s ",b))getch();}(eu tive que substituir getchar()por um getch()).
Comintern

@ Internin, seu código ainda trava no meu sistema, mas é um bom trabalho fazê-lo funcionar. Eu acho que é como eu disse - cada versão do programa será executada em 1 computador.
feersum

Por que você não usa protótipos K&R? Por exemplo, em *fopen()vez de *fopen(a,b)?
FUZxxl

1

Perl - 87 bytes

#!/usr/bin/perl -040
use Term::ReadKey;open F,$0;ReadMode 3;print''.<F>while ReadKey 0

Eu não vi nada nas regras sobre o que fazer depois que o arquivo foi lido até o final, então ele simplesmente fica aguardando a entrada após a impressão do último pedaço.


1

node.js com LiveScript:

#!/usr/local/bin/lsc
console.log <| require \fs .readFileSync __filename, encoding: \utf8

versão assíncrona:

#!/usr/local/bin/lsc
require \fs .readFile __filename, encoding: \utf8, -> console.log &1

1

Cobra - 147

class P
    def main
        while 1,for a in File.readLines(CobraCore.exePath[:-4]+'.cobra'),print if('[Console.readKey]'and (Console.cursorLeft=0)<1,a,'')*

CobraCore.exePath é tão útil!


1

Javascript ES6, 154

Firefox 154 :

(a= (i=1,b="(a= "+a+")()",s="") => {window.onkeydown=()=>{clear();i=b.indexOf(" ",i+1),d=b.slice(0,i<0?b.length:i);console.log(s+d);if(i<0){i=0,s+=d}}})()

Chrome 175 :

( a= function (i,s){b="( a= "+a+")()";c=console,window.onkeydown=function(){c.clear();s=s||"",i=b.indexOf(" ",i+1),d=b.slice(0,i<0?b.length:i);c.log(s+d);if(i<0){i=0,s+=d}}})()

Ambos 274 :

( a= function (i,s){b="( a= "+a+")()";c=console,window.onkeydown=function(){(clear)?clear():c.clear?c.clear():0;s=s||"",i=b.indexOf(" ",i+1),d=b.slice(0,i<0?b.length:i);c.log(s+d);if(i<0){i=0,s+=d}}})()

Ungolfed (chrome):

( a= function (i,s){        // starting index | undefined, output string
    b="( a= "+a+")()";      // get a string representation of the function
    c=console,
    window.onkeydown=function(){    // on each key down event
        c.clear();                  // clear the output 
        s=s||"";
        i=b.indexOf(" ",i+1);       // get the index of next space
        d=b.slice(0,i<0?b.length:i);// get the string part wanted
        c.log(s+d);                 // print the string
        if(i<0){
            i=0,                    // reset counters
            s+=d                    // adding the string to the main output
        }
    }
})()

Possui duas versões, porque o Chrome não suporta a função de seta e o console não é limpo com o mesmo método

O Firefox trabalha com firebug, parece que o console do desenvolvedor padrão não pode ser limpo de um script.


Você perdeu o requisito de que o usuário tenha que pressionar teclas aleatórias para imprimir a saída?
Optimizer

com certeza !, vou reescrever isso.
Hacketo

0

Groovy - 379

import java.nio.file.*
Path p = Paths.get(System.getProperty("user.dir"))
DirectoryStream<Path> f = Files.newDirectoryStream(p,"*.groovy")
try{for(e in f){read(e.toAbsolutePath().toString())}}
catch(Exception e){ }
finally{f.close()}

void read(String x){
    def s = new File(x).text
    for(e in s.replace("%n"," %n").split(" ")) 
        print e + " " 
    Thread.sleep(200)
}   

Como não existe getch()ou equivalente em linguagens Java e Java-esque como Groovy ... basicamente meu código não lida com pressionamentos de tecla. Isso é tudo: D


0

C, 248 caracteres

Quine verdadeiro

Só funciona no unix, no windows seria implementado usando _getch.

main(){char *p="main(){char *p=\"%s\",s[400];sprintf(s,p,p);system(\"stty raw\");for(p=s;*p!=0;putchar(*p++))getchar();system(\"stty cooked\");}",s[400];sprintf(s,p,p);system("stty raw");for(p=s;*p!=0;putchar(*p++))getchar();system("stty cooked");}

0

HTML e Javascript, 232 bytes

<body><script>var n=0;var f=function (){document.onkeypress=function(){document.body.innerHTML+=("&lt;body>&lt;script>var n=0;var f="+f.toString()+"f()&lt;/script>&lt;/body>").split(" ")[n]+" ";n++;}};f()</script></body>

O tradicional Javascript quine, mas modificado.

JSFiddle aqui .


0

SmileBASIC, 79 75 bytes

LOAD"PRG1:"+PRGNAME$()
PRGEDIT 1
@L
IF BUTTON(2)THEN?PRGGET$();
WAIT
GOTO@L

É muito fácil obter uma linha específica de um programa no SmileBASIC, por isso, basta colocar os espaços antes de cada quebra de linha. Eu pensei que era tão inteligente, colocando os espaços antes de cada quebra de linha, mas aparentemente podemos usar quebras de linha em vez de espaços ...

Explicação:

LOAD "PRG1:"+PRGNAME$() 'load the code into slot 1 so we can easily read 1 line at a time
PRGEDIT 1 'Edit slot 1
@LOOP
IF BUTTON(2) THEN 'When a button is pressed...
                   PRINT PRGGET$(); 'get a line of code and print it
WAIT 'delay so we don't detect the same press multiple times in a single frame.
GOTO @LOOP 

-1

Haskell

{-# LANGUAGE CPP #-}
main = readFile __FILE__ >>= putStrLn

Isso apenas imprime sua fonte.
Carcigenicate
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.