Programando um mundo intocado


87

Vamos definir um programa intocado como um programa que não possui nenhum erro, mas com erro se você modificá-lo removendo qualquer substring contíguo de N caracteres, onde 1 <= N < program length.

Por exemplo, o programa Python 2 de três caracteres

`8`

é um programa primitivo ( obrigado, Sp ) porque todos os programas resultantes da remoção de substrings de comprimento 1 causam erros (na verdade, erros de sintaxe, mas qualquer tipo de erro provoca):

8`
``
`8

e também todos os programas resultantes da remoção de substrings de comprimento 2 causam erros:

`
`

Se, por exemplo, `8tivesse sido um programa sem erros, `8`não seria intocado, porque todos os resultados da remoção de substring devem ter erro.

Sua tarefa neste desafio é escrever o programa intocado mais curto possível, que não requer entrada, mas gera qualquer uma das cinco seguintes palavras:

world
earth
globe
planet
sphere

Qual palavra você escolhe depende inteiramente de você. A única palavra e uma nova linha opcional à direita devem ser impressas em stdout (ou a alternativa mais próxima do seu idioma). O programa mais curto em bytes vence.

Notas:

  • É necessário um programa independente, não uma função.
  • As palavras diferenciam maiúsculas de minúsculas; saída Worldou EARTHnão é permitido.
  • Os avisos do compilador não contam como erros.
  • Os subprogramas com erro podem receber entrada ou dar saída ou fazer qualquer outra coisa, desde que sempre acabem errando.

Aqui está um trecho de pilha que lista os programas que precisam de erro, considerando um programa potencialmente intocado:

<script src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js'></script><script>function go() { var s = $('#i').val(), e = []; for (var i = 1; i < s.length; i++) { for (var j = 0; j <= s.length - i; j++) { e.push(s.substring(0, j) + s.substring(j + i)); } } $('#o').val(e.join('\n---\n')); }</script>Program:<br><textarea id='i' rows='16' cols='80'>`8`</textarea><br><button onclick='go()' type='button'>Go</button><br><br>Programs that should error: (--- separated)<br><textarea id='o' rows='16' cols='80'></textarea><br>


1
@geokavel Sim. Capturar a exceção significa que não é mais um erro.
Calvin's Hobbies

33
Duas vezes mais respostas excluídas que não excluídas. Isso é uma conquista!
9609 DLosc

1
Um programa pode ler seu próprio código-fonte?
113015 Shelvacu

2
Onde visualizar o cemitério de respostas "fechadas, mas sem charuto" e seus comentários?
Vi.

1
@Vi. Obtenha 2.000 representantes para poder ver as postagens excluídas .
ThisSuitIsBlackNot

Respostas:


46

Trilho , 24 bytes

$'main'    #
 -[world]o/

Eu acho que isso funciona. E é ao mesmo tempo curto e legível (tanto quanto o Rail).

  • Se a substring removida incluir qualquer parte $'main'que recebermos Internal Error: Crash: No 'main' function found.
  • Se a subseqüência removida incluir o #, não há como o programa sair corretamente, portanto, ele sempre será encerrado com Crash: No valid move. Acredito que não é possível excluir uma subcadeia, de forma que a faixa forme um loop (infinito) válido.
  • Se a substring removida estiver na frente da #, ela será desconectada do final da pista, para que o trem caia (com o mesmo erro acima).
  • Se a substring removida for posterior a #, ela também desconectará a #partir do final da trilha (e potencialmente até o início da trilha a partir do ponto de entrada $). Então, novamente o mesmo erro.

Quanto ao programa atual: todo programa ferroviário precisa ter uma $'main'(ou uma variante mais longa, mas estamos jogando golfe aqui) como um ponto de entrada para a função e o trem começa no $sudeste. Tudo nessa primeira linha pode fazer parte da trilha, portanto, removê- 'main'la é:

$          #
 -[world]o/

Os -e /são simplesmente trilhos que precisamos deixar o trem fazer essas curvas de 45 °.

[world]empurra a corda worlde a oimprime. #marca o fim da pista - a única maneira de encerrar com segurança um programa ferroviário.

Curiosamente, essa solução é possível porque o Rail permite que as faixas passem pela mainlinha - se isso não fosse possível, #seria após a primeira nova linha e o código sempre poderia ser reduzido para

$'main'
 #

que é um programa válido que não faz nada. (Caracteres não espaciais entre 'e #não afetariam isso.)

Também é bastante interessante: se eu tivesse acabado de jogar a tarefa de imprimir world, não teria sido muito mais curta ou mais simples:

$'main'
 -[world]o#

4
E se eu remover qualquer caractere entre [e]?
Martin Lütke

@ MartinLütke desconectará o /do #.
Martin Ender

2
@ MartinLütke Você não pode apenas remover os suportes, pois eles não são contíguos.
Calvin's Hobbies

E se remover a nova linha entre as duas linhas?
Vi.

1
@Vi. Isso desconecta o sistema $desde o início da linha, de modo que o trem trava imediatamente (a Rail espera que a linha continue no sudeste do país $).
Martin Ender

43

Função ( 186 136 bytes em UTF-16)

╔══════════════╗
║19342823075080╟
║88037380718711║
╚══════════════╝

Este programa imprime "mundo".

A maioria das substrings removidas impede que seja uma caixa completa, da qual o analisador reclamará. As únicas remoções possíveis que deixam uma caixa completa são:

 ╔══════════════╗
|║19342823075080╟  (remove this whole line)
|║88037380718711║
 ╚══════════════╝
 ╔══════════════╗
 ║|19342823075080╟   ← substring starts at | here
 ║|88037380718711║   ← substring ends at | here
 ╚══════════════╝
... ↕ or anything in between these that removes a whole line’s worth ↕ ...
 ╔══════════════╗
 ║19342823075080|╟   ← substring starts at | here
 ║88037380718711|║   ← substring ends at | here
 ╚══════════════╝
 ╔══════════════╗
|║19342823075080╟
 ║88037380718711║  (both lines entirely)
|╚══════════════╝
 ╔══════════════╗
 ║19342823075080╟
|║88037380718711║  (remove this whole line)
|╚══════════════╝

A maioria deles remove a extremidade pendente no canto superior direito da caixa, que é o conector de saída. Sem essa ponta solta, a caixa é apenas um comentário:

╔══════════════╗
║88037380718711║
╚══════════════╝

Este não é mais um programa válido porque o analisador espera um programa com exatamente uma saída:

Erro: os arquivos de origem não contêm um programa (o programa deve ter uma saída).

A única possibilidade que deixa um conector de saída é a última das opções acima, que deixa o seguinte:

╔══════════════╗
║19342823075080╟
╚══════════════╝

No entanto, esse número não codifica uma seqüência de caracteres Unicode válida no UTF-21 esotérico da Funciton. Tente executar isso, você obtém:

Exceção não tratada: System.ArgumentOutOfRangeException: um valor UTF32 válido está entre 0x000000 e 0x10ffff, inclusive, e não deve incluir valores substitutos de ponto de código (0x00d800 ~ 0x00dfff).

Portanto, este programa é intocado.


3
Eu sinto como se você teve sorte no último caso (não que isso é assim tão fácil de obter acidentalmente uma seqüência Unicode válido, mas ainda assim ...)
Esolanging Fruit

34

Visual C ++ - 96 95 bytes

#include<iostream>
#define I(a,b)a<<b
int main()I({std::cout,I('w',I('o',I('r',I('l','d';)))))}

Propriedades:

  1. Você não pode remover nenhuma parte dele int main()sem um erro de compilação.
  2. Você não pode remover a modificar a expansão macros AT ALL, a remoção ade todos os meios main()nunca fica {, removendo ba todos os meios a nossa linha não termina em um ;, removendo <os meios std::cout<'w'provoca um erro, e remoção de <<causas std::cout'w', 'w''o'etc.
  3. Você não pode remover parâmetros da definição ou invocação da macro, os únicos nomes válidos para a definição seriam I(a): I(b)que nunca correspondem e Ique se expandem para antes (; por outro lado, usando I(,causas <<<<e ,)descarta o ponto- e -vírgula (exceto quaisquer outros erros).
  4. Você não pode remover parte de tudo std::coutsem encontrar um líder <<e, portanto, não pode remover nenhum #include<iostream>no início sem um erro de compilação.
  5. Você não pode remover nenhuma parte de um único caractere, ''possui um erro de caractere vazio e 'w,, etc ... tenta transformar tudo em um caractere.
  6. Você não pode remover o lado esquerdo / direito de uma macro sem deixar muitos )ou (do outro lado, por exemplo, você não pode fazer coisas como I('w',I('r'.

Compila online usando o Visual C ++ .

Mais uma vez, isso não é uma prova exaustiva. Se você acha que pode fazê-lo funcionar sem a seção, informe-me.

As versões anteriores usavam uma abordagem consideravelmente diferente e provaram não ser primitivas, por isso removi essas pontuações.


Verificação:

O programa a seguir confirmou que esta versão é pura, usando o clcompilador do Visual C ++ 2010. Queria ter me dado ao trabalho de escrever isso antes:

#include <fstream>
#include <iostream>
char *S = "#include<iostream>\n#define I(a,b)a<<b\nint main()I({std::cout,I('w',I('o',I('r',I('l','d';)))))}";
//uncomment to print source code before compile
// #define prints
int main(){
   for(int i=0; i<95; i++)
      for(int j=i; j<95; j++){
         std::fstream fs;
         fs.open ("tmptst.cpp",std::fstream::out);
         for(int k=0; k<95; k++)
         if(k<i || k>j){
            fs << S[k];
            #ifdef prints
               std::cout<<S[k];
            #endif
         }
         fs.close();
         #ifdef prints
            std::cout<<'\n';
         #endif
         //Compile and surpress/pipe all output
         //if it doesn't compile we get a nonzero errorlevel (i.e.true) from system.
         if(!system("cl -nologo tmptst.cpp >x"))
            return 0;
      }
      std::cout<<"PRISTINE!";
}

1
Observamos que, embora isso seja primitivo neste compilador, não em todos os compiladores.
Joshua

1
Por favor, dê um exemplo ....
Linus

3
Em alguns compiladores, o programa C ++ vazio gera um programa que não faz nada. Dependendo da implementação do iostream, #include <iostream> também pode ser compilado.
Joshua

5
@ Josué Somente subprogramas de tamanho 1 ou superior importam, por isso é irrelevante o que o programa vazio faz.
ThisSuitIsBlackNot

2
@ Comintern, na verdade não. Se você não marcar a caixa para executar o executável, a /copção será incluída automaticamente e ela será compilada (como se estivesse criando uma biblioteca e não um programa). Se você marcar a caixa de execução que o site não inclui /c, você não receberá uma mensagem de sucesso e, em vez disso, encontrará a "LINK: erro fatal LNK1561: o ponto de entrada deve ser definido".
Linus

32

Python 3, 79 33

if 5-open(1,'w').write('world'):a

open(1,'w')abre a saída padrão e, em seguida, imprimimos a sequência. writeretorna o número de caracteres gravados. Isso é usado para proteger contra a remoção de substring: a remoção de parte da string faz com que algo diferente de 5 seja retornado e 5 menos esse valor é avaliado como true. Mas isso faz com que o if-body seja executado e aé indefinido.

Isso é baseado na inteligência primitiva de Anders Kaseorg aqui .

Como apenas uma única instrução precisa ser verificada, isso é muito mais curto que a solução antiga, mas também menos geral.

Solução antiga:

try:
 q="print('world');r=None"
 if exec('e=q')==eval(q[17:]):exec(e)
finally:r

Para verificar se realmente é um programa intocado:

w=r'''try:
 q="print('world');r=None"
 if exec('e=q')==eval(q[17:]):exec(e)
finally:r'''
exec(w)
for j in range(1,len(w)):
 for i in range(len(w)+1-j):
  e=w[:i]+w[i+j:]
  try:exec(e,{});print('WORKED',e)
  except:pass

Alguns pontos-chave:

  • Toda declaração executada pode ser excluída. A verificação de que qfoi executada requer uma declaração fora de q. Os tryresolve esse bem, exigindo pelo menos duas declarações, nenhum dos quais podem ser eliminados totalmente.
  • A verificação do que qfoi executado acontece avaliando rno final.
  • A verificação de que qnão foi modificado é alcançada por eval(q[17:]), que deve avaliar Nonepara qser executado.
  • A ifcondição é um pouco difícil de acertar. Para garantir que foi avaliado, tem o bom efeito colateral da configuração e, que é necessário para definir r. (Esta é a razão pela qual eu usei o Python 3, exprcomo uma função que faz maravilhas para efeitos colaterais no nível da expressão.)

O desafio não é que nenhuma remoção resulte em erro de sintaxe? Você parece provocar erros de tempo de execução.
Martin Lütke

5
@ MartinLütke Qualquer tipo de erro é bom.
Calvin's Hobbies

1
Hum, isso não é 79 bytes?
O Matt

@TheMatt Yeah? Eu apenas os contei novamente e você parece estar certa. Talvez o passado contasse as novas linhas da CRLF ... Que vergonha. Obrigado!
Philipp

25

Haskell, 61

x=uncurry(:)
main=putStr$x('w',x('o',x('r',x('l',x('d',[])))))

Algum tipo de erro está OK? Nesse caso:

Haskell, 39

main=putStr$take 5$(++)"world"undefined

Isso funciona se você remover uma das letras?
lirtosiast

Falha durante a execução. Porque ele tentará avaliar indefinido.
Martin Lütke

Isto e excelente. Preguiçoso avaliação FTW, parece!
DLosc 10/11/2015

1
Desejo 'inits' foi no prelúdio :( Então: main = putStr $ inits "mundo" !! 5 (27 bytes).
Martin Lütke

16

JavaScript, 74 73 35 bytes

if((alert(a="world")?x:a)[4]!="d")x

Acontece que a resposta foi muito mais simples do que eu pensava ...

Explicação

if(
  (
    alert(a="world") // throws a is not defined if '="world"' is removed
        ?x           // throws x is not defined if 'alert' or '(a="world")' is removed
        :a           // throws a is not defined if 'a="world"' or 'a=' is removed
  )
  [4]!="d"           // if "world" is altered fifth character will not be "d"
                     // if 'd' is removed it will compare "world"[4] ("d") with ""
                     // if '[4]' is removed it will compare "world" with "d"
                     // if '(alert(a="world")?x:a)' is removed it will compare [4] with "d"
                     // if '?x:a' is removed [4] on alert result (undefined[4]) will error
                     // if '[4]!="d"' is removed the if will evaluate "world" (true)
                     // if '!', '!="d"' or '(alert...[4]!=' is removed the if will
                     //     evaluate "d" (true)
)x                   // throws x is not defined if reached

// any other combination of removing substrings results in a syntax error

remover tudo a="world", exceto , não com erro
anOKsquirrel 11/11

3
@anOKsquirrel Apenas uma única substring pode ser removida.
Dennis

4
Eu passei por isso como "Posso remover isso? Não, esse erro ocorreria. Isso pode ser excluído? Bem, acho que causaria esse outro erro. Aha! Esses caracteres podem ser removidos! Ah, espera ..." +1
ETHproductions

if(a="world")["bol"+a[4]]não erro.
Anoksquirrel 11/11/2015

4
Vaca sagrada, é duas vezes mais impressionante agora! Gostaria de poder marcar com +1 novamente ...
ETHproductions

15

Java 8, 301 bytes

Porque cada pergunta precisa de uma resposta Java.

class C{static{System.out.print(((((w='w')))));System.out.print((((o='o'))));System.out.print(((r='r')));System.out.print((l='l'));System.out.print(d='d');e=(char)((f=1)/((g=8)-C.class.getDeclaredFields()[h=0].getModifiers()));}public static void main(String[]a){}static final char w,o,r,l,d,e,f,g,h;}

Expandido

class C {
    static {
        System.out.print(((((w = 'w')))));
        System.out.print((((o = 'o'))));
        System.out.print(((r = 'r')));
        System.out.print((l = 'l'));
        System.out.print(d = 'd');
        e = (char) ((f = 1) / ((g = 8) - C.class.getDeclaredFields()[h = 0].getModifiers()));
    }

    public static void main(String[] a) { }

    static final char w, o, r, l, d, e, f, g, h;
}

Explicação

  • public static main(String[]a){} É necessário.
  • Se as declarações de campo forem removidas (ou tornadas não estáticas), o primeiro bloco estático não poderá encontrá-las.
  • Se o bloco estático for removido (ou não estático), os campos não serão inicializados.

A parte mais difícil:

  • Se a finalpalavra-chave for removida, a segunda linha será avaliada 1/(8-8), causando uma / by zeroexceção.

Por que você não pode remover o interior de nenhuma das instruções de impressão?
Nic Hartley

2
@QPaysTaxes Não existe um System.out.print()método vazio . Existe para println(), mas não para print(). Então, se você removê- d='d'lo, daria The method print(boolean) in the type PrintStream is not applicable for the arguments ()como erro (E se você o removesse d=, daria The blank final field d may not have been initializedcomo erro).
Kevin Cruijssen 12/10

15

Função , 143 142 136 bytes

A pontuação está em UTF-8, como de costume, pois o UTF-16 seria dois bytes maior (devido à BOM).

╔══════════╗
║1934282307║╔╗
║5080880373╟╚╝
║80718711  ║
╚══════════╝

Então, eu estou pensando em uma resposta do Funciton há um tempo e achei que seria impossível, porque você sempre pode remover uma linha completa e o código ainda forma um bloco válido. Então conversei com Timwi sobre o assunto, e ele descobriu que você pode colocar o número inteiro em uma única linha, de forma que removê-lo interromperia o programa por falta de um conector de saída.

Porém, literais em uma única linha são notoriamente caros, devido à maior contagem de caracteres e ao maior número de caracteres não ASCII. E sua menção a um bloco de "comentário vazio" me fez pensar ...

Então, eu vim com essa solução mais eficiente, que usa um bloco de comentários vazio adicional, que é interrompido quando você tenta remover qualquer coisa que deixe o bloco literal intacto:

  • Não é possível remover a terceira linha, porque removeríamos o conector de saída.
  • Se removermos a segunda linha, o bloco de comentários perde sua borda superior e quebra.

Isso deixa duas opções (obrigado a Steve por apontar isso):

  • Retire a quarta linha. Isso deixa ambas as caixas intactas. No entanto, quando o número inteiro resultante 19342823075080880373é decodificado, a sequência correspondente conterá o ponto de código 0x18D53Bque não é um caractere Unicode válido, System.Char.ConvertFromUtf32trava com um ArgumentOutOfRangeException.
  • Remova uma linha completa iniciando após o canto superior direito. Novamente, ambas as caixas são deixadas intactas, mas o número inteiro resultante 508088037380718711conteria dois pontos de código inválidos 0x1B0635e 0x140077, levando à mesma exceção.

Observe que, mesmo sem o bloco de comentários vazio, remover a segunda linha levaria a um ponto de código inválido. Mas o bloco de comentários impede que tomemos uma linha de dentro da segunda linha, para obter um número inteiro como, 193428037380718711por exemplo, o que não causaria um erro.


O que acontece se você remover a substring começando com o caractere após o conector de saída e terminando exatamente 1 linha depois? isto é, remover a linha do meio do bloco de comentários e a linha que contém "80718711" no bloco principal, mas deixando os cantos de ambas as caixas intactas.
Steve

@ Steve Alterei a resposta para cobrir esse caso. Depois de analisar um pouco mais, isso realmente me permitiu salvar dois caracteres / seis bytes.
22826 Martin Ender

10

Ruby, 36

eval(*[(s="planet")[$>.write(s)^6]])

Atribuímos e s="planet", em seguida, escrevemos essa string em STDOUT. Isso retorna o número de caracteres gravados. Nós adicionamos 6 com 6, para que, se algo além de 6 caracteres fosse escrito, obteríamos um número inteiro diferente de zero. Em seguida, cortamos sesse índice. Somente o 0º caractere de s"p" é uma sequência de códigos válida (no-op). Passamos isso para eval, usando a (*[argument])sintaxe equivalente a apenas (argument)exceto que não é válida fora de uma chamada de método.

Pristineness verificado programaticamente no Ruby 1.9.3 e 2.2


Caralho. Isso é incrível.
clap

O que acontece se você remover o *?
usar o seguinte

Então você está passando uma matriz para avaliar em vez de uma string, que é um ArgumentError.
histocrat

9

C #, 128 118 101 bytes

Pensou em abusar da regra de substring contígua.

O código

class h{static void Main()=>System.Console.Write(new char[1
#if!i
*5]{'w','o','r','l','d'
#endif
});}

Por que Funciona

  1. class he static void Main()são obrigatórios.
  2. A remoção de qualquer um dos caracteres 'w','o','r','l','d'causa um erro porque a matriz de caracteres é inicializada com comprimento 1*5.
  3. Você não pode remover o conteúdo dentro de Main () sem violar a regra de caracteres contíguos, pois as partes são separadas por pré-processos. (Ver abaixo)

Antes do Golfe e Separação

class h
{
    static void Main() =>
        System.Console.Write(new char[1 * 5]{'w','o','r','l','d'});
}

Verificado com

https://ideone.com/wEdB54

EDITAR:

  • Salva alguns bytes usando em #if !xvez de #if x #else.
  • =>Sintaxe de função usada . #if!xem vez de #if !x. Créditos para @JohnBot.
  • Devido à =>sintaxe da função, é possível remover a condição preproc extra.

Oi hélice! Você acha que poderia explicar como e por que sua resposta funciona um pouco mais?
Isaacg

@isaacg Editado. Prova a seguir.
Helix Quar

Eu não posso fazê-lo funcionar sem staticon Main.
Johnbot

@Johnbot Yeah. Deve ter copiado. Fixo.
Helix Quar

Você pode salvar um personagem, fazendo Mainuma função membro Expression-bodied e mais 2, removendo os espaços antes a condição pré-processador: class h{static void Main()=>System.Console.Write(new char[1\n#if!l\n*5]{'w','o','r','l','d'\n#if!o\n});\n#endif\n}\n#endif. Isso é 115 pela minha contagem.
Johnbot

9

MATLAB, 37 36 33 bytes

feval(@disp,reshape('world',1,5))

Como não tenho certeza se temos permissão para gerar também ans = , tive que encontrar uma solução alternativa para a saída de maneira adequada. Usar o fprintf por si só não funcionou, porque não importa o que eu tentei, ele simplesmente se recusou a erro. Usar disp por si só não era uma opção, pois seria necessário apenas 1 argumento e esse argumento, obviamente, também seria executado sem erros.

Se não houver problema em incluir também ans = na saída, o MATLAB poderá ser feito com 20 bytes :

reshape('world',1,5)

eu realmente preciso aprender mais sobre funções
internas

2
Isso realmente depende de quão rigorosas são as regras. Eles afirmam que apenas 'mundo' (+ nova linha à direita opcional) deve ser impresso, então são 33 bytes.
slvrbld

Sim, vamos contar isso como 33. Obrigado pela compreensão :)
de Calvino Hobbies

9

> <> , 17 bytes

e"ooooo7-c0pBhtra

Experimente online!

Imprime "terra".

A única maneira de um ><>programa sair sem erro é executar o ;caractere, o que é um problema, pois você pode remover todos os caracteres antes disso, de modo que esse ;é o primeiro caractere executado. Você pode contornar isso usando o pcomando para modificar o programa para incluir ;durante a execução. A remoção de qualquer seção do código faz com que o ;de nunca ser produzido causando erros através das instruções inválidas B, he t, stack underflow, e loops infinitos tornando-se, eventualmente, ficar sem memória. Eu só tinha que ter certeza de que todos os loops infinitos continuassem preenchendo a pilha.

Todas as variantes foram testadas usando este snippet python:

code = 'e"ooooo7-c0pBhtra'
count = {"invalid":0, "underflow":0, "memory":0}
for l in range(1, len(code)):
    for x in range(0, len(code)-l+1):
        print(code[:x] + code[x+l:], "\t\t", end='')
        try:
            interp = Interpreter(code[:x]+code[x+l:])
            for _ in range(0,1000):
                interp.move()
            print(len(interp._stack), "< ", end='')
            interp2 = Interpreter(code[:x]+code[x+l:])
            for _ in range(0,2000):
                interp2.move()
            print(len(interp2._stack))
            count["memory"] += 1
        except Exception as e:
            print(e)
            if str(e) == "pop from empty list": count["underflow"] += 1
            else: count["invalid"] += 1
print(count) 
#don't judge me

adicionado (uma versão ligeiramente modificada) ao intérprete oficial fish.py pelo criador do> <>. Dos 152 possíveis subprogramas possíveis, 92 com erro devido a instruções inválidas, 18 com excesso de pilha e 42 com falta de memória.

Curiosidades, a primeira versão disso e"ooooo6-c0pAhtratinha alguns subprogramas estranhos que conseguiram usar o comando put para colocar um [que limparia a pilha, no lugar da instrução inválida A. Além disso, "earth" é a única das frases que funcionará com esse método, porque a primeira letra eé uma instrução válida ><>. Caso contrário, o "comando deve ser colocado na frente do programa, e um subprograma válido pode ser "por si só.


8

Ruby, 34

eval(*[($>.write("world")-1).chr])

Isso tem alguns componentes:

eval(*[ O expr ]) é emprestado da resposta do histocrat e é primitivo, além de verificar o valor de retorno do expr é um programa válido de ruby ​​que não gera erros. method(*arr)é uma sintaxe ruby ​​que chama methodcom os valores de arrcomo os argumentos. A razão pela qual isso é necessário aqui é porque ele é válido apenas como parâmetros para um método; portanto, se evalfor removido, (*[expr])será um erro de sintaxe. Se expr for removido, evalreclama-se de não ter argumentos suficientes

$>.write("world")-1não pode ser mutilado, exceto dentro da cadeia e da subtração. $>.write("world")grava "world" em STDOUT e retorna o número de caracteres gravados e subtrai 1. Portanto, se o programa for desmembrado, o valor será exatamente 4 . Se for mutilado (o -1removido ou o encurtado), ele retornará um de -1,0,1,2,3 ou 5 . Qualquer outra manipulação resulta em um erro de sintaxe.

A chamada chrde um número retorna o caractere representado por esse número. Portanto, quando chamado no resultado do exemplo acima, ele gera um erro em -1 e, caso contrário, retorna uma cadeia de caracteres únicos.

Na verdade, não sei por que, mas parece que o ruby ​​interpreta \x04como um caractere de espaço em branco, o que significa que a expressão é válida (programas vazios de ruby ​​não fazem nada). No entanto, qualquer um dos outros caracteres ( \x00- \x03e \x05) resulta em Invalid char '\x01' in expression. Eu descobri isso simplesmente repetindo a matemática possível que eu poderia fazer com o número retornado. Anteriormente eu tinha usado

$>.write("planet
")*16

onde "planet" mais uma nova linha eram 7 caracteres, vezes 16 para obter 112 p, a única função de letra única em ruby ​​definida por padrão. Quando não há argumentos, é efetivamente um no-op


Menção honrosa: $><<"%c"*5%%w(w o r l d)é muito próxima, mas não intocada. Remover "%c"*5%resultados sem erros. Mini-explicação:

$>é stdout e <<é uma função que está sendo chamada. "%c"*5gera a string de formato "%c%c%c%c%c", que então tenta ser formatada ( %) por uma matriz: %w(w o r l d)que é uma versão mais curta ['w','o','r','l','d']. Se houver muito poucos ou muitos elementos na matriz para que não correspondam à sequência de formatação, será gerado um erro. O calcanhar de Aquiles é esse "%c"*5, e %w(w o r l d)ambos podem existir independentemente, e $><<só precisa de um argumento de ambos. Portanto, existem algumas maneiras diferentes de confundir esse programa com primos sem erros.


Validado usando isso:

s = 'eval(*[($>.write("world")-1).chr])'
puts s.size
(1...s.length).each do |len| #how much to remove
  (0...len).each do |i| #where to remove from
    to_test = s.dup
    to_test.slice!(i,len)
    begin #Feels so backwards; I want it to error and I'm sad when it works.
      eval(to_test)
      puts to_test
      puts "WORKED :("
      exit
    rescue SyntaxError
      #Have to have a separate rescue since syntax errors
      #are not in the same category as most other errors
      #in ruby, and so are not caught by default with 
      #a plain rescue
    rescue
      #this is good
    end
  end
end

Uma explicação na linha da resposta do histocrata seria legal. Parece que você está usando a mesma abordagem básica, mas como não conheço Ruby, não consigo entender os detalhes.
carregar a caixa de mensagens

@ThisSuitIsBlackNot Fiz o meu melhor, qualquer coisa que você não entende?
113015 Shelvacu

Excelente explicação, obrigado!
ThisSuitIsBlackNot

6

Python 3 , 43 bytes

for[]in{5:[]}[open(1,"w").write("world")]:a

Experimente online!

Como funciona

Para proteger contra exclusões de substring, usamos em open(1,"w").writevez de print. No Python 3, writeretorna o número de caracteres escritos, que iremos verificar 5para garantir que nenhuma parte da string tenha sido excluída. Fazemos isso pesquisando o valor de retorno no dicionário {5:[]}e repetindo o resultado com for[]in…:a, que falhará se não obtivermos uma iterável vazia ou se a forinstrução for excluída.


4

Javascript (Node.js), 93 95 bytes

if(l=arguments.callee.toString().length,l!=158)throw l;console.log("world");if(g=l!=158)throw g

Verifique seu próprio tamanho duas vezes, se houver algum caractere faltando, será gerado um erro. O comprimento é 156 porque o Node.js precede function (exports, require, module, __filename, __dirname) {o código no tempo de execução.

Obrigado Martin Büttner por apontar um erro. Corrigido agora.


4

Perl 5.10+, 71 63 bytes

(${open 0;@{\(read(0,$a,63)!=63?die:@_)};say"world"});{$a//die}

Imprime worldcom uma nova linha à direita. Execute assim:

perl -M5.010 file

Isso depende da contagem de bytes do código-fonte, portanto filedeve conter o código acima e nada mais (sem shebang, sem nova linha à direita). O Perl 5.10+ é necessário para sayo operador definido ou //.


É incrivelmente difícil criar um programa primitivo com o Perl, porque:

  • Qualquer identificador bareword (por exemplo foo, a, _) é uma declaração válida com no strict 'subs';(o padrão). Isso significa que o programa não pode começar nem terminar com uma letra, número ou sublinhado.

  • Como explica tchrist , "os identificadores especificados por meio de dreferencing simbólico não têm absolutamente nenhuma restrição em seus nomes". Isto significa que o programa não pode começar com qualquer um dos sigilos $, @, %, ou *, uma vez que a remoção de todos, mas o primeiro e último personagem iria deixar sempre um nome de variável válido.

  • Muitas funções internas (incluindo a maioria das funções capazes de produzir saída) funcionam $_por padrão, portanto, as chamadas geralmente funcionam mesmo se você remover o argumento (por exemplo, say"world"vs. say).

Como funciona

Essa solução foi inspirada na resposta Node.js. de Naouak , que verifica seu próprio comprimento para garantir que os caracteres não foram removidos.

O programa possui duas seções, uma entre parênteses e a outra dentro de um bloco:

(...);{...}

A primeira seção lê o arquivo de origem e morre se tiver menos de 63 caracteres. A segunda seção verifica se o readexecutado foi executado com sucesso. Se uma seção for removida (com ou sem parênteses ou chaves), a outra seção lançará uma exceção.

Remover o lado central, esquerdo ou direito do programa desequilibrará os parênteses e / ou chaves, causando um erro de sintaxe.

Se o primeiro dieé alterada (a d, e, di, de, ou ie, que são todos os identificadores válidos), a verificação de comprimento torna-se:

@{\(read(0,$a,63)!=63?di:@_)};

que avalia como:

@{\'di'};

Isso leva uma referência a uma string e tenta desreferenciá-la como uma matriz, produzindo um erro:

Not an ARRAY reference

Se qualquer outra instrução for alterada, a verificação do comprimento falhará e o programa morrerá.


Verificado como novo com o seguinte programa:

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;

use File::Temp;
use List::MoreUtils qw(uniq);

sub delete_substr {
    my ($str, $offset, $len) = @_;

    my $tmp = $str;
    substr($tmp, $offset, $len) = '';

    return $tmp;
}

sub generate_subprograms {
    my ($source) = @_;

    my $tot_len = length $source;
    my @subprograms;                                             

    foreach my $len (1 .. $tot_len - 1) { 
        foreach my $offset (0 .. $tot_len - $len) {
            push @subprograms, delete_substr($source, $offset, $len);
        }                                                        
    }                                                            

    return uniq @subprograms;                                    
}                                                                

chomp(my $source = <DATA>);                                                                                                       
my $temp = File::Temp->new;                                                                                        

foreach my $subprogram ( generate_subprograms($source) ) {       
    print $temp $subprogram;

    my $ret = system(qq{/usr/bin/perl -M5.010 $temp > /dev/null 2>&1});
    say($subprogram), last if $ret == 0;

    truncate $temp, 0;
    seek $temp, 0, 0;
}

__DATA__
(${open 0;@{\(read(0,$a,63)!=63?die:@_)};say"world"});{$a//die}

4

Ruby + coreutils, 33 27 26 bytes

`base#{$>.write"world
"}4`

