досягати улову, коли все в блоці спробу вже спіймано


19

Я думаю, це обмежено Java та C # синтаксисом.

У цій головоломці програмування ви повинні створити Exceptions, які можуть бути спіймані, але знову кинуті в кінці блоку 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
}

Ви можете вільно ставити код до та після цього фрагмента.

Виграє найкоротший код для досягнення зовнішнього catchблоку.


1
Я думаю, що Python теж може змагатися.
користувач12205

1
Ви можете вільно поставити код до і після мого фрагмента.
користувач21634

2
Шкода, що це закрито. У мене є рішення . До @algorithmshark, Майкла та Яна Дворака: Це НЕ загальне питання програмування. Це головоломка програмування, подібна до Коли жирафа не є жирафом? . Я висуваю це для повторного відкриття.
користувач12205

1
Ухххххх, Whaaat ???
TheDoctor

1
@algorithmshark Я б пішов із сумою довжин вставлень
user12205

Відповіді:


24

C #, 46 (88 включаючи котельну плиту)

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()Метод викликає ThreadAbortException , який полягає в спеціальному виняток, яке автоматично викликаний повторно в кінці кожного блоку улову (якщо Thread.ResetAbort()не називається).


20

C # 24 Персонажі

припиняє внутрішній блок спробу раніше, ніж було призначено, що дозволяє мені викликати виняток поза блоком спробувати.

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

1
Людина це геній! Чому я не придумав цього? (Btw чи можете ви скоротити його, фактично спричинивши виняток, замість того, щоб викидати виняток? Наприклад int a=1/0;?)
user12205

Вам int a=там потрібно ? Деякі мови дозволяють просто написати вираз1/0
gnibbler

Це не повний робочий приклад, чи не так? Тож 24 символи не рахуються ...
Метт

13

Ява, 76 або 31

Підрахунок лише вставок, внесених до коду, ігнорування нових рядків. 76, якщо ви порахуєте все, що я додав, 31 якщо ви виключаєте перший і останній рядок, тобто лише підрахунок 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){}
}}

На жаль, я не звернув уваги на те, як ви рахували. Я оновлю свою відповідь, щоб додати інший метод підрахунку. Я вважаю, що просто підрахунок символів у блоці спробу краще, оскільки в іншому випадку ми в основному порівнюємо C # і Java котлован. Але це може ускладнитися, якщо хтось надсилає відповідь з важливим кодом поза блоком спробу (як це дозволяють правила).
БенМ

@BenM Не хвилюйся, і я розумію, чому ти так порахував. Просто в ОП не було вказано, на який спосіб рахувати, тож я подумав, що включатиму і те й інше.
користувач12205

Дуже розумне рішення.
Ніколя Барбулеско

@NicolasBarbulesco Чесно кажучи, я думаю, що відповідь Райана розумніша за мою. Зрештою, я додав catchблок після фрагмента, він не став.
користувач12205

3

Попередження : ці програми - це клонові бомби (така собі менш небезпечна, але все-таки небезпечна форма вилкової бомби); як такий, не запускайте їх у виробничій системі без пісочниць або обмежень ресурсів . Клоновані бомби створюють нитки в циклі (на відміну від вилкових бомб, які створюють процеси в циклі), таким чином ви можете зупинити їх, просто вбиваючи процес, про який йде мова (роблячи їх набагато менш небезпечними, ніж вилкові бомби, що може бути дуже важко очистити); але вони, швидше за все, пов'язатимуть більшу частину вашого процесора, поки вам не вдасться це зробити (або поки програма не виграє і не вийде природним шляхом сама по собі). Попросивши вашу ОС встановити обмеження на об'єм пам'яті та час процесора, якими ці програми можуть використовуватись, слід створити безпечне середовище, в якому їх можна перевірити.

Java (OpenJDK 8) , 65 60 байт (з незначною зміною обгортки)

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

Спробуйте в Інтернеті!

Потрібно catch (Exception …)змінити обидва екземпляри запитання catch (Throwable …). Теоретично цього повинно бути більше безпечним, а не меншим, але це дозволяє зробити це рішення можливим.

Я врятував 5 байт на першій версії цієї відповіді за допомогою посилання на метод, а не лямбда.

Java 4, 104 байти (не перевірено, має працювати з оригінальною обгорткою)

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

Спробуйте в Інтернеті! (посилання йде на реалізацію Java 8, тому не працюватиме)

Використовуючи функції, вилучені з сучасних версій Java, можна вирішити навіть версію головоломки, яка вимагає Exception . Напевно, принаймні. (Java 4 на сьогоднішній день дуже стара, і я не можу згадати, які функції в ній були, а не містилися. Як видно, у Java тоді було набагато менше функцій, і тому вона була більш багатослівною; у нас не було лямбда, тому мені довелося створити внутрішній клас.)

Пояснення

