Programmazione di un mondo incontaminato


87

Definiamo un programma incontaminato come un programma che non ha alcun errore in sé, ma lo farà se lo modifichi rimuovendo qualsiasi sottostringa contigua di N caratteri, dove 1 <= N < program length.

Ad esempio, il programma Python 2 a tre caratteri

`8`

è un programma incontaminato ( grazie, Sp ) perché tutti i programmi risultanti dalla rimozione di sottostringhe di lunghezza 1 causano errori (in effetti errori di sintassi, ma qualsiasi tipo di errore lo farà):

8`
``
`8

e anche tutti i programmi risultanti dalla rimozione di sottostringhe di lunghezza 2 causano errori:

`
`

Se, per esempio, `8fosse stato un programma senza errori, allora `8`non sarebbe incontaminato perché tutti i risultati della rimozione della sottostringa devono essere errati.

Il tuo compito in questa sfida è quello di scrivere il programma più breve possibile che non accetta input ma emette una delle seguenti cinque parole:

world
earth
globe
planet
sphere

Quale parola scegli dipende interamente da te. L'unica parola più una nuova riga finale opzionale deve essere stampata su stdout (o l'alternativa più vicina alla tua lingua). Vince il programma più breve in byte.

Appunti:

  • È richiesto un programma autonomo, non una funzione.
  • Le parole fanno distinzione tra maiuscole e minuscole; in uscita Worldo EARTHnon è permesso.
  • Gli avvisi del compilatore non vengono considerati errori.
  • I sottoprogrammi in errore possono accettare input o fornire output o fare qualsiasi altra cosa purché alla fine si verifichino errori.

Ecco uno snippet di stack che elencherà quali programmi necessitano di errore dato un programma potenzialmente incontaminato:

<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 Sì. Catturare l'eccezione significa che non è più un errore.
Hobby di Calvin,

33
Il doppio delle risposte eliminate rispetto a quelle non eliminate. Questo è un risultato!
DLosc

1
Un programma può leggere il proprio codice sorgente?
Shelvacu,

2
Dove visualizzare il cimitero di risposte "chiudi ma niente sigaro" e i loro commenti?
Vi.

1
@Vi. Ottieni 2.000 rappresentanti in modo da poter visualizzare i post eliminati .
ThisSuitIsBlackNon

Risposte:


47

Rail , 24 byte

$'main'    #
 -[world]o/

Penso che funzioni. Ed è sia breve che leggibile (per quanto riguarda Rail).

  • Se la sottostringa rimossa include qualsiasi parte di ciò $'main'che otteniamo Internal Error: Crash: No 'main' function found.
  • Se la sottostringa rimossa include il #, non c'è modo per il programma di uscire in modo pulito, quindi terminerà sempre con Crash: No valid move. Credo che non sia possibile eliminare una sottostringa in modo tale che la traccia formi un ciclo valido (infinito).
  • Se la sottostringa rimossa si trova di fronte #, verrà disconnessa dalla fine del binario, quindi il treno andrà in crash (con lo stesso errore di cui sopra).
  • Se la sottostringa rimossa è successiva a #, disconnetterà anche #la fine della traccia (e potenzialmente anche l'inizio della traccia dal punto di ingresso $). Quindi di nuovo lo stesso errore.

Per quanto riguarda il programma attuale: ogni programma Rail deve avere una $'main'(o una variante più lunga, ma stiamo giocando a golf qui) come punto di ingresso nella funzione e il treno inizia a $sud-est. Tuttavia, tutto su quella prima linea può far parte della traccia, quindi rimuovere 'main'la traccia è:

$          #
 -[world]o/

I -e /sono semplicemente pezzi di binario di cui abbiamo bisogno per consentire al treno di fare quelle svolte a 45 °.

[world]spinge la stringa worlde la ostampa. #segna la fine della traccia - l'unico modo per terminare in sicurezza un programma Rail.

È interessante notare che questa soluzione è possibile solo perché Rail consente alle tracce di passare attraverso la mainlinea - se ciò non fosse possibile #sarebbe dopo la prima nuova riga e il codice potrebbe sempre essere abbreviato in

$'main'
 #

che è un programma valido che non fa nulla. (I caratteri non spaziali tra 'e #non influenzerebbero quello.)

Anche abbastanza interessante: se avessi appena giocato a golf il compito di stampare worldnon sarebbe stato molto più breve o più semplice:

$'main'
 -[world]o#

4
Cosa succede se rimuovo un carattere tra [e]?
Martin Lütke,

@ MartinLütke si disconnetterà /dal #.
Martin Ender,

2
@ MartinLütke Non è stato possibile rimuovere solo le parentesi poiché non sono contigue.
Hobby di Calvin,

Cosa succede se rimuovere la nuova riga tra le due linee?
Vi.

1
@Vi. Ciò disconnette $dall'inizio del binario, quindi il treno si blocca immediatamente (Rail si aspetta che il binario continui a sud-est del $).
Martin Ender,

43

Funciton ( 186 136 byte in UTF-16)

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

Questo programma stampa "mondo".

La maggior parte delle sottostringhe rimosse da questo impedirà che sia una scatola completa, di cui si lamenterà il parser. Le uniche possibili rimozioni che lasciano una scatola completa sono:

 ╔══════════════╗
|║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)
|╚══════════════╝

La maggior parte di questi rimuove l'estremità pendente nella parte superiore destra della scatola, che è il connettore di uscita. Senza questa estremità libera, la scatola è solo un commento:

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

Questo non è più un programma valido perché il parser prevede un programma con esattamente un output:

Errore: i file di origine non contengono un programma (il programma deve avere un output).

L'unica possibilità che lascia un connettore di uscita è l'ultima delle precedenti, che lascia questo:

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

Tuttavia, questo numero non codifica una stringa Unicode valida nell'UTF-21 esoterico di Funciton. Prova a eseguire questo, ottieni:

Eccezione non gestita: System.ArgumentOutOfRangeException: un valore UTF32 valido è compreso tra 0x000000 e 0x10ffff, inclusi e non deve includere valori di punti di codice surrogati (0x00d800 ~ 0x00dfff).

Pertanto, questo programma è incontaminato.


3
Sento che sei stato fortunato nell'ultimo caso (non che sia così facile ottenere accidentalmente una sequenza Unicode valida, ma comunque ...)
Esolanging Fruit

34

Visual C ++ - 96 95 byte

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

Proprietà:

  1. Non è possibile rimuovere alcuna parte int main()senza un errore di compilazione.
  2. Non è possibile rimuovere la modifica l'espansione delle macro a tutti, togliendo aa tutti i mezzi main()non viene mai {, eliminando bdel tutto significa la nostra linea non si esaurisce in una ;, la rimozione di <mezzi std::cout<'w'provoca un errore, e la rimozione di <<cause std::cout'w', 'w''o'e così via
  3. Non è possibile rimuovere i parametri dalla definizione macro o dall'invocazione, gli unici nomi validi per la definizione sarebbero I(a), I(b)che non corrispondono mai e Iche si espandono a prima (; d'altra parte usando I(,cause <<<<e ,)rilascia il punto e virgola (salvo eventuali altri errori).
  4. Non è possibile rimuovere parte di tutto std::coutsenza incorrere in un lead <<e pertanto non è possibile rimuoverne nessuno #include<iostream>all'inizio senza un errore di compilazione.
  5. Non è possibile rimuovere alcuna parte di un singolo personaggio, ''ha un errore di carattere vuoto e 'w,, ecc., Provare a trasformare tutto in un personaggio.
  6. Non puoi rimuovere il lato sinistro / destro di una macro senza lasciarne troppi )o (dall'altro lato, ad esempio non puoi fare cose del genere I('w',I('r'.

Compilare online utilizzando Visual C ++ .

Ancora una volta questa non è una prova esaustiva. Se pensi di riuscire a farlo funzionare anche senza sezione assicurati di farmelo sapere.

Le versioni precedenti utilizzavano un approccio notevolmente diverso ed era dimostrato di non essere incontaminate, quindi ho rimosso quei punteggi.


Verifica:

Il seguente programma ha confermato che questa versione è incontaminata usando il clcompilatore di Visual C ++ 2010. Avrei voluto disturbarmi a scrivere prima:

#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
Notiamo che mentre questo è incontaminato su questo compilatore, non così su tutti i compilatori.
Giosuè,

1
Per favore, fai un esempio ....
Linus,

3
Su alcuni compilatori il programma C ++ vuoto produce un programma che non fa nulla. A seconda dell'implementazione di iostream, #include <iostream> potrebbe anche essere compilato.
Giosuè,

5
@Joshua Solo i sottoprogrammi di lunghezza 1 o superiore contano, quindi è irrilevante cosa fa il programma vuoto.
ThisSuitIsBlackNon

2
@Comintern, non proprio. Se non si seleziona la casella per eseguire l'eseguibile, l' /copzione viene automaticamente inclusa e viene compilata (come se si stesse creando una libreria e non un programma). Se selezioni la casella /cEsegui il sito non include , non otterrai un messaggio di successo e troverai invece il naturale "LINK: errore fatale LNK1561: il punto di ingresso deve essere definito".
Linus,

32

Python 3, 79 33

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

open(1,'w')apre l'output standard, quindi stampiamo la stringa. writerestituisce il numero di caratteri scritti. Questo è usato per indurire contro la rimozione della sottostringa: la rimozione di parte della stringa provoca la restituzione di qualcosa di diverso da 5 e 5 meno quel valore, quindi viene considerato vero. Ma questo fa sì che il ifcorpo venga eseguito e anon è definito.

Questo si basa sull'intelligente quine incontaminata di Anders Kaseorg qui .

Poiché è necessario verificare solo una singola istruzione, questa è molto più breve della vecchia soluzione, ma anche meno generale.

Vecchia soluzione:

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

Per verificare che sia davvero un programma incontaminato:

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

Alcuni punti chiave:

  • Ogni istruzione eseguita potrebbe essere eliminata. La verifica qdell'esecuzione richiede una dichiarazione al di fuori di q. Lo tryrisolve bene, richiedendo almeno due affermazioni, nessuna delle quali può essere cancellata completamente.
  • La verifica che qè stata eseguita avviene valutando ralla fine.
  • La verifica che qnon sia stata modificata viene ottenuta da eval(q[17:]), che deve valutare Noneper qessere eseguita.
  • La ifcondizione è un po 'difficile da ottenere. Per assicurarsi che sia stato valutato, ha il piacevole effetto collaterale dell'impostazione e, che è necessario impostare r. (Questo è il motivo per cui ho usato Python 3, exprpoiché una funzione fa miracoli per gli effetti collaterali a livello di espressione.)

Non è la sfida che nessuna rimozione provocherebbe un errore di sintassi? Sembra che provochiate errori di runtime.
Martin Lütke,

5
@ MartinLütke Qualsiasi tipo di errore va bene.
Hobby di Calvin,

1
Uhm, non sono 79 byte?
Matt

@TheMatt Sì? Li ho contati di nuovo e sembra che tu abbia ragione. Forse il passato ha contato le nuove linee del CRLF ... Che imbarazzo. Grazie!
Philipp,

25

Haskell, 61

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

Qualsiasi tipo di errore è OK? In quel caso:

Haskell, 39

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

Funziona se rimuovi una delle lettere?
Lirtosiast

Si bloccherà durante l'esecuzione. Perché proverà a valutare indefinito.
Martin Lütke,

Questo è eccellente Valutazione pigra FTW, sembra!
DLosc,

1
Vorrei che 'inits' fosse nel preludio :(. Quindi: main = putStr $ inits "world" !! 5 (27 byte)
Martin Lütke,

16

JavaScript, 74 73 35 byte

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

Si scopre che la risposta è stata molto più semplice di quanto pensassi ...

Spiegazione

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

rimuovere tutto tranne a="world", non si
sbaglia

3
@anOKsquirrel È possibile rimuovere solo una singola sottostringa.
Dennis,

4
Ho provato questo tipo "Potrei rimuoverlo? No, si verificherebbe questo errore. Potrebbe essere eliminato? Beh, immagino che causerebbe questo altro errore. Ah! Quei caratteri possono essere rimossi! Oh aspetta ..." +1
ETHproductions

if(a="world")["bol"+a[4]]non si sbaglia.
anOKsquirrel,

4
Vacca sacra, ora è due volte più impressionante! Vorrei poter fare +1 di nuovo ...
ETHproductions

15

Java 8, 301 byte

Perché ogni domanda ha bisogno di una risposta 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;}

allargato

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;
}

Spiegazione

  • public static main(String[]a){} è obbligatorio.
  • Se le dichiarazioni di campo vengono rimosse (o rese non statiche), il primo blocco statico non le trova.
  • Se il blocco statico viene rimosso (o reso non statico), i campi non vengono inizializzati.

La parte più difficile:

  • Se la finalparola chiave viene rimossa, viene valutata la seconda riga 1/(8-8), causando / by zeroun'eccezione.

Perché non riesci a rimuovere l'interno di nessuna delle dichiarazioni di stampa?
Nic Hartley,

2
@QPaysTaxes Non esiste un System.out.print()metodo vuoto . C'è per println(), ma non per print(). Quindi se lo rimuovessi d='d'darebbe The method print(boolean) in the type PrintStream is not applicable for the arguments ()come errore (E se lo rimuovessi d=darebbe The blank final field d may not have been initializedcome errore).
Kevin Cruijssen,

15

Funciton , 143 142 136 byte

Il punteggio è in UTF-8 come al solito, poiché UTF-16 sarebbe più grande di due byte (a causa della distinta base).

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

Quindi, sto contemplando una risposta di Funciton da un po 'e ho pensato che sarebbe impossibile, perché potresti sempre rimuovere una riga completa e il codice formerebbe comunque un blocco valido. Poi ne ho parlato con Timwi e ha capito che puoi semplicemente mettere l'intero numero in una sola riga, in modo che rimuoverlo si spezzerebbe il programma per mancanza di un connettore di uscita.

Ma i letterali su una sola riga sono notoriamente costosi, sia per il maggior numero di caratteri sia per il maggior numero di caratteri non ASCII. E la sua menzione di un blocco "commento vuoto" mi ha fatto pensare ...

Quindi ho trovato questa soluzione più efficiente che utilizza un blocco di commenti vuoto aggiuntivo che si interrompe quando provi a rimuovere qualsiasi cosa che lasci intatto il blocco letterale:

  • Non è possibile rimuovere la terza riga, perché rimuoveremmo il connettore di uscita.
  • Se rimuoviamo la seconda riga, il blocco dei commenti perde il suo bordo superiore e si rompe.

Questo lascia due opzioni (grazie a Steve per averlo sottolineato):

  • Rimuovi la quarta riga. Ciò lascia intatte entrambe le scatole. Tuttavia, quando 19342823075080880373viene decodificato il numero intero risultante , la stringa corrispondente conterrà il punto di codice 0x18D53Bche non è un carattere Unicode valido, si System.Char.ConvertFromUtf32arresta in modo anomalo con un ArgumentOutOfRangeException.
  • Rimuovi una linea intera che inizia dopo l'angolo in alto a destra. Ancora una volta, entrambe le caselle vengono lasciate intatte, ma il numero intero risultante 508088037380718711conterrebbe due punti di codice non validi 0x1B0635e 0x140077, portando alla stessa eccezione.

Si noti che anche senza il blocco di commenti vuoto, la rimozione della seconda riga comporterebbe un punto di codice non valido. Ma il blocco dei commenti impedisce che stiamo prendendo una riga dall'interno della seconda riga, per ottenere un numero intero come 193428037380718711ad esempio, che non causerebbe un errore.


Cosa succede se si rimuove la sottostringa che inizia con il carattere dopo il connettore di uscita e termina esattamente 1 riga dopo? cioè rimuovendo la linea mediana del blocco dei commenti e la linea contenente "80718711" nel blocco principale, ma lasciando intatti gli angoli di entrambe le caselle.
Steve,

@Steve Ho modificato la risposta per coprire quel caso. Dopo aver esaminato un po 'di più, questo in realtà mi ha permesso di salvare due caratteri / sei byte.
Martin Ender,

10

Ruby, 36 anni

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

Assegniamo s="planet", quindi scriviamo quella stringa su STDOUT. Ciò restituisce il numero di caratteri scritti. Lo diciamo con 6, in modo che se venisse scritto qualcosa di diverso da 6 caratteri, avremo un numero intero diverso da zero. Quindi dividiamo scon quell'indice. Solo il 0 ° carattere di s"p" è una stringa di codice valida (no-op). Lo passiamo a eval, usando la (*[argument])sintassi che equivale a solo (argument)tranne che non è valida al di fuori di una chiamata di metodo.

Pristineness verificato a livello di codice su Ruby 1.9.3 e 2.2


Merda santa. Questo è fantastico
applaude il

Cosa succede se si rimuove il *?
LegionMammal978,

Quindi stai passando un array per valutare invece di una stringa, che è un ArgumentError.
istocratico,

9

C #, 128 118 101 byte

Pensato di abusare della regola di sottostringa contigua.

Il codice

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

Perché funziona

  1. class he static void Main()sono richiesti.
  2. La rimozione di uno qualsiasi dei caratteri 'w','o','r','l','d'provoca un errore poiché l'array di caratteri viene inizializzato con lunghezza 1*5.
  3. Non è possibile rimuovere i contenuti all'interno di Main () senza violare la regola del carattere contiguo poiché le parti sono separate da preprocs. (Vedi sotto)

Prima del golf e della separazione

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

Verificato con

https://ideone.com/wEdB54

MODIFICARE:

  • Ho salvato alcuni byte usando #if !xinvece di #if x #else.
  • =>Sintassi di funzione utilizzata . #if!xinvece di #if !x. Crediti a @JohnBot.
  • A causa della =>sintassi delle funzioni, è possibile rimuovere condizioni di pre-elaborazione aggiuntive.

Ciao elica! Pensi di poter spiegare come e perché la tua risposta funziona un po 'di più?
isaacg,

@isaacg Edited. Prova da seguire.
Helix Quar,

Non riesco a farlo funzionare senza staticil Main.
Johnbot,

@Johnbot Sì. Deve aver sbagliato. Fisso.
Helix Quar,

È possibile salvare un carattere facendo Mainun membro funzione di espressione di corpo e più 2 rimuovendo gli spazi prima che la condizione preprocessore: 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. Sono 115 dal mio conteggio.
Johnbot,

9

MATLAB, 37 36 33 byte

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

Dal momento che non sono sicuro che ci sia consentito anche l'output ans = , ho dovuto trovare un modo per aggirare l'output in modo corretto. L'uso di fprintf da solo non ha funzionato, perché qualunque cosa io abbia provato, si è semplicemente rifiutato di sbagliare. L'uso di disp di per sé non era un'opzione, in quanto avrebbe preso solo 1 argomento e quell'argomento stesso avrebbe ovviamente eseguito senza errori.

Se non è un problema includere anche ans = nell'output, MATLAB può essere fatto con 20 byte :

reshape('world',1,5)

Devo davvero saperne di più sulle funzioni integrate (+1) // a proposito del tuo programma è segnato 20
Abr001

2
Dipende molto da quanto rigide siano le regole. Essi affermano che solo 'mondo' (+ optional finale nuova riga) deve essere stampato, in modo da allora è di 33 byte.
slvrbld,

Sì, lo considereremo come 33. Grazie per la comprensione :)
Hobby di Calvin l'

9

> <> , 17 byte

e"ooooo7-c0pBhtra

Provalo online!

Stampa "terra".

L'unico modo in cui un ><>programma esce senza errori è l'esecuzione del ;personaggio, il che è un problema in quanto puoi semplicemente rimuovere tutti i caratteri prima di quello, quindi quello ;è il primo carattere eseguito. È possibile aggirare ciò utilizzando il pcomando per modificare il programma da includere ;durante l'esecuzione. La rimozione di qualsiasi sezione del codice fa sì che il ;mai essere prodotto causando errori tramite le istruzioni non valide B, he t, pila underflow, e cicli infiniti che lo rende alla fine a corto di memoria. Dovevo solo assicurarmi che tutti gli anelli infiniti continuassero a riempire la pila.

Tutte le varianti sono state testate utilizzando questo frammento di pitone:

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

aggiunto a (una versione leggermente modificata di) l' interprete ufficiale fish.py dal creatore di> <>. Su 152 possibili sottoprogrammi, 92 errati da istruzioni non valide, 18 da underflow dello stack e 42 da memoria esaurita.

Curiosità, la prima versione di questo e"ooooo6-c0pAhtraaveva un paio di sottoprogrammi bizzarri che riuscirono a usare il comando put per posizionare un oggetto [che avrebbe cancellato lo stack, al posto dell'istruzione non valida A. Inoltre, "terra" è l'unica delle frasi che funzionerà con questo metodo, poiché la prima lettera eè un'istruzione valida in ><>. In caso contrario, il "comando deve essere posizionato nella parte anteriore del programma e un sottoprogramma valido potrebbe essere solo "da solo.


8

Ruby, 34

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

Questo ha alcuni componenti:

eval(*[ expr ]) è preso in prestito dalla risposta di Histocrat ed è incontaminato, così come la verifica del valore di ritorno di expr è un programma ruby ​​valido che non sbaglia. method(*arr)è una sintassi ruby ​​che chiama methodcon i valori di arrcome argomenti. Il motivo per cui ciò è necessario qui è perché è valido solo come parametro per un metodo, quindi se evalviene rimosso (*[expr])è un errore di sintassi. Se expr viene rimosso, si evallamenta di non avere abbastanza argomenti

$>.write("world")-1non può essere alterato se non all'interno della stringa e della sottrazione. $>.write("world")scrive "world" su STDOUT e restituisce il numero di caratteri scritti, quindi sottrae 1. Pertanto, se il programma non è modificato, il valore sarà esattamente 4 . Se è alterato (o -1viene rimosso o la stringa accorciata) restituirà uno di -1,0,1,2,3 o 5 . Qualsiasi altra manomissione provoca un errore di sintassi.

Chiamare chrun numero restituisce il carattere rappresentato da quel numero. Pertanto, quando viene richiamato sul risultato dell'esempio precedente, viene errato su -1 e in caso contrario restituisce una stringa a carattere singolo.

In realtà non sono sicuro del perché, ma sembra che Ruby interpreti \x04come un carattere di spazio, il che significa che l'espressione è valida (i programmi Ruby vuoti non fanno nulla). Tuttavia, uno qualsiasi degli altri caratteri ( \x00- \x03e \x05) risulta Invalid char '\x01' in expression. Ho trovato questo semplicemente ripetendo la possibile matematica che avrei potuto fare per il numero restituito. In precedenza avevo usato

$>.write("planet
")*16

dove "planet" più una nuova riga erano 7 caratteri, volte 16 per ottenere 112 p, l'unica funzione a lettera singola in rubino definita di default. Se non viene dato alcun argomento, è effettivamente una no-op


Menzione d'onore: $><<"%c"*5%%w(w o r l d)è molto vicino ma non immacolato. La rimozione non "%c"*5%provoca errori. Mini-spiegazione:

$>è stdout ed <<è una funzione chiamata su di esso. "%c"*5genera la stringa di formato "%c%c%c%c%c", che quindi cerca di essere formattata ( %) da un array: %w(w o r l d)che è una versione più corta di ['w','o','r','l','d']. Se nell'array sono presenti troppi o troppi elementi in modo che non corrispondano alla stringa di formato, viene generato un errore. Il tallone d'Achille è quello "%c"*5, e %w(w o r l d)può esistere entrambi in modo indipendente, e ha $><<solo bisogno di una discussione su entrambi. Quindi ci sono alcuni modi diversi di trasformare questo programma in cugini senza errori.


Convalidato usando questo:

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

Una spiegazione sulla falsariga della risposta dell'istocratico sarebbe buona. Sembra che tu stia usando lo stesso approccio di base, ma dal momento che non conosco Ruby, non riesco a capire i dettagli.
ThisSuitIsBlackNon

@ThisSuitIsBlackNot Ha fatto del mio meglio, qualcosa che non capisci?
Shelvacu,

Ottima spiegazione, grazie!
ThisSuitIsBlackNon

6

Python 3 , 43 byte

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

Provalo online!

Come funziona

Per proteggere dalle eliminazioni di sottostringhe, utilizziamo open(1,"w").writeinvece di print. In Python 3, writerestituisce il numero di caratteri scritti, che verificheremo 5per garantire che nessuna parte della stringa sia stata eliminata. Lo facciamo cercando il valore restituito nel dizionario {5:[]}e ripetendo il risultato con for[]in…:a, che fallirà se non otteniamo un iterable vuoto o se l' foristruzione viene eliminata.


4

Javascript (Node.js), 93 95 byte

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

Controlla la sua dimensione due volte, quindi se manca qualche carattere viene generato un errore. La lunghezza è 156 perché Node.js antepone function (exports, require, module, __filename, __dirname) {al codice in fase di esecuzione.

Grazie Martin Büttner per aver segnalato un errore. Riparato ora.


4

Perl 5.10+, 71 63 byte

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

Stampa worldcon una nuova riga finale. Esegui in questo modo:

perl -M5.010 file

Questo si basa sul conteggio dei byte del codice sorgente, quindi filedeve contenere il codice sopra e nient'altro (niente shebang, nessuna nuova riga finale). Perl 5.10+ è richiesto per saye l'operatore definito //.


È incredibilmente difficile creare un programma incontaminato con Perl, perché:

  • Qualsiasi identificatore bareword (ad esempio foo, a, _) è una dichiarazione valida con no strict 'subs';(il default). Ciò significa che il programma non può né iniziare né terminare con una lettera, un numero o un trattino basso.

  • Come spiega Tchrist , "Gli identificatori specificati tramite la dereferenziazione simbolica non hanno assolutamente alcuna restrizione sui loro nomi". Ciò significa che il programma non può iniziare con uno qualsiasi dei sigilli $, @, %, o *, dal momento che la rimozione di tutti tranne il primo e l'ultimo carattere sarebbe sempre lasciare un nome di variabile valido.

  • Molte funzioni integrate (inclusa la maggior parte delle funzioni in grado di produrre output) funzionano $_di default, quindi le chiamate spesso funzionano anche se si rimuove l'argomento (ad es. say"world"Vs. say).

Come funziona

Questa soluzione è stata ispirata dalla risposta Node.js di Naouak , che controlla la sua lunghezza per assicurarsi che i personaggi non siano stati rimossi.

Il programma ha due sezioni, una tra parentesi e l'altra all'interno di un blocco:

(...);{...}

La prima sezione legge il file sorgente e muore se è lunga meno di 63 caratteri. La seconda sezione verifica che l' readesecuzione sia stata eseguita correttamente. Se una delle sezioni viene rimossa (con o senza le parentesi racchiuse o le parentesi graffe), l'altra sezione genererà un'eccezione.

La rimozione della parte centrale o sinistra o destra del programma sbilancia le parentesi e / o le parentesi graffe, causando un errore di sintassi.

Se il primo dieè modificato (a d, e, di, de, o ie, che sono tutti identificatori validi), il controllo della lunghezza diventa:

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

che valuta a:

@{\'di'};

Questo prende un riferimento a una stringa e tenta di dereferenziarlo come un array, producendo un errore:

Not an ARRAY reference

Se viene modificata qualsiasi altra istruzione, il controllo della lunghezza fallirà e il programma morirà.


Verificato incontaminato con il seguente programma:

#!/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 byte

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

Provalo online!

I backtick in ruby ​​eseguono il comando al loro interno e restituiscono qualsiasi stringa inserita nel programma STDOUT. La #{expr}sintassi consente l'incorporamento di espressioni in stringhe e backtick. Questo programma potrebbe essere riscritto (in modo non originale) come:

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

IO#writerestituisce il numero di byte scritti, quindi se la stringa è accorciata, non sarà il numero giusto. #{}l'incorporamento trasforma automaticamente il numero in una stringa. Se un pezzo viene rimosso e non si verifica un errore di sintassi, verrà eseguito il comando errato. Se una parte di "world"viene rimossa rispetto a una di base04queste base54tenterà di eseguire.

La nuova riga, dentro o fuori la stringa, è obbligatoria. Altrimenti i primi 5 caratteri ( `base) possono essere rimossi, rendendo l'intera riga un commento. Inoltre ci devono essere uno o più caratteri tra il primo backtick e #, in caso contrario, {possono essere rimossi per rendere l'intera cosa un commento shell .


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

