osiągnąć pułap, gdy wszystko w bloku try jest już złapane

19

Sądzę, że jest to ograniczone do Java i C # przez składnię.

W tej łamigłówce programistycznej masz wytworzyć Exceptions, które można złapać, ale które są rzucane ponownie na końcu bloku catch.

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
}

Możesz swobodnie wstawiać kod przed i po tym fragmencie.

catchWygrywa najkrótszy kod do osiągnięcia zewnętrznego bloku.

użytkownik21634
źródło
1
Myślę, że Python może być w stanie konkurować.
user12205
1
Możesz swobodnie wstawiać kod przed i po moim fragmencie.
user21634
2
Szkoda, że ​​jest zamknięty. Mam rozwiązanie . Do @algorytmshark, Michael i Jan Dvorak: To NIE jest ogólne pytanie programistyczne. To łamigłówka programistyczna, podobna do Kiedy żyrafa nie jest żyrafą? . Nominuję to do ponownego otwarcia.
user12205
1
Uhhhhhh, co ???
TheDoctor
1
@algorytmshark poszedłbym z sumą długości wstawek
użytkownik12205

Odpowiedzi:

24

C #, 46 (88 łącznie z płytą grzewczą)

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

Abort()Sposób podnosi ThreadAbortException , który jest wyjątek specjalny, który jest automatycznie rethrown na końcu każdego bloku zatrzaskowej (o ile nie Thread.ResetAbort()jest wywoływany).

BenM
źródło
20

C # 24 znaków

kończy wewnętrzny blok try przed wcześniejszym planowaniem, pozwalając mi na spowodowanie wyjątku poza blokiem try.

}finally{int a=1/0;}try{
rdans
źródło
1
Człowieku, to jest genialne! Dlaczego o tym nie pomyślałem? (Przy okazji, czy możesz go skrócić, powodując wyjątek zamiast int a=1/0;
zgłaszać
Potrzebujesz int a=tam Niektóre języki pozwalają po prostu napisać wyrażenie1/0
gnibbler
To nie jest kompletny działający przykład, prawda? Tak więc 24 znaki się nie liczą ...
Matt
13

Java, 76 lub 31

Licząc tylko wstawki wykonane w kodzie, ignorując nowe wiersze. 76 jeśli policzysz wszystko , co dodałem, 31 jeśli wykluczysz pierwszą linię i ostatnią linię, tj. Tylko liczenie 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){}
}}
użytkownik12205
źródło
Ups, przepraszam, nie zwracałem uwagi na to, jak się liczyłeś. Zaktualizuję moją odpowiedź, aby dodać inną metodę liczenia. Uważam, że po prostu policzenie znaków w bloku try jest lepsze, ponieważ w przeciwnym razie porównalibyśmy w zasadzie C # vs Java. Ale może się to skomplikować, jeśli ktoś prześle odpowiedź z ważnym kodem poza blokiem try (zgodnie z regułami).
BenM
@BenM Nie martw się i rozumiem, dlaczego tak to policzyłeś. Po prostu OP nie określił, który sposób liczyć, więc pomyślałem, że uwzględnię oba.
user12205
Bardzo sprytne rozwiązanie.
Nicolas Barbulesco
@NicolasBarbulesco Szczerze mówiąc, myślę, że odpowiedź Ryana jest mądrzejsza niż moja. W końcu dodałem catchblok po fragmencie, nie zrobił tego.
user12205
3

Ostrzeżenie : te programy to bomby klonujące (rodzaj mniej niebezpiecznej, ale wciąż niebezpiecznej formy bomby widelcowej); jako takie nie uruchamiaj ich w systemie produkcyjnym bez piaskownicy lub limitów zasobów . Klonowane bomby tworzą nici w pętli (w przeciwieństwie do bomb rozwidlających, które tworzą procesy w pętli), dlatego możesz je zatrzymać, po prostu zabijając dany proces (czyniąc je znacznie mniej niebezpiecznymi niż bomby widelcowe, co może być bardzo trudne oczyścić); ale najprawdopodobniej będą wiązać większość procesora, dopóki tego nie zrobisz (lub dopóki program nie wygra i nie wyłączy się sam). Poproszenie systemu operacyjnego o ograniczenie ilości pamięci i czasu procesora, z których te programy mogą korzystać, powinno stworzyć bezpieczne środowisko do ich testowania.

Java (OpenJDK 8) , 65 60 bajtów (z niewielką modyfikacją opakowania)

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

Wypróbuj online!

Wymaga zmiany obu wystąpień catch (Exception …)pytania catch (Throwable …). Teoretycznie powinno to być bardziej bezpieczne, nie mniej, ale umożliwia to rozwiązanie.

Zapisałem 5 bajtów w pierwszej wersji tej odpowiedzi, używając odwołania do metody zamiast lambda.

Java 4, 104 bajty (nieprzetestowane, powinien działać z oryginalnym opakowaniem)

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

Wypróbuj online! (link prowadzi do implementacji Java 8, więc nie będzie działać)

Korzystając z funkcji, które zostały usunięte z nowoczesnych wersji Javy, możliwe jest rozwiązanie nawet wersji układanki, która wymaga Exception. Prawdopodobnie przynajmniej. (Java 4 jest już bardzo stara i nie pamiętam, jakie funkcje ona zawierała, a których nie zawierała. Jak widać, w Javie było wtedy o wiele mniej funkcji i dlatego była bardziej szczegółowa; nie mieliśmy lambdas, więc musiałem stworzyć wewnętrzną klasę.)

Objaśnienia