Більшість рішень цього питання знаходяться в C # (разом із рішенням Java, яке обманює використання неврівноважених дужок як форми введення коду, і рішення Perl, яке також відсутнє на Java). Тому я подумав, що варто спробувати показати, як ця головоломка може бути розв'язана "належним чином" і в Java.

Обидві програми фактично однакові (таким чином, той факт, що перша програма працює, дає мені високу впевненість, що друга програма теж буде працювати, якщо тільки я випадково не використовував функцію, яка не є Java-4; Thread#stop була заборонена в Java 5).

Thread#stopМетод Java працює поза кадром, через те, що кидається в нитку, про яку йдеться. Цільова мета, яка призначена для цієї мети ThreadDeathErrorсаме тому, що люди часто намагаються виганяти винятки, і дизайнери Java не хотіли, щоб це сталося), хоча це дозволяє кидати що-небудь (або звик; у якийсь момент після того, як API був розроблені дизайнерами Java зрозуміли, що це неймовірно погана ідея, і видалили версію методу, яка виводить аргументи прямо). Звичайно, навіть версія, яка кидає, ThreadDeath- це досить ризикована операція, щодо якої ви можете дати кілька гарантій (наприклад, вона дозволяє вирішити цю головоломку, те, що "не повинно" бути можливим), тому вам не слід використовуйте його, але як у Java 8, він все ще працює.

Ця програма працює за допомогою нерестування нової нитки та прохання її насильно перекинути виняток у основний потік. Якщо нам пощастить, це зробиться в той момент, коли ми знаходимось поза внутрішнім catchблоком (ми не можемо уникнути зовнішнього catchблоку, поки програма не закінчиться, оскільки навколо нього є петля). Оскільки у нас вже зручно додано цикл, це економія байтів просто використовувати цю петлю, щоб ми могли продовжувати створювати нитки, сподіваючись, що одна з них врешті-решт потрапить у правильний час. Здається, це зазвичай відбувається через пару секунд.

(Примітка TIO: поточна версія TIO досить схильна знищити цю програму на початку її виконання, імовірно, завдяки всім створеним потокам. Вона може працювати на TIO, але не працює надійно, тому часто потрібно кілька спроб отримати вихід "Ви виграли!".)


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
Ласкаво просимо до головоломки програмування та коду для гольфу! Оскільки це питання є кодовим завданням для гольфу , будь ласка, спробуйте зробити свій код якомога коротшим і включити кількість символів у верхній частині вашої відповіді. Спасибі!
ProgramFOX

1

Perl 5 , 37 або 36 байт

eval {
    while (1) {
        eval {

 

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

 

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

Спробуйте в Інтернеті!

Виявляється, це питання перекладається на Perl досить добре, щоб скласти і тут цікаву головоломку. tryЕквівалент Perl викликається (трохи заплутано) evalі визначає виняток, встановлюючи @_виняток, якщо він стався, а нульовий рядок - інакше. Як такий, catchблок реалізується за допомогою порівняння @_з нульовим рядком.

Це рішення працює, створюючи об’єкт (клас якого - програма в цілому; ви можете використовувати довільні файли Perl, як класи, на зразок реверсу Java (де ви можете використовувати довільні класи, як файли)). Це bless[]частина ( blessяк правило, відображається лише глибоко всередині конструкторів, як примітив, який перетворює речі в об'єкти в першу чергу, але ви можете використовувати їх безпосередньо, якщо цього дуже хочеться; []це розподільник пам'яті для об'єкта - конструктор списку, в цьому case - і клас не заданий, тому він вважається поточним виконуваним). Тим часом, ми надаємо нашому "класу" (тобто головному файлу) користувальницький метод порівняння-рядка через use overload, і робимо цей метод викиданням винятку (таким чином, вириваючись з циклу і вирішуючи головоломку); ми можемо насправді поставитиuse overloadв будь-якому місці, і хоча це традиційно укладається з іншими визначеннями методу і наближається до верхньої частини файлу, ми можемо помістити його в прогалину, яку нам дали, а він все ще працює. (Якщо ми помістимо його в кінці файлу, ми можемо опустити крапку з комою після нього, що призведе до 36-байтового рішення, але це, мабуть, обман, оскільки це залежить від програми, яка має в першу чергу крапку з комою, тобто не гарантується.) Насправді коротше перевантажити операцію Strify та дозволити Perl автогенерувати рядки порівняння з цим, ніж це було б перевантажувати порівняння рядків безпосередньо (тому що перевантаження деяких операторів змушує вас перевантажувати й інших операторів).

Тепер все, що нам потрібно зробити, це кинути наш об’єкт за допомогою die. У evalзавершуючи, тоді , коли ми намагаємося порівняти $@з нулем рядок (щоб побачити, є виняток), порівняння кидає ще один виняток , і ми уникаємо зовні eval.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.