Experimente online!

Os backticks em ruby ​​executam o comando dentro deles e retornam o que o programa colocou no STDOUT como uma string. A #{expr}sintaxe permite incorporar expressões em strings e backticks. Este programa pode ser reescrito (de forma inexistente) como:

system("base" + (STDOUT.write("world\n")).to_s + "4")

IO#writeretorna o número de bytes gravados; portanto, se a string for encurtada, não será o número certo. #{}a incorporação transforma automaticamente o número em uma sequência. Se alguma peça for removida e não resultar em erro de sintaxe, o comando errado será executado. Se parte de "world"for removida, uma das base04passagens base54tentará executar.

A nova linha, dentro ou fora da cadeia, é necessária. Caso contrário, os 5 primeiros caracteres ( `base) podem ser removidos, tornando a linha inteira um comentário. Também deve haver um ou mais caracteres entre o primeiro backtick e #, caso contrário, ele {pode ser removido para tornar a coisa toda um comentário do shell .


exec(*[(s="ec%co earth")%s[10]])

execSubstitui o processo ruby ​​atual pelo comando especificado. Veja minha outra resposta para uma explicação da meth(*[])sintaxe e da necessidade dela.

(s="ec%co earth")atribui a string "ec% co terra" para a variável s. As atribuições retornam o que foi atribuído, portanto, a sequência também é retornada.

"format string %d" % 5é açúcar sintático para sprintf("format string %d",5), no entanto, espaços ao redor do %não são necessários.

s[10]obtém o caractere na sequência no índice 10. Quando não é mutilado, esse caractere é "h", a última letra da sequência. No entanto, a remoção de qualquer caractere na cadeia de caracteres significa que a cadeia é mais curta; portanto, não há caracteres no índice 10; portanto , s[10]retorna nile "%c" % nilcausa um erro.

se %s[10]for removido, o ruby ​​tenta executar o comando ec%co earthque não funciona.

Alterar 10para 1ou 0também resulta em um comando desconhecido ( eceoou ecco). Removê-lo totalmente não é tecnicamente um erro de sintaxe, pois chama o método #[]na cadeia de caracteres, mas, em seguida, reclama de argumentos insuficientes.


Uma observação sobre como resolver isso em geral: Você deve ter um invólucro que verifique o código interno em um sentido abstrato enquanto estiver intocado. Por exemplo, um programa com divisão no final ( blablabla/somevar) nunca funcionará porque uma divisão sempre pode ser removida ( blablabla). Estes são alguns dos invólucros que usei até agora:

  • eval(*[código ])usado pelo histocrat e na minha primeira resposta. Valida se a saída é um programa ruby ​​válido
  • exec(*[código ])usado acima, valida que a resposta é um comando válido
  • `#{ código }`

A sintaxe do backtick também executa um comando (e, portanto, valida que seja válido), no entanto, STDOUT é capturado como uma sequência em vez de ser exibido como o processo pai '(Ruby's) STDOUT. Devido a isso, não pude usá-lo para esta resposta, EDIT: fiz o trabalho. Limitações descritas acima.

