Так вроде сразу говорили или богатый спонсор или киллер.
E>Понятно, что у всего, что стало популярным был какой-то путь к популярности. Но механически его воспроизводить таки глупо. Хороший язык постепенно приглянется кому-то настолько, что на нём появятся хорошие программы...
Угу, например с питоном и руби так и было. Но это долгая история, лет 10 — 15.
Здравствуйте, nikov, Вы писали:
N>Windows подойдет?
Они вроде как на С...
E>>FORTRAN, например... N>Библиотеки BLAS, LAPACK, SPARSKIT. N>К ним до сих пор делают байндинги из современных языков.
Только вот библиотеки эти появились ПОСЛЕ того, как FORTRAN стал популярен...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, FR, Вы писали:
FR>Угу, например с питоном и руби так и было. Но это долгая история, лет 10 — 15.
Ну и что? Это чему-то мешает?
Наоборот есть много шансов, что за 10 лет найдётся много хороших решений по улучшению и допиливанию языка.
Только я больше верю в такой сценарий, как у UNIX -- найдётся задача, для которой язык подходит, на ней язык допилят, а там, глядишь, и другим подойдёт...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, AndrewVK, Вы писали:
AVK>У фортрана еще и автор соответствующий, конторка под названием IBM.
Эта конторка родила кучу мёртворождённого ПО. От языка управления заданиями из OS 360 и до гнутой полуоси
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, AndrewVK, Вы писали:
AVK>Это никак не отменяет того факта, что за фортраном стояло серьезное бабло.
Но и не доказывает его необходимости...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
AVK>>Это никак не отменяет того факта, что за фортраном стояло серьезное бабло. E>Но и не доказывает его необходимости...
Кому как.
... << RSDN@Home 1.2.0 alpha 4 rev. 1245 on Windows 7 6.1.7100.0>>
Здравствуйте, Mystic, Вы писали: M>Зависит от задачи. Если код на 60% зависит от представления, то выбор представления очень важен.
Если код на 60% зависит от представления, то это очень плохой код. У тебя — именно такой. Современные компиляторы очень хорошо устраняют абстракции, поэтому оптимизация — не оправдание. M>Есть и второй ньюанс: с этим представлением может быть связано очень много самых разных функций, то код получается неструктурированным. Ну например, в шахматах у нас есть класс "позиция", в нем тысяча методов, а все остальное всего ничего.
Про шахматы ничего не знаю. Про структурирование кода — вот у тебя получился совершенно неструктурированный код. Непонятно что, непонятно где.
S>>Для покера нам достаточно функции Compare, которая отображает два hand на (-1, 0, 1).
M>А достаточно ли? Самый простой пример вывести название комбинации, перейти в переборе рук к следующей. Не говоря уже о подсчете аутов и всяких других символических рассуждениях. Ты какую задачу решаешь, что так просто утверждаешь "достаточно"?
Это я пытаюсь угадать, какую задачу решаешь ты. По коду этого сказать невозможно. Ты вот уже после моего поста написал два сообщения, и до сих пор непонятно, что твоя библиотека должна делать.
M>Собственно задача и состоит в написании оптимальной версии. Проще говоря, я пишу библиотеку, где код должен работать оптимально. Где будет использована библиотека? Например, в покерном движке. Или в калькуляторе.
Сначала нужно написать работающую, понятную версию. А уже потом, после профилирования, её оптимизировать. Ты начинаешь с непонятной версии; причём код у тебя устроен максимально неудачно — если профилирование покажет необходимость изменить представление, тебе придётся вручную переписать 80%. При нормальной реализации ты бы изменил 5% кода.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: Статья "Введение в Nemerle" - по критикуйте
Здравствуйте, Erop, Вы писали:
E>Статья супер, но я никак не доберусь до свободного времени, чтобы почитать с компьютером, а не просто с книжки.
Спасибо. :shuffle: А тот некоторые уже заклевать успели :).
E>Если кратко, то мне кажется, что надо сделать несколько модификаций.
E>1) сделать какие-то отступления для тех, кто хочет подробностей. Что-то типа сносок. Чтобы те, кому понятнее с ассоциативностями или там с оператором хитрым каким, посмотрели и обрадовались. Чем хорошо показывать потроха, так тем, что сразу можно экспериментировать ;)
Я и так старался делать сноски. Про ассоциативность надо конечно добавить. Про остальное... Тут нужны конкретные места. А то мой глаз замылен.
Что же касается нескольких версий, то я боюсь, что запутаюсь сам и запутаю других.
E>2) Мне кажется, что надо как-то собрать в кучку рекламу языка, и отделить её от собственно изложения. Можно по ходу дела писать ссылки назад. Типа "это одна из тех особенностей, которые обеспечивают ту мощность языка, о которой мы говорили выше"... Мне кажется, что люди, которым нужно узнать и люди, которым нужно захотеть узнать -- это разные люди. И первым надо дать возможность перейти сразу к делу, а вторых надо "обрабатывать" не переходя к "лишним" подробностям в самом начале. Может стоит привести пару примеров какого-нибудь крайне удачного кода, привести для сравнения код на шарпе, и пообещать, что к концу цикла читатель сможет переписать одно в другое сам. Или ещё какой рекламный трюк придумать (если реклама языка вообще входит в цели цикла)
Вся рекламщина в этой статье вынесена во врезку ("16 причин...", ну, по крайней мере мне так кажется). Примеры есть в других статьях. Самый очевидный, наверно, это пример замены ОО-подхода основанного на паттерне проектирования Посетитель на сопоставление с образцом. Его можно найти здесь
. Возможно имеет смысл дать ссылку на эту и другие статьи и явно описать, что "если вы знакомы с C# или ООП, то возможно для принятия решения об изучении этого языка вам стоит прочесть эти статьи". Я уже слышу не первую подобную просьбу, но тащить такие объемы из других статей как-то не хочется.
E>3) IMHO, не надо по тексту апеллировать к K&R. Те, кто ценят эту книгу, всё равно узнают, а тем, кто не в курсе, не интересно. Можно отсылки к K&R вынести в эпиграфы какие-нибудь, во введение и т. д...
Дык, а разве я много апеллирую? Только во введении упомянул, чтобы не сочли за плагиат.
E>Лучше высказать вначале какие-то принципы, ну типа того, что ты хочешь рассказать о том, как работает язык, на примере его собственной стандартной библиотеки и нескольких относительно простых задач.
Я это сделал, но те читатели-"вычитыватели" что читали статью первыми сказали, что это плохо и я убрал эти пояснения. Тут на всех не угодишь. Одному много, другому мало.
E>Так что те, кто умеют программировать на чём-то другом, должны воспринимать этот цикл, как обзор того, что надо забыть, а что надо пересмотреть из знания, например, PASCAL, чтобы проникнуться N.
Разве людей можно заставить что-то забыть? :)
Иногда и следовало бы, но ведь знания становятся второй натурой человека. :(
E>Я как доберусь так, чтобы с транслятором посидеть, отпишусь ещё.
Вот это было бы очень полезно! Язык без практики не освоить. Особенно интересно задачки. Насколько их легко решить? Насколько они ясны? Насколько они наталкивают на исследование тех или иных вопросов? Не создают ли они тупиковых ситиуаций?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[8]: Статья "Введение в Nemerle" - по критикуйте
Отлично. Еще один фрагмент кода, где детали выпячены вперёд, а смысл спрятан как можно глубже.
M>Для корректной работы этого кода мне нужны массивы magic_flush, magic_normal и hand_ranks, которые и должен создать скрипт на C#/Nemerle. Собственно говоря, для построения этого скрипта и надо (1) построить тот словарь (2) обработать его.
А зачем здесь вообще массивы? Я в принципе не понимаю, что должен делать этот код.
M>Ок, как бы ты предложить более просто сформировать массивы magic_flush, magic_normal и ranks?
Я бы предложил для начала вообще обойтись без массивов. Для начала нужно понять, что за задача решается. Вот у тебя есть функция evaluate_5. Что она возвращает? Почему у неё UB для случая, если переданы не 5 карт?
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[9]: Статья "Введение в Nemerle" - по критикуйте
Здравствуйте, Sinclair, Вы писали:
S>Отлично. Еще один фрагмент кода, где детали выпячены вперёд, а смысл спрятан как можно глубже.
Это и есть детали реализации. Причем эти детали надо реализовать максимально производительно. Весь высокий уровень расположен выше.
M>>Для корректной работы этого кода мне нужны массивы magic_flush, magic_normal и hand_ranks, которые и должен создать скрипт на C#/Nemerle. Собственно говоря, для построения этого скрипта и надо (1) построить тот словарь (2) обработать его. S>А зачем здесь вообще массивы? Я в принципе не понимаю, что должен делать этот код.
Код оценивает пятикарточную руку в покере. Массивы нужны для производительности. Основной смысл в том, что если каждому номиналу карты сопоставить простое число, то их произведение не зависит от порядка карт и однозначно определяет комбинацию в руке без учета мастей. Знание этого произведения, а также того факта, в руке флеш или нет, позволяет нам моментально по таблицам получить силу руки.
S>Я бы предложил для начала вообще обойтись без массивов. Для начала нужно понять, что за задача решается. Вот у тебя есть функция evaluate_5. Что она возвращает? Почему у неё UB для случая, если переданы не 5 карт?
Хорошо, одно из возможных применений покер-калькулятор. Ты задаешь спектр своих рук, спектр рук оппонента, стол. Задача состоит в том, чтобы перебрать все варианты и выдать процент на победу каждого игрока.
На счет UB это отдельный холивар. Куча C-шных библиотек имеют UB в случае неверных параметров, но больших палок в колеса это не ставит.
Re[10]: Статья "Введение в Nemerle" - по критикуйте
Здравствуйте, Mystic, Вы писали: M>Это и есть детали реализации. Причем эти детали надо реализовать максимально производительно. Весь высокий уровень расположен выше.
Эти детали — не нужны.
M>Код оценивает пятикарточную руку в покере. Массивы нужны для производительности.
Это неочевидно. Я имею в виду — производительность. M>Основной смысл в том, что если каждому номиналу карты сопоставить простое число, то их произведение не зависит от порядка карт и однозначно определяет комбинацию в руке без учета мастей.
Это понятно. Непонятно, почему было выбрано именно произведение чисел, и зачем было затачивать весь код именно на него?
Вот простой пример: можно всю руку всунуть в 32 бита, назначив битовые поля номиналам и мастям. При этом можно нормализовывать их так, чтобы устранять зависимость от порядка.
Все нужные тебе операции — в том числе проверка на флеш — делаются примитивными битовыми маскированиями.
Это может оказаться быстрее, чем умножения и деления. Если бы твой код был написан нормально, в соответствии со здравым смыслом и архитектурой, то при смене представления руки не пришлось бы переписывать всё. M>Знание этого произведения, а также того факта, в руке флеш или нет, позволяет нам моментально по таблицам получить силу руки.
Ну, в принципе, это более-менее нормальный подход. С современными объемами памяти можно просто тупо построить массив всех возможных комбинаций.
M>Хорошо, одно из возможных применений покер-калькулятор. Ты задаешь спектр своих рук, спектр рук оппонента, стол.
Плохо. Задачи описывать ты по-прежнему не умеешь. M>Задача состоит в том, чтобы перебрать все варианты и выдать процент на победу каждого игрока.
Варианты чего нужно перебирать? M>На счет UB это отдельный холивар. Куча C-шных библиотек имеют UB в случае неверных параметров, но больших палок в колеса это не ставит.
А, ну-ну.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[11]: Статья "Введение в Nemerle" - по критикуйте
Здравствуйте, Sinclair, Вы писали:
M>>Это и есть детали реализации. Причем эти детали надо реализовать максимально производительно. Весь высокий уровень расположен выше. S>Эти детали — не нужны.
На самом деле я могу выступать как сторонний разработчик. Т. е. сама задача для меня состоит в построении производительной реализации функции оценки руки. Для чего она нужна заказчику секрет.
M>>Основной смысл в том, что если каждому номиналу карты сопоставить простое число, то их произведение не зависит от порядка карт и однозначно определяет комбинацию в руке без учета мастей. S>Это понятно. Непонятно, почему было выбрано именно произведение чисел, и зачем было затачивать весь код именно на него? S>Вот простой пример: можно всю руку всунуть в 32 бита, назначив битовые поля номиналам и мастям. При этом можно нормализовывать их так, чтобы устранять зависимость от порядка.
Кроме пятикарточного покера есть еще другие варианты, такие как техас, омаха, 7-карточный стад. Так что кроме функции evaluate_5 могут быть еще функции evaluate_7, evaluate_omaxa и т. п. Во-вторых, тут играет свою роль также то, как этот код будет использоваться. Например, самая топорная реализация evaluate_7 это перебор 21-го варианта.
S>Все нужные тебе операции — в том числе проверка на флеш — делаются примитивными битовыми маскированиями.
Проверка на флеш у меня и сейчас битовые операции: четыре OR-а, пять AND-ов, декремент и никаких условий.
S>Это может оказаться быстрее, чем умножения и деления. Если бы твой код был написан нормально, в соответствии со здравым смыслом и архитектурой, то при смене представления руки не пришлось бы переписывать всё.
Ну считай это лабораторными работами, research. Я пробую разные варианты представления руки и смотрю на получаемую производительность. Моя задача выбрать наилучший вариант.
M>>Хорошо, одно из возможных применений покер-калькулятор. Ты задаешь спектр своих рук, спектр рук оппонента, стол. S>Плохо. Задачи описывать ты по-прежнему не умеешь.
Мне кажется, что слова "покер-калькулятор" говорят сами за себя. Проще говоря необходимо вычислить таблицу шансов (odds). Например, игра в Texas Hold'em, префлоп. У игрока #1 AKs, у игрока #2 QQ. Задача в том, чтобы перебрать все варианты из пяти закрытых карт и определить шансы каждого игрока на победу. Другими словами это те проценты, что высвечиваются в телетрансляции. Пример такого калькулятора тут. Вот как это выглядит:
Re[12]: Статья "Введение в Nemerle" - по критикуйте
Здравствуйте, Mystic, Вы писали:
M>На самом деле я могу выступать как сторонний разработчик. Т. е. сама задача для меня состоит в построении производительной реализации функции оценки руки. Для чего она нужна заказчику секрет.
Тем не менее, детали всё равно не нужны.
M>Кроме пятикарточного покера есть еще другие варианты, такие как техас, омаха, 7-карточный стад. Так что кроме функции evaluate_5 могут быть еще функции evaluate_7, evaluate_omaxa и т. п. Во-вторых, тут играет свою роль также то, как этот код будет использоваться. Например, самая топорная реализация evaluate_7 это перебор 21-го варианта.
И? Это что, как-то оправдывает грязь в коде? Использование должно быть как-то отделено от реализации.
S>>Все нужные тебе операции — в том числе проверка на флеш — делаются примитивными битовыми маскированиями. M>Проверка на флеш у меня и сейчас битовые операции: четыре OR-а, пять AND-ов, декремент и никаких условий.
Зато определение категории делается умножениями и делениями. Кстати, в том варианте, который пришёл бы в голову мне, проверка на флеш делалась бы одним AND и одним сравнением.
M>Ну считай это лабораторными работами, research. Я пробую разные варианты представления руки и смотрю на получаемую производительность. Моя задача выбрать наилучший вариант.
Гм. Тем более у тебя представление руки должно быть отделено от всего остального. Не нужно пропихивать его во все места в явном виде. Табличный подход, вообще говоря, ортогонален способу хранения самой руки. Тут весь выбор — между тем, какую долю информации о руке можно выкинуть, и всё еще быть способным оценить её силу. В классическом покере настолько мало комбинаций, что можно тупо все их поместить в таблицу — этот подход будет хорошо работать для серверов с большой нагрузкой. Благодаря тому, что памяти у них достаточно, и она строго иммутабельна. Если узкое место — это память, то можно провести формальный разбор для категоризации — сгруппировать карты по номиналу и отсортировать группы по размеру. Получится всего пять вариантов паттернов:
41 — Quads
32 — Full House
311 — Trips
221 — Two Pair
2111 — Pair
11111 — Garbage либо Straight
M>Мне кажется, что слова "покер-калькулятор" говорят сами за себя.
Мне кажется, что за себя говорит твой код. С таким подходом к написанию далеко не уедешь.
M>Проще говоря необходимо вычислить таблицу шансов (odds). Например, игра в Texas Hold'em, префлоп. У игрока #1 AKs, у игрока #2 QQ. Задача в том, чтобы перебрать все варианты из пяти закрытых карт и определить шансы каждого игрока на победу. Другими словами это те проценты, что высвечиваются в телетрансляции. Пример такого калькулятора тут. Вот как это выглядит: M>
Ну и как будет устроен код?
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[13]: Статья "Введение в Nemerle" - по критикуйте
Здравствуйте, Sinclair, Вы писали:
S>Зато определение категории делается умножениями и делениями. Кстати, в том варианте, который пришёл бы в голову мне, проверка на флеш делалась бы одним AND и одним сравнением.
Неправда, четырьмя AND-ами и четырьмя сравнениями. Ибо в колоде четыре масти.
M>>Ну считай это лабораторными работами, research. Я пробую разные варианты представления руки и смотрю на получаемую производительность. Моя задача выбрать наилучший вариант. S>Гм. Тем более у тебя представление руки должно быть отделено от всего остального. Не нужно пропихивать его во все места в явном виде. Табличный подход, вообще говоря, ортогонален способу хранения самой руки. Тут весь выбор — между тем, какую долю информации о руке можно выкинуть, и всё еще быть способным оценить её силу. В классическом покере настолько мало комбинаций, что можно тупо все их поместить в таблицу — этот подход будет хорошо работать для серверов с большой нагрузкой. Благодаря тому, что памяти у них достаточно, и она строго иммутабельна. Если узкое место — это память, то можно провести формальный разбор для категоризации — сгруппировать карты по номиналу и отсортировать группы по размеру. Получится всего пять вариантов паттернов: S>41 — Quads S>32 — Full House S>311 — Trips S>221 — Two Pair S>2111 — Pair S>11111 — Garbage либо Straight
Не совсем так. Вообще в покере чуть больше чем 7000 различных вариантов рук. Точное число выводит мой C#-повский исходник. Но вообще, существует C(52,5) вариантов руки из пяти карт (это 2.6M). Если же порядок следования карт существенен, то 310M. Вообще, карты попадают нам в функцию в неотсортированном порядке, на нормализацию закладываться нехорошо. Делать ее на лету? По сути трюк с простыми числами и есть такой вариант нормализации.
Например, вероятности считаются по методу монте-карло примерно так:
player1.Hand.Clear();
player1.Hand.Add(CARD_Ac); // Трефовый туз
player1.Hand.Add(CARD_Kd); // Бубновый король
player2.Hand.Add(CARD_Qd); // Бубновая дама
player2.Hand.Add(CARD_Qs); // Пиковая дамаint total = 0;
for(;;)
{
if (UserTerminate()) break;
Player1.Hand.Truncate(2); //Оставить только первые две карты
Player2.Hand.Truncate(2);
CardSet avail = CardSet.AllCards - Player1.Hand - Player2.Hand;
Card c1 = avail.ExtractRandomCard();
Card c2 = avail.ExtractRandomCard();
Card c3 = avail.ExtractRandomCard();
player1.Hand.Add(new Cards[] {c1, c2, c3});
player2.Hand.Add(new Cards[] {c1, c2, c3});
int firstHandRank = player1.Hand.Estimate(); // Внутри вызов estimate_5 или другого estimate_XXX в зависимости от вида игрыint secondHandRank = player2.Hand.Estimate();
if (firstHandRank > secondHandRank) player1.IncVictoryCount();
if (firstHandRank < secondHandRank) player2.IncVictoryCount();
++total;
}
Console.WriteLine("Player 1: {0:f}", 100.0 * player1.VictoryCount / total);
Console.WriteLine("Player 2: {0:f}", 100.0 * player2.VictoryCount / total);
Опять же это прикидка одного из вариантов использования.
Re[14]: Статья "Введение в Nemerle" - по критикуйте
Здравствуйте, Mystic, Вы писали:
M>Неправда, четырьмя AND-ами и четырьмя сравнениями. Ибо в колоде четыре масти.
Да, немножко ошибся. Одним AND и четырьмя сравнениями. Это если не привлекать MMX.
Но это всё неважно. Важно то, что тебе нужна алгебра рук. Как эта алгебра будет устроена внутри — и есть предмет твоих экспериментов.
Но для начала нужно отделить потребителей алгебры от её реализации. У тебя проведена очень крупногранулярная граница. Нет отдельного метода, который отвечает за конверсию руки во внешнем представлении в её тег.
M>Не совсем так. Вообще в покере чуть больше чем 7000 различных вариантов рук.
Как-то мало. M>Точное число выводит мой C#-повский исходник. Но вообще, существует C(52,5) вариантов руки из пяти карт (это 2.6M).
Вот именно. Всего 2.6м. Если присвоить каждому варианту 32хбитный "тег силы", то вся таблица займёт 10.4 Mb — семечки.
Сравнение рук будет делаться за два lookup. Понятно, что для семикартных вариантов это уже не пройдёт. Именно поэтому важно отделить алгоритмы от представления.
Вот твой "Rank" — он чему соответствует?
M>Опять же это прикидка одного из вариантов использования.
В этом варианте совершенно непонятно, где учитывается старшинство карт для случая двух full house, к примеру. Как-то он выглядит подозрительно.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[15]: Статья "Введение в Nemerle" - по критикуйте
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Mystic, Вы писали:
S>Вот твой "Rank" — он чему соответствует?
Ты назвал его "тегом силы". Некоторое число, которое показывает силу руки. Две одинаковые по силе руки имеют одинаковый ранг. Если одна рука сильнее, то ее ранг соответственно больше.
S>Но это всё неважно. Важно то, что тебе нужна алгебра рук. Как эта алгебра будет устроена внутри — и есть предмет твоих экспериментов. S>Но для начала нужно отделить потребителей алгебры от её реализации. У тебя проведена очень крупногранулярная граница. Нет отдельного метода, который отвечает за конверсию руки во внешнем представлении в её тег.
M>>Не совсем так. Вообще в покере чуть больше чем 7000 различных вариантов рук. S>Как-то мало.
Скажем так, чуть более 7000 вариантов различной силы рук. Т. е. рука Ah Kh Qh Jh Th (флеш-рояль в червах) получает ранг 1, рука As Ks Qs Js Ts тоже получает ранг 1 (флеш-рояль в пике), а вот рука Kh Qh Jh Th 9h уже получит ранг 2 и т. п.
M>>Точное число выводит мой C#-повский исходник. Но вообще, существует C(52,5) вариантов руки из пяти карт (это 2.6M). S>Вот именно. Всего 2.6м. Если присвоить каждому варианту 32хбитный "тег силы", то вся таблица займёт 10.4 Mb — семечки. S>Сравнение рук будет делаться за два lookup. Понятно, что для семикартных вариантов это уже не пройдёт. Именно поэтому важно отделить алгоритмы от представления.
Да, 10.4 Mb (5.2 Mb) семечки. Но это размер таблицы для того случая, когда рука на входе уже нормализована. Вопрос еще в том, как руке на входе сопоставить число от 0 до 2.6M. Конечно, если я отсортирую руку и переведу ее из биномиальной системы счисления в обычную, то я получу искомый индекс. Но это так же требует операций и ветвления. А если же поступать совсем тупо, то 52 варианта это 6 бит, 5*6 = 30, 2^30 = 1 Gb элементов, если брать по два байта на каждый, получим 2Gb. Достаточно многовато для машины юзверя, например.
Итак, берем вариант сортировка + перевод из биноминальной системы счисления. С переводом из биноминальной системы проще: пять сложений + пять обращений к таблице. А вот сортировка это, имхо, несколько неудачно. Во-первых, это сравнения и перемещения. Во-вторых, она меняет порядок следования карт. Так что или дополнительное копирование, или неприятности для пользователя библиотеки (в моем примере, вызовы Truncate уже не пройдут, надо руку инициализировать заново).
И всему этому противостоит изначальный вариант. Который содержит 1 IF (ветвление), 6 AND, 4 OR, 1 DEC, 4 MUL, 1 DIV и пять обращений к таблице. Правда тот вариант, что я привел, использует сжатый формат таблицы, поэтому надо добавить еще 1 ADD, 1 INC, 1 DIV и еще одно обращение к таблице. К тому же передаваемая рука не меняется.
M>>Опять же это прикидка одного из вариантов использования. S>В этом варианте совершенно непонятно, где учитывается старшинство карт для случая двух full house, к примеру. Как-то он выглядит подозрительно.
Все в таблице. Смотри, есть full house KKKTT и QQQJJ. K это 12, Q это 11, J это 10, T это 9. Primary[12] = 37, Primary[11] = 31, Primary[10] = 29, Primary[9] = 23. Получаем для руки KKKTT значение Product = 37*37*37*23*23 = 26795437 (при этом это значение не зависит от порядка карт). Для руки QQQJJ получаем Product = 31*31*31*29*29 = 25054231. Собственно говоря, эти числа (26795437 и 25054231) однозначно характеризуют силу руки. Нельзя придумать другую руку, которая бы дала означенное произведение в силу единства разложения на простые сомножители. Единственное исключение из этого правила это флеш, поэтому надо надо иметь две таблицы, одна для случая флеша, другая для случая остальных рук. Теперь осталось только по Dictionary, который строил мой самый первый пример на C# вытащить "тег силы", или в моих наименованиях hand rank.
Максимальное возможное значение произведения это AAAAK это 104553157 (104.5M). Умножаем на два, получаем 209M. Еще на два (флеш и не флеш) и уже 418M. Может для сервера это приемлемо, но для обычным пользователей это может быть многовато. Можно ли эту таблицу сжать? Да, можно. В нашем словаре точно не будет более чем 7300 различных произведений. Поэтому можно подобрать такое число, чтобы остаток от деления на это число для всех интересующих нас произведений был различный. Думаю, что это будет простое число из интервала до 10 000 — 50 000.
В моем исходнике я делал хэширование в два этапа при помощи двух таблиц. Вначале я делаю MOD с некоторым простым числом (MAGIC_SIZE, я выбирал это число в районе 2000-3000). Соответственно у меня получалось, что некоторые произведения имели одинаковые остатки. Вторым шагом я просто для каждого такого конфликта подбирал еще одно число, чтобы остатки от деления для всех конфликтных значений были различны. Таким образом, в моем исходнике таблицы magic_flush и magic_normal просто содержат индекс в таблице hand_ranks. Элемент hand_ranks[magic_index] содержит подобранное число, на которое надо поделить произведение. hand_ranks[magic_index+1], hand_ranks[magic_index+2], ..., hand_ranks[magic_index+hand_ranks[magic_index]] содержат ранги рук (теги силы). Отсюда и получаются дополнительные операции.
В целом я считаю, что этот метод вполне имеет себе право на жизнь (скромный размер таблиц, разумное число операций). По крайней мере с ним можно поэкспериментировать. А раз так, почему бы не реализовать его и не проверить в жизни? А для этого первым этапом и нужен тот Dictionary, который я строил. Ну и нужен вспомогательный исходник, который бы эти таблицы мне создал.