maglub Postad 11 Augusti , 2005 Rapport Postad 11 Augusti , 2005 Tjenare, Jag tänkte mig göra en liten statistisk analys av pokerhänder medelst SQL (för er oinvigda är det ett funktionellt språk som används i databaser). Inte för att jag egentligen vet exakt hur man gör det på bästa sätt, utan det hoppas jag andra ADB-intresserade pokerspelare kan hjälpa mig med. Det jag tänkte börja med är att visa hur man i MySQL enkelt kan generera ett par tabeller, som vi kan använda som utgångspunkt, och ett par enka utsökningar för att representera lite olika händer. Det är ganska många olika saker att hålla reda på samtidigt, men jag tror att vi gemensamt kan göra något bra av det hela. Att skapa de tabellerna jag rekommenderar i mitt inlägg kommer kräva några hundra MB på din hårddisk. MySQL är gratis och hämtas enkelt ner från http://www.mysql.com och kan installeras på Windows, Linux och lite annat smått och gått. Jag tycker själv inte alls om MySQL, men använder den för att den är enkel att installera för er andra och den är ganska populär i den så kallade akademiska världen. Jag vill heller inte påstå att jag är någon självutnämnd expert varesig inom statistik, sannolikhetslära eller ADB, utan vill lära mig lite grand och hoppas på hjälp från likasinnade. Som grund för att kunna hänga med här måste du själv ladda ner MySQL och installera programvaran. Sedan måste du öppna MySQL command line client. Om du inte fixar det, fråga gärna inte mig hur man gör. Jag kommer ändå inte riktigt ha tid att hjälpa till. Det finns hur mycket hjälp att få med det på google. Över till själva databasen. Först måste vi ha en databas. Den skapar man enklast så här: drop database poker; create database poker; use poker; Så där, då är databasen skapad. Ingenting ligger i den, utan den är bara förberedd så vi kan göra något med den. Det vi sedan behöver är en kortlek. Den tillverkar man enkelt genom att först skapa en tabell och sedan lägga in kort för kort i den: drop table kortlek; create table kortlek ( id int, suite text, value int ); -- Hjärter insert into kortlek values ( 1, 'H', 1); insert into kortlek values ( 2, 'H', 2); insert into kortlek values ( 3, 'H', 3); insert into kortlek values ( 4, 'H', 4); insert into kortlek values ( 5, 'H', 5); insert into kortlek values ( 6, 'H', 6); insert into kortlek values ( 7, 'H', 7); insert into kortlek values ( 8, 'H', 8); insert into kortlek values ( 9, 'H', 9); insert into kortlek values ( 10, 'H', 10); insert into kortlek values ( 11, 'H', 11); insert into kortlek values ( 12, 'H', 12); insert into kortlek values ( 13, 'H', 13); -- Ruter insert into kortlek values ( 14, 'R', 1); insert into kortlek values ( 15, 'R', 2); insert into kortlek values ( 16, 'R', 3); insert into kortlek values ( 17, 'R', 4); insert into kortlek values ( 18, 'R', 5); insert into kortlek values ( 19, 'R', 6); insert into kortlek values ( 20, 'R', 7); insert into kortlek values ( 21, 'R', 8); insert into kortlek values ( 22, 'R', 9); insert into kortlek values ( 23, 'R', 10); insert into kortlek values ( 24, 'R', 11); insert into kortlek values ( 25, 'R', 12); insert into kortlek values ( 26, 'R', 13); -- Klöver insert into kortlek values ( 27, 'K', 1); insert into kortlek values ( 28, 'K', 2); insert into kortlek values ( 29, 'K', 3); insert into kortlek values ( 30, 'K', 4); insert into kortlek values ( 31, 'K', 5); insert into kortlek values ( 32, 'K', 6); insert into kortlek values ( 33, 'K', 7); insert into kortlek values ( 34, 'K', 8); insert into kortlek values ( 35, 'K', 9); insert into kortlek values ( 36, 'K', 10); insert into kortlek values ( 37, 'K', 11); insert into kortlek values ( 38, 'K', 12); insert into kortlek values ( 39, 'K', 13); -- Spader insert into kortlek values ( 40, 'S', 1); insert into kortlek values ( 41, 'S', 2); insert into kortlek values ( 42, 'S', 3); insert into kortlek values ( 43, 'S', 4); insert into kortlek values ( 44, 'S', 5); insert into kortlek values ( 45, 'S', 6); insert into kortlek values ( 46, 'S', 7); insert into kortlek values ( 47, 'S', 8); insert into kortlek values ( 48, 'S', 9); insert into kortlek values ( 49, 'S', 10); insert into kortlek values ( 50, 'S', 11); insert into kortlek values ( 51, 'S', 12); insert into kortlek values ( 52, 'S', 13); commit; Nu har vi en kortlek, från vilken vi kan "dra" kort. Man kan fråga databasen om en massa ointressanta saker. Exempelvis, hur många hjärter finns det i leken? mysql> select count(*) from kortlek where suite='H'; +----------+ | count(*) | +----------+ | 13 | +----------+ 1 row in set (0.00 sec) Nu avslutar jag mitt första inlägg och fortsätter lite mer i ett nytt inlägg. Hoppas någon mer hänger på. //magnus Citera
maglub Postad 11 Augusti , 2005 Författare Rapport Postad 11 Augusti , 2005 Tjenare igen, Det är ju inte så jätteintressant att bara ha en kortlek, utan man vill ju gärna göra någonting med den. Här har ni ett par intressanta utsökningar att leka med: De första två korten. Hur många olika händer finns det? select a.id as k1, b.id as k2 FROM kortlek a, kortlek b WHERE a.id <> b.id and a.id < b.id; Jag kollar i denna utsökning inte alls efter vilken valör eller färg som finns. Det enda jag kollar är att det andra kortet inte är samma som det första, samt att jag ser till att jag inte både får handen {1,2} och {2,1}. Sammanlagt returneras alltså 1326 rader i denna utsökningen. Men vän av ordning vet ju att det inte finns så många "unika" händer. Klöver Ess i kombination med Hjärter Kung är lika mycket värt som Ruter Ess i kombination med Ruter Kung. Detta kan man undersöka med följande utsökning, där man helt enkelt måste ta hänsyn till färg och valör på korten: -- första handen när olika färger är lika värda select a.id as k1, b.id as k2, a.suite, a.value, b.suite, b.value FROM kortlek a, kortlek b WHERE a.id <> b.id and a.id < b.id group by a.value, b.value; Med den utsökningen returneras 169 starthänder. På skärmen ser det ut så här: mysql> select a.id as k1, b.id as k2, a.suite, a.value, b.suite, b.value -> FROM kortlek a, kortlek b -> WHERE -> a.id <> b.id -> and a.id < b.id -> group by a.value, b.value; +------+------+-------+-------+-------+-------+ | k1 | k2 | suite | value | suite | value | +------+------+-------+-------+-------+-------+ | 1 | 14 | H | 1 | R | 1 | | 1 | 2 | H | 1 | H | 2 | | 1 | 3 | H | 1 | H | 3 | | 1 | 4 | H | 1 | H | 4 | | 1 | 5 | H | 1 | H | 5 | ... | 13 | 25 | H | 13 | R | 12 | | 13 | 26 | H | 13 | R | 13 | +------+------+-------+-------+-------+-------+ 169 rows in set (0.03 sec) Nu börjar det röra lite på sig. //magnus edit: ändrade utsökningarna så de fungerar även i postgresql Citera
vetgirig Postad 11 Augusti , 2005 Rapport Postad 11 Augusti , 2005 Varför inte implementera det hela med enums ? http://dev.mysql.com/doc/mysql/en/enum.html Då slipper man att man någonsin skulle skicka in kort som inte finns i en kortlek. Citera
maglub Postad 11 Augusti , 2005 Författare Rapport Postad 11 Augusti , 2005 Och som en liten sista gottebit, vill jag ge er ett par lite mer saftiga utsökningar. Först skapar vi en ny tabell, som får representera alla möjliga kombinationer som kan ses på bordet efter "river". -- alla möjliga kombinationer på bordet create table bordet as select a.id k1, b.id k2, c.id k3, d.id k4, e.id k5 from kortlek a, kortlek b, kortlek c, kortlek d, kortlek e WHERE a.id <> b.id and a.id <> c.id and a.id <> d.id and a.id <> e.id and b.id <> c.id and b.id <> d.id and b.id <> e.id and c.id <> d.id and c.id <> e.id and d.id <> e.id and a.id < b.id and b.id < c.id and c.id < d.id and d.id < e.id; Denna tabell är ganska intressant, då man ur den kan söka ut alla möjliga bordkombinationer mot en tvåkortshand. Tabellen blir ca 2.6 Miljoner rader lång och kommer ta upp ca 200 MB på hårddisken. Dock är det mycket snabbare att skapa denna tabeller i förhand än att göra en komplex utsökning varje gång man vill analysera innehållet (eller skapa en så kallad "vy" i databasen). Exempelvis kan man med en enkel utsökning se att för varje hand man har, finns det ca 2.1 Miljoner olika bordkombinationer. Vi använder oss av en godtycklig hand (kort nummer 1 och 2), som får representera "vilken hand som helst". select count(*) from flop where k1 not in (1,2) and k2 not in (1,2) and k3 not in (1,2) and k4 not in (1,2) and k5 not in (1,2); Utsökningen tar ca 8.91 sekunder på min laptop och ger följande resultat: mysql> select count(*) from flop -> where -> k1 not in (1,2) -> and k2 not in (1,2) -> and k3 not in (1,2) -> and k4 not in (1,2) -> and k5 not in (1,2); +----------+ | count(*) | +----------+ | 2118760 | +----------+ 1 row in set (8.91 sec) Någon annan som har något intressant att tillägga? Det jag skulle vilja göra, är att för varje möjlig starthand (alla 1326 eller 169 starthänder) göra en inbördes rangordning, hur bra den är, alltså hur många av de andra (1325 eller 168) händerna som rent kombinatoriskt är sämre. Det kommer kräva ganska mycket datakapacitet att göra denna analys, samt ganska mycket tankeverksamhet - hur man jämför en hand mot en annan, då man måste sätta poäng på handen (ett par är sämre än två par...). Det kan bli ett intressant litet projekt det här. Speciellt om det finns fler som skulle kunna vara intresserade. Ha det gott! //magnus Citera
maglub Postad 11 Augusti , 2005 Författare Rapport Postad 11 Augusti , 2005 Vetgirig: Tackar för kommentaren. Jag tror du har rätt, om man är ute efter att göra tabellen "safe". I det här exemplet tror jag vi vill ha en så kompakt tabell (liten i storlek) som möjligt, samt kanske optimera i datatyper som kräver så lite datakraft som möjligt att läsa. Exempelvis, spara kollumnen suite som char istället... Men just kortleken är inte det som är kritiskt, tror jag, då mina "följd"-tabeller för tillfället inte använder sig av annat än integers för att peka vilket kort i leken som refereras till. Eventuellt vill vi aggregera den informationen in i en mer lättsökt (läs utan joins) tabell i något typexempel senare. //magnus Citera
vetgirig Postad 11 Augusti , 2005 Rapport Postad 11 Augusti , 2005 Vetgirig: Tackar för kommentaren. Jag tror du har rätt, om man är ute efter att göra tabellen "safe". I det här exemplet tror jag vi vill ha en så kompakt tabell (liten i storlek) som möjligt, samt kanske optimera i datatyper som kräver så lite datakraft som möjligt att läsa. Exempelvis, spara kollumnen suite som char istället... //magnus För enumen så kostar det 1 bytes medan för din TEXT kostar det 3 bytes och INT 4 bytes så att använda enum borde minska lagringstorleken från 7 bytes till 2 per kort. Så om du använder enum för valör och färg så minskar lagringsbehovet till 28% av din lösning. Citera
x31xx Postad 11 Augusti , 2005 Rapport Postad 11 Augusti , 2005 Undrar lite varför du använder en databas men det kanske ger sig med tiden. Att göra ett program som håller kortleken i minnet och utför de beräkningar du gjort skulle gå +1000ggr snabbare. Citera
jezaja Postad 11 Augusti , 2005 Rapport Postad 11 Augusti , 2005 Undrar lite varför du använder en databas men det kanske ger sig med tiden.Att göra ett program som håller kortleken i minnet och utför de beräkningar du gjort skulle gå +1000ggr snabbare. Blir ju mkt mer dynamiskt än att behöva skriva nya saker till ett program varje gång man vill testa sig fram till något nytt. Dock kan jag rekommendera ett färdigt API på: http://sourceforge.net/projects/pokersource/ Citera
maglub Postad 13 Augusti , 2005 Författare Rapport Postad 13 Augusti , 2005 Gott, tack for lanken! En av anledningarna till att jag vill gora denna studie i SQL, ar att jag daa och daa har tillgang till vaeldigt kraftfulla prylar, stora datorer och professionell lagring, vi snackar terabyte med snabb storage, upp till en eller ett par gigabyte per sekund. Ibland, inte alltid, kan man kora lite funktionstester paa egen hand. Och just naer man kan bygga en "kub" med ett gaeng haender och faa ut en analys om hur bra just den handen aer, paa ett saett som kraever mycket stort internminne eller stor diskcache, saa aer det smidigt med just SQL och en databas. //magnus Citera
maglub Postad 18 Augusti , 2005 Författare Rapport Postad 18 Augusti , 2005 Ok, har lite tråkigt i dag, även om jag egentligen inte har tid. Här är en utsökning, som visar hur många första två kort som är suited: -- suited i given select count(*) FROM kortlek a, kortlek b WHERE a.id <> b.id and a.id < b.id and a.suite = b.suite; count ------- 312 (1 row) Dela det med 1326 (antaled första två händer), så ser ni att det är 23.5% sannolikhet att få suited i given. Lätt att räkna med kombinatorik också: Första kortet är egalt: (52/52) Andra kortet skall vara lika: (12/51) (52/52)*(12/51)=23.5% //magnus Citera
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.