execSostituisce l'attuale processo ruby ​​con il comando specificato. Vedi la mia altra risposta per una spiegazione della meth(*[])sintassi e della necessità di essa.

(s="ec%co earth")assegna la stringa "ec% co earth" alla variabile s. Le assegnazioni restituiscono ciò che è stato assegnato, quindi viene restituita anche la stringa.

"format string %d" % 5è zucchero sintattico per sprintf("format string %d",5), tuttavia gli spazi attorno al %non sono necessari.

s[10]ottiene il carattere nella stringa in corrispondenza dell'indice 10. Se non modificato, questo carattere è "h", l'ultima lettera nella stringa. Tuttavia, la rimozione di qualsiasi carattere nella stringa significa che la stringa è più corta, quindi non vi è alcun carattere nell'indice 10, quindi s[10]restituisce nile "%c" % nilcausa un errore.

se %s[10]viene rimosso, quindi ruby ​​tenta di eseguire il comando ec%co earthche non funziona.

La modifica 10al 1o 0anche si traduce in un comando sconosciuto (sia eceoo ecco). Rimuoverlo del tutto non è tecnicamente un errore di sintassi poiché chiama il metodo #[]sulla stringa, ma poi si lamenta di argomenti insufficienti.


Una nota sulla risoluzione di questo in generale: è necessario disporre di un wrapper che verifichi il codice all'interno in senso astratto pur essendo incontaminato. Ad esempio, un programma con divisione alla fine ( blablabla/somevar) non funzionerà mai perché una divisione può sempre essere rimossa ( blablabla). Questi sono alcuni wrapper che ho usato finora:

  • eval(*[codice ])usato da histocrat e nella mia prima risposta. Convalida che l'output è un programma ruby ​​valido
  • exec(*[il codice ])usato sopra, conferma che la risposta è un comando valido
  • `#{ codice }`

