began work on tuning the stat weights for various actions
This commit is contained in:
parent
e647a33499
commit
de46f85dfe
68
SimHoc.py
68
SimHoc.py
|
@ -1,4 +1,5 @@
|
|||
import os, player, tweepy, twitHandler, time
|
||||
import os, player, tweepy, twitHandler, time, skillContests, random
|
||||
from attributes import normalDis
|
||||
|
||||
if __name__ == "__main__":
|
||||
#for name in ["Vivi", "Artemis", "Laika", "Sharks", "Dragons", "Melua", "Sabriina", "Jorts (Buttered)", "Jorts (Unbuttered)"]:
|
||||
|
@ -8,16 +9,57 @@ if __name__ == "__main__":
|
|||
# print(atr)
|
||||
# print("----------")
|
||||
|
||||
twitter = twitHandler.TwitHandler()
|
||||
if os.path.exists(os.path.join("Data", "lastID.twt")):
|
||||
with open(os.path.join("Data", "lastID.twt")) as idFile:
|
||||
lastID = idFile.readline().strip()
|
||||
else:
|
||||
lastID = 0
|
||||
atkPlayer = player.Player("Vivi")
|
||||
defPlayer = player.Player("Artemis")
|
||||
for plyr in [atkPlayer, defPlayer]:
|
||||
print(f"{plyr.name}:")
|
||||
for atr in plyr.attributes:
|
||||
print(atr)
|
||||
print("----------")
|
||||
|
||||
|
||||
def skillContest(atkPlayer:player.Player, defPlayer:player.Player, params:skillContests.SkillContestParams):
|
||||
"""Contests the two players with the given stats and stat weights. Returns True on offensive success."""
|
||||
if params.override is not None:
|
||||
print(params.override)
|
||||
else:
|
||||
atkValue = 0
|
||||
defValue = 0
|
||||
for attr, weight in params.atkStats:
|
||||
atkValue += 95 * weight/100
|
||||
for attr, weight in params.defStats:
|
||||
defValue += 35 * weight/100
|
||||
|
||||
print(f"Attack: {atkValue}")
|
||||
print(f"Defense:{defValue}")
|
||||
|
||||
success = 0
|
||||
total = 5000
|
||||
|
||||
for i in range(0,5000):
|
||||
atkRoll = normalDis(atkValue, atkValue/2, 0)
|
||||
defRoll = normalDis(defValue, defValue/2, 0)
|
||||
success += (atkRoll-defRoll) > 0
|
||||
print(f"Success {round(success/total*100,3)}% of the time.")
|
||||
|
||||
defAction = player.DefAction.Poke
|
||||
for atkAction in [player.AtkAction.SkateF]:
|
||||
params = skillContests.SkillContestParams(atkAction, defAction, skillContests.Situations.EvenStrength)
|
||||
skillContest(atkPlayer, defPlayer, params)
|
||||
|
||||
#twitter = twitHandler.TwitHandler()
|
||||
#if os.path.exists(os.path.join("Data", "lastID.twt")):
|
||||
# with open(os.path.join("Data", "lastID.twt")) as idFile:
|
||||
# lastID = idFile.readline().strip()
|
||||
#else:
|
||||
# lastID = 0
|
||||
|
||||
#while True:
|
||||
# twitter.scanForMention(lastID)
|
||||
# time.sleep(30)
|
||||
# with open(os.path.join("Data", "lastID.twt")) as idFile:
|
||||
# lastID = idFile.readline().strip()
|
||||
|
||||
|
||||
#twitter.sendTextTweet(player.Player("Amogus").twitterString())
|
||||
|
||||
while True:
|
||||
twitter.scanForMention(lastID)
|
||||
time.sleep(30)
|
||||
with open(os.path.join("Data", "lastID.twt")) as idFile:
|
||||
lastID = idFile.readline().strip()
|
||||
#twitter.sendTextTweet(player.Player("Amogus").twitterString())
|
|
@ -23,6 +23,15 @@
|
|||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="attributes.py" />
|
||||
<Compile Include="game.py">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="skillContests.py">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="team.py">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="twitHandler.py">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
|
|
|
@ -76,13 +76,20 @@ class Attribute:
|
|||
|
||||
|
||||
|
||||
def normalDis(generator:random.Random, mean:float, stdDev:float, min:float=-math.inf, max:float=math.inf) -> float:
|
||||
"""Generates random number from normal distribution with given mean and standard deviation. Optionally takes min and max values."""
|
||||
def seededNormalDis(generator:random.Random, mean:float, stdDev:float, min:float=-math.inf, max:float=math.inf) -> float:
|
||||
"""Generates random number from seeded normal distribution with given mean and standard deviation. Optionally takes min and max values."""
|
||||
num = generator.gauss(mean, stdDev)
|
||||
while min > num or num > max:
|
||||
num = generator.gauss(mean, stdDev)
|
||||
return num
|
||||
|
||||
def normalDis(mean:float, stdDev:float, min:float=-math.inf, max:float=math.inf) -> float:
|
||||
"""Generates random number from normal distribution with given mean and standard deviation. Optionally takes min and max values."""
|
||||
num = random.gauss(mean, stdDev)
|
||||
while min > num or num > max:
|
||||
num = random.gauss(mean, stdDev)
|
||||
return num
|
||||
|
||||
#Attributes to generate
|
||||
#["sample name", mean, stdDev, min(optional), max(optional)]
|
||||
masterList = [
|
||||
|
@ -92,9 +99,9 @@ masterList = [
|
|||
["Strength", 40, 60, 0, 100], #power of slapshot/body checking (Defense)
|
||||
["Dexterity", 50, 25, 10, 100], #power of wrist shot/dekes (Forward)
|
||||
["Shot Accuracy", 40, 25, 10, 100], #accuracy on shots (Secondary/All Skaters)
|
||||
["Pass Accuracy", 60, 35, 0, 100], #does what you think it does (Defense)
|
||||
["Wisdom", 40, 50, 0, 100], #takes better shots/makes safer passes (Secondary/All)
|
||||
["Stickhandling", 50, 35, 0, 100], #dekes/checking (Secondary/All)
|
||||
["Pass Accuracy", 60, 20, 20, 100], #does what you think it does (Defense)
|
||||
["Wisdom", 60, 50, 0, 100], #takes better shots/makes safer passes (Secondary/All)
|
||||
["Stickhandling", 75, 20, 30, 100], #dekes/checking (Secondary/All) 35-95
|
||||
["Discipline", 75, 60, 0, 100], #Higher means less penalties
|
||||
["Intelligence", 50, 50, 0, 100], #Skill at positioning (as skater or goalie) (Secondary/All)
|
||||
["Constitution", 60, 20, 0, 100] #Stamina/injury resilience
|
||||
|
@ -111,5 +118,5 @@ def attributesFromName(name:str):
|
|||
generator.seed(name)
|
||||
atrs = [versionNumber] #in case of stat changes, record which number to use
|
||||
for template in masterList:
|
||||
atrs.append(Attribute(template[0], normalDis(generator, *template[1:])))
|
||||
atrs.append(Attribute(template[0], seededNormalDis(generator, *template[1:])))
|
||||
return atrs
|
63
game.py
Normal file
63
game.py
Normal file
|
@ -0,0 +1,63 @@
|
|||
import random, team, player
|
||||
from team import Team
|
||||
from player import Player, AtkAction, DefAction
|
||||
from skillContests import SkillContestParams, Situations
|
||||
|
||||
class Game(object):
|
||||
"""A game of hockey!"""
|
||||
|
||||
def __init__(self, awayTeam:Team, homeTeam:Team, threes:bool=False):
|
||||
self.away = awayTeam
|
||||
self.home = homeTeam
|
||||
|
||||
self.lineSize = 5
|
||||
if len(awayTeam.roster) != 10 or len(homeTeam.roster) != 10 or threes:
|
||||
self.lineSize = 3
|
||||
|
||||
self.goalieHome = self.home.chooseGoalie()
|
||||
self.goalieAway = self.away.chooseGoalie()
|
||||
|
||||
self.playerInPossession = None
|
||||
self.teamInPossession = None
|
||||
|
||||
self.skatersHome = [] #LW LD C RD RW
|
||||
self.skatersAway = []
|
||||
|
||||
self.penaltyBoxAway = []
|
||||
self.penaltyBoxHome = []
|
||||
self.pulledGoalieAway = False
|
||||
self.pulledGoalieHome = False
|
||||
|
||||
self.period = 1
|
||||
self.clock = 60*20 #clock will be given in seconds
|
||||
|
||||
self.eventLog = []
|
||||
|
||||
def defendingTeam(self):
|
||||
if teamInPossession == self.home:
|
||||
return self.away
|
||||
else:
|
||||
return self.home
|
||||
|
||||
def homeAttacking(self):
|
||||
return teamInPossession == self.home
|
||||
|
||||
def currentSituation(self):
|
||||
skatersH = self.lineSize + self.pulledGoalieHome - len(self.penaltyBoxHome)
|
||||
skatersA = self.lineSize + self.pulledGoalieAway - len(self.penaltyBoxAway)
|
||||
if self.teamInPossession == self.home:
|
||||
return Situations(skatersH - skatersA)
|
||||
else:
|
||||
return Situations(skatersA - skatersH)
|
||||
|
||||
def skillContest(self, atkPlayer:Player, defPlayer:Player, params:SkillContestParams):
|
||||
"""Contests the two players with the given stats and stat weights. Returns True on offensive success."""
|
||||
if params.override is not None:
|
||||
return params.override
|
||||
else:
|
||||
atkValue = 0
|
||||
defValue = 0
|
||||
for attr, weight in params.atkStats:
|
||||
atkValue += atkPlayer.getAttribute(attr) * weight/100
|
||||
for attr, weight in params.defStats:
|
||||
defValue += defPlayer.getAttribute(attr) * weight/100
|
30
player.py
30
player.py
|
@ -1,4 +1,5 @@
|
|||
import attributes
|
||||
from enum import Enum
|
||||
|
||||
class CreationError(Exception):
|
||||
pass
|
||||
|
@ -27,6 +28,12 @@ class Player(object):
|
|||
send += "\n"
|
||||
return send
|
||||
|
||||
def getAttribute(self, shortname:str):
|
||||
for attr in self.attributes:
|
||||
if attr.name.lower().startswith(shortname.lower()):
|
||||
return attr.value
|
||||
return None
|
||||
|
||||
def __eq__(self, value):
|
||||
if isinstance(value, Player):
|
||||
return self.name == value.name
|
||||
|
@ -41,4 +48,25 @@ class Skater(Player):
|
|||
|
||||
|
||||
class Goalie(Player):
|
||||
"""A hockey player that *is* a goalie."""
|
||||
"""A hockey player that *is* a goalie."""
|
||||
|
||||
class AtkAction(Enum):
|
||||
SkateB = 0
|
||||
SkateF = 1
|
||||
SkateT = 2
|
||||
SkateA = 3
|
||||
PassS = 4
|
||||
PassF = 5
|
||||
PassB = 6
|
||||
Dump = 7
|
||||
ShotS = 8
|
||||
ShotW = 9
|
||||
|
||||
class DefAction(Enum):
|
||||
Steal = 0
|
||||
Poke = 1
|
||||
BlockLn = 2
|
||||
Body = 3
|
||||
Force = 4
|
||||
Pin = 5
|
||||
BlockSlot = 6
|
43
skillContests.py
Normal file
43
skillContests.py
Normal file
|
@ -0,0 +1,43 @@
|
|||
from player import AtkAction, DefAction
|
||||
from enum import Enum
|
||||
|
||||
class Situations(Enum):
|
||||
EvenStrength = 0
|
||||
PP1 = 1 #4v3, 5v4, or 6v5
|
||||
PP2 = 2 #5v3 or 6v4
|
||||
SH1 = -1 #3v4, 4v5, 5v6
|
||||
SH2 = -2 #3v5 or 4v6
|
||||
|
||||
class SkillContestParams(object):
|
||||
"""Basic structure for contests of skill."""
|
||||
atkStats = []
|
||||
defStats = []
|
||||
override = None
|
||||
|
||||
def __init__(self, atkAction:AtkAction, defAction:DefAction, situation:Situations):
|
||||
"""Determines which skills to test, and how strongly."""
|
||||
if situation == Situations.EvenStrength:
|
||||
result = evenTable[atkAction.value][defAction.value]
|
||||
if isinstance(result, bool):
|
||||
self.override = result
|
||||
return
|
||||
self.atkStats = result[0]
|
||||
self.defStats = result[1]
|
||||
|
||||
|
||||
|
||||
|
||||
#Bool overrides, or [List of (stat,weight) , List of (stat,weight)]
|
||||
evenTable = [
|
||||
#Steal #Poke #block lane #Body check #Force off puck #Pin to wall #Body block
|
||||
[[[('Sti',100)],[('Sti',20)]], [[('Dex',75),('Sti',35)],[('Sti',40)]], True, [[('Agi',110)],[('Spe',100)]],[[('Agi',110)],[('Str',100)]], [[('Agi',110)],[('Str',100)]], True], #Skate back
|
||||
[[[('Sti',100)],[('Sti',40)]], [[('Dex',50),('Sti',30)],[('Sti',100)]], True, [[('Str',100)],[('Str',100)]],[[('Spe',60),('Str',40)],[('Str',100)]],[[('Spe',60),('Str',40)],[('Str',100)]],True], #Skate forward
|
||||
[[[('Dex',75),('Sti',25)],[('Sti',50)]], [[('Dex',70),('Sti',30)],[('Sti',100)]], [[('Ref',50),('Sti',50)],[('Sti',100)]],[[('Dex',100)],[('Str',100)]],True, True, [[('Sti',100)],[('Ref',100)]]], #Skate through
|
||||
[[[('Sti',100)],[('Sti',30)]], [[('Dex',70),('Sti',30)],[('Sti',100)]], True, [[('Agi',100)],[('Str',100)]],[[('Sti',100)],[('Str',100)]], [[('Sti',100)],[('Str',100)]], True], #Skate around
|
||||
[True, [[('Pas',100)],[('Sti',100)]], [[('Pas',100)],[('Ref',100)]], True, [[('Str',80),('Pas',20)],[('Str',100)]],[[('Str',80),('Pas',20)],[('Str',100)]],True], #Stretch pass
|
||||
[[[('Pas',100)],[('Ref',20),('Sti',40)]],[[('Pas',100)],[('Sti',100)]], [[('Pas',100)],[('Ref',100)]], True, [[('Str',100)],[('Str',100)]], [[('Str',100)],[('Str',100)]], [[('Pas',100)],[('Ref',100)]]], #Forward pass
|
||||
[[[('Pas',100)],[('Int',20)]], True, True, True, True, [[('Sti',100)],[('Str',100)]], True], #Backward pass
|
||||
[True, True, [[('Wis',100)],[('Ref',100)]], True, True, True, True], #Dump/ice
|
||||
[False, False, True, False, True, False, [[('Sho',100)],[('Ref',70),('Int',30)]]], #Slapshot
|
||||
[[[('Dex',100)],[('Sti',40)]], [[('Dex',100)],[('Sti',100)]], [[('Sho',100)],[('Ref',100)]], [[('Dex',100)],[('Str',100)]],[[('Dex',100)],[('Str',100)]], [[('Dex',100)],[('Str',100)]], True] #Wrist shot
|
||||
]
|
Loading…
Reference in a new issue