Compare commits
3 Commits
35a70fddd7
...
4a898a321f
Author | SHA1 | Date |
---|---|---|
Charles Reid | 4a898a321f | 3 years ago |
Charles Reid | ee86bf307a | 3 years ago |
Charles Reid | ffe67789c9 | 3 years ago |
8 changed files with 173 additions and 46 deletions
@ -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) |
@ -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 |
||||||
|
Loading…
Reference in new issue