Compare commits

...

3 Commits

  1. 19
      v3/game.py
  2. 8
      v3/gators.py
  3. 16
      v3/inninggenerator.py
  4. 23
      v3/logsetup.py
  5. 10
      v3/players.py
  6. 2
      v3/requirements.txt
  7. 121
      v3/roll.py
  8. 20
      v3/simulator.py

19
v3/game.py

@ -3,7 +3,7 @@ import logging
from players import Team from players import Team
from gators import Congregation from gators import Congregation
from generators import InningGenerator from inninggenerator import InningGenerator
from states import GameState, TeamState from states import GameState, TeamState
@ -18,14 +18,12 @@ class Game(object):
""" """
def __init__(self, config, redteam, blueteam, congregation): def __init__(self, config, redteam, blueteam, congregation):
logger.warning("...") logger.warning("\n\n")
logger.warning("...")
logger.warning("---------------------- STARTING GAME -------------------------") logger.warning("---------------------- STARTING GAME -------------------------")
logger.warning("WARNING level: on") logger.warning("WARNING level: on")
logger.info("INFO level: on") logger.info("INFO level: on")
logger.debug("DEBUG level: on") logger.debug("DEBUG level: on")
logger.warning("...") logger.warning("\n\n")
logger.warning("...")
self.config = config self.config = config
@ -50,10 +48,17 @@ class Game(object):
logger.warning('====================================') logger.warning('====================================')
logger.warning('============ TOP INNING ============') logger.warning('============ TOP INNING ============')
logger.warning('====================================') logger.warning('====================================')
top_inning = InningGenerator.generate_half(self.config, self.state, True) t1_w, t1_r = InningGenerator.generate_half(self.config, self.state, True)
logger.warning('====================================') logger.warning('====================================')
logger.warning('============ BOT INNING ============') logger.warning('============ BOT INNING ============')
logger.warning('====================================') logger.warning('====================================')
bottom_inning = InningGenerator.generate_half(self.config, self.state, False) t2_w, t2_r = InningGenerator.generate_half(self.config, self.state, False)
logger.warning('====================================')
logger.warning('=========== GAME SUMMARY ===========')
logger.warning('====================================')
state = self.state
logger.info(f"{state.team1.name}: {state.state1.wickets} / {state.state1.runs} - {len(t1_r)}.{len(t1_r[-1])}")
logger.info(f"{state.team2.name}: {state.state2.wickets} / {state.state2.runs} - {len(t2_r)}.{len(t2_r[-2])}")

8
v3/gators.py

@ -21,7 +21,7 @@ class Gator(object):
def __init__(self): def __init__(self):
self.id = str(uuid.uuid4()) self.id = str(uuid.uuid4())
self.attr = {} self.attr = {}
self.attr['agg'] = random.randint(1,5) self.attr['agg'] = 3 # random.randint(1,5)
self.attr['rea'] = random.randint(1,5) self.attr['rea'] = 3 # random.randint(1,5)
self.attr['rxn'] = random.randint(1,5) self.attr['rxn'] = 3 # random.randint(1,5)
self.attr['con'] = random.randint(1,5) self.attr['con'] = 3 # random.randint(1,5)

16
v3/generators.py → v3/inninggenerator.py

