Loading [MathJax]/jax/element/mml/optable/Latin1Supplement.js
39 svar
265 visningar
naytte Online 6134 – Moderator
Postad: 15 apr 22:59 Redigerad: 15 apr 23:01

Intressant, enkelt kortspel - jämnt eller udda?

Halloj!

Jag funderade lite på optimala strategier i olika kortspel förut och funderade på ett enkelt kortspel jag kallar för "jämnt eller udda". En runda går till på följande vis:

  • Huset delar ut ett kort till dig och ett kort till sig själv ur samma, välblandade kortlek med 52 kort. Valörerna som finns är 2,3,...,14
  • Spelaren får titta på sitt kort. Utifrån sitt kort måste han gissa om summan av valörerna hos det egna kortet och husets kort är jämn eller udda
  • Om spelarens kort har samma valör som husets (de utgör ett par) vinner huset automatiskt
  • Om spelaren har gissat rätt utan att korten utgör ett par vinner han

Frågan är nu vem (om någon) som har ett övertag i det här spelet. Gynnar reglerna huset eller gynnar de spelaren? Hur ser vinstchanserna ut?

Jag är nyfiken på vad ni kommer fram till. Jag har kommit fram till ett svar (och simulerat det 10 miljoner gånger för att bekräfta det) och jag tyckte att det var... förvånande.

Marilyn 3919
Postad: 16 apr 00:07 Redigerad: 16 apr 00:09

Alltid riskabelt att riskera sitt anseende på kombinatorik och sannolikhet, men hoppas jag fattat reglerna rätt.

 

Leken har 28 jämna och 24 udda kort

Sh (sannolikheten) att korten har samma valör är 3/51 = 1/17.

Fall 1: Sh att du får udda är 6/13. I så fall ser man direkt att du bör gissa att huset får jämnt, dvs udda summa; sh för det är 28/51.

Totalt (6*28) / (13 * 51).

Fall 2: Sh att du får jämnt är 7/13. I så fall är sh att huset får jämnt av annan valör 24/51 och att det får udda 24/51.

Oavsett om du gissar jämn eller udda summa vinner du med sh 7/13 * 24/51.

 

Totalt är din vinstchans (6*28 + 7*24) / (13*51) = 112 / 221

 

Koll: Sh att huset vinner är 6/13 * 23/51 + 7/13 * 27/51 = 109/221

Om jag tänkt rätt bör, inför varje parti, du lägga 112 dukater och huset 109 dukater i potten, winner takes it all. Då är spelet rättvist.

Vad är ditt resultat?

naytte Online 6134 – Moderator
Postad: 16 apr 00:25 Redigerad: 16 apr 01:14

Jag håller med!

Jag missade att tänka på att sannolikheten att spelaren får ett jämnt kort inte är detsamma som att denne får ett udda kort (räknade med att sannolikheterna var desamma), men efter en korrigering får jag samma svar som du.

Snyggt!


Tillägg: 16 apr 2025 01:14

Tänk om vi gör en modifiering nu... Låt säga att huset delar ut det första kortet till sig själv, och det andra kortet till spelaren, med resterande regler oförändrade. Hur förändras vinstchanseran då?

Marilyn 3919
Postad: 16 apr 01:51
naytte skrev

Tillägg: 16 apr 2025 01:14

Tänk om vi gör en modifiering nu... Låt säga att huset delar ut det första kortet till sig själv, och det andra kortet till spelaren, med resterande regler oförändrade. Hur förändras vinstchanseran då?

Hmm, jag är inte med. Det spelar väl ingen roll i vilken ordning de får korten?

Jag kan gissa att summan är udda redan innan vi börjar dela ut kort. Min sannolikhet att vinna är likafullt 112/221.

Det stämmer! Insåg det först efter att jag gjorde beräkningen igen.

Är tydligen för trött för sannolikhet just nu...

Jag får däremot konstiga resultat nu när jag simulerar vidare. Återkommer imorgon efter lite sömn.

Marilyn 3919
Postad: 16 apr 12:14 Redigerad: 16 apr 12:14
naytte skrev:

Jag får däremot konstiga resultat nu när jag simulerar vidare. Återkommer imorgon efter lite sömn.

Även en simulant kan bli trött. Problemet är väldigt väl lämpat för ett sannolikhetsträd.