Edit: Obrigado a @histocrat por apontar algumas falhas


Abordagem legal! Você pode (e, portanto, deve) remover o espaço entre writee o início da string, mas acho que isso não afeta a pureza. Além disso, minha máquina base64ficará pendurada aguardando entrada, o que pode ser contra as regras.
histocrat

@histocrat Uau, estou surpreso que $>.write"world"funcione, obrigado! Quanto à base64 aguardando entrada, ela parece variar de acordo com o sistema. O TIO funciona bem. Isso torna ainda mais confuso se segue as regras.
Shelvacu 13/07/19

3

PowerShell, (97 bytes + 5 para o nome do programa) = 102 bytes

"$(try{if(($a=(gc .\c.ps1).Length)-eq97){"world";a}}catch{if($a-ne97){a}$error.clear();exit}a)";a

Verifica-se antes de se destruir ... duas vezes.

Espera ser salvo como c.ps1e executado a partir do diretório local como tal:
PS C:\Tools\Scripts\Golfing\> .\c.ps1.

O alias gcé curto Get-Contente é semelhante a uma catleitura de um arquivo (neste caso, nosso caminho de execução .\c.ps1). Obtemos .Lengtho arquivo, configuramos para $ae verificamos se não é igual a 97 com -eq97. Se for igual (ou seja, o programa não foi modificado), imprimimos com "world"e executamos um comando inválido a. Isso força o catchefeito, o que nos permite verificar a nós mesmos novamente. Dessa vez, se nosso código não for igual a 97, lançamos um comando inválido para que nosso programa cometa um erro e imprima o texto do erro na saída. Nós então clear()o erro e exitnormalmente.