@ -38,10 +38,6 @@ class InningGenerator(object):
final_runs = [] final_runs = []
final_wickets = [] final_wickets = []
# Keep running track of runs/wickets
current_runs = batting_state.runs
current_wickets = batting_state.wickets
team_name = batting_team.name team_name = batting_team.name
opi = config['OVERS_PER_INNING'] opi = config['OVERS_PER_INNING']
@ -57,7 +53,7 @@ class InningGenerator(object):
# Increment runs/wickets and update pokers # Increment runs/wickets and update pokers
if outcome > 0: if outcome > 0:
# Outcome is runs for the player # Outcome is runs for the player
current_runs += outcome batting_state.runs += outcome
this_over.append(outcome) this_over.append(outcome)
this_wickets.append(0) this_wickets.append(0)
if outcome%2 == 1: if outcome%2 == 1:
@ -69,8 +65,8 @@ class InningGenerator(object):
elif outcome < 0: elif outcome < 0:
# Outcome is wickets # Outcome is wickets
current_wickets += 1 batting_state.wickets += 1
this_over.append(-1) this_over.append(0)
this_wickets.append(1) this_wickets.append(1)
# If we have reached maximum number of wickets, this will be None, check happens below # If we have reached maximum number of wickets, this will be None, check happens below
batting_state.pokers[0] = batting_team.get_next_player() batting_state.pokers[0] = batting_team.get_next_player()
@ -82,11 +78,11 @@ class InningGenerator(object):
# Determine if the side should end # Determine if the side should end
if cls.check_runs_end_over(config, batting_state, bowling_state, top): if cls.check_runs_end_over(config, batting_state, bowling_state, top):
logger.warning(f"{team_name}: Over {current_over+1}: Game ends due to {team_name} getting required runs!") logger.warning(f"{team_name}: Over {iover+1}: Game ends due to {team_name} getting required runs!")
batting_state.done = True batting_state.done = True
if cls.check_wickets_end_over(config, batting_state, bowling_state, top): if cls.check_wickets_end_over(config, batting_state, bowling_state, top):
logger.warning(f"{team_name}: Over {current_over+1}: Inning ends due to {team_name} getting maximum wickets!") logger.warning(f"{team_name}: Over {iover+1}: Inning ends due to {team_name} getting maximum wickets!")
batting_state.done = True batting_state.done = True
if batting_state.done: if batting_state.done:
@ -97,7 +93,7 @@ class InningGenerator(object):
logger.info("---------------") logger.info("---------------")
logger.info(f"{team_name}: This Over ({iover+1}): {sum(this_wickets)} / {' '.join([str(z) if z>=0 else 'W' for z in this_over])}") logger.info(f"{team_name}: This Over ({iover+1}): {sum(this_wickets)} / {' '.join([str(z) if z>=0 else 'W' for z in this_over])}")
logger.info(f"{team_name}: Cumulative: {current_wickets} / {current_runs} - {iover+1}") logger.info(f"{team_name}: Cumulative: {batting_state.wickets} / {batting_state.runs} - {iover+1}")
logger.info(f"--------------") logger.info(f"--------------")
if batting_state.done: if batting_state.done:

23
v3/logsetup.py

@ -0,0 +1,23 @@
import logging
# Set basic universal log options
# (level should be WARNING INFO DEBUG)
loglevel = logging.DEBUG
logging.basicConfig(format='', level=logging.WARNING)
root_logger = logging.getLogger()
root_logger.handlers = []
# Create gp logger and add handlers
### logger = logging.Logger('gp')
logger = logging.getLogger('gp')
logger.setLevel(loglevel)
fh = logging.FileHandler('output.log')
fh.setLevel(loglevel)
logger.addHandler(fh)
sh = logging.StreamHandler()
sh.setLevel(loglevel)
logger.addHandler(sh)

10
v3/players.py

@ -24,7 +24,7 @@ class Team(object):
""" """
Check if there is a next player to return Check if there is a next player to return
""" """
return self.index >= len(self.roster) return self.index < len(self.roster)
def get_next_player(self): def get_next_player(self):
""" """
@ -40,7 +40,7 @@ class Player(object):
def __init__(self): def __init__(self):
self.id = str(uuid.uuid4()) self.id = str(uuid.uuid4())
self.attr = {} self.attr = {}
self.attr['agg'] = random.randint(1,5) self.attr['agg'] = 3 # random.randint(1,5)
self.attr['rea'] = random.randint(1,5) self.attr['rea'] = 3 # random.randint(1,5)
self.attr['rxn'] = random.randint(1,5) self.attr['rxn'] = 3 # random.randint(1,5)
self.attr['con'] = random.randint(1,5) self.attr['con'] = 3 # random.randint(1,5)

2
v3/requirements.txt

@ -0,0 +1,2 @@
numpy
scipy

121
v3/roll.py

