среда, 3 сентября 2014 г.

Чупакабра

Как-то решая веселую задачку, проиллюстрировал решение в Visio. По-моему, стоит опубликовать. Как рекламу Visio :)
Задачка была такой:
Круглое озеро, Вы в центре озера на лодке. На берегу, не останавливаясь, бегает Чупакабра, очень хитрая. Когда Вы на лодке плывёте в какую-нибудь сторону, она по самому кратчайшему пути начинает вдоль берега бежать к Вам (в озере не плавает). Понятно дело если она на берегу встретит Вас – Вам конец. А на берег вам очень надо! Печаль Ваша была бы меньше, если бы не то обстоятельство, которое Вы знаете: максимальная скорость лодки в 4 раза меньше скорости бега Чупакабры!!! (плавать без лодки Вы не умеете)
По какой траектории Вам надо плыть, чтоб достичь какой-нибудь точки на берегу раньше, чем там окажется Чупакабра?
Одно из решений (не самое оптимальное, но это неважно):
Лодочка убегает зигзагами под 45 градусов от направления на Чупакабру.
Выбор направления определяется тем, где зверюга - справа или слева от центральной линии.
Чупакабра идет по кратчайшему расстоянию в своей системе координат (в реализации - крутит озеро).
Иллюстрация решения заняла в Visio 16 строк кода! (Комментарии не считаем).
Sub NextStep()
   'Чупакабра оценивает направление и "крутит озеро"
   If al > 0 Then
       sh1.Cells("Angle") = sh1.Cells("Angle") + 0.05
   Else
       sh1.Cells("Angle") = sh1.Cells("Angle") - 0.05
   End If
   'Лодочник тоже оценивает направление и прогнозирует точку следующего шага
   posX1 = sh.Cells("PinX"): posY1 = sh.Cells("PinY")
   If al > 0 Then
       posX = posX1 + 0.005
   Else
       posX = posX1 - 0.005
   End If
   posY = posY1 + 0.005
   'Прорисовка пути лодочки от текущего положения до следующего
   Set shtemp = sh1.DrawLine(posX1, posY1, posX, posY)
   'И лодочка попадает в новое положение
   sh.Cells("PinX") = posX: sh.Cells("PinY") = posY
   'Пересчет в систему координат листа для вычисления направления на следующем шаге
   sh.XYToPage posX - 0.5, posY - 0.5, xprime, yprime
   'Вычисление направления
   If xprime > 0 Then al = 0 Else al = 1
End Sub 
Там есть, конечно, еще запускающий макрос и таймер... Но это ведь к решению отношения не имеет.
Вообще, как мне кажется, пример будет полезен для начинающих. Здесь и просто рисование, и пересчет координат, и пример использования таймера... Рисунок-то ведь динамический.
Файл прилагается.
Скачать. Открыть.
Выполнить макрос ThisDocument.StartTest.
Наблюдать построение траектории, пока лодочка не доплывет до берега.
Если нужно прервать, выполнить макрос ThisDocument.StopTest.