naytte Online 6134 – Moderator
Postad: 16 apr 14:14 Redigerad: 16 apr 14:15

Jag är också lite fundersam till dina beräkningar i #2. Om man bara räknar på sannolikheten att två slumpvis dragna kort har en jämn eller udda summa så får man också 109/221 respektive 112/221. Man får alltså detta svar utan att ta hänsyn till parregeln, där huset vinner direkt.

När jag simulerar att spelaren gissar på "jämn summa" hela tiden får jag vinstchansen 43.4  över en miljon simuleringar:

Scriptet som jag använder
from Cards import Deck


def distribute_cards():
    total_games = 1000000
    win = 0
    loss = 0

    for _ in range(total_games):
        deck = Deck().shuffle()  # Blandar en lek med 52 kort

        # Poppar kort 1 & 2
        card1 = deck.pop()
        card2 = deck.pop()

        # Hämtar kortens valörer
        val1 = card1.get_card_value()
        val2 = card2.get_card_value()

        if val1 == val2:
            loss += 1  # Huset vinner automatiskt om det blir par
        elif (val1 + val2) % 2 == 0:
            win += 1   # Spelaren gissar jämnt
        else:
            loss += 1  # Eftersom spelaren gissar jämnt förlorar han om summan blir udda

    probability_of_win = (win / total_games) * 100
    print(f"Probability of player winning: {probability_of_win:.2f}%")


if __name__ == "__main__":
    distribute_cards()

Sannolikheten att två kort med en jämn summa är ett par borde väl vara:

7142+6142282+242=13109\displaystyle \frac{\binom{7}{1}\binom{4}{2}+\binom{6}{1}\binom{4}{2}}{\binom{28}{2}+\binom{24}{2}}=\frac{13}{109}

Så sannolikheten att två kort med jämn summa inte utgör ett par borde vara:

1-13109=96109\displaystyle 1-\frac{13}{109}=\frac{96}{109}

Summa summarum borde vinstchansen om man alltid gissar jämn summa alltså vara:

Pvinst=Pjämn summa·Pinte par|jämn summa=109221·96109=9622143.34 %\displaystyle P\left(\text{vinst}\right)=P\left(\text{jämn summa}\right)\cdot P\left(\text{inte par}|\text{jämn summa}\right)=\frac{109}{221}\cdot\frac{96}{109}=\frac{96}{221}\approx43.\!34\; \%

Detta stämmer ganska bra överrens med det empiriska resultatet (om jag nu har gjort mitt script rätt...)

Marilyn 3919
Postad: 16 apr 15:10

Jag börjar med att gissa jämn summa.

 

Fall 1 Sh jag får jämnt kort är 7/13.

Sh att huset isåfall får jämnt som inte är par är 24/51.

Fall 2 Sh att jag får udda kort är 6/13.

Sh att huset får udda som inte är par är 20/51.

 

Så sh att jag vinner är (7*24+6*20)/(13*51) = 96/221 ≈ 0,434

 

Så gissar jag jämnt är sh för vinst 96/221, gissar jag udda är sh för vinst 112/221.

naytte Online 6134 – Moderator
Postad: 16 apr 15:15 Redigerad: 16 apr 15:17

Så sant!

Det stämmer också med min simulering. Så det bästa beslutet är med andra ord alltid att gissa på udda summa, då vinner man alltid i längden.

Det som förvirrade var att sannolikheten att summan blir udda är densamma som vinstchansen om man gissar på udda...

Trinity2 2712
Postad: 16 apr 15:36
naytte skrev:

Jag är också lite fundersam till dina beräkningar i #2. Om man bara räknar på sannolikheten att två slumpvis dragna kort har en jämn eller udda summa så får man också 109/221 respektive 112/221. Man får alltså detta svar utan att ta hänsyn till parregeln, där huset vinner direkt.

När jag simulerar att spelaren gissar på "jämn summa" hela tiden får jag vinstchansen 43.4 %43.\!4\;\% över en miljon simuleringar:

Scriptet som jag använder
from Cards import Deck