É óbvio que, se uma das ifinstruções for violada, a outra terá um erro. Se qualquer parte "world";for adulterada, a primeira ifcausará um erro. Como precisa ser contíguo, não podemos remover as duas ifinstruções. Seqüências de caracteres no meio resultam em parênteses incompatíveis ou no segundo {a}sendo executado. O try/ catché capturar o erro da primeira ifinstrução para que possamos limpá-lo adequadamente. A parte externa "$( )"impede que as strings de cada extremidade sejam cortadas. A final ;aé impedir que partes do meio sejam cortadas, o que resultaria em programas válidos (por exemplo "it}a)";a, que serão impressos it}a)e, em seguida, com erro).

Existem várias circunstâncias especiais:

  • Se o gc, gc<space>ou gc .\for removido, o programa eventualmente cometerá algum erro de falta de memória (devido a repetidas chamadas de auto-execução) e provavelmente travará o shell (e talvez o computador). Não testado.
  • Se o <space>.\c.ps1ou .\c.ps1for removido, o programa será interrompido e solicitará a entrada do usuário. Não importa o que o usuário insira, o programa continuará com erro, pois a contagem de tamanho estará errada.
  • Se uma subcadeia iniciando no $e terminando antes do último "for cortada, o programa emitirá o que restar e depois erro, porque anão é válido.

