atteindre la capture lorsque tout dans le bloc d'essai est déjà pris


19

Ceci est limité à Java et C # par la syntaxe, je suppose.

Dans ce casse-tête de programmation, vous devez produire des Exceptions qui peuvent être capturés mais qui sont lancés à nouveau à la fin du bloc de capture.

try
{
    while(true)
        try
        {
            // you are only allowed to modify code between this try { } brackets
        }
        catch(Exception ex2) {  }
}
catch(Exception ex1)
{
    // your goal is to reach this catch block by modifying the code ...
    // in the inner try block above
    // You win if you reach this part and execute on of the following code lines
    Console.WriteLine("You won!"); // for C#
    // Or
    System.out.println("You won!"); // for Java
}

Vous pouvez librement mettre du code avant et après cet extrait.

Le code le plus court pour atteindre le catchbloc externe gagne.


1
Je pense que Python peut également être compétitif.
user12205

1
Vous pouvez mettre librement du code avant et après mon extrait de code.
user21634

2
Dommage qu'il soit fermé. J'ai une solution . À @algorithmshark, Michael et Jan Dvorak: Ce n'est PAS une question de programmation générale. C'est un puzzle de programmation, similaire à Quand une girafe n'est-elle pas une girafe? . Je propose cette réouverture.
user12205

1
Uhhhhhh, Whaaat ???
TheDoctor

1
@algorithmshark J'irais avec la somme des longueurs des insertions
user12205

Réponses:


24

C #, 46 (88 avec passe-partout)

using System;class P{static void Main(){
        try
        {
            while(true)
                try
                {
                    System.Threading.Thread.CurrentThread.Abort();
                }
                catch(Exception ex2) {  }
        }
        catch(Exception ex1)
        {
            // your goal is to reach this catch block by modifying the code ...
            // in the inner try block above
            // You win if you reach this part and execute on of the following code lines
            Console.WriteLine("You won!"); // for C#
        }
}}

La Abort()méthode déclenche une ThreadAbortException , qui est une exception spéciale qui est automatiquement renvoyée à la fin de chaque bloc catch (sauf si elle Thread.ResetAbort()est appelée).


20

Personnages C # 24

termine le bloc try interne avant l'intention, ce qui me permet de provoquer une exception en dehors du bloc try.

}finally{int a=1/0;}try{

1
C'est du génie! Pourquoi n'y ai-je pas pensé? (Btw pouvez-vous le raccourcir en provoquant une exception au lieu de lancer une exception? Par exemple int a=1/0;?)
user12205

En avez-vous besoin int a=? Certaines langues vous permettent d'écrire simplement l'expression1/0
gnibbler

Ce n'est pas un exemple de travail complet, n'est-ce pas? Donc les 24 personnages ne comptent pas ...
Matt

13

Java, 76 ou 31

En comptant uniquement les insertions effectuées dans le code, en ignorant les nouvelles lignes. 76 si vous comptez tout ce que j'ai ajouté, 31 si vous excluez la première ligne et la dernière ligne, c'est-à-dire seulement le comptage int a=1/0;try{}catch(Error e){}.

class P{public static void main(String[]A){
try
{
    while(true)
        try
        {
            int a=1/0;try{
        }
        catch(Exception ex2) {  }
}
catch(Exception ex1)
{
    // your goal is to reach this catch block by modifying the code ...
    // in the inner try block above
    // You win if you reach this part and execute on of the following code lines
    //Console.WriteLine("You won!"); // for C#
    // Or
    System.out.println("You won!"); // for Java
}
}catch(Error e){}
}}

Oups, désolé, je n'ai pas fait attention à la façon dont vous comptiez. Je mettrai à jour ma réponse pour ajouter l'autre méthode de comptage. Je pense que compter les caractères dans le bloc try est mieux, car sinon nous comparerions essentiellement C # vs Java passe-partout. Mais cela pourrait devenir compliqué si quelqu'un soumet une réponse avec un code important en dehors du bloc try (comme le permettent les règles).
BenM

@BenM Pas de soucis, et je comprends pourquoi vous l'avez compté de cette façon. C'est juste que l'OP n'a pas spécifié de quelle manière compter, alors j'ai pensé que j'inclurais les deux.
user12205

Solution très intelligente.
Nicolas Barbulesco

@NicolasBarbulesco Pour être honnête, je pense que la réponse de Ryan est plus intelligente que la mienne. Après tout, j'ai ajouté un catchbloc après l'extrait de code, il ne l'a pas fait.
user12205

3

Avertissement : Ces programmes sont des bombes clones (une sorte de forme moins dangereuse mais toujours dangereuse de bombe à fourche); en tant que tels, ne les exécutez pas sur un système de production sans bac à sable ni limites de ressources . Les bombes clones créent des threads dans une boucle (contrairement aux bombes fork, qui créent des processus dans une boucle), vous pouvez donc les arrêter simplement en tuant le processus en question (ce qui les rend beaucoup moins dangereux que les bombes fork, qui peuvent être très difficiles à nettoyer); mais ils bloqueront probablement la majeure partie de votre processeur jusqu'à ce que vous parveniez à le faire (ou jusqu'à ce que le programme gagne et se termine naturellement par lui-même). Demander à votre système d'exploitation de limiter la quantité de mémoire et le temps processeur que ces programmes sont autorisés à utiliser devrait créer un environnement sûr dans lequel les tester.