def distribute_cards():
    total_games = 1000000
    win = 0
    loss = 0

    for _ in range(total_games):
        deck = Deck().shuffle()  # Blandar en lek med 52 kort

        # Poppar kort 1 & 2
        card1 = deck.pop()
        card2 = deck.pop()

        # Hämtar kortens valörer
        val1 = card1.get_card_value()
        val2 = card2.get_card_value()

        if val1 == val2:
            loss += 1  # Huset vinner automatiskt om det blir par
        elif (val1 + val2) % 2 == 0:
            win += 1   # Spelaren gissar jämnt
        else:
            loss += 1  # Eftersom spelaren gissar jämnt förlorar han om summan blir udda

    probability_of_win = (win / total_games) * 100
    print(f"Probability of player winning: {probability_of_win:.2f}%")


if __name__ == "__main__":
    distribute_cards()

Sannolikheten att två kort med en jämn summa är ett par borde väl vara:

7142+6142282+242=13109\displaystyle \frac{\binom{7}{1}\binom{4}{2}+\binom{6}{1}\binom{4}{2}}{\binom{28}{2}+\binom{24}{2}}=\frac{13}{109}

Så sannolikheten att två kort med jämn summa inte utgör ett par borde vara:

1-13109=96109\displaystyle 1-\frac{13}{109}=\frac{96}{109}

Summa summarum borde vinstchansen om man alltid gissar jämn summa alltså vara:

Pvinst=Pjämn summa·Pinte par|jämn summa=109221·96109=9622143.34 %\displaystyle P\left(\text{vinst}\right)=P\left(\text{jämn summa}\right)\cdot P\left(\text{inte par}|\text{jämn summa}\right)=\frac{109}{221}\cdot\frac{96}{109}=\frac{96}{221}\approx43.\!34\; \%

Detta stämmer ganska bra överrens med det empiriska resultatet (om jag nu har gjort mitt script rätt...)

För oss fåtal dinosaurier som överlevde... vilket programmeringsspråk är detta? Python?

Ja, det är Python!

Marilyn 3919
Postad: 16 apr 15:55 Redigerad: 16 apr 15:57

Grejen är att om det är par så är summan aldrig udda (ja du har redan sett det)

(eftersom u+u = j+j = j).

Därför är det oförmånligt att gissa jämn summa, du kan gissa rätt, men förlorar likafullt.

naytte Online 6134 – Moderator
Postad: 16 apr 16:55 Redigerad: 16 apr 16:58

Yes, snyggt!

Nu har jag en modifikation som påverkar oddsen. Låt säga att spelaren istället får två kort, medan huset fortfarande får ett kort:

  • Spelaren gör en gissning om summans paritet (alltså summan av valörerna på de två egna korten och husets ena kort)
  • Om spelarens hand utgör ett par i sig så vinner spelaren automatiskt, oavsett vad huset har för kort och oavsett gissning.
  • Om något kort i spelarens hand utgör ett par med husets kort så vinner huset, oavsett vad spelaren gissar

Vem är det nu som har bäst vinstchanser?

Marilyn 3919
Postad: 16 apr 16:59

Men om spelare och hus får triss, vem vinner då?

naytte Online 6134 – Moderator
Postad: 16 apr 17:01 Redigerad: 16 apr 17:03

Då vinner spelaren eftersom hans hand utgör ett par i sig. Ordningen jag skrev upp punkterna i tänker jag är "viktigheten" i kriterierna eller vad man ska säga.

  • Spelaren gissar pariteten
  • Om spelaren har ett par själv ==> spelaren vinner oavsett gissning och oavsett vad huset hade
  • Om spelaren inte hade par själv men det kan bildas ett par mellan något av spelarens kort och husets kort ==> huset vinner
  • Om inget av de två ovanstående kriterierna uppfylls vinner spelaren om han gissar pariteten rätt, och förlorar om han gissar fel
Marilyn 3919
Postad: 16 apr 20:35

Men det blir ett svinkrångligt träd, om man inte kan förenkla är det inte matematik.

Har också förgäves försökt lösa det analytiskt en stund nu. Komplexiteten ökade tydligen extremt fort med den lilla förändringen. 😅

"Empiriskt" så ligger chansen för vinst om man gissar jämn på ca. 46.4 %, och chansen för vinst på ca. 48.1 % om man gissar udda.

Marilyn 3919
Postad: 16 apr 20:40

PS min burk hängde sig, därför jag var seg med svaret.

Marilyn 3919
Postad: 16 apr 20:43