Verificado com o seguinte:

$x='"$(try{if(($a=(gc .\c.ps1).Length)-eq97){"world";a}}catch{if($a-ne97){a}$error.clear();exit}a)";a'
$yy='"$(try{if(($a=( .\c.ps1).Length)-eq97){"world";a}}catch{if($a-ne97){a}$error.clear();exit}a)";a'
$yyy='"$(try{if(($a=(.\c.ps1).Length)-eq97){"world";a}}catch{if($a-ne97){a}$error.clear();exit}a)";a'
$yyyy='"$(try{if(($a=(c.ps1).Length)-eq97){"world";a}}catch{if($a-ne97){a}$error.clear();exit}a)";a'

for($i=1;$i-lt$x.Length;$i++){
  for($j=0;$j-lt($x.Length-$i);$j++){
    $y=($x[0..$j]+$x[($i+$j+1)..$x.Length])-join''
    $y>.\c.ps1
    $error.clear()
    if(!($y-in($yy,$yyy,$yyyy))){try{.\c.ps1}catch{};if(!($error)){exit}}
    $q++;
    write-host -n "."
    if(!($q%150)){""}
  }
}
"No success."

(Obrigado a Martin por sua extensa assistência!)


3

C (gcc) (Linux -Werror=undef), 66 bytes