La sintassi backtick esegue anche un comando (e quindi conferma che è valida), tuttavia STDOUT viene acquisito come stringa anziché essere emesso come processo padre "(Ruby) STDOUT. Per questo motivo non sono stato in grado di usarlo per questa risposta, EDIT: l'ho fatto funzionare. Limitazioni descritte sopra.

Modifica: grazie a @histocrat per aver segnalato alcuni difetti


Approccio fantastico! È possibile (e quindi è necessario) rimuovere lo spazio tra writee l'inizio della stringa, ma non credo che ciò influenzi la incontaminatezza. Inoltre, sulla mia macchina base64resterà in attesa di input, il che potrebbe essere contrario alle regole.
istocratico,

@histocrat Wow, sono sorpreso che funzioni $>.write"world", grazie! Per quanto riguarda la base64 in attesa di input, sembra variare a seconda del sistema. TIO funziona bene. Ciò rende ancora più confuso il fatto che segua le regole.
Shelvacu,

3

PowerShell, (97 byte + 5 per il nome del programma) = 102 byte

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

Si controlla prima di distruggersi ... due volte.

Si attende di essere salvati come c.ps1ed eseguiti dalla directory locale come ad esempio:
PS C:\Tools\Scripts\Golfing\> .\c.ps1.

L'alias gcè l'abbreviazione di Get-Contented è simile a una catlettura di un file (in questo caso, il nostro percorso di esecuzione .\c.ps1). Otteniamo .Lengthil file, lo impostiamo su $ae controlliamo se non è uguale a 97 con -eq97. Se è uguale (ovvero, il programma non è stato modificato), stampiamo con "world"ed eseguiamo un comando non valido a. Questo costringe catcha fare effetto, il che ci consente di ricontrollare noi stessi. Questa volta, se il nostro codice non è uguale a 97, lanciamo un comando non valido, quindi il nostro programma ha errato e stampato il testo dell'errore sull'output. Abbiamo quindi clear()l'errore e exitnormalmente.