Jag ser inte att det är svårare än det förra problemet. Egentligen. Men för eller senare gör man ett slarvfel och då är man lost. 

Det är 52*51*50 permutationer av de tre första korten, det gäller att få ihopp just så mänga disjunkta utfall.

naytte Online 6134 – Moderator
Postad: 16 apr 20:46 Redigerad: 16 apr 21:01

Jo men precis. Det är ju delvis detta som gör spel som Blackjack så himla krångliga att lösa analytiskt också (tror inte ens att det har gjorts). Det finns så många fall att ta hänsyn till att det blir nästan omöjligt.

Marilyn 3919
Postad: 16 apr 21:18 Redigerad: 16 apr 22:03

 

, se nästa post

Marilyn 3919
Postad: 16 apr 22:01

Jo men det gick till sist!

 

Sätt 52*51*50 = N

Då fås sh att du vinner med eget par = 7800/N

Sh att huset parar med din hand = 14976/N

Sh att summan udda utan par = 56064/N

Sh att summan jämn utan par = 53760/N

Jag tar bort förra bilden, diverse slarvfel där.

Marilyn 3919
Postad: 17 apr 00:05

Jag tänkte på det, om du får dina två kort, så bör oddset för jämn eller udda totalsumma påverkas av huruvida du tittar på J+J, J+U eller U+U. Men den analysen får vila till senare. I din presentation av problemet tolkar jag det som att man satsar innan man sett sina egna kort (rimligt iofs, när du ser dina kort vet du om du kan plocka hem en direktvinst pga eget par).

Bedinsis 3207
Postad: 17 apr 09:22 Redigerad: 17 apr 09:57

Jag får det till:

slh att man får eget par är 1*(3/51).

Om man fått J+J är slh för vinst om man säger "J" (20/50), slh för vinst om man säger "U" (24/50)

Om man fått J+U är slh för vinst om man säger "J" (20/50), slh för vinst om man säger "U" (24/50)

Om man fått U+U är slh för vinst om man säger "J" (28/50), slh för vinst om man säger "U" (16/50)

slh för J+J men inget par är (28/52)*(24/51)

slh för J+U är (28/52)*(24/51)

slh för U+U men inget par är (24/52)*(20/51)

Så sannolikheten för vinst om man spelar optimalt borde bli:

3/51+(28/52)*(24/51)*(24/50)+(28/52)*(24/51)*(24/50)+(24/52)*(20/51)*(28/50)=

3/51+ (1/(52*51*50))*(28*24*24*2+28*24*20)=

3/51+ (28*24*68)/(52*51*50)= 0,4034389140271493...

Huset vinner.

Jag är dock osäker på om jag nu räknat tagit hänsyn till ordningen för J & U, och om jag borde ha gjort det. I sådant fall blir slh för vinst 0,5250678733031674..., dvs huset förlorar.

Marilyn 3919
Postad: 17 apr 16:59

Jag ska gå ut i solen, men detta kan inte vänta.

 

Ett realistiskt spel är att du tittar på dina två kort, men huset har inte visat sitt kort.

Ska du gissa att summan av era tre kort är jämn eller udda?

Om vi då räknar bort fallen med par som du inte kan påverka så får jag

1 Du har två udda kort. Gissa på jämn summa, vinstchans 7/11, förlustrisk 4/11.

Du har ett eller två jämna kort. Gissa udda summa, vinstch 6/11 förlrisk 5/11.

 

Det är lurigt med betingade sh. Jag ska göra en översyn när solen gått ner.

naytte Online 6134 – Moderator
Postad: 17 apr 21:51 Redigerad: 17 apr 21:57

Spännande inlägg!

Jag är själv för dålig för att försöka mig på detta analytiskt men jag har precis börjat lära mig om "Q-Learning" och det skulle nog passa perfekt för ett problem som detta. Jag har redan börjat slipa lite på lite kod i Python där jag tänker försöka bygga en modell som hittar den optimala spelstrategin och blir så bra som möjligt över miljontals rundor.

Kanske kan vi få några bra insikter av det! :D

Marilyn 3919
Postad: 17 apr 23:16 Redigerad: 18 apr 01:19

Så här blev det för mig:

 

Du spelar spelet N = 52!/49! gånger (dvs 52*51*50 = 132600 ggr) med ny permutation av korten varje gång (är man systematisk behöver man inte köra miljontals gånger).