main(a){a
=
1
/
(puts("world")/
6);
#if(7^__LINE__)
#else
}
#endif

Experimente online!

Grande desafio! Isso foi enganosamente difícil, mas tenho certeza que tenho um programa válido agora!

Usa um comando do pré-processador para que nenhuma linha nova possa ser removida, pois o colchete de fechamento para mainé incluído apenas se __LINE__==6. Também evita que você limpe maincompletamente, já que isso deixa #endifflutuando (por isso é importante que #endifesteja fora main).

Eu usei #elseporque eu me tornei bastante convencido de que não há versão do __LINE__==6que não pode ter uma substring removido e ainda ser verdade, já que ambos 6e __LINE__por si mesmos são truthy. Ele também é usado -Werror=undefpara que algo como #ifdef(LINE__)não seja avaliado como falso, mas seja um erro.

Com o gcc (no Linux, pelo menos), putsretorna o número de caracteres impressos (incluindo a nova linha à direita); portanto, remover qualquer parte da string puts("...")/6retorna 0, 1/0causando uma exceção de ponto flutuante. Observe que essa exceção não é causada, a menos que 1/0seja atribuída a algo, portanto a=é necessário.

Nenhuma outra parte de qualquer linha pode ser removida sem criar um erro, geralmente um erro de sintaxe ou um erro de vinculação.

