Comments 124
Конечно, при реальных переговорах, 20% в денежном выражении совсем не мало, но от конкурса алгоритмов интуитивно ожидаешь большего результата
Привет, FlameStorm!
Точнее, тут просто не видно никакой возможности существования алгоритма, работающего лучше всех и могущего взять призовое место, — всё сильно зависит от остальных решений, с которыми будет вести диалог твоё.
всё сильно зависит от остальных решений, с которыми будет вести диалог твоё.
Как и в жизни.
return false
.Суровые однако решения. Ладно хоть не выиграли. ) Я кстати читал, что в том конкурсе происходило, были и решения наоборот с другой стороны хардкорности.
Кстати по лимитам тут озвученным — а example.js
гарантированно будет участвовать? И если вдруг все сторонние участники закинут решения отличные (по принимаемым решениям о сделках) от example.js
, этот пункт ограничений будет снят с рассмотрения, или таки если никто не отправит клон экзампла, то он будет отправлен by Alexey (вне конкурсной таблицы)?
example.js
. Их «авторы», конечно, могут закачать на их место что-нибудь новое — в этом маловероятном случае, да, добавлю одну копию от себя.Могло быть и 4 копии, если б не успел увидеть в телеграм канале сообщение о пробном забеге) Текущая версия не всегда уже отправлена как решение. Вполне вероятно, что из этих трёх останется меньше трёх. Но добавят новых example.js
подоспевшие участники ))
Кстати вопрос — если сиды идентичные и у всех абсолютно равные условия забега, как вообще хоть на 1 очко разницы могло получиться у тех трёх копий example.js
из таблицы?
Math.random
.Не понятно. Так копии или не копии example.js? Те которые на строчках 59, 60 и 61
Math.random
. Из-за них у всех чуть колеблются результаты, ведь они дают вклад в итоговый счёт каждого решения.А, спасибо, теперь ясно. Что-то сразу не догнал до этого момента.
У меня кстати у самого используется рандом, но не Math'овский, а собственная копия простейшего из генераторов. Уже не помню почему сделал именно так, наверное для хоть и похожести на случайное поведение, но предсказуемости — сид задаётся на основе входных данных торгов, потому при том же первом ходящем, том же количестве раундов и тех же количествах и ценах вещей мой бот сыграет всегда одинаково. Так что если что, я рандома остальным не насыпал, то был кто-то ещё. :)
Ваш идентификатор — в автоматическом письме, которое Вы получили после отправки решения.
Хм, а я ни какого письма не получил, хотя решение отправлял. Что делать?
А то как-то грустно смотреть на одностороннюю торговлю, когда свой бот торгуется, а противник всегда выставляет одно и то же предложение.
> сравнить результаты алгоритмов
Эти результаты в зачёт не пойдут. В зачёт пойдут результаты игр top50 между собой. Эрго, промежуточные результаты бесполезны (разве что могут намекнуть, попадёшь в первую полусотню или нет — но туда попасть довольно просто.)
Submissions are no longer accepted after the deadline
github.com/indutny/haggling_rl
github.com/morozec/HolaHaggling
Я уже устал думать. За лишние две недели все равно ничего не улучшил, зато мозг поизносился.
Параметры:
— список предложений сортируется по правилу F. Например, {F=max(S1+S2); F >= 0.6}
— предложение оппонента мы оцениваем с точки зрения «он бы не отдал нам то, что дает ему в сумме более N денег» и перестраиваем предположение о ценах
— отказ оппонента мы воспринимаем как «для него ценность этих вещей меньше M» и снова перестраиваем предположение о ценах
— если нам предлагают вариант больше L, то соглашаемся
— последним ходом соглашаемся на все, что выгоднее K, вне зависимости от того, сколько получит противник
Функция F + набор коэффициентов (N,M,L,K) и определяет поведение алгоритма — «жадный», «наивный», «рисковый», «сбалансированный» и т.д. По большому счету, задача сводится к нахождению идеальных коэффициентов на арене и собственных тестах.
Конечно же, алгоритм может включать какие-то небольшие улучшения, которые и могут перетянуть чашу весов. Частные случаи вроде «никогда не соглашаться последним ходом» это на самом деле вырожденные значения каких-то из коэффициентов. Поведение example.js тоже можно выразить этим алгоритмом с коэффициентами (L = 0.5; K = 0; M = 1; N = 1) и отсутствием продвижения по списку вариантов.
Код на C#, включая транслированный в JS вариант через Bridge.Net с ручной чисткой:
github.com/Nomad1/Detective
А вот что хочется увидеть, так это совершенно нестандартное решение, без предсказаний и поисков компромиссов. Может с обучаемой нейросетью, может с непонятной логикой, дающей отличный результат, может с продвинутым блефом или угадыванием карт противника странными ходами.
И вообще думать над этой задачей долго не хотелось, поэтому сделал решение простое как валенок.
Соглашаюсь сразу на 8 и более баксов. Тут я пожадничал, наверное ))
Сортирую все предложения по максимальной выгоде для себя. Предполагаю в начале одинаковую ценность объектов для противника и предлагаю вариант, максимальный для меня и не нулевой для него. После каждого хода уточняю ценности объектов противника. Для этого в два раза уменьшаю ценности объектов, от которых он отказался. Сумма при этом станет меньше 10, поэтому остаток распределяю поровну между объектами. При такой манипуляции ценности объектов будут нецелыми, поэтому ищу в списке ценностей вариант максимально близкий к вычисленному. Опять сортирую список предложений, выкинув предыдущие предложения и учтя новые ценности объектов противника.
На последнем раунде соглашаюсь сразу на все, что больше 0. Если же мой ход первый, то смотрю, не предлагали ли мне раньше что-то повыгодней и если да, предлагаю этот же вариант в ответ. Или же предлагаю вариант, в котором противник получит 5 и более баксов (исходя из моих предположений), а я получу хоть что-то. Тут я расщедрился ))
Были еще идеи улучшений, но не рискнул их использовать в условиях, когда невозможно определить, какой эффект они дают. На серверах рейтинг в течение дня прыгал очень сильно. Алгоритм вроде бы точно должен был улучшиться, а ты опускаешься вниз. Или наоборот, ничего не менял, а стою первым в рейтинге.
Отсюда возник вопрос. Можно ли выиграть у всех, проигрывая каждому в отдельности? В теории, конечно, можно. Но каковы шансы сделать это на практике.
предметы: 1,1,1
наши цены: 0,4,6
цены противника: 3,3,4
Это весьма неприятный случай и мы можем сказать, только что у противника цена каждого предмета от 0 до 10 и единственное, что можно выбросить это набор цен 0,4,6, потому что он уже занят нами. Но из таблицы ходов сразу можно убрать то, что гарантированно дает нечестный результат — «все мне», «все противнику» и «я не получаю ничего».
001: my income 6, enemy average 6.707692, enemy median 6, range [0, 10] — хороший компромиссный вариант
101: my income 6, enemy average 3.323077, enemy median 3, range [0, 10] — плохой вариант, но в целом можно попробовать
010: my income 4, enemy average 6.676923, enemy median 7, range [0, 10] — мы получим 4, а противник с большой вероятностью 6-7. это валидный ход, но желательно оставить его на крайний случай
110: my income 4, enemy average 3.292308, enemy median 4, range [0, 10] — скорее всего, все получат мало.
Тут и к гадалке не ходи, надо пробовать ходить 011 (точнее, отдать 100, т.е. то, что нам не нужно). Если противник откажется, значит мы можем спокойно выбросить варианты, в которых цена его первого предмета составляет 8, 9, 10 (предположение зависит от коэффициентов).
Встречное предложение было 000 (скрипт example.js), оно нам ничего не говорит.
101: my income 6, enemy average 3.59322, enemy median 0, range [0, 10]
010: my income 4, enemy average 6.40678, enemy median 10, range [0, 10]
110: my income 4, enemy average 3.559322, enemy median 7, range [0, 10]
Посылаем предложение 001 (противнику достается 110).
010: my income 4, enemy average 7.714286, enemy median 7, range [3, 10] — гарантированно знаем, что оппонент получит не меньше 3
110: my income 4, enemy average 5.314286, enemy median 5, range [3, 10]
Но т.к. это был example.js, то он согласился и получил 6 баллов, мы получили столько же.
Конечно же, у противника цены могли быть 5,5,0 либо 0,10,0 и тогда бы второй ход закончил игру со счетом 6/10, но наша цель не обставить противника как можно больше, а уйти с максимумом дохода. Бывают случаи, когда вообще все предположения ошибочны, а реальная цена где-то на краю диапазона, но у нас нет данных для других предсказаний, ничего поделать с этим нельзя.
А вот это откуда следует: «единственное, что можно выбросить это набор цен 0,4,6, потому что он уже занят нами»? В условиях такого не видел. Разве не могут быть одинаковые ценности?
1. Исключаем все предметы с нулевой ценностью для нас, т.к. смысла торговаться за них нет, будем отдавать их сразу.
2. Из оставшихся предметов генерируем все возможные комбинации, группируем по суммарной ценности (например, все комбинации, которые дают $10, $9, $8...), сортируем группы в порядке убывания
3. Начинаем торговаться, начиная с максимально выгодных комбинаций
Основной момент тут — ограничение количества ходов. Т.е. для того, чтобы уменьшить количество торгов, надо предлагать максимально выгодное предложение для меня и, в то же время, максимально выгодное для противника.
Для уменьшения количества торгов нужно примерно оценить стоимость товар для противника, и выкинуть из торгов комбинации, манипулирующие товарами, не имеющими стоимости для противника — т.е. для таких товаров мы всегда требуем всё.
После этого сортируем комбинации внутри ценовой группы и отдаём, начиная с самых выгодных для противника, и заканчивая самыми невыгодными (по нашей оценке).
Оценку производим по встречным предложениям.
Почти наверняка первым ходом противник предложит товары, не имеющие для него ценности, т.е. 0. Затем будет торговаться, предлагая товары, имеющие малую стоимость, затем большую и большую, вплоть до товара с максимальной стоимостью.
Возможны варианты, когда для противника все товары имеют стоимость, поэтому первым ходом противник не отдаст ничего (это ожидаемый жадный ход), либо противник отдаст только один товар с минимальной стоимостью. Если товаров с минимальной стоимостью несколько, то это можно определить. Если товар с минимальной стоимостью только один, то отличить его от товара с нулевой стоимостью не получится (но этот случай исключение).
Дальше мы назначаем примерную стоимость для всех товаров, которые предложил противник от 0.001 до 0.999 (0 — только для товаров из первого предложения, 1 и более назначать нельзя, чтобы уменьшить вероятность ошибок и неверных предложений от противника). Если были оценены не все товары, то оставшиеся товары оцениваются по следующему алгоритму — все оценки товаров от 0.001 до 0.999 приравниваем 1, умножаем на их количество и отнимаем от общей суммы. Остаток после вычислений делим нацело на каждый из типов товаров.
Например, у нас 4 позциции товаров [A, B, C, D] с количеством [2, 3, 1, 2] и общая сумма $12.
Предложения, поступившие от оппонента [0, 0, 0, 1], [0, 0, 0, 2], [0, 0, 1, 0].
По логике, описанной выше, если бы первым предложением было [0, 0, 0, 2], то товар D получил бы нулевую стоимость. Но т.к. первым предложением была часть товара, поэтому стоит предположить, что товар имеет не нулевую ценность (но нельзя сказать, что он стоит 1). Поэтому товару D присваиваем 0.001, а товару C — 0.002. Теперь надо вычислить примерную стоимость товаров A и B. Увеличиваем минимальную стоимость товаров C, D до 1, умножаем на количество, получаем $3.
$12 — $3 = $9. Именно столько приходится на оставшиеся два товара по нашим предположениям. У нас осталось 2 товара A и 3 товара B. У товара A предполагаемая стоимость будет 9 / 2 = $4, у товара B ~ 9 / 3 = $3.
Итого примерная оценка товаров противника для сортировки будет [4, 3, 0.002, 0.001]
Переоценка товаров происходит после каждого предложения от оппонента, как и пересчёт порядка комбинаций внутри ценовых групп.
Всё просто
Т.е. по-сути, наши решения будут соревноваться лишь в мелких оптимизациях, коэффициентах, ну и удачливости.
Как и в прошлых конкурсах.
В jsdash надо было просчитывать ходы и строить оптимальный маршрут. Было два варианта алгоритмов: считать и передвигаться на каждый ход или считать, пропуская ходы, а потом ходить по рассчитанному. Ожидаемо победил второй вариант.
В классификаторе слов тоже было два варианта алгоритмов — одни честно пытались ужать словарь, другие считали повторы слов. Ожидаемо победил второй вариант ))
Здесь пока все описывают один алгоритм. Хотелось бы конечно увидеть что-то особенное.
Тут бы очень не помешала еще статья на хабре с извинениями и объяснениями, рассылка с человеческим текстом (текущая похожа на робота или спам), ну и все-таки фильтрация, есть ли от конкретного человека апдейт или нет.
На 17 июля было 82 решения. Логично предположить, что они были забекаплены во время промежуточного теста. Затем была информация, что осталось прислать заново еще 77 решений. Таким образом мы можем предположить, что в первом туре не меньше 82 решений, а всего в конкурсе порядка 159 участников (+-50)*.
Просчитаем разумный максимум, например с 201 решением (число с потолка, для удобства подсчетов), тогда есть всего 40200 комбинаций участников и для 250 сидов надо провести 100500 * 10^2 игр. Если считать, что каждая игра идет до 10 ходов и каждый ход занимает секунду, мы получим время тестирования в ~100 миллионов секунд, т.е. около трех лет (1161.2 дней).
Теперь просчитаем по минимуму: 82 решения, время на партию около 0.1с (примем инициализацию и запись результата бесплатными). Время такого теста 166 050 секунд, это ~2 дня.
Попробуем просчитать средний вариант: 159 решений, время на партию 0.5с (включая не-бесплатную инициализацию и запись результата). Получается весь тест займет 3 140 250 секунд, это ~872 часа (около 36 дней).
Задача отлично распараллеливается по сидам, тогда последний вариант на 8 ядрах будет считаться 109 часов, т.е. четыре с половиной дня + некоторое время на синхронизацию и накладные расходы.
Было бы странно предположить, что организаторы будут ждать 36 дней, значит наверняка задача либо была распараллелена, либо временная оценка заметно меньше, либо меньше количество участников, либо все вместе. А нам остается только ждать и обмениваться шляпами, книгами и мячами :)
* мы не знаем, насколько числа 77 и 82 пересекаются между собой и не знаем, сколько человек не попало в оба списка, поэтому это все гадание на кофейной куще. Собственно, как и сама суть конкурса.
5b6194d9adb0280402fd774d
5b6194f3adb0280402fd774e
Вот жеж лидеры мыслили одинаково :D
5b61aac7adb0280402fd774f
и выше я писал
Очевидно — решения из одной головы
Очевидно — все они повлияли на тех, кто мог бы быть в 50.
Я могу продолжить дальше охоту на ведьм, но нужно ли это?
Я просто поиском по коду нашел уже 5 скриптов жуликов :)
Несколько человек спрашивали, можно ли двум или более участникам, работавшим в команде над одним и тем же решением, закачать разные его варианты. Я сказал, что каждый, кто работал над решением, может закачать его вариант, но не третьи лица (друзья, родственники).
Эти выглядят как самостоятельные, достаточно сильные решения
Это два идентичных решения которые различаются только в настройках коэффициентов. Автор мог заслать таким образом еще сотню вариантов пробуя разные настройки. Никогда не видел чтобы при выступлении команды ее участники отсылали индивидуальные решения, это немного противоречит смыслу командного выступления.
5b646019adb0280402fd779c
594,595d593
< const bestJokerOfferSoFar = this.joker.history.offers
< .reduce((acc, elm) => Math.max(acc, elm.batmanValue), 0);
600c598
< if (batmanValueToJokerOffer >= 5) {
---
> if (batmanValueToJokerOffer >= 1) {
605,611d602
< if (batmanValueToJokerOffer >= this.config.acceptableThresholdForLastPlay * this.total) {
< this.log(`accept offer. value ${batmanValueToJokerOffer} worth more than ${this.config.acceptableThresholdForLastPlay * 100}% of ${this.total}`);
< this.counterOfferRoot = "JTYOL_AC";
< return;
< }
< this.log(`reject offer. too lower offer ${batmanValueToJokerOffer} for last round תמות נפשי עם פלשתים`);
< this.counterOfferRoot = "JTYOL_RJ";
Но если так можно было… Значит все честно :) Снимаю шляпу (по три). И укатываю свой мяч.
Здесь же мы видим просто два похожих решения. Каждое из них попало бы в финал и без другого.
Я не имею ввиду «спойлеры», «помогаторы», «прочее».
Я вижу, что в списке топ-50 встречаются скрипты практически одинаковые. И недоумеваю. Почему автор самого сильного на данный момент решения не догадался прислать его 10 раз и утереть всем нос. Он же тоже может быть «команда».
Да и если по существу — такое условие, как разрешить плодить решения, которые согласны либо на 70%, либо 80% и тд от всей возможной суммы и только этим — не было оговорено в основном описании условия задачи.
Работает команда — приз на команду. Хорошо, что не было(а может и была, я не все проверил) команды из 40 человек.
17 — 5b64e7f2adb0280402fd77ea
26 — 5b64eb06adb0280402fd77f3
27 — 5b64e7baadb0280402fd77e8
35 — 5b64eaabadb0280402fd77f2
39 — 5b64e9c6adb0280402fd77ef
71 — 5b64e93badb0280402fd77ee
Глазками тяжело искать, устал. Вот бы инструмент, который ищет похожесть и показывает степень похожести.
31 — 5b646257adb0280402fd779e
66 — 5b645263adb0280402fd7790
36 — 5b64575dadb0280402fd7794
63 — 5b648f06adb0280402fd77af
46 — 5b649223adb0280402fd77b3
51 — 5b649339adb0280402fd77b5
58 — 5b64b128adb0280402fd77c8
62 — 5b5f368eadb0280402fd7705
И как сразу все говорили, будет решать рандом, если даже одинаковые/похожие решения раскидало на 10-30 позиций.
можно отправлять столько решений сколько людей
Скорее сколько почтовых аккаунтов. Я последние две недели парился с подбором коэффициентов и незначительными правками кода. Оказалось, зря, надо было всего-лишь на создавать аккаунтов и отправить все свои решения, которые вызывали сомнения.
Скорее сколько почтовых аккаунтов.
По правилам именно «физических людей», а не почтовых аккаунтов.
- Один участник может использовать для отправки решения только один адрес электронной почты. Отправка множества решений, находящихся в «сговоре», с разных адресов запрещена; все решения, участвующие в такой схеме, будут дисквалифицированы.
- Нам нужно знать Ваше полное имя, но если Вы хотите, мы опубликуем вместо него псевдоним. Мы сохраним Ваш адрес электронной почты в тайне.
21 5b64e9e0adb0280402fd77f0 1202516
21 5b64cb2dadb0280402fd77d8 1202516
Код при этом существенно отличается, но мы знаем, что чудес не бывает
=)
п.с. Навскидку, судя по использованию предвычисленных комбинаций и обфускации первые два места будто занял один и тот же человек. Сами алгоритмы не изучал.
Конкурс по программированию: Торговля (промежуточные результаты и объявления)