Архив Июль 2010
Как нарисовать стрелку
Лично у меня такая задача возникала не один раз, поэтому придется посвятить ей целый пост.
Итак, даны координаты начала и конца вектора, надо нарисовать стрелку.
Результат будет вот такой:
А теперь к тому, как собственно рисуется стрелка. Чертеж, сделанный в paint (кликабельно):
Повернем точку B вокруг точки A на alpha и на -alpha. Укоротим полученные векторы так, чтобы их длина составляла M (M <= 1) от длины вектора AB. Тогда получим векторы AC и AD.
Соединим точки A и B, B и C, B и D отрезками – стрелка нарисована.
Теперь как это выглядит конкретно на C++ и SFML:
void RotatePoint(double &x, double &y, double ox, double oy, double alpha)
{
double xn, yn;
xn = ox + (x-ox)*cos(alpha) - (y-oy)*sin(alpha);
yn = oy + (x-ox)*sin(alpha) + (y-oy)*cos(alpha);
x = xn;
y = yn;
}
void DecreaseVector(double x1, double y1, double &x_n1, double &y_n1)
{
double dx = (x_n1 - x1)*0.9;
double dy = (y_n1 - y1)*0.9;
x_n1 = x1 + dx;
y_n1 = y1 + dy;
}
void SFMLVizualizer::DrawArrow(int x1, int y1, int x2, int y2, int icolor)
{
int red, green, blue;
blue = icolor%255;
icolor/=255;
green = icolor%255;
icolor/=255;
red = icolor;
sf::Color color = sf::Color(red, green, blue);
int line_width = 1;
w->Draw(sf::Shape::Line(x1, y1, x2, y2, line_width, color));
double x_n1, y_n1, x_n2, y_n2;
x_n1 = x_n2 = x2;
y_n1 = y_n2 = y2;
RotatePoint(x_n1, y_n1, x1, y1, pi/48);
RotatePoint(x_n2, y_n2, x1, y1, -pi/48);
DecreaseVector(x1, y1, x_n1, y_n1);
DecreaseVector(x1, y1, x_n2, y_n2);
w->Draw(sf::Shape::Line(x_n1, y_n1, x2, y2, line_width, color));
w->Draw(sf::Shape::Line(x_n2, y_n2, x2, y2, line_width, color));
}
Такие стрелочки имеют свойство масштабироваться в зависимости от длины вектора. Выглядит очень симпатично, я даже сам не ожидал такого!
Debug me!
Вы же знаете, что такое Crack me? Ну, я уверен, что все даже игрались когда-то. Как там, берем Crack me #2 (потому что #1 уже одолели), открываем в IDA Pro Disassembler и вперед… Исправляем JNE на JNZ или что-то в таком духе.
А недавно я видел человека, который писал игру “Дурак” на C++ с использованием классов.
И все было бы прекрасно, если бы не один глюк.
Сначала кажется, что глючим мы – когда пишем код. Но потом мы ищем ошибку и не находим ее. Потом ищем еще раз – и опять не находим! Очевдно, что глючим не мы. Глючит компилятор, операционка, клавиатура, все, что угодно – только не мы. Потому что код просмотрен и проверен уже 100 раз!
На этот раз глючила колода. Я не шучу. Не помню деталей, но по-моему колода имела метод
Card Deck::GetCard()
который возвращал из колоды карту.
Удивительно, но после раздачи 6 карт компьютеру и 6 карт человеку в колоде оставалось то 24, то 23 карты. Причем чаще 24.
Отладка происходила довольно тупым способом. Сперва повесили printf()’ы сразу после { и перед }, в которых выводили все, что могло принести какую-то пользу: количество карт в колоде, карты на руках у игроков.
Потом додумались до “инварианта цикла”, круто?
Прям в лучших традициях Кормэна! Суть в том, что deck.cards_count() + player1.cards_count() + player2.cards_count() == 36 всегда.
Таким образом повесив if (…) мы дали программе возможность самой определять, произошла ли ошибка.
Потом пришлось все-таки делать обертки из printf()’ов еще для нескольких фукнций. В итоге определилось место ошибки (точно функцию не помню, но смысл такой же) :
bool Card::Exists()
{
return this->num > 0;
}
Ошибка в num > 0 (надо было num >= 0).
По-моему, очень глупая ошибка. Связанная с невнимательностью и нетривиальной задумкой по поводу хранения карт в колоде.
Нет бы сделать List <Card> или Vector <Card>, так нет блин… )))
Но сам процесс отладки лично мне доставил удовольствие и вот, что я подумал.
А вдруг, кто-то, найдя очередную подобную ошибку, не просто исправит ее, а запишет, запомнит и потом на основе ее сделает “Debug me!”.
Да и вообще, сделать бы сайт для программистов. Куча мелких программ, в каждой какая-то ошибка, которую надо исправить! Вау.
Идея утопическая, конечно, потому что дай только такому сайту появиться – сразу студенты запостят свои лабы.