Como um bônus, isso fornece uma solução de 86 bytes para C ++ de maneira bastante trivial, basta adicionar #include <cstdio>e declarar acomo int. Experimente online! (C ++)


A menos que eu esteja enganado, você pode remover 1/enquanto sai da nova linha e ela ainda será executada .
Gastropner 6/07

@gastropner Você está certo. 1era suposto na linha anterior, eu acredito.
Chris

Infelizmente, a mesma coisa vale. Você pode remover =1. Eu acho que você precisa colocar o 1 em uma linha por conta própria.
Gastropner

@gastropner Acho que você está certo. Vou procurar mais tarde. Obrigado!
Chris

2

PHP, 73 bytes

<?=call_user_func(($p='ns')|(($f="u{$p}erialize"))?$f:'','s:5:"world"');

Explicação

Eu assumo a configuração padrão do php.ini. Então short_tags está desativado. Isso significa que você não pode remover o =da marca de abertura.

Isto é basicamente <?=unserialize('s:5:"world"');.

Se você remover qualquer parte da string serializada, receberá um erro.

Você pode simplesmente remover unserializee o script produzirá apenas a sequência serializada. Para superar isso eu uso call_user_func. A remoção de um dos parâmetros resultará em um erro.

'<?=call_user_func('unserialize','s:5:"world"');

No entanto, você pode remover un, para chamar a serializefunção. Então tiramos 'ns'. A remoção de qualquer caractere não resultaria em um nome de função incorreto.

<?=call_user_func(($p='ns')&&($f="u{$p}erialize")?$f:'','s:5:"world"');

Usaremos um inline se estiver usando atribuição de variável com a tag de saída. Em vez de usar &&, usamos '|' para evitar remover uma única &ou remover a $fatribuição

Você pode remover ='ns')&&($f="u{$p}erialize"e acabar com ($p)?$f:''. Portanto, adiciono parênteses extras $f="u{$p}erialize".

Nota

Tecnicamente, você pode remover as tags de abertura sem gerar um erro. No entanto, este não é mais um script PHP, mas apenas um arquivo de texto simples.


2
Sobre sua última observação, o arquivo de texto sem formatação ainda seria um programa PHP válido, certo? Portanto, não tenho certeza se isso é válido.
Calvin's Hobbies

Não é mais PHP, mas texto simples / html, portanto, não um-php-programa mais válido
Martijn

1

Matlab (77)

bsxfun(@(c,b)arrayfun(@(x)getfield(c,{x}),conv(b,ismember(4,b))),'world',1:5)

tente

Nota:

Seguindo o conselho do @ Optimiser de projetar uma RCP ou algo assim, fui confrontado com substratos imprevistos que não levaram a nenhum erro de compilação quando removidos; exemplo: remover arrayfun(@(x)a(x),prod(b,ismember(4,1:5))),desta edição anterior feval(@(a)arrayfun(@(x)a(x),prod(b,ismember(4,1:5))),'world')não gera nenhum bug! também, na mesma edição recente, houve bsxfun(@(a,b)arrayfun(@(x)(x),prod(b,ismember(4,b))),'world',1:5)e bsxfun(@(a,b)a,'world',1:5), se você perguntou como eu estava ao encontrá-los no meu console de saída, chorei como um bebê, então aqui está o programa:

b=0;string='bsxfun(@(c,b)arrayfun(@(x)getfield(c,{x}),conv(b,ismember(4,b))),''world'',1:5)'
for u=1:numel(string),for j=u:numel(string)-2,try a=eval([string(1:u) string(j+2:end)]);catch(b); a=0;end; if a~=0, ['here is it : ' string(1:u) string(j+2:end)],end;end;end

Um exemplo de um programa não intocado

editar:

Obrigado a todos ao lado de @Martin por apontarem os meus códigos anteriores (não erros).


1

SmileBASIC, 63 bytes

REPEAT
A=1/(PRGSIZE(0,1)==63)?"world
UNTIL 1/(PRGSIZE(0,1)==63)

1

Uma pereira , 17 bytes

Este programa contém bytes com o conjunto de bits alto (que não é válido UTF-8 e, portanto, não pode ser publicado no TIO), então aqui está um xxdhexdump reversível:

00000000: 7072 696e 7427 776f 726c 6427 23cd 4290  print'world'#.B.
00000010: bf                                       .

Explicação

Isso é apenas print'world'com uma soma de verificação anexada. Eu verifiquei por força bruta que nenhuma das exclusões possíveis fornece um programa com uma soma de verificação válida; portanto, você recebe um erro após qualquer possível exclusão.

Bastante chato, mas amarra o líder atual, então eu senti que valia a pena postar.

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.