@ -1,14 +1,127 @@
import numpy as np
import random import random
import logging
from scipy.stats import beta
logger = logging.getLogger('gp')
class Roll(object): class Roll(object):
"""
Provides class methods to perform various rolls using players and gators.
Uses beta functions under the hood to generate random outcomes.
"""
@classmethod
def random_sample_beta_inv_cdf(cls, E, a):
"""
Sample a beta inverse CDF with expectation E and alpha param a.
The values of E and alpha will fix the value of beta.
"""
y_in = random.random()
b = a * (1.0/E - 1.0)
# Use the percent point function - inverse CDF
x_out = beta.ppf(y_in, a, b)
x = y_in # This is the input random number, uniform between 0-1
y = x_out # This is the output weighted random number
return (x, y)
@classmethod @classmethod
def attr_roll(cls, attr_lab, player, gator): def attr_roll(cls, attr_lab, player, gator):
player_attr = player.attr[attr_lab] """
gator_attr = gator.attr[attr_lab] Use player/gator attributes to construct a beta function, and sample it randomly.
Return the player and gator rolls (bounded between 0-1 inclusive).
"""
nstars = 5
# Map star ratings to new spaces
# Expected outcome
player_attr_min = 0.25
player_attr_max = 0.75
player_attr_space = np.linspace(player_attr_min, player_attr_max, nstars)
# Consistency (alpha param of beta distribution)
player_con_space = np.logspace(-0.5, 0.5, nstars)
# Expected outcome
gator_attr_min = 0.25
gator_attr_max = 0.75
gator_attr_space = np.linspace(gator_attr_min, gator_attr_min, nstars)
# Consistency
gator_con_space = np.logspace(-0.5, 0.5, nstars)
# Get attribute
pa = player.attr[attr_lab]
ga = gator.attr[attr_lab]
# Get consistency
pc = player.attr['con']
gc = gator.attr['con']
# Transform to get beta function parameters (expectation E, alpha)
p_E = player_attr_space[pa-1]
g_E = gator_attr_space[ga-1]
p_alpha = player_con_space[pc-1]
g_alpha = gator_con_space[gc-1]
_, p_outcome = cls.random_sample_beta_inv_cdf(p_E, p_alpha)
_, g_outcome = cls.random_sample_beta_inv_cdf(g_E, g_alpha)
return (p_outcome, g_outcome)
@classmethod @classmethod
def roll(cls, player, gator): def roll(cls, player, gator):
outcomes = [-3, -2, -1, 0, 1, 4, 6] """
return random.choice(outcomes) Given a player and a gator, run the various rolls and find an outcome.
"""
# First roll requires gator or player wins both aggressiveness and reach rolls
agg = cls.attr_roll('agg', player, gator)
rea = cls.attr_roll('rea', player, gator)
rxn = cls.attr_roll('rxn', player, gator)
agg_diff = agg[0] - agg[1]
rea_diff = rea[0] - rea[1]
rxn_diff = rxn[0] - rxn[1]
if agg_diff > 0 and rea_diff > 0:
# Player won
if rxn_diff < 0:
# Player won but gator got reversal
logger.debug(f"Player flinched!")
return 0
else:
# Outcome: runs
diff = rxn[0] - rxn[1]
if diff > 0.8:
logger.debug(f"Gator got slapped!")
return 6
elif diff > 0.5:
logger.debug(f"Gator got booped in the snoot!")
return 4
else:
logger.debug(f"Gator got poked!")
return 1
elif agg_diff < 0 and rea_diff < 0:
# Gator won
if rxn_diff > 0:
# Gator won but player got reversal
logger.debug(f"Gator flinched!")
return 0
else:
# Outcome: wickets
if abs(rxn_diff) > 0.8:
logger.debug(f"Player was eaten by gator!")
return -3
elif abs(rxn_diff) > 0.5:
logger.debug(f"Player's arm got chomped by the gator!")
return -2
elif abs(rxn_diff) > 0.2:
logger.debug(f"Player's finger got chomped by the gator!")
return -1
else:
logger.debug(f"Player escaped!")
return 0
else:
logger.debug(f"Nothing happened!")
return 0

20
v3/simulator.py

@ -1,38 +1,26 @@
import logging import logging
import random import random
import logsetup
from config import Config from config import Config
from players import Team from players import Team
from gators import Congregation from gators import Congregation
from game import Game from game import Game
# 1 = critical info logger = logging.getLogger('gp')
# 2 = all info
# 3 = debug
LOG_LEVEL = 3
loglevels = [logging.WARNING, logging.INFO, logging.DEBUG]
logging.basicConfig(format='', level=logging.DEBUG)
logger = logging.Logger('gp')
logger.addHandler(logging.StreamHandler())
logger.addHandler(logging.FileHandler('output.log'))
class GameSimulator(object): class GameSimulator(object):
def simulate(self): def simulate(self):
logger.warning("...") logger.warning("\n\n")
logger.warning("...")
logger.warning("---------------------- STARTING SIMULATOR -------------------------") logger.warning("---------------------- STARTING SIMULATOR -------------------------")
logger.warning("logger warning level: on") logger.warning("logger warning level: on")
logger.info("logger info level: on") logger.info("logger info level: on")
logger.debug("logger debug level: on") logger.debug("logger debug level: on")
logger.warning("...") logger.warning("\n\n")
logger.warning("...")
config_dict = dict( config_dict = dict(
PLAYERS_PER_SIDE = 11, PLAYERS_PER_SIDE = 11,

Loading…
Cancel
Save