7800 gånger vinner du pga eget par.

14976 ggr vinner huset för att det parar sig med någon av dina valörer.

Jag räknar bort de tillfällena i fortsättningen. u och j betecknar udda resp jämnt kort, U och J betyder udda resp jämn summa.

Då fördelar sig summorna som följer

u+u+u = U:   7680 ggr.                       u+u+j = J:     13440 ggr

u+j+j el j+u+j = U: 32256 ggr.           u+j+u el j+u+u = J:  26880 ggr

j+j+u = U:   16128 ggr                           j+j+j = J:   13440 ggr

 

Så ska du gissa innan du sett dina kort så ska du gissa U. Då har du sh 

(7680+32256+16128+7800) / N ≈ 63864/132600 ≈ 0,4816 att vinna.

Om du sett dina kort men inte husets så ska du gissa J om du har u+u, i annat fall U.

Då har du sh 

(13440+32256+16128+7800)/N = 69624/132600 ≈  0,5251 att vinna.

 

PS. Det vore litet kul att se hur snabbt din Pyton/Monte C-metod snävar in mot mina värden.

naytte Online 6134 – Moderator
Postad: 18 apr 01:55 Redigerad: 18 apr 01:56

Har skrivit något som verkar fungera, och nu efter några miljoner iterationer ligger vinstchansen i snitt på typ 49 %, alltså högre än om man bara gissar jämn/udda utan att ta hänsyn till sin hand.

Jag återkommer om några dagar när jag har förfinat detta och har tillgång till mer datorkraft. Är på landet nu och har bara min fjuttiga laptop, medan burken hemma sitter på 24 trådar… 

sictransit 1916 – Livehjälpare
Postad: 18 apr 08:15 Redigerad: 18 apr 08:15

Spännande tråd! Detta ger jag mig absolut inte på med p&p, men kanske med c#. 

Har ni funderat på (säg) sex stycken kortlekar utan återläggning, med fler spelare som har hyfsat minne? 😅

Marilyn 3919
Postad: 18 apr 13:47

Jag har funderat på 52 kortlekar. Med ett kort var.

Jag trodde först det var ett enkelt problem, bara rita träddiagram, klart. Och i efterhand känns det inte så märkvärdigt. Men när jag var inne i det, var det krångligare och mer tidskrävande än jag hade trott, ett antal felräkningar på vägen. Sannolikheten betingat av att jag inte har par osv, hänsyn till ordning mm. Jag lärde mig en del på att försöka reda ut det.

naytte Online 6134 – Moderator
Postad: 18 apr 21:48 Redigerad: 18 apr 21:49

Det ser lovande ut, hörni!

Nu efter några miljoner rundor (typ 7 miljoner) har modellens vinstchans stigit till ca. 51 % (körde 1 miljon testrundor med epsilon = 0 och tog genomsnittet):

Din analytiska lösning verkar stämma, @Marilyn! :D

naytte Online 6134 – Moderator
Postad: 19 apr 17:49 Redigerad: 19 apr 18:07

Jag har tränat modellen nu några miljoner gånger (går ganska långsamt så jag skulle tippa på endast 20 milj. hittills) och har extraherat datan modellen har hittills.

Det verkar som om även din strategi (om när man ska gissa vad) stämmer, @Marilyn! (däremot anser modellen att man har bättre vinstchans om man gissar jämnt med paret (8,2), tror den behöver några miljoner rundor till på sig).

Här är några exempel på den bästa strategin hittills för olika par av kort som spelare (i de fall man har par spelar gissningen givetvis ingen roll):


Tillägg: 19 apr 2025 18:04

Jag tänker visualisera den här datan och återkomma, t.ex. se hur "sant" det är hittills att u+u -> [j är bästa gissningen]

Marilyn 3919
Postad: 19 apr 19:13 Redigerad: 19 apr 19:15

För dokumentationens skull :) Hoppas det blev rätt papper.


Marilyn 3919
Postad: 19 apr 20:45 Redigerad: 19 apr 22:34

Just det, det blev ju mycket enklare! Jäkla betingningar.

 

Om du sitter med u+u (ej par) så finns det 22 u och 28 j kvar.

Då är sh (vinst om jag gissar summa U) = 16/50

