Имя пользователя:
Пароль:  
Помощь | Регистрация | Забыли пароль?  | Правила  

Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » Алгоритм подсчета покерной руки

Ответить
Настройки темы
Алгоритм подсчета покерной руки

(*.*)


Сообщения: 36491
Благодарности: 6675


Конфигурация

Профиль | Сайт | Отправить PM | Цитировать


Изменения
Автор: Vadikan
Дата: 19-04-2005
Вложения
Тип файла: txt project.txt
(8.0 Kb, 23 просмотров)
Тип файла: txt five_integers.txt
(1.2 Kb, 42 просмотров)
Тип файла: txt calc_hand.txt
(2.6 Kb, 34 просмотров)
Доброго времени суток!

Вот добрался я и до этого форума Сразу скажу, что программист я никакой, и весь мой опыт программирования сводится к нескольким заданиям в рамках курса VB.NET в универе. Курс предназначен для людей, не имеющих опыта программирования, и знакомит с элементарными понятиями. Поскольку курс преподается на англ. языке, я знаю только английскую терминологию. Предположу, что array - массив, a data structure - структура данных.

Финальный проект курса формулируется так. Надо сгенерировать колоду карт на 52 листа. Сначала нужно создать структуру данных, у которой два члена: face (номинал карты) и suit (масть). Затем нужно сформировать массив, который и будет наполнен 52 картами. Затем нужно сгенерировать 5 случайных уникальных номеров от 0 до 51 (или от 1 до 52) и на основе этих номеров сформировать покерную руку. Ну и самое главное - определить покерную комбиниацию, которая получится в рез-те. Покерные комбинации такие

Flush (все одной масти)
Четверка (четыре карды одного номинала)
Full house (3+2)
Тройка
Две пары
Пара
Ничего

Как видите, вариант упрощенный - straight (стрит) подсчитывать не нужно (курс-то для начинающих ;-) Ну и вывести надо 5 карт и название комбинации. Никаких картинок карточной колоды, все в текстовом виде.

Затрудненения у меня вызвали пять уникальных случайных кард и алгоритм подсчета покерной руки. С пятью уникальными картами я вроде разобрался относительно легко.

Прикрепленный файл

Если я что-то упустил, то буду признателен, если вы укажете на ошибки.

С подсчетом покерных комбинаций было сложнее. В конечном итоге, я его определил, но хотелось бы услышать и ваше мнение. Возможно, я что-то где-то упустил, или можно все сильно упростить.

Основная идея: в руке не может быть более двух различных совпадающих номиналов карт. Т.е. если есть два туза и два короля, то пятой карте пары уже точно не будет. Значит надо подсчитать сколько раз совпали два различных номинала.

Прикрепленный файл

Ну а дальше уже детали. По порядку проверяем следующие условия:
  1. Если все карты одной масти, то flush (масти берутся из массива на основе 5 уникальных чисел, сгенерированных ранее)
  2. Если первый счетчик равен 4, то у нас четверка.
  3. Если счетчики 3+2 или 2+3, то у нас full house.
  4. Если первый счетчик равен 3, то тройка (причем, второй счетчик может быть равен 3 только в случае 2+3).
  5. Если счетчики 2+2, то две пары.
  6. Если первый счетчик равен 2, то пара (причем второй счетчик может быть равен 2 только в случае 3+2 или 2+2)
  7. Ну а во всех остальных случаях нету даже пары.

Вот так я себе это представил, и вроде даже работает. Буду признателен, если вы проверите алгоритм на наличие ошибок или предложите более оптимальный вариант. Может где-то есть лишние шаги, которые можно убрать, упростив код.

Спасибо за внимание.

P.S. Полный код проекта прикреплен.

-------
Канал Windows 11, etc | Чат @winsiders


Отправлено: 11:05, 18-04-2005

 

Аватара для hasherfrog

Старый параноик


Сообщения: 2423
Благодарности: 85

Профиль | Отправить PM | Цитировать


Немного путанно или я старый уже, мозги усохли :] Можно уточнить условия?

>> Затем нужно сгенерировать 5 случайных уникальных номеров от 0 до 51 (или от 1 до 52) и на основе этих номеров сформировать покерную руку

Что такое "сформировать покерную руку"? Нужно просто рандомом (следя за неповторяющимися номерами) выбрать 5 чисел от 1 до 52? И всё? Так? Т.е. "сдать пять карт"?

>> Ну и самое главное - определить покерную комбиниацию, которая получится в рез-те.

Опять непонятно. Честно, я не очень понимаю. Нужно просто сказать, какая комбинация карт получилась из сданных пяти? Так? Т.е. никаких подсчётов вероятностей, никаких"взять ещё три" и "сколько сдать карт, чтобы получить флэш" и т.д.?

Отправлено: 11:40, 18-04-2005 | #2



Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети.

Если же вы забыли свой пароль на форуме, то воспользуйтесь данной ссылкой для восстановления пароля.