Większość rozwiązań tego pytania jest w języku C # (wraz z rozwiązaniem Java, które oszukuje za pomocą niezrównoważonych nawiasów jako formy wstrzykiwania kodu, oraz rozwiązaniem Perla, które również nie jest w Javie). Pomyślałem więc, że warto spróbować pokazać, jak tę zagadkę można rozwiązać „poprawnie” również w Javie.

Oba programy są w rzeczywistości identyczne (stąd fakt, że pierwszy program działa, daje mi dużą pewność, że drugi program również zadziała, chyba że przypadkowo użyłem funkcji innej niż Java-4; Thread#stopzostał wycofany w Javie 5).

Thread#stopMetoda Javy działa za kulisami, powodując wrzucenie rzucanego przedmiotu do wątku. Rzucanie przeznaczone do tego celu jest ThreadDeath( Errorszczególnie dlatego, że ludzie często próbują uchwycić wyjątki, a projektanci Javy nie chcieli, aby tak się działo), chociaż pozwala to na rzucanie czegokolwiek (lub przywykło; w pewnym momencie po API był zaprojektowane, projektanci Javy zdali sobie sprawę, że był to niesamowicie zły pomysł i usunęli wersję metody, która przyjmuje argumenty wprost). Oczywiście nawet wersja, która rzuca, ThreadDeathjest dość ryzykowną operacją, na którą możesz zrobić kilka gwarancji (na przykład pozwala rozwiązać tę zagadkę, co „nie powinno być możliwe”), więc nie powinieneś użyj go, ale od wersji Java 8 nadal działa.

Ten program działa, odradzając nowy wątek i prosząc go, aby siłą wrzucił wyjątek z powrotem do głównego wątku. Jeśli będziemy mieli szczęście, zrobimy to w momencie, gdy znajdziemy się poza catchblokiem wewnętrznym (nie możemy uciec z catchbloku zewnętrznego , dopóki program się nie skończy, ponieważ wokół niego jest pętla). Ponieważ pętla została już dogodnie dodana, oszczędzanie bajtów polega na zwykłym użyciu tej pętli, aby umożliwić nam tworzenie wątków w nadziei, że jeden z nich ostatecznie osiągnie właściwy czas. Wydaje się, że dzieje się to zwykle w ciągu kilku sekund.

(Uwaga TIO: obecna wersja TIO jest skłonna zabić ten program na wczesnym etapie jego wykonywania, prawdopodobnie ze względu na wszystkie tworzone wątki. Może działać na TIO, ale nie działa niezawodnie, więc często potrzeba kilku prób, aby uzyskać wynik „Wygrałeś!”).

ais523
źródło
1

DO#

    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");

    }
devendra
źródło
1
Witamy w Programowaniu Puzzle i Code Golf! Ponieważ pytanie to stanowi wyzwanie dla golfa , postaraj się, aby Twój kod był jak najkrótszy i zawierał liczbę znaków na górze odpowiedzi. Dzięki!
ProgramFOX,
1

Perl 5 , 37 lub 36 bajtów

eval {
    while (1) {
        eval {

 

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

 

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

Wypróbuj online!

Okazuje się, że to pytanie przekłada się na Perla wystarczająco dobrze, aby stworzyć tam również interesującą zagadkę. Odpowiednik Perla trynazywa się (trochę myląco) evali określa wyjątek poprzez ustawienie @_wyjątku, jeśli wystąpił, a łańcuch zerowy w przeciwnym razie. Jako taki, catchblok jest implementowany poprzez porównywanie @_z łańcuchem zerowym.

To rozwiązanie działa, tworząc obiekt (którego klasą jest program jako całość; możesz używać dowolnych plików Perla, takich jak klasy, coś w rodzaju odwrotnej strony Javy (gdzie możesz używać dowolnych klas, takich jak pliki)). To jest bless[]część ( blesszwykle pojawia się tylko głęboko w konstruktorach, jako prymityw, który przede wszystkim zamienia rzeczy w obiekty, ale możesz go użyć bezpośrednio, jeśli naprawdę chcesz; []jest to alokator pamięci dla obiektu - konstruktor listy, w tym case - i klasa nie jest podana, więc zakłada się, że jest aktualnie wykonywana). Tymczasem dajemy naszej „klasie” (tj. Plikowi głównemu) niestandardową metodę porównywania z ciągiem znaków use overloadi robimy , aby ta metoda generowała wyjątek (w ten sposób wyłamując się z pętli i rozwiązując zagadkę); możemy faktycznie umieścićuse overloadgdziekolwiek i chociaż tradycyjnie wchodziłby w inne definicje metod i zbliżał się do górnej części pliku, możemy umieścić go w luce, którą nam podano, i nadal działa. (Jeśli umieścimy go na końcu pliku, możemy pominąć średnik po nim, co prowadzi do rozwiązania 36-bajtowego, ale jest to prawdopodobnie oszustwo, ponieważ zależy od tego, czy program ma w pierwszej kolejności średnik końcowy, który jest nie jest gwarantowane.) W rzeczywistości jest krótsze, aby przeciążyć operację strunizacji i pozwolić Perlowi na automatyczne wygenerowanie łańcucha porównującego z tego, niż byłoby to przeciążenie porównania łańcucha bezpośrednio (ponieważ przeciążenie niektórych operatorów zmusza cię do przeciążenia również innych operatorów).

Teraz wystarczy rzucić naszym przedmiotem die. W evalodebrane, a następnie, gdy staramy się porównać $@do łańcucha pustego (aby sprawdzić, czy nie był wyjątkiem), porównanie rzuca kolejny wyjątek i uciec na zewnątrz eval.


źródło