Писане на покер бот
В тази статия няма да има пълни изходни кодове, само теоретично какво и как може
използване и някои части от функции. Ако се интересувате от това, няма да можете да поставите всичко в една снимка и да напишете своя собствена. Също така няма да преподавам стратегии за игри, можете да намерите много информация в интернет за термини или стратегии, както и правила.
Започнах да играя преди около 5 години, през това време са изиграни повече от 1 милион ръце. По принцип това е No Limit Holdem (холдем без лимит) на къси маси (от 2 до 6 души на масата), има опит в играта на Omaha, HU NL Holdem. Играта е нещо като хоби и развлечение. И така, с приятели дойде идеята да се напише бот, първата идея беше да се напише limit hold'em и когато ботът беше наполовина написан, те приеха закон, забраняващ на американците да играят покер, в резултат на което те хвърлиха бот с лимит. Първата версия е написана на невронна мрежа с разпознаване на изображения, което означава, че ботът е обучен да разпознава карти от екранни снимки, но вие сами разбирате, че това е неточно
метод, но с достатъчно добро обучение, той разпозна с точност от 98-99% Допълнителни версии на ботовете вече работеха директно с прозорците на стаите, използвайки техните ресурси., както и в тандем с програми за анализ и събиране на статистика на играта.
Покер залите не спят.
Почти всички покер зали имат някакъв вид защита и система за откриване на покер ботове. Нека разгледаме някои от тях. Дълга игра - когато човек отнема твърде много време
играе, става подозрителен, така че в някои стаи може да се появят прозорци с въпроси. Като защита, не правете дълги игрови сесии. Действия на масата - натискане на бутони, избор на прозорци, действията не трябва да се извършват без движение на мишката, в минимизиран прозорец. Траекториите на мишката са най-добре зададени малко нелинейни, като щракнетеразлични места на бутоните, скоростта на движение също не е мигновена. Сканиране на работещи процеси и екранни снимки на екрана - защита, както беше споменато по-горе, не играйте в минимизирани прозорци, наричайте процеса на бота не покер бот и други подобни, не оставяйте прозореца на бота увеличен на екрана, променете името на процеса след известно време (например след x минути, рестартирайте бота с ново име на процес).
Схема на покер бот.
Диаграмата може да бъде разделена на 3 части:
- Блок 1 - блок за взаимодействие с клиента за игра на покер
- Блок 2 - блок за решение
- Блок 3 е блок за събиране на статистика, според мен е по-добре да използвате софтуер на трети страни, като PokerTracker 3, като същевременно деактивирате показването на статистика на екрана.
Нека разгледаме всеки блок по-подробно.
Блок 1 - блок за взаимодействие с клиента за игра на покер.
Този блок се използва за събиране на информация за игралната маса и прехвърлянето й към блока за приемане.
решение, както и получаване на отговор с решение за извършване на това или онова действие като Fold, Raise, Call или All-In. Сега разгледайте този блок. Част от тази част е взаимодействието с главния прозорец.
програми, това са действия като избор на лимит, избор на маса на която ще играем, това също е голяма част, но няма да се спираме на нея. Нека разгледаме по-подробно частта вече с масата. Първо трябва да намерим манипулаторите на всички отворени маси (прозорци) на играта, това може да стане с помощта на функциятаEnumWindows
ФункциятаEnumWindowsизброява всички прозорци от най-високо ниво на екрана, като предава манипулатор на всеки прозорец на свой ред към функция за обратно извикване, дефинирана от приложението. EnumWindows продължава, докато не бъде изброен последният прозорец от най-високо ниво или докато функцията за обратно извикване се върнеFALSE стойност.
WNDENUMPROC lpEnumFunc, // указател към функция за обратно извикване
LPARAM lParam // програмно дефинирана стойност
Сочи към функция за обратно извикване, дефинирана от приложението. За повече информация вижте функцията за обратно извикване на EnumWindowsProc.
Задава 32-битова програмно дефинирана стойност, която да бъде предадена на функцията за обратно извикване.
Ако функцията е успешна, се връща ненулева стойност. Ако функцията е неуспешна, върнатата стойност е нула.
Ако функцията работи успешно, можем да получим името на прозорецаGetWindowTextи след като го анализираме, за да разберем дали прозорецът е необходим или не, обикновено вашият псевдоним, името на покер залата и лимита са в заглавието на прозореца. Освен това няма да навреди да запазите дръжките на всички намерени прозорци, за по-нататъшна употреба, без повторно търсене, търсенето ще трябва да се извърши само ако се отвори нов прозорец.
Сега, след като имаме манипулатора на прозореца на играта, можем да изтеглим информация за масата. По-голямата част от информацията се съхранява в прозореца на дилъра. От него можем да научим всичко
участници на масата, кой е влязъл, кой е напуснал масата, кой е направил какво действие, картите на масата и техните карти. За да направим това, имаме нужда от анализатор на текст, няма да казвам как да го напиша, това е отделна тема, основното е, че идеята е ясна J. Но преди анализатора първо трябва да намерим елементите на прозореца и сред тях да намерим прозореца на дилъра. Много често дилърският прозорец е клас, извлечен от Internet Explorer_Server, за да го намерим, използваме функциятаEnumChildWindowsи след товаGetClassName.
дъщерни прозорци, които принадлежат към определен родителски прозорец, в техните собствени
опашка, предавайки манипулатор на всяко детепрозорци във функцията за повторение
повикване, определено от програмата. Функцията EnumChildWindows работи до
последният дъщерен прозорец е в списъка или функцията за обратно извикване няма да се върне
FALSE стойност.
Идентифицира родителския прозорец, чиито дъщерни прозорци трябва да бъдат изброени.
Сочи към функция за обратно извикване, дефинирана от приложението. За повече информация относно функцията за обратно извикване вижте функцията за обратно извикване EnumChildProc.
Задава 32-битова програмно дефинирана стойност, която да бъде предадена на функцията за обратно извикване.
Ако функцията е успешна, се връща ненулева стойност. Ако функцията е неуспешна, върнатата стойност е нула.
Сега можете да започнете да анализирате текста. Нашият ход или не може да бъде анализиран въз основа на това кои бутони са достъпни за нас в момента. Това може да стане както чрез ресурси, така и просто чрез точки на екрана в този прозорец. Освен това, ако ходим, ние прехвърляме известните данни към блока за вземане на решения. Когато получим отговор, предприемаме съответните действия. В тази част все още не е разгледано как да натискате бутоните, но мисля, че можете да го направите сами.
Блок 2 - блок за решение
итерации. За да играем достатъчно уверено срещу опонента, трябва да знаем неговия диапазон и как играе (този елемент е свързан със статистиката), има и определени стратегии за игра, които зависят от сумата пари, която имате, от броя на играчите на масата и самата стратегия за игра. Началният диапазон от ръце зависи от всичко това и действията на следващите улици, например, човек, който играе според стратегията с малък стак (SSS), рядко прави ходове на ривъра (когато на масата са поставени 5 карти), т.к. до този момент тойчесто вече в Allin (факирал). Оценката на ситуациите също влиза в броенето на аутове, аутовете са броят карти, които ще подобрят нашата позиция на следващите улици, следователно следват комбинации като стрейт дроу, стрейт в дупка, флъш дроу и т.н. Равенството също е комбинация и в зависимост от броя на аутовете си има цена.И имайки определена комбинация, дори в момента да не е печеливша, ние вече градим линия на игра. Благодарение на тези допълнителни данни вече можем да вземаме решения в зависимост от избраната стратегия, ако добавим повече статистика на играчите отгоре, те ще бъдат още по-точни, а ако добавим пълната
тази извадка все още може да бъде допълнена. Надявам се, че предадох идеята си за намаляване на пробите и вземане на решения, всичко се свежда до личен опит от играта и
вземане на решения, защото в няколко изречения не можете да кажете теорията на покера, която е публикувана в много томове, за различни ситуации, които са безброй, въпреки че могат да бъдат разделени на основни групи...
Първо трябва да разберем ситуацията на масата и каква комбинация имаме. Ето пример за код за дефиниране на комбинация (пренаписан по-ясно, но може и да не е така
normal;mso-layout-grid-align:none;text-autospace:none"> 9.5pt;font-family:"Arial","sans-serif";color:green">// функция за попълване на масив от карти, връща поредния номер на картата 9.5pt;font-family:"Arial","sans-serif"">
normal;mso-layout-grid-align:none;text-autospace:none"> EN-US">int mso-ansi-language:EN-US"> CardToNumber( char Card)
normal;mso-layout-grid-align:none;text-autospace:none"> if ((Card> '1' )&&(Card
normal;mso-layout-grid-align:none;text-autospace:none"> if (Card== 'T' ) return 10;
normal;mso-layout-grid-align:none;text-autospace:none"> if (Card== 'J') върне 11;
normal;mso-layout-grid-align:none;text-autospace:none"> if (Card== 'Q' ) return 12;
normal;mso-layout-grid-align:none;text-autospace:none"> if (Card== 'K' ) return 13;
normal;mso-layout-grid-align:none;text-autospace:none"> if (Card== 'A' ) return 14;
normal;mso-layout-grid-align:none;text-autospace:none"> return -1;
normal;mso-layout-grid-align:none;text-autospace:none"> 9.5pt;font-family:"Arial","sans-serif";color:green">// функция за получаване на бита, съответстваща масти карта font-family:"Arial","sans-serif"">
normal;mso-layout-grid-align:none;text-autospace:none"> EN-US">int mso-ansi-language:EN-US"> MastToNumber( char mast)
normal;mso-layout-grid-align:none;text-autospace:none"> if (mast== 'h' ) return 1;
normal;mso-layout-grid-align:none;text-autospace:none"> if (mast== 'd' ) return 2;
normal;mso-layout-grid-align:none;text-autospace:none"> if (mast== 'c' ) return 4;
normal;mso-layout-grid-align:none;text-autospace:none"> if (mast== 's' ) return 8;
normal;mso-layout-grid-align:none;text-autospace:none"> return 0;
нормален;mso-layout-grid-align:none;text-autospace:none"> EN-US">// цвят:зелен">функции color:green;mso-ansi-language:EN-US"> font-family:"Arial","sans-serif";color:green">разчета EN-US"> цвят:зелен">комбинации font-family:"Arial","sans-serif";mso-ansi-language:EN-US">
normal;mso-layout-grid-align:none;text-autospace:none"> EN-US">int mso-ansi-language:EN-US"> Hand( char *MyHand_, char *CardsTable_)
промиване_, промиване; //0- нищо mso-ansi-language:EN-US"> 1- "Arial","sans-serif";color:green">флэшь EN-US"> 2- color:green">флэшь color:green;mso-ansi-language:EN-US"> font-family:"Arial","sans-serif";color:green">dro EN-US"> 3- color:green">baedorflasher font-family:"Arial","sans-serif";color:green;mso-ansi-language:EN-US"> 4- font-family:" Arial","sans -serif";color:green">EN-US flash"> color:green">on color:green;mso-ansi-language:EN-US"> font-family:"Arial","sans-serif";color:green">EN-US table">(без карти) font-family:"Arial","sans-serif" ;mso-ansi-language:EN -US">
normal;mso-layout-grid-align:none;text-autospace:none"> font-family:"Arial","sans-serif";color:blue">int 9.5pt;font-family:"Arial","sans-serif""> карти[15][4]; //i-карти j1-брой карти j2-цвет битове 1,2,3 ,4-h ,d,c,s j3-0/1 - 1-наша карта 0-не наша (на масата)
normal;mso-layout-grid-align:none;text-autospace:none"> 9.5pt;font-family:"Arial","sans-serif""> int прав; //0-няма, 1-стрейт, 2-оупън стрейт (2-way) 3-гътшот 4-нът стрейт на борда 5-стрейт на борда
normal;mso-layout-grid-align:none;text-autospace:none"> 9.5pt;font-family:"Arial","sans-serif""> int readyhand; //0-не е готова, 1-готова комбинация
normal;mso-layout-grid-align:none;text-autospace:none"> 9.5pt;font-family:"Arial","sans-serif""> mso-ansi-language:EN-US">int font-family:"Arial","sans-serif";mso-ansi-language:EN-US"> i,j, maxi, flag_, flag, flmax, top, pair_, pair, three, four, over, set_, trees, quad, num, kicker;
normal;mso-layout-grid-align:none;text-autospace:none"> font-family:"Arial","sans-serif";color:green">// запълване на масива с карти въз основа на входните данни
normal;mso-layout-grid-align:none;text-autospace:none"> 9.5pt;font-family:"Arial","sans-serif""> mso-ansi-language:EN-US">за семейство шрифтове:"Arial","sans-serif";mso-ansi-language:EN-САЩ">(i=1;i
normal;mso-layout-grid-align:none;text-autospace:none"> за (j=1;j
normal;mso-layout-grid-align:none;text-autospace:none"> cards[CardToNumber(MyHand_[0])][2]=cards[CardToNumber(MyHand_[0])][2] 2*MastToNumber(MyHand_[1]));