Значит, недосмотрел где-то. У меня была та же ошибка в PC-BASIC, я ее долго отлаживал, нашел фундаментальную проблему с логикой, починил, теперь у меня минимум 5 минут бежит без проблем. Но исходники я выложил уже починенные, я перепроверил, так что еще другой баг остался, видимо.
Вообще эта простая программа показывает интересным образом эффекты разных trade-off'ов. Поле состоит из 20x20x клеток, каждая размером в 15x15 пикселей. Напрашивается подход, в котором мы держим массив 20x20 булевых значений (ну в бейсике их нет, будут числа, но по сути), указывающий, к какой группе принадлежит данная клетка. Шарики тоже принадлежат к клеткам и прыгают между ними атомарным образом, после каждого прыжка принимается решение, как шарик отражается и какие клетки им "съедаются". Гладкое движение шарика между клетками обеспечивается другим способом, не имеющим отношения к логике принятия решений. Можно в цикле из 15 перемещений отрисовывать движение обоих шариков, потом принимать решение насчет отражений и съедания, и опять. В еще более простом подходе вся доска просто перерисовывается каждый фрейм, автоматически учитывая апдейты по принадлежности клеток, и рисуя шарики в процессе движения.
На Бейсике это все получается очень медленно и/или громоздко. Вариант с полным рефрешем доски каждый раз вообще невыносимо медленный.
Я хотел иметь меньше строчек кода, поэтому уже в начале работы избавился от массива 20x20 и стал просто читать с экрана пиксели, чтобы знать принадлежность близлежащих к шарику клеток. Дальше стало понятно, что можно также избавиться от внутреннего цикла "передвинуть шарик с одной клетки на другую". Если условия отражения написаны правильно, можно двигать шарики на +1/-1 каждый раз и проверять после каждого движения, и тогда проверка реально будет что-то делать только на границах клеток. Главный цикл кода ничего не знает про клетки или их границы, оно просто само так работает.
Получился код очень компактный и элегантный, но из-за того, что в нем смешана логика движения и отрисовка, тяжелый для отладки. Слишком много важных инвариантов в нем не задано самой структурой данных (напр. массивом состояний 20x20), и поэтому когда из-за сложной ошибки они нарушаются, код это "не замечает" и продолжает вести себя все более неправильно.
Правильнее было все-таки сделать логику отдельно, в виде процедуры решения, и вызывать ее только в дискретные моменты прихода шариков в новые клетки; но при этом отрисовывать только изменившиеся, съеденные клетки, а не все. Строк кода при этом вышло бы в 2-3 раза больше.
Вообще эта простая программа показывает интересным образом эффекты разных trade-off'ов. Поле состоит из 20x20x клеток, каждая размером в 15x15 пикселей. Напрашивается подход, в котором мы держим массив 20x20 булевых значений (ну в бейсике их нет, будут числа, но по сути), указывающий, к какой группе принадлежит данная клетка. Шарики тоже принадлежат к клеткам и прыгают между ними атомарным образом, после каждого прыжка принимается решение, как шарик отражается и какие клетки им "съедаются". Гладкое движение шарика между клетками обеспечивается другим способом, не имеющим отношения к логике принятия решений. Можно в цикле из 15 перемещений отрисовывать движение обоих шариков, потом принимать решение насчет отражений и съедания, и опять.
В еще более простом подходе вся доска просто перерисовывается каждый фрейм, автоматически учитывая апдейты по принадлежности клеток, и рисуя шарики в процессе движения.
На Бейсике это все получается очень медленно и/или громоздко. Вариант с полным рефрешем доски каждый раз вообще невыносимо медленный.
Я хотел иметь меньше строчек кода, поэтому уже в начале работы избавился от массива 20x20 и стал просто читать с экрана пиксели, чтобы знать принадлежность близлежащих к шарику клеток. Дальше стало понятно, что можно также избавиться от внутреннего цикла "передвинуть шарик с одной клетки на другую". Если условия отражения написаны правильно, можно двигать шарики на +1/-1 каждый раз и проверять после каждого движения, и тогда проверка реально будет что-то делать только на границах клеток. Главный цикл кода ничего не знает про клетки или их границы, оно просто само так работает.
Получился код очень компактный и элегантный, но из-за того, что в нем смешана логика движения и отрисовка, тяжелый для отладки. Слишком много важных инвариантов в нем не задано самой структурой данных (напр. массивом состояний 20x20), и поэтому когда из-за сложной ошибки они нарушаются, код это "не замечает" и продолжает вести себя все более неправильно.
Правильнее было все-таки сделать логику отдельно, в виде процедуры решения, и вызывать ее только в дискретные моменты прихода шариков в новые клетки; но при этом отрисовывать только изменившиеся, съеденные клетки, а не все. Строк кода при этом вышло бы в 2-3 раза больше.
Reply
Leave a comment