<jupyter_start><jupyter_text>In the following notebook, you will see two games run, both with AIPlayerPerfectNoMemory. In game 0 (or variable 'g'), a total of 1 million rounds are played. In game 1 (or variable 'g1'), 1,000 rounds are played. This is in order to compare the two. Analysis can be found at the bottom of the notebook. :)<jupyter_code>from mynotebook import *

# import all players from ai_simple3.py
from ai_perfect4 import * 
# NOTE: you'll need to re-run this import to use any changes 
# made in that file or files it depends on.  If you can't
# see them, try restarting your notebook kernel.

# other imports:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import math

# jupyter notebook specific setup
%matplotlib inline


### THIS GAME IS WITH 1 MILLION ROUNDS!!!! GOOD FOR FINDING "TRUE" EG!!!!!!!

## shared experimental parameters ##
bankroll = 50000    # starting player balance
min_bet = 1         # min allowed bet
num_deck = 2        # number decks in shoe
inf_deck = True     # True if using infinte deck
seed = None         # seed value to assign before every run
#num_round = 1000      # number rounds to play
#num_round = 10**3
#num_round = 10**4
#num_round = 10**5
num_round = 10**6

## other parameters ##
# have Game print a reasonable number of rounds:
print_n = 1 if num_round <= 20 else max(1, math.ceil(num_round/math.log2(num_round)))
#print_b = 0         # suppess round printing entirely


### Initialize the player
p = AIPlayerPerfectNoMemory(bankroll, min_bet)

###  you do not need to change anything below this line ###
# Creates and runs a game using Player p and the common settings 
print('\nSetting up a game with', p.__class__.__name__)
random.seed(seed)
d = DealerH17()
shoe = Shoe(num_deck, infinite=inf_deck)
g = Game(d, p, shoe, num_round, print_n=print_n)
g.playerClass = p.__class__.__name__ # Name of AIPlauer class that was run
print('Starting..')
g.run()
print('Finished')
g.summary()

### Initilizing the AIPlayerS17
#let's run some experiments!!!! 
## shared experimental parameters ##
bankroll = 50000    # starting player balance
min_bet = 1         # min allowed bet
num_deck = 2        # number decks in shoe
inf_deck = True     # True if using infinte deck
seed = None         # seed value to assign before every run
#num_round = 1000      # number rounds to play
num_round = 10**3
#num_round = 10**4
#num_round = 10**5
#num_round = 10**6

## other parameters ##

### THIS GAME IS ONLY WITH 1,000 ROUNDS!!!! BETTER FOR LOOKING AT "MEASURED" EG!!!

# have Game print a reasonable number of rounds:
print_n = 1 if num_round <= 20 else max(1, math.ceil(num_round/math.log2(num_round)))
#print_b = 0         # suppess round printing entirely


### Initialize the player
p = AIPlayerPerfectNoMemory(bankroll, min_bet)

###  you do not need to change anything below this line ###
# Creates and runs a game using Player p and the common settings 
print('\nSetting up a game with', p.__class__.__name__)
random.seed(seed)
d = DealerH17()
shoe = Shoe(num_deck, infinite=inf_deck)
g1 = Game(d, p, shoe, num_round, print_n=print_n)
g1.playerClass = p.__class__.__name__ # Name of AIPlauer class that was run
print('Starting..')
g1.run()
print('Finished')
g1.summary()

### Initilizing the AIPlayerS17
# Create a pandas "game" Dataframe to hold game results

### FOR 1 MILLION GAME RESULTS!

g.df = game2gdf(g)  # add the dataframe as an attribute to the game.
g.df[:20] # print out first three rounds

# Create a pandas "game" Dataframe to hold game results

### FOR 1,000 GAME RESULTS

g1.df = game2gdf(g1)  # add the dataframe as an attribute to the game.
g1.df[:20] # print out first three rounds
##computes some helpful stats

### FOR 1 MILLION GAME RESULTS!

g.df.describe()
##computes some helpful stats

### FOR 1,000 GAME RESULTS!

g1.df.describe()
## EQUITY CURVE FOR 1 MILLION GAME RESULTS!
g.df[['final_bankroll']].plot(legend=False, grid=True)
plt.title(g.playerClass)
plt.xlabel('Round')
plt.ylabel('Bankroll')
plt.show()
## EQUITY CURVE FOR 1,000 GAME RESULTS!
g1.df[['final_bankroll']].plot(legend=False, grid=True)
plt.title(g.playerClass)
plt.xlabel('Round')
plt.ylabel('Bankroll')
plt.show()
## FOR 1 MILLION GAME RESULTS!!!