Java (OpenJDK 8) , 65 60 octets (avec une légère modification du wrapper)

Thread x=Thread.currentThread();new Thread(x::stop).start();

Essayez-le en ligne!

Nécessite que les deux instances de catch (Exception …)la question soient remplacées par catch (Throwable …). Cela devrait en théorie être plus sûr, pas moins, mais cela permet à cette solution d'être possible.

J'ai économisé 5 octets sur la première version de cette réponse en utilisant une référence de méthode plutôt qu'un lambda.

Java 4, 104 octets (non testé, devrait fonctionner avec le wrapper d'origine)

final Thread x=Thread.currentThread();new Thread(){public void run(){x.stop(new Exception());}}.start();

Essayez-le en ligne! (le lien va vers une implémentation Java 8, donc ne fonctionnera pas)

En utilisant des fonctionnalités qui ont été supprimées des versions modernes de Java, il est possible de résoudre même la version du puzzle qui nécessite un Exception. Probablement, au moins. (Java 4 est très ancien maintenant et je ne me souviens plus quelles fonctionnalités il contenait et ne contenait pas. Comme on peut le voir, il y avait beaucoup moins de fonctionnalités à l'époque à Java et il était donc plus détaillé; nous n'avions pas lambdas, j'ai donc dû créer une classe intérieure.)

Explications

La plupart des solutions à cette question sont en C # (avec une solution Java qui triche via l'utilisation de crochets non équilibrés comme forme d'injection de code, et une solution Perl qui n'est pas non plus en Java). J'ai donc pensé qu'il valait la peine d'essayer de montrer comment ce puzzle peut être résolu "correctement" en Java aussi.

Les deux programmes sont effectivement identiques (donc le fait que le premier programme fonctionne me donne une grande confiance que le deuxième programme fonctionnerait aussi, sauf si j'ai accidentellement utilisé une fonctionnalité non Java-4; a Thread#stopété dépréciée dans Java 5).

La Thread#stopméthode de Java fonctionne, en arrière-plan, en provoquant le lancement d'un objet jetable dans le thread en question. Le jetable prévu à cet effet est ThreadDeath(un Error, en particulier parce que les gens essaient souvent de détecter les exceptions et que les concepteurs de Java ne voulaient pas que cela se produise), bien qu'il vous permette de lancer quoi que ce soit (ou l'habitude; à un moment donné après que l'API ait été conçu, les concepteurs de Java ont réalisé que c'était une idée incroyablement mauvaise et ont supprimé la version de la méthode qui prend les arguments au clair). Bien sûr, même la version qui lance ThreadDeathest une opération assez risquée pour laquelle vous pouvez faire peu de garanties (par exemple, cela vous permet de résoudre ce puzzle, quelque chose qui "ne devrait pas" être possible), donc vous n'êtes pas censé l'utiliser, mais à partir de Java 8, cela fonctionne toujours.

Ce programme fonctionne en générant un nouveau thread et en lui demandant de renvoyer de force une exception dans le thread principal. Si nous sommes chanceux, cela se fera à un moment où nous serons en dehors du catchbloc interne (nous ne pouvons pas échapper au catchbloc externe jusqu'à la fin du programme, car il y a une boucle autour de lui). Parce que nous avons déjà ajouté la boucle de manière pratique, il est économiseur d'octets d'utiliser simplement cette boucle pour nous permettre de continuer à créer des threads, dans l'espoir que l'un d'entre eux atteindra finalement le bon timing. Cela semble normalement se produire en quelques secondes.

(Remarque TIO: la version actuelle de TIO est assez encline à tuer ce programme au début de son exécution, probablement en raison de tous les threads créés. Il peut fonctionner sur TIO, mais ne fonctionne pas de manière fiable, si souvent quelques tentatives sont nécessaires pour obtenez la sortie "Vous avez gagné!".)


1

C #

    try
    {
        int i = 0, j = 1, k;

        int flag = 0;
        lbl:
        if (flag == 1)
        {
            k = j / i;
        }

        while (true)
            try
            {
                k = j / i;

            }
            catch (Exception e)
            {
                flag = 1;
                goto lbl;
                //Console.WriteLine("loose");

            }
    }
    catch (Exception e)
    {
        Console.WriteLine("Won");

    }

1
Bienvenue sur Programmation Puzzles & Code Golf! Comme cette question est un défi de code-golf , veuillez essayer de rendre votre code aussi court que possible et inclure le nombre de caractères en haut de votre réponse. Merci!
ProgramFOX

1

Perl 5 , 37 ou 36 octets

eval {
    while (1) {
        eval {

 

use overload'""',sub{die};die bless[]

 

        };
        $@ eq "" or 0;
    }
};
$@ eq "" or print "You won!\n";

Essayez-le en ligne!

Il s'avère que cette question se traduit assez bien en Perl pour y créer un puzzle intéressant. L' tryéquivalent de Perl est appelé (un peu confus) eval, et spécifie une exception en définissant @_une exception si elle s'est produite, et la chaîne nulle sinon. En tant que tel, un catchbloc est implémenté via une comparaison @_avec la chaîne nulle.

Cette solution fonctionne en créant un objet (dont la classe est le programme dans son ensemble; vous pouvez utiliser des fichiers Perl arbitraires comme des classes, un peu comme l'inverse de Java (où vous pouvez utiliser des classes arbitraires comme des fichiers)). C'est la bless[]partie ( blessn'apparaît normalement qu'au fond des constructeurs, comme la primitive qui transforme les choses en objets en premier lieu, mais vous pouvez l'utiliser directement si vous le souhaitez vraiment; []est l'allocateur de mémoire pour l'objet - un constructeur de liste, dans ce case - et la classe n'est pas donnée, elle est donc supposée être celle en cours d'exécution). Pendant ce temps, nous donnons à notre "classe" (c'est-à-dire le fichier principal) une méthode de comparaison à chaîne personnalisée via use overload, et faisons en sorte que cette méthode lève une exception (rompant ainsi la boucle et résolvant le casse-tête); nous pouvons mettreuse overloadn'importe où, et bien que cela irait traditionnellement avec les autres définitions de méthode et se rapprocherait du haut du fichier, nous pouvons le placer dans l'espace qui nous a été donné à la place et cela fonctionne toujours. (Si nous le mettons à la fin du fichier, nous pourrions omettre le point-virgule après lui, ce qui conduit à une solution de 36 octets, mais cela triche sans doute car cela dépend du programme ayant un point-virgule de fin en premier lieu, qui est non garanti.) Il est en fait plus court de surcharger l'opération de stringify et de laisser Perl générer automatiquement une chaîne de comparaison à partir de cela, qu'il ne le serait de surcharger directement la chaîne de comparaison (car la surcharge de certains opérateurs vous oblige à surcharger d'autres opérateurs également).

Maintenant, tout ce que nous avons à faire est de lancer notre objet en utilisant die. Le se evaltermine, puis lorsque nous essayons de comparer $@à la chaîne nulle (pour voir s'il y avait une exception), la comparaison lève une autre exception et nous échappons à l'extérieur eval.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.