Det ska inte jämföras med sh (förlust om jag gissar U)  = 34/50, utan med

sh(vinst om jag gissar J) = 28/50

 

Om du sitter med u+j eller j+u så är

sh(vinst om du gissar U) = 24/50

sh(vinst om du gissar J) = 20/50

 

Om du sitter med j+j så är

sh(vinst om du gissar U) = 24/50

sh(vinst om du gissar J) = 20/50

 

Så har du u+u ska du gissa summa J. I övriga fall ska du gissa U.

 

I ditt fall (8, 2) så blir det vinst på alla 24 udda kort och förlust på de övriga om du gissar U.

Sh (vinst om du gissar U) = 0,48

Om du gissar J så vinner du på alla j-kort utom 2 och 8 och förlorar på de övriga.

Sh (vinst om du gissar J) = 0,40.

 

För detta resonemang behöver man inte mitt stora träd och långa beräkningar.

Det luriga är att man gärna ställer

sh(vinst om jag gissar U) mot sh(förlust om jag gissar U).

Men det intressanta för mitt val är

sh(vinst om jag gissar U) mot sh(vinst om jag gissar J).

naytte Online 6134 – Moderator
Postad: 20 apr 00:28 Redigerad: 20 apr 00:32

Nu har  jag låtit datorn tugga några miljoner episoder till och har sänkt modellens "learning rate" över tid (för att minimera störningar från slumpen i min data) och det kan nog knappt bli bättre än så här:

EDIT:

VI BÖRJAR NÄRMA OSS :D

Marilyn 3919
Postad: 20 apr 03:16

Ja, det finns ju flera sannolikheter att beräkna.

Dels ska du avgöra om du ska spela spelet eller inte. Har du mer eller mindre än 50 & chans att vinna?

Om du spelar, så är nästa fråga: ska du gissa på U eller J? Om du gissar innan du sett dina kort så ska du välja U och har i så fall sh 0,4816.att vinna. Om du gissar när du har sett korten så har du redan cashat in en viss matematisk vinst som inte påverkas av din gissning, och du ska göra bästa val av U eller J utifrån korten du tittar på. Det var min sista beräkning – betingat av att du inte tittar på ett par, vad är vinstsh vid val av U eller J?

 

Som någon matematiker sa, hjärnan är hjälpligt konstruerad för att hantera krångliga problem inom geometri, analys och algebra, men inte ens för skenbart enkla shproblem. Märkligt att en så enkel situation kan bli så krånglig att bena upp. Man måste verkligen formulera premisserna glasklart för den sh man beräknar.

naytte Online 6134 – Moderator
Postad: 21 apr 02:15 Redigerad: 21 apr 12:19

Nu har jag skrivit om min kod en aning och har tränat en modell som är så nära perfekt jag kommer komma med tanke på att slumpen är ganska stor. Den ger följande strategi efter extraherande av data:

Vi ser en liten anomali vid paret (6, 14) som egentligen borde mappas mot U. Här är för övrigt koden jag har skrivit om någon är intresserad:

Actions.py
from enum import Enum

class Action(Enum):
    GUESS_EVEN = 0
    GUESS_ODD = 1
Cards.py
import random
import enum


class CardSuites(enum.Enum):
    heart = 0x00
    spades = 0x01
    clubs = 0x02
    diamonds = 0x03


class CardValues(enum.Enum):
    val_1 = 1
    val_2 = 2
    val_3 = 3
    val_4 = 4
    val_5 = 5
    val_6 = 6
    val_7 = 7
    val_8 = 8
    val_9 = 9
    val_10 = 10
    val_A = 11
    val_K = 12
    val_Q = 13
    val_Kn = 14


class Card:

    def __init__(self, suite: CardSuites, value: CardValues):
        self.suite: CardSuites = suite
        self.value: CardValues = value

    def get_card_value(self) -> int:
        return self._internal_value_to_card_value()

    def _internal_value_to_card_value(self) -> int:
        if self.value == CardValues.val_10:
            return 10

        if self.value == CardValues.val_Q:
            return 12

        if self.value == CardValues.val_K:
            return 13

        if self.value == CardValues.val_Kn:
            return 11

        if self.value == CardValues.val_A:
            return 14

        return self.value.value

    def __repr__(self):
        val = self._internal_value_to_card_value()
        return "{0} - {1}".format(val, self.suite)