Аватара для hasherfrog

Старый параноик


Сообщения: 2423
Благодарности: 85

Профиль | Отправить PM | Цитировать


Тасование колоды:
Цитата:
Алгоритм #4.
Код: Выделить весь код
    1. ячейки вектора инициализируются значениями своих индексов
    2. R{ight} ← N {"текущая" длина вектора}
    3. генерируется случайное число K из интервала 1..R
    4. обмен содержимым между K-й и R-й ячейками
    5. R ← R-1
    6. if R = 1 then Exit
    7. переход к шагу 3
Приведенный механизм известен под именем алгоритма "тасования колоды". Его легко переписать, используя уже знакомые нам процедуры, приходится лишь заменить интервал 0..N-1 на 1..N.
Код: Выделить весь код
type
  index = 1..N; {N>1}
  massive1 = array [index] of index;

procedure RandomN(var Mas: massive1);
var i, K: index;
begin
  for i := 1 to N do Mas[i] := i;
  Randomize;
  for i := N downto 2 do begin
    K := Random(i) + 1;
    Swap(Mas[K], Mas[i]);
  end;
end;
Соответственно, получение 5 карт можно дать так:
1. Инициализируем массив, от 1 до 52, Перемешиваем массив - RandomN()
2. Берём его первые 5 элементов.

Отправлено: 12:03, 18-04-2005 | #3


Аватара для hasherfrog

Старый параноик


Сообщения: 2423
Благодарности: 85

Профиль | Отправить PM | Цитировать


Масть - номер карты (0-51) mod 4 (остаток от деления) 0 - пики... 3 - бубны
Номинал - номер карты (0-51) / 4 (целочисленное деление) 0 - двойка ... 12 - туз

Отправлено: 12:10, 18-04-2005 | #4


Аватара для hasherfrog

Старый параноик


Сообщения: 2423
Благодарности: 85

Профиль | Отправить PM | Цитировать


Проверку на флеш делаем очень быструю, без массивов.
Флеш - это когда K[0]%4 == k[1]%4 == k[2]%4 == k[3]%4 == k[4]%4
% - остаток от деления
== - равно
Сорри за мой С :-Р

Поверки по номиналам даём с использованием промежуточного массива.
1. Делаем пустой масив номиналов S размером от 0(двойка) до 12 (туз), итого 13 элементов.
2. Инициализируем его нулями - это счётчики встреч
3. Для каждой карты K из массива k[0..4](пять карт) увеличиваем счётчик номинала.

для i от 0 до 4
счётчик[K[i]/4] ++
/ - целочисленое деление
++ - увеличение на 1.

Далее сортируем массив S (счётчиков номинала по возрастанию) и проверяем результат:
1. если первый элемент стал 4 - "каре".
2. если первый элемент стал 3:
2а. если второй элемент равен 2 - "полный дом".
2б. если второй элемент равен 0 или 1 - "тройка"
3. если первый елемент равен 2:
3а. если второй элемент равен 2 - "две пары".
3б. если второй элемент равен 0 или 1 - "пара"

Комбинации "туз" и "стрит-флеш" тоже легко вычисляются.

Осталось только расписать "сортируем массив счётчиков" - это простая пузырьковая сортировка, например. Или чего-нибудь продвинутое :]

Отправлено: 12:29, 18-04-2005 | #5


Аватара для hasherfrog

Старый параноик


Сообщения: 2423
Благодарности: 85

Профиль | Отправить PM | Цитировать


Сортировка (два-три метода)
http://www.relib.com/articles/article.asp?id=197

Отправлено: 12:37, 18-04-2005 | #6


(*.*)


Сообщения: 36491
Благодарности: 6675

Профиль | Сайт | Отправить PM | Цитировать


hasherfrog
LOL
Цитата:
Т.е. "сдать пять карт"?
Да, пять неповторяющихся карт.
Цитата:
Нужно просто сказать, какая комбинация карт получилась из сданных пяти?
Ок, можно и так сказать. Не вижу принципиальной разницы между этим и тем, что я сказал Наверное, твой вариант проще Спасибо за ответы.

Насчет тасования колоды я понял идею, но не слишком понял реализацию. Что делает следующий код?
Код: Выделить весь код
for i := N downto 2 do begin
    K := Random(i) + 1;
    Swap(Mas[K], Mas[i]);
Конкретнее, downto2 do begin вообще непонятно, сорри.

А для подсчета совпадений номиналов твой вариант действительно проще. Общая идея, как я вижу, такая же: отталкиваемся от факта, что у нас не более двух различных совпадающих номиналов карт. Однако исполнение намного проще. Мне как-то в голову не пришло использовать целочисленое деление
Я сделал так. Допустим, у меня уже есть массив Hand(4), 5 элементов которого являются случайными числами от 0 до 51. Теперь создается массив HandFaces(12) для номиналов
Код: Выделить весь код
  Dim HandFaces(12) As Integer
        For i = 0 To 12
            HandFaces(i) = 0
        Next