## Prints out mean gain & confidence interval
m = g.df['gain'].mean()
sem = g.df['gain'].std()/(g.df['gain'].count())**.5
c_low = m-1.96*sem
c_high = m+1.96*sem

print('EG = {:3.6f}, 95% confidence interval = [{:3.6f},{:3.6f})'.format(m, c_low, c_high))
## FOR 1,000 GAME RESULTS!!!

## Prints out mean gain & confidence interval
m = g1.df['gain'].mean()
sem = g1.df['gain'].std()/(g1.df['gain'].count())**.5
c_low = m-1.96*sem
c_high = m+1.96*sem

print('EG = {:3.6f}, 95% confidence interval = [{:3.6f},{:3.6f})'.format(m, c_low, c_high))
### FOR 1 MILLION GAME RESULTS!!!

## Prints out mean gain estimates!


print('Overall EG:')             
print('EGgivenALL = {:3.6f}, 95% confidence interval = [{:3.6f},{:3.6f})'.format(*estimate_EG_CI(g.df)))

print()
print('Round types available in current results: ', g.df['type'].unique())
print()

print('For all rounds where of dealer and/or player got a BJ:')
indBJ = g.df['type'].isin(['D_BJ', 'P_BJ', 'PD_BJ']) # logical index               
print('EGgivenBJ = {:3.6f}, 95% confidence interval = [{:3.6f},{:3.6f})'.format(*estimate_EG_CI(g.df[indBJ])))

print()

print('For all rounds where player got to use next_move:')
indHS = g.df['type'].isin(['P_Bust', 'D_Bust', 'P_Won', 'P_Lost', 'PD_Draw']) # logical index
print('EGgivenBJ = {:3.6f}, 95% confidence interval = [{:3.6f},{:3.6f})'.format(*estimate_EG_CI(g.df[indBJ])))
### FOR 1,000 GAME RESULTS!!!

## Prints out mean gain estimates!


print('Overall EG:')             
print('EGgivenALL = {:3.6f}, 95% confidence interval = [{:3.6f},{:3.6f})'.format(*estimate_EG_CI(g1.df)))

print()
print('Round types available in current results: ', g1.df['type'].unique())
print()

print('For all rounds where of dealer and/or player got a BJ:')
indBJg1 = g1.df['type'].isin(['D_BJ', 'P_BJ', 'PD_BJ']) # logical index               
print('EGgivenBJ = {:3.6f}, 95% confidence interval = [{:3.6f},{:3.6f})'.format(*estimate_EG_CI(g1.df[indBJ])))

print()

print('For all rounds where player got to use next_move:')
indHSg1 = g1.df['type'].isin(['P_Bust', 'D_Bust', 'P_Won', 'P_Lost', 'PD_Draw']) # logical index
print('EGgivenBJ = {:3.6f}, 95% confidence interval = [{:3.6f},{:3.6f})'.format(*estimate_EG_CI(g1.df[indBJ])))
## FOR 1 MILLION GAME RESULTS!
## We like pie!

fig, ax = plt.subplots()
g.df['type'].value_counts().plot.pie(colors=['coral','red','orange','gold','olivedrab','green','lightseagreen',
                                           'darkslategray','navy','darkviolet'], autopct='%1.3f%%', pctdistance=.9)
plt.title(g.playerClass)
ax.axis('equal')
plt.show()
## FOR 1,000 GAME RESULTS!
## We like pie!

fig, ax = plt.subplots()
g1.df['type'].value_counts().plot.pie(colors=['coral','red','orange','gold','olivedrab','green','lightseagreen',
                                           'darkslategray','navy','darkviolet'], autopct='%1.3f%%', pctdistance=.9)
plt.title(g1.playerClass)
ax.axis('equal')
plt.show()
## FOR 1 MILLION GAME RESULTS
PofBJ = indBJ.mean() # Prob of BJ
PofHS = indHS.mean() # Prob of player getting to use theit hit-stand stratgy
EGgivenALL = g.df['gain'].mean() # Overall expected Gain
EGgivenBJ = g.df['gain'][indBJ].mean() # EG given BJ occured
EGgivenHS = g.df['gain'][indHS].mean() # EG given hit-stand occured