class Deck:

    def __init__(self):
        self.cards = []
        for suite in CardSuites:
            for value in CardValues:
                if value == CardValues.val_1:
                    continue
                self.cards.append(Card(suite, value))

    def shuffle(self):
        shuffled_deck: list[Card] = self.cards.copy()
        random.shuffle(shuffled_deck)
        return shuffled_deck
GameEnvironment.py
from Actions import Action
from Cards import Deck

class GameEnv:
    def __init__(self):
        self.reset()

    def reset(self):
        self.deck = Deck().shuffle()
        self.player_hand = [self.deck.pop(), self.deck.pop()]
        self.dealer_card = self.deck.pop()
        self.reward = 0
        return self._get_observation()

    def _get_observation(self):
        return tuple(card.get_card_value() for card in self.player_hand)

    def step(self, action: Action):

        if self.player_hand[0].get_card_value() == self.player_hand[1].get_card_value():
            self.reward = 2
            return self._get_observation(), self.reward, {"reason: ": "player pair"}

        total = sum(card.get_card_value() for card in self.player_hand + [self.dealer_card])
        is_even = total % 2 == 0

        dealer_val = self.dealer_card.get_card_value()
        player_vals = [card.get_card_value() for card in self.player_hand]

        if dealer_val in player_vals:
            self.reward = -1
            return self._get_observation(), self.reward, {"reason: ": "dealer pair"}

        if (action == Action.GUESS_EVEN and is_even) or (action == Action.GUESS_ODD and not is_even):
            self.reward = 1
            return self._get_observation(), self.reward, {"reason: ": "correct guess"}
        else:
            self.reward = -1
            return self._get_observation(), self.reward, {"reason: ": "incorrect guess"}
Agent.py
import random
from Actions import Action
from collections import defaultdict
import pickle

class QLearningAgent:
    def __init__(self, epsilon = 0.0, alpha = 0.0001): #välj epsilon och alpha efter behov
        self.q_table = defaultdict(lambda: {action: 0.0 for action in Action})
        self.epsilon = epsilon
        self.alpha = alpha

    def choose_action(self, state):
        if random.random() < self.epsilon:
            return random.choice(list(Action))
        else:
            actions = self.q_table[state]
            return max(actions, key=actions.get)

    def learn(self, state, action, reward):
        old_q = self.q_table[state][action]
        new_q = old_q + self.alpha * (reward - old_q)
        self.q_table[state][action] = new_q

    def save_q_table(self, filename="q_table.pkl"):
        with open(filename, "wb") as f:
            pickle.dump(dict(self.q_table), f)

    def load_q_table(self, filename="q_table.pkl"):
        with open(filename, "rb") as f:
            data = pickle.load(f)
            self.q_table = defaultdict(lambda: {action: 0.0 for action in Action}, data)
main.py
from Agent import QLearningAgent
from GameEnvironemnt import GameEnv

env = GameEnv()
agent = QLearningAgent()

try:
    agent.load_q_table()
    print("Loaded saved Q-table")
except FileNotFoundError:
    print("No saved Q-table, starting fresh...")

num_episodes = 1000000
wins = 0

for episode in range(num_episodes):
    state = env.reset()
    action = agent.choose_action(state)
    observation, reward, info = env.step(action)

    if reward > 0:
        wins += 1

    agent.learn(state, action, reward)

agent.save_q_table()
print(f"Win rate: {wins/num_episodes}")

Jag vill även tacka ChatGPT för scriptet för den fina grafiken. Den använde libb jag inte ens visste fanns. Kommer med ett git-repo imorgon.


Tillägg: 21 apr 2025 02:16

Du hade med andra ord helt rätt, @Marilyn. Snyggt!

Bedinsis 3207
Postad: 21 apr 09:44
Marilyn skrev:

Dels ska du avgöra om du ska spela spelet eller inte. Har du mer eller mindre än 50 & chans att vinna?

Om alternativet att välja att inte spela för de givna korten finns är uppgiften superenkel: kontrollera om du har fått ett par eller inte. Om inte: spela inte; om du har ett par: spela. 3/51 av alla rundor kommer du spela och garanterat vinna.

Jag trodde det var tydligt men jag tänker givetvis att man gör sin insats innan man får sina kort.

Svara
Close