Пользователь CarpetPython опубликовал новый взгляд на эту проблему, в котором гораздо больше внимания уделяется эвристическим решениям из-за увеличенного пространства поиска. Я лично считаю, что этот вызов намного приятнее моего, поэтому подумайте над тем, чтобы попробовать его!
Векторные гонки - это захватывающая игра, в которую можно играть с ручкой и листом бумаги с квадратной линией. Вы рисуете произвольную гоночную трассу на бумаге, определяете начало и конец, а затем управляете автомобилем с точечными размерами пошаговым способом. Доберись до конца как можно быстрее, но будь осторожен, чтобы не оказаться в стене!
Трек
- Карта представляет собой двумерную сетку, где каждая ячейка имеет целочисленные координаты.
- Вы двигаетесь по ячейкам сетки.
- Каждая ячейка сетки является либо частью дорожки, либо стеной.
- Ровно одна ячейка трека является начальной координатой.
- По крайней мере одна ячейка пути обозначена как цель. Посадка на любой из них завершает гонку. Несколько клеток цели не обязательно связаны.
Управление автомобилем
Ваш автомобиль начинается с заданной координаты и вектора скорости (0, 0)
. В каждом повороте вы можете регулировать каждый компонент скорости ±1
или оставить его как есть. Затем результирующий вектор скорости добавляется к позиции вашего автомобиля.
Картинка может помочь! Красный круг был вашей позицией в последний ход. Синий круг - это ваша текущая позиция. Ваша скорость - это вектор от красного до синего круга. В этом случае, в зависимости от того, как вы отрегулируете свою скорость, вы можете перейти к любому из зеленых кругов.
Если вы приземлитесь в стене, вы немедленно проиграете.
Твое задание
Вы уже догадались: напишите программу, которая, учитывая вход в гоночную трассу, направляет машину к одной из клеток ворот за как можно меньшее количество оборотов. Ваше решение должно быть в состоянии справиться с произвольно выбранными треками и не должно быть специально оптимизировано для предоставленных тестовых случаев.
вход
Когда ваша программа вызывается, читайте из stdin :
target
n m
[ASCII representation of an n x m racetrack]
time
target
максимальное количество ходов, которое вы можете совершить, чтобы завершить трек, и time
ваш общий бюджет времени для трека в секундах (не обязательно целое число). Смотрите ниже подробности о времени.
Для дорожки с разделителями новой строки используются следующие символы:
#
- стенаS
- начало*
- цель.
- все остальные трековые ячейки (т.е. дорога)
Предполагается, что все ячейки за пределами n x m
предоставленной сетки являются стенами.
Начало координат находится в верхнем левом углу.
Вот простой пример:
8
4.0
9 6
###...***
###...***
###...***
......###
S.....###
......###
Используя индексирование на основе 0, начальная координата будет (0,4)
.
После каждого хода вы будете получать дополнительные данные:
x y
u v
time
Где x
, y
, u
, v
все 0 на основе целых чисел. (x,y)
ваша текущая позиция и (u,v)
ваша текущая скорость. Обратите внимание, что x+u
и / или y+v
может быть за пределами.
time
это все, что осталось от вашего бюджета времени, в секундах. Не стесняйтесь игнорировать это. Это только для участников, которые действительно хотят довести свою реализацию до установленного срока.
Когда игра закончится (потому что вы приземлились в стене, вышли за границы, превысили target
обороты, не хватило времени или достигли цели), вы получите пустую строку.
Выход
Для каждого хода пишите в stdout :
Δu Δv
где Δu
и Δv
каждого из них один из -1
, 0
, 1
. Это будет добавлено (u,v)
для определения вашей новой позиции. Просто чтобы уточнить, направления следующие
(-1,-1) ( 0,-1) ( 1,-1)
(-1, 0) ( 0, 0) ( 1, 0)
(-1, 1) ( 0, 1) ( 1, 1)
Оптимальным решением для приведенного выше примера будет
1 0
1 -1
1 0
Обратите внимание, что контроллер не присоединяется к stderr , поэтому вы можете использовать его для любого отладочного вывода, который может вам понадобиться при разработке вашего бота. Пожалуйста, удалите / закомментируйте любой такой вывод в представленном вами коде.
Ваш бот может занять полсекунды, чтобы ответить в каждом ходу. Для поворотов, которые занимают больше времени, у вас будет время (на трек) в target/2
секундах. Каждый раз, когда ход занимает больше полсекунды, дополнительное время будет вычитаться из вашего временного бюджета. Когда ваш временной бюджет достигнет нуля, текущая гонка будет прервана.
Новое: по практическим соображениям я должен установить ограничение памяти (так как память кажется более ограничивающей, чем время для разумных размеров дорожек). Поэтому мне придется прервать любой тестовый прогон, когда гонщик использует более 1 ГБ памяти, что измеряется Process Explorer как частные байты .
счет
Существует эталон из 20 треков. Для каждого трека:
- Если вы пройдете трассу, ваш счет - это количество ходов, необходимое для достижения ячейки цели, деленное на
target
. - Если у вас закончилось время / память или вы не достигли цели до того
target
, как пройдут ходы, или вы в любой момент приземлились в стене / за пределами, ваш счет равен2
. - Если ваша программа не является детерминированной, ваш результат составляет в среднем более 10 пробежек на этом треке (укажите это в своем ответе).
Ваш общий балл - это сумма баллов отдельных треков. Самый низкий балл побеждает!
Кроме того, каждый участник может (и настоятельно рекомендуется) предоставить дополнительный контрольный трек , который будет добавлен в официальный список. Предыдущие ответы будут переоценены, включая этот новый трек. Это делается для того, чтобы убедиться, что ни одно решение не адаптировано слишком близко к существующим тестовым примерам, и для учета интересных крайних случаев, которые я мог пропустить (но которые вы можете заметить).
Разрыв связи
Теперь, когда уже существует оптимальное решение, это, вероятно, будет основным фактором для оценки участников.
Если есть связь (из-за того, что несколько ответов решают все треки оптимально или иным образом), я добавлю дополнительные (более крупные) контрольные примеры, чтобы разорвать связь. Чтобы избежать предвзятости человека при создании этих тай-брейков, они будут сгенерированы фиксированным образом:
- Я увеличу длину стороны
n
по10
сравнению с последним треком, сгенерированным таким образом. (Я могу пропустить размеры, если они не сломают галстук.) - Основа этой векторной графики
- Это будет растеризовано с желаемым разрешением, используя этот фрагмент Mathematica .
- Начало в левом верхнем углу. В частности, это будет самая левая ячейка самого верхнего ряда этого конца дорожки.
- Цель в правом нижнем углу. В частности, это будет самая правая ячейка самого нижнего ряда этого конца дорожки.
target
Воля4*n
.
Финальная дорожка исходного теста уже была сгенерирована следующим образом n = 50
.
Контроллер
Программа, которая проверяет представленные материалы, написана на Ruby и может быть найдена на GitHub вместе с файлом эталонного теста, который я буду использовать. Там также есть пример бота randomracer.rb
, который просто выбирает случайные ходы. Вы можете использовать его базовую структуру в качестве отправной точки для вашего бота, чтобы увидеть, как работает связь.
Вы можете запустить свой собственный бот для файла трека по вашему выбору следующим образом:
ruby controller.rb track_file_name command to run your racer
например
ruby controller.rb benchmark.txt ruby randomracer.rb
Хранилище также содержит два класса Point2D
и Track
. Если ваша заявка написана на Ruby, не стесняйтесь использовать ее для вашего удобства.
Командная строка
Вы можете добавить параметры командной строки -v
, -s
, -t
перед именем файла в бенчмарка. Если вы хотите использовать несколько переключателей, вы также можете сделать, например, -vs
. Вот что они делают:
-v
(подробный): Используйте это, чтобы произвести немного больше отладочного вывода от контроллера.
-s
(без звука): Если вы предпочитаете самостоятельно отслеживать свою позицию и скорость и не заботитесь о временном бюджете, вы можете отключить эти три строки вывода каждый ход (отправленный на ваше представление) с помощью этого флага.
-t
(дорожки): позволяет выбрать отдельные дорожки для проверки. Например, -t "1,2,5..8,15"
будут проверяться только треки 1, 2, 5, 6, 7, 8 и 15. Большое спасибо Ventero за эту функцию и парсер опций.
Ваше представление
В заключение, пожалуйста, включите в свой ответ следующее:
- Твой счет.
- Если вы используете случайность, укажите это, чтобы я мог усреднить ваш результат за несколько прогонов.
- Код для вашего представления.
- Расположение бесплатного компилятора или интерпретатора для вашего языка, выбранного на компьютере с Windows 8.
- Инструкция по компиляции при необходимости.
- Строка командной строки Windows для запуска вашего представления.
- Требует ли ваше представление
-s
флаг или нет. - (опционально) Новый, разрешимый трек, который будет добавлен в тест. Я определю разумный
target
для вашего трека вручную. Когда трек будет добавлен в тест, я отредактирую его из вашего ответа. Я оставляю за собой право попросить вас о другой дорожке (на случай, если вы добавите непропорционально большую дорожку, включите в нее непристойную графику ASCII и т. Д.). Когда я добавлю тестовый набор в набор тестов, я заменим трек в вашем ответе ссылкой на трек в файле тестов, чтобы уменьшить беспорядок в этом посте.
Как вы можете видеть, я буду тестировать все материалы на компьютере с Windows 8. Если нет абсолютно никакой возможности запустить ваше представление в Windows, я также могу попробовать виртуальную машину Ubuntu. Это будет значительно медленнее, поэтому, если вы хотите максимально увеличить ограничение времени, убедитесь, что ваша программа работает в Windows.
Пусть лучший водитель появится в векторе!
Но я хочу играть!
Если вы хотите попробовать игру самостоятельно, чтобы лучше почувствовать ее, есть такая реализация . Правила, используемые там, немного более изощренны, но я думаю, что они достаточно похожи, чтобы быть полезными.
Leaderboard
Последнее обновление: 01.09.2014, 21:29 UTC
Дорожки в тесте: 25
Размеры стяжки: 290, 440
- 6.86688 - Курой Неко
- 8.73108 - user2357112 - 2-я подача
- 9.86627 - nneonneo
- 10.66109 - user2357112 - 1-я подача
- 12.49643 - Рэй
- 40.0759 - псевдоним117 (вероятностный)
Подробные результаты теста . (Баллы за вероятностные представления были определены отдельно.)
источник
400
, так как это соответствует тому, как я определил все другие цели (кроме прерывателя связей). Я обновлю основной пост, как только перейду на все остальные материалы.C ++, 5.4 (детерминированный, оптимальный)
Решение для динамического программирования. Достаточно оптимально. Очень быстро: решает все 20 тестов за 0,2 с. Должно быть особенно быстро на 64-битных машинах. Предполагается, что доска занимает менее 32 000 мест в каждом направлении (что, надеюсь, должно быть правдой).
Этот гонщик немного необычен. Он вычисляет оптимальный путь в начальной строке, а затем мгновенно выполняет вычисленный путь. Он игнорирует контроль времени и предполагает, что он может завершить этап оптимизации вовремя (что должно быть верно для любого достаточно современного аппаратного обеспечения). На слишком больших картах есть небольшая вероятность того, что гонщик может потерпеть неудачу. Если вы можете убедить его в segfault, вы получите точку брауни, и я исправлю это, используя явный цикл.
Компилировать с
g++ -O3
. Может потребоваться C ++ 11 (для<unordered_map>
). Для запуска просто запустите скомпилированный исполняемый файл (никакие флаги или опции не поддерживаются; все данные вводятся в stdin).Полученные результаты
Новый тест-кейс
источник
Python 2 , детерминированный, оптимальный
Вот мой гонщик. Я не тестировал его в тестах (все еще сомневаюсь, какую версию и установщик Ruby установить), но он должен решить все оптимально и в установленные сроки. Команда для запуска это
python whateveryoucallthefile.py
. Требуется-s
флаг контроллера.Изучив гонщика nneonneo (но на самом деле не тестируя его, поскольку у меня также нет компилятора C ++), я обнаружил, что он выполняет почти исчерпывающий поиск в пространстве состояний, независимо от того, насколько близка цель или насколько коротка путь уже найден. Я также обнаружил, что правила времени означают, что построение карты с длинным, сложным решением требует длительного, скучного временного ограничения. Таким образом, моя карта очень проста:
Новый тест-кейс
(GitHub не может отобразить длинную строку. Трек
*S.......[and so on].....
)Дополнительные материалы: Python 2, двунаправленный поиск
Это подход, который я написал около двух месяцев назад, когда пытался оптимизировать свою первую подачу. Для тестовых случаев, которые существовали в то время, это не дало улучшения, поэтому я не представил его, но для новой карты Курои она, кажется, просто сжимается под крышкой памяти. Я все еще ожидаю, что решатель Курои справится с этим, но мне интересно, как это выдержит.
источник
n = 400
.) Пожалуйста, дайте мне знать, если вы примените какие-либо оптимизации, чтобы я мог повторно запустить тесты.Python 3: 6.49643 (оптимальный, BFS)
Для старого файла 20 тестов он получил 5,35643 балла. Решение @nneonneo не является оптимальным, поскольку оно получило 5.4. Возможно, некоторые ошибки.
Это решение использует BFS для поиска в графе, каждое состояние поиска имеет вид (x, y, dx, dy). Затем я использую карту для отображения состояний на расстояния. В худшем случае сложность времени и пространства равна O (n ^ 2 m ^ 2). Такое случается редко, так как скорость не будет слишком высокой или гонщик упадет. На самом деле, на моем компьютере понадобилось 3 секунды, чтобы пройти все 22 теста.
# Полученные результаты
источник
O(√n)
что сделает вашу реализациюO(n³)
на квадратных сетках (как и другие, я полагаю). Я добавлю прерыватель связи, чтобы оценить вашу работу по сравнению с user2357112 позже сегодня.n=270
, поэтому вы теперь находитесь позади двух других «оптимальных» представлений. Тем не менее, ваше представление также является самым медленным из трех, так что в любом случае было бы третьим, только с большим тай-брейком.RandomRacer, ~ 40.0 (в среднем за 10 прогонов)
Дело не в том, что этот бот никогда заканчивает трек, но определенно гораздо реже, чем один раз в 10 попыток. (Я получаю оценку не в худшем случае каждые 20–30 симуляций или около того.)
Это в основном служит базовым вариантом и демонстрирует возможную (Ruby) реализацию для гонщика:
Запустить его с
источник
Случайный гонщик 2.0, ~ 31
Что ж, это не превзойдет опубликованный оптимальный алгоритм, но это небольшое улучшение для случайного гонщика. Основное отличие состоит в том, что этот гонщик будет рассматривать случайное движение только там, где нет стены, если только у него не закончатся места для перемещения, и если он сможет двигаться к цели в этом повороте, он сделает это. Он также не будет двигаться, чтобы оставаться на том же месте, если только нет другого доступного движения (маловероятно, но возможно).
Реализован на Java, скомпилирован с java8, но Java 6 должна быть в порядке. Нет параметров командной строки. Там довольно хороший кластерный иерарх, так что я думаю, что я делаю Java правильно.
Результаты (лучший случай, который я видел)
источник
.class
по какой-то причине находится файл (а не из каталога, где находится контроллер). Пинг мне (с комментарием), если вы решите добавить тестовый пример, чтобы я мог добавить его в тест. Ваша оценка была около 33 за 10 пробежек (см. Таблицу лидеров), но это может измениться с каждым новым тестовым треком, который добавляется в тест.java -cp path/to/class/file VectorRacing