# Because a blackjack occurs or the player gets to hit-stand
# P_BJ + P_HS must some to 1, let's check this:
print("Sanity check = ", PofBJ+PofHS) 
# Let's examine the expected gains for each case, weighted by the probability they occured:
print('PofBJ*EgivenBJ = {:3.6f}, PofHS*EGgivenHS ={:3.6f}'.format(PofBJ*EGgivenBJ, PofHS*EGgivenHS))
# Finally let's compare the weighted sum with the overall game EG estimate.
print('PofBJ*EgivenBJ + PofHS*EGgivenHS ={:3.6f}, EG = {:3.6f}'.format(PofBJ*EGgivenBJ + PofHS*EGgivenHS,EGgivenALL))       
## FOR 1,000 GAME RESULTS
PofBJ = indBJg1.mean() # Prob of BJ
PofHS = indHSg1.mean() # Prob of player getting to use theit hit-stand stratgy
EGgivenALL = g1.df['gain'].mean() # Overall expected Gain
EGgivenBJ = g1.df['gain'][indBJ].mean() # EG given BJ occured
EGgivenHS = g1.df['gain'][indHS].mean() # EG given hit-stand occured

# Because a blackjack occurs or the player gets to hit-stand
# P_BJ + P_HS must some to 1, let's check this:
print("Sanity check = ", PofBJ+PofHS) 
# Let's examine the expected gains for each case, weighted by the probability they occured:
print('PofBJ*EgivenBJ = {:3.6f}, PofHS*EGgivenHS ={:3.6f}'.format(PofBJ*EGgivenBJ, PofHS*EGgivenHS))
# Finally let's compare the weighted sum with the overall game EG estimate.
print('PofBJ*EgivenBJ + PofHS*EGgivenHS ={:3.6f}, EG = {:3.6f}'.format(PofBJ*EGgivenBJ + PofHS*EGgivenHS,EGgivenALL))       
## FOR 1 MILLION GAME RESULTS
## Invidiual outcome counts
ax = g.df['type'].value_counts().plot(kind='bar',grid=True)
ax.set_ylabel("Count");
## FOR 1,000 GAME RESULTS
## Invidiual outcome counts
ax = g1.df['type'].value_counts().plot(kind='bar',grid=True)
ax.set_ylabel("Count");
## FOR 1 MILLION GAME RESULTS!
## Outcome probability estimates
P = (g.df['type'].value_counts()/len(g.df))
ax=P.plot(kind='bar',grid=True)
ax.set_ylabel("Probability");
# check
P
## FOR 1,000 GAME RESULTS!
## Outcome probability estimates
P = (g1.df['type'].value_counts()/len(g1.df))
ax=P.plot(kind='bar',grid=True)
ax.set_ylabel("Probability");
# check
P
## FOR 1 MILLION GAME RESULTS!
## Gain estimates

EGgiven = g.df.groupby(['type'])['gain'].mean() 
EG = P*EGgiven
ax = EG.plot(kind='bar',grid=True)
ax.set_ylabel("Gain")
# Checks:
print(EG)
sum(P), EG.sum(), g.df['gain'].mean()
## FOR 1,000 GAME RESULTS!
## Gain estimates

EGgiven = g1.df.groupby(['type'])['gain'].mean() 
EG = P*EGgiven
ax = EG.plot(kind='bar',grid=True)
ax.set_ylabel("Gain")
# Checks:
print(EG)
sum(P), EG.sum(), g1.df['gain'].mean()<jupyter_output>D_BJ      -0.0440
D_Bust     0.2340
PD_BJ      0.0000
PD_Draw    0.0000
P_BJ       0.1014
P_Bust    -0.1440
P_Lost    -0.2860
P_Won      0.1590
dtype: float64
{'fraction_non_alphanumeric': 0.1587129784512447, 'fraction_numerical': 0.030797992718685427, 'mean_word_length': 4.494054054054054, 'pattern_counts': {'":': 0, '<': 6, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '1', 'dir': 'jupyter-structured-clean-dedup', 'id': '629595', 'license': 'MIT', 'n_tokens_mistral': 4018, 'n_tokens_neox': 3698, 'n_words': 1052, 'path': 'ai_perfect4.ipynb', 'repo_name': 'eweiss545/BlackJack', 'size': '10163'}