È ovvio che se una delle due ifistruzioni viene manomessa, l'altra avrà un errore. Se una parte di "world";viene manomessa, la prima ifprovocherà un errore. Dal momento che deve essere contiguo, non possiamo rimuovere entrambe le ifistruzioni. Le stringhe nel mezzo comporteranno parentesi non corrispondenti o comporteranno l' {a}esecuzione della seconda . Il try/ catchè quello di catturare l'errore dalla prima ifistruzione in modo da poterlo cancellare correttamente. L'esterno "$( )"impedisce che le stringhe di entrambe le estremità vengano spezzate. Il finale ;aè quello di evitare che parti del mezzo vengano spezzate e ciò comporterebbe programmi validi (ad es. "it}a)";a, Che stamperanno it}a)e quindi si guasteranno).

Esistono diverse circostanze speciali:

  • Se il gc, gc<space>o gc .\vengono rimossi, il programma alla fine si guasterà con un po 'di errore di memoria esaurita (a causa di ripetute chiamate di auto-esecuzione) e probabilmente arresterà in modo anomalo la shell (e forse il computer). Non testato.
  • Se vengono rimossi <space>.\c.ps1o .\c.ps1, il programma si arresterà e richiederà l'input dell'utente. Indipendentemente da ciò che l'utente inserisce, il programma continuerà ad avere errori poiché i conteggi delle dimensioni saranno errati.
  • Se viene estratta una sottostringa che inizia $e termina prima dell'ultima ", il programma produrrà tutto ciò che rimane e quindi l'errore perché anon è valido.