и все элементы наполняются нулями. Затем для каждого элемента из массива Hand выполняется целочисленное деление, получившееся число становится индексом массива HandFaces и значение данного элемента увеличивается на единицу.
Код: Выделить весь код
        For i = 0 To 4
            HandFaces(Hand(i) \ 4) += 1
        Next
Я правильно понял? Затем массив HandFaces сортируется. Я, честно говоря, не знаю как отсортировать в обратном порядке. Поэтому мне нужно смотреть на последний и предпоследний элементы. Правильно?

-------
Канал Windows 11, etc | Чат @winsiders


Отправлено: 00:46, 19-04-2005 | #7


Аватара для hasherfrog

Старый параноик


Сообщения: 2423
Благодарности: 85

Профиль | Отправить PM | Цитировать


>> Правильно?
Ну да :]

Кстати... Я только сейчас увидел, что дал кусок про тасовку карт на паскале... :-P
LOL, даже ROTFLMAO

По-русски :] это будет так:
Код: Выделить весь код
Sub shuffle()
'массив карт
Dim L(0 To 51) As Integer

'инициализация колоды
For I = 0 To 51 Step 1
L(I) = I
Next I

'печать для екселя - надо же что-то узреть :)
For I = 0 To 51 Step 1
Worksheets(1).Cells(I + 1, 1).Value = L(I)
Next I

'тасовка
For I = 51 To 0 Step -1
R = Int(52 * Rnd)
If R <> I Then
T = L(R): L(R) = L(I): L(I) = T
End If
Next I

'снова печать - результат тасования
For I = 0 To 51 Step 1
Worksheets(1).Cells(I + 1, 2).Value = L(I)
Next I

End Sub

Отправлено: 10:00, 19-04-2005 | #8


(*.*)


Сообщения: 36491
Благодарности: 6675

Профиль | Сайт | Отправить PM | Цитировать


hasherfrog
Да я уже разобрался как отсортировать массив в обратном порядке. На самом деле мне это не нужно, без разницы какой элемент использовать для подсчета сопвадений.
Кстати, хорошая идея с
Цитата:
Масть - номер карты (0-51) mod 4 (остаток от деления) 0 - пики... 3 - бубны
Номинал - номер карты (0-51) / 4 (целочисленное деление) 0 - двойка ... 12 - туз
Я "подсократил" колоду сразу. В задании сказано создать структуру, состоящую из мастей и номиналов. Вот я "заполнял" мастями все 52 карты. На самом деле достаточно 13 по числу номиналов, и четыре масти обозначить. А потом уже из них по твоему методу все брать.

Спасибо за пояснения по тасовке колоды. Я понял теперь Ты с VB на Си, a потом на паскаль прыгаешь, совсем меня запутал. Я же сказал, что я начинающий На самом деле, я вижу преимущества такого метода вообще, т.к. если надо сдать две руки, то берутся просто следующие пять элементов массива. В моем же случае с одной единственной рукой я, пожалуй, оставлю свой код. Нет нужды в создании массива на 52 элемента, если нужно всего 5. Логично?

Признателен за ответы

-------
Канал Windows 11, etc | Чат @winsiders


Отправлено: 10:32, 19-04-2005 | #9


Аватара для hasherfrog

Старый параноик


Сообщения: 2423
Благодарности: 85

Профиль | Отправить PM | Цитировать


У-ё.
Неправильно я расписал тасовку. Так тужился, вспоминая васик... :] Переупростил код и потерял смысл использования -1. Надо так:
Код: Выделить весь код
'тасовка
For I = 51 To 1 Step -1
R = Int((I + 1) * Rnd)
If R <> I Then
T = L(R): L(R) = L(I): L(I) = T
End If
Next I
>> Я же сказал, что я начинающий
Стоит только начать... ;]
Удачи при сдаче.

Отправлено: 11:38, 19-04-2005 | #10



Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » Алгоритм подсчета покерной руки

Участник сейчас на форуме Участник сейчас на форуме Участник вне форума Участник вне форума Автор темы Автор темы Шапка темы Сообщение прикреплено

Похожие темы
Название темы Автор Информация о форуме Ответов Последнее сообщение
FreeBSD - Кривые руки xolod. Общий по FreeBSD 2 14-05-2009 12:02
[решено] мои руки\цп\мать кто виноват и что делать) SoA Непонятные проблемы с Железом 12 14-08-2008 17:34
DNS (опустились руки) 53 порт локального сервера Virtus1k Microsoft Windows NT/2000/2003 3 03-01-2008 11:16
Программа подсчета трафика. NewWind Общий по Linux 1 04-06-2007 16:37
Кривые руки при разгоне - и комп перестал грузится... Shaytan Непонятные проблемы с Железом 13 06-03-2005 21:56




 
Переход