Verificato con quanto segue:

$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."

(Grazie a Martin per la sua vasta assistenza!)


3

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

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

Provalo online!

Grande sfida! Questo è stato ingannevolmente difficile, ma sono abbastanza sicuro di avere un programma valido ora!

Utilizza un comando preprocessore in modo che non sia possibile rimuovere nuove righe, poiché la parentesi quadra di chiusura mainè inclusa solo se __LINE__==6. Ti impedisce anche di schiarirti maincompletamente, poiché lascia #endifgalleggiare (quindi è importante che #endifsia al di fuori di main).

L'ho usato #elseperché sono diventato abbastanza convinto che non esiste una versione __LINE__==6che non possa essere rimossa una sottostringa ed essere ancora vera, poiché entrambi 6e __LINE__da soli sono veritieri. Utilizza anche in -Werror=undefmodo che qualcosa di simile #ifdef(LINE__)non valuti come falso, ma sia un errore.

Con gcc (almeno su Linux), putsrestituisce il numero di caratteri stampati (inclusa la nuova riga finale), quindi la rimozione di qualsiasi parte della stringa fa puts("...")/6ritorno 0, in modo da 1/0causare un'eccezione in virgola mobile. Nota che questa eccezione non è causata a meno che non 1/0sia assegnata a qualcosa, quindi a=è obbligatoria.

Nessun'altra parte di una riga può essere rimossa senza creare un errore, in genere un errore di sintassi o un errore di collegamento.

Come bonus, questo offre una soluzione a 86 byte per C ++ piuttosto banalmente, basta aggiungere #include <cstdio>e dichiarare acome int. Provalo online! (C ++)


A meno che non mi sbagli, è possibile rimuovere 1/lasciando la nuova riga e continuerà a funzionare .
Gastropner,

@gastropner Hai ragione. 1era supposto sulla riga precedente credo.
Chris,

Purtroppo, la stessa cosa vale. È quindi possibile rimuovere =1. Penso che tu debba mettere l'1 su una riga da solo.
Gastropner,

@gastropner Penso che tu abbia ragione. Guarderò più tardi. Grazie!
Chris,

2

PHP, 73 byte

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

explination

Presumo la configurazione predefinita di php.ini. Quindi short_tags è disabilitato. Ciò significa che non è possibile rimuovere il =tag di apertura.

Questo è fondamentalmente <?=unserialize('s:5:"world"');.

Se rimuovi qualsiasi parte della stringa serializzata, otterrai un errore.

Puoi semplicemente rimuovere unserializee lo script produrrà semplicemente la stringa serializzata. Per superare questo uso call_user_func. La rimozione di uno dei parametri comporterà un errore.

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

Tuttavia è possibile rimuovere un, per chiamare la serializefunzione. Quindi eliminiamo "ns". La rimozione di qualsiasi carattere non comporterebbe un nome di funzione errato.

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

Useremo un inline se usare l'assegnazione di variabili con il tag di output. Invece di usare &&usiamo '|' per impedire la rimozione di un singolo &o la rimozione del $fcompito

È possibile rimuovere ='ns')&&($f="u{$p}erialize"e finire con ($p)?$f:''. Quindi aggiungo parentesi extra in giro $f="u{$p}erialize".

Nota

Tecnicamente puoi rimuovere i tag di apertura senza produrre un errore. Questo comunque non è più uno script PHP ma solo un file di testo.


2
Circa la tua ultima nota, il file di testo normale sarebbe comunque un programma PHP valido, giusto? Quindi non sono sicuro che questo sia valido.
Hobby di Calvin l'

Non è più PHP, ma solo testo / html, quindi non è più un programma php valido
Martijn,

1

Matlab (77)

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

Provalo

Nota:

Seguendo il consiglio di @ Optimizer di progettare un CPR o qualcosa del genere, mi sono trovato di fronte a una sottostringa imprevista che non ha provocato alcun errore di compilazione quando rimosso, ad esempio: la rimozione arrayfun(@(x)a(x),prod(b,ismember(4,1:5))),da questa modifica precedente non feval(@(a)arrayfun(@(x)a(x),prod(b,ismember(4,1:5))),'world')genera alcun bug! inoltre, per la stessa recente edizione, c'erano bsxfun(@(a,b)arrayfun(@(x)(x),prod(b,ismember(4,b))),'world',1:5)e bsxfun(@(a,b)a,'world',1:5), se mi chiedevi come stavo scoprendoli nella mia console di output, ho pianto come un bambino, quindi ecco il programma:

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

Un esempio di un programma non incontaminato

modificare:

Grazie a tutti quelli accanto a @Martin per aver segnalato il mio codice precedente (non errori).


1

SmileBASIC, 63 byte

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

1

Un albero di pere , 17 byte

Questo programma contiene byte con il bit alto impostato (che non sono UTF-8 validi e quindi non possono essere pubblicati su TIO), quindi ecco un xxdhexdump reversibile:

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

Spiegazione

Questo è solo print'world'con un checksum aggiunto. Ho verificato con forza bruta che nessuna delle possibili eliminazioni fornisce un programma con un checksum valido, quindi si ottiene un errore dopo ogni possibile eliminazione.

Abbastanza noioso, ma lega l'attuale leader, quindi ho pensato che valesse la pena pubblicare.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.