Implemented basic action matrix, set weights to initial values

This commit is contained in:
Sakimori 2022-01-09 16:11:34 -05:00
parent de46f85dfe
commit cc0487469a
7 changed files with 161 additions and 75 deletions

View file

@ -1,5 +1,6 @@
import os, player, tweepy, twitHandler, time, skillContests, random
from attributes import normalDis
from hocTests import AttributeTest
if __name__ == "__main__":
#for name in ["Vivi", "Artemis", "Laika", "Sharks", "Dragons", "Melua", "Sabriina", "Jorts (Buttered)", "Jorts (Unbuttered)"]:
@ -9,43 +10,8 @@ if __name__ == "__main__":
# print(atr)
# print("----------")
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)
test = AttributeTest()
test.allTests()
#twitter = twitHandler.TwitHandler()
#if os.path.exists(os.path.join("Data", "lastID.twt")):

View file

@ -26,6 +26,9 @@
<Compile Include="game.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="hocTests.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="skillContests.py">
<SubType>Code</SubType>
</Compile>

View file

@ -27,7 +27,7 @@ class Attribute:
return f"{valueString} - {self.name}"
def __str__(self):
return f"{self.name}: {int(self.value)}"
return f"{self.name} - {int(self.value)}"
#Comparison helpers
def __eq__(self, other): #can compare attributes by name, or find attribute by value
@ -95,7 +95,7 @@ def normalDis(mean:float, stdDev:float, min:float=-math.inf, max:float=math.inf)
masterList = [
["Speed", 60, 25, 0, 100], #sprint speed (Forward)
["Agility", 50, 35, 0, 100], #changing directions/goaltending slide (Goalie)
["Reflexes", 50, 35, 0, 100], #deflections/goaltending blocks/intercepting passes (Goalie)
["Reflexes", 50, 35, 20, 100], #deflections/goaltending blocks/intercepting passes (Goalie)
["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)
@ -120,3 +120,15 @@ def attributesFromName(name:str):
for template in masterList:
atrs.append(Attribute(template[0], seededNormalDis(generator, *template[1:])))
return atrs
def singleAttribute(shortname:str):
"""Generates a tuple of (name,value) of an attribute with given shortname"""
for atr in masterList:
if atr[0].lower().startswith(shortname.lower()):
return (atr[0], normalDis(*atr[1:]))
def attributeMinMax(shortname:str):
"""Retrieves a single attribute's minimum and maximum values. Returns (min, max)."""
for atr in masterList:
if atr[0].lower().startswith(shortname.lower()):
return (atr[3], atr[4])

10
game.py
View file

@ -2,11 +2,13 @@ import random, team, player
from team import Team
from player import Player, AtkAction, DefAction
from skillContests import SkillContestParams, Situations
from attributes import normalDis
class Game(object):
"""A game of hockey!"""
def __init__(self, awayTeam:Team, homeTeam:Team, threes:bool=False):
if awayTeam is not None and homeTeam is not None:
self.away = awayTeam
self.home = homeTeam
@ -58,6 +60,10 @@ class Game(object):
atkValue = 0
defValue = 0
for attr, weight in params.atkStats:
atkValue += atkPlayer.getAttribute(attr) * weight/100
atkValue += atkPlayer.getAttribute(attr).value * weight/100
for attr, weight in params.defStats:
defValue += defPlayer.getAttribute(attr) * weight/100
defValue += defPlayer.getAttribute(attr).value * weight/100
atkRoll = normalDis(atkValue, atkValue/2, 0)
defRoll = normalDis(defValue, defValue/2, 0)
return atkRoll-defRoll > 0

88
hocTests.py Normal file
View file

@ -0,0 +1,88 @@
import skillContests, player, team, game, attributes
class AttributeTest(object):
def __init__(self):
self.atkAction = player.AtkAction.ShotW
self.defAction = player.DefAction.BlockSlot
self.atkPlayer = player.Player(None)
self.defPlayer = player.Player(None)
self.fakeGame = game.Game(None, None)
self.params = skillContests.SkillContestParams(self.atkAction, self.defAction)
def lowStats(self):
"""Tests attacker and defender with minimum stats."""
for i in [0,1]:
setPlayer = [self.atkPlayer, self.defPlayer][i]
statSet = [self.params.atkStats, self.params.defStats][i]
for shortname, weight in statSet:
longname, value = attributes.singleAttribute(shortname)
setPlayer.setAttribute(longname, attributes.attributeMinMax(longname)[0]+5)
self.getAvg("mutual minimum stats")
def lowAtkHighDef(self):
for shortname, weight in self.params.atkStats:
longname, value = attributes.singleAttribute(shortname)
self.atkPlayer.setAttribute(longname, attributes.attributeMinMax(longname)[0]+5)
for shortname, weight in self.params.defStats:
longname, value = attributes.singleAttribute(shortname)
self.defPlayer.setAttribute(longname, attributes.attributeMinMax(longname)[1]-5)
self.getAvg("bad attack, good defence")
def highAtkLowDef(self):
for shortname, weight in self.params.atkStats:
longname, value = attributes.singleAttribute(shortname)
self.atkPlayer.setAttribute(longname, attributes.attributeMinMax(longname)[1]-5)
for shortname, weight in self.params.defStats:
longname, value = attributes.singleAttribute(shortname)
self.defPlayer.setAttribute(longname, attributes.attributeMinMax(longname)[0]+5)
self.getAvg("good attack, bad defence")
def highStats(self):
for i in [0,1]:
setPlayer = [self.atkPlayer, self.defPlayer][i]
statSet = [self.params.atkStats, self.params.defStats][i]
for shortname, weight in statSet:
longname, value = attributes.singleAttribute(shortname)
setPlayer.setAttribute(longname, attributes.attributeMinMax(longname)[1]-5)
self.getAvg("mutual maximum stats")
def randomStats(self):
success = 0
total = 0
for i in range(0, 5000):
for shortname, weight in self.params.atkStats:
self.atkPlayer.setAttribute(*attributes.singleAttribute(shortname))
for shortname, weight in self.params.defStats:
self.defPlayer.setAttribute(*attributes.singleAttribute(shortname))
total += 1
success += self.fakeGame.skillContest(self.atkPlayer, self.defPlayer, self.params)
print(f"Testing random stats...")
print(f"Success rate: {str(round(success/total*100,2))}%")
print("-------")
def allTests(self):
self.lowStats()
self.lowAtkHighDef()
self.highAtkLowDef()
self.highStats()
self.randomStats()
def getAvg(self, testName:str):
success = 0
total = 0
for i in range(0, 5000):
total += 1
success += self.fakeGame.skillContest(self.atkPlayer, self.defPlayer, self.params)
print(f"Testing {testName}...")
print("Attacker stat values:")
for attr, w in self.params.atkStats:
print(self.atkPlayer.getAttribute(attr))
print("Defender stat values:")
for attr, w in self.params.defStats:
print(self.defPlayer.getAttribute(attr))
print(f"Success rate: {str(round(success/total*100,2))}%")
print("-------")

View file

@ -8,8 +8,11 @@ class Player(object):
"""A hockey player with attributes and various functions."""
def __init__(self, name:str):
if len(name) > 30:
if name is None:
self.attributes = []
elif len(name) > 30:
raise CreationError("Player name too long.")
else:
self.name = name
self.attributes = self.loadAttributes()
@ -29,11 +32,19 @@ class Player(object):
return send
def getAttribute(self, shortname:str):
"""Returns an Attribute object with given shortname."""
for attr in self.attributes:
if attr.name.lower().startswith(shortname.lower()):
return attr.value
return attr
return None
def setAttribute(self, shortname:str, value:float):
for attr in self.attributes:
if attr.name.lower().startswith(shortname.lower()):
attr.value = value
return True
self.attributes.append(attributes.Attribute(attributes.singleAttribute(shortname)[0],value))
def __eq__(self, value):
if isinstance(value, Player):
return self.name == value.name

View file

@ -14,7 +14,7 @@ class SkillContestParams(object):
defStats = []
override = None
def __init__(self, atkAction:AtkAction, defAction:DefAction, situation:Situations):
def __init__(self, atkAction:AtkAction, defAction:DefAction, situation:Situations=Situations.EvenStrength):
"""Determines which skills to test, and how strongly."""
if situation == Situations.EvenStrength:
result = evenTable[atkAction.value][defAction.value]
@ -30,14 +30,14 @@ class SkillContestParams(object):
#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
[[[('Sti',100)],[('Sti',20)]], [[('Dex',110),('Sti',35)],[('Sti',30)]], True, [[('Agi',11)],[('Spe',8)]], [[('Agi',20)],[('Str',8)]], [[('Agi',20)],[('Str',10)]], True], #Skate back
[[[('Sti',100)],[('Sti',40)]], [[('Dex',70),('Sti',30)],[('Sti',100)]], True, [[('Str',80)],[('Str',100)]], [[('Spe',60),('Str',40)],[('Str',80)]], [[('Spe',60),('Str',40)],[('Str',100)]],True], #Skate forward
[[[('Dex',75),('Sti',25)],[('Sti',50)]], [[('Dex',50),('Sti',30)],[('Sti',100)]], [[('Ref',20),('Sti',60)],[('Sti',100)]],[[('Dex',70)],[('Str',100)]], [[('Spe',60),('Str',40)],[('Str',120)]],True, [[('Sti',1)],[('Ref',3)]]], #Skate through
[[[('Sti',100)],[('Sti',40)]], [[('Dex',70),('Sti',30)],[('Sti',100)]], True, [[('Agi',100)],[('Str',100)]],[[('Sti',100)],[('Str',100)]], [[('Sti',100)],[('Str',110)]], True], #Skate around
[True, [[('Pas',70)],[('Sti',30)]], [[('Pas',80)],[('Ref',110)]], True, [[('Pas',100)],[('Str',80)]], [[('Pas',100)],[('Str',90)]], True], #Stretch pass
[[[('Pas',100)],[('Ref',40),('Sti',30)]],[[('Pas',70)],[('Sti',30)]], [[('Pas',80)],[('Ref',110)]], True, [[('Pas',100)],[('Str',80)]], [[('Pas',100)],[('Str',100)]], [[('Pas',1)],[('Ref',3)]]], #Forward pass
[[[('Pas',100)],[('Int',30)]], True, True, True, True, [[('Sti',100)],[('Str',100)]], True], #Backward pass
[True, True, [[('Wis',100)],[('Ref',20)]], True, True, True, True], #Dump/ice
[False, False, True, False, True, False, [[('Sho',120)],[('Ref',70),('Int',30)]]], #Slapshot
[[[('Dex',120)],[('Sti',40)]], [[('Dex',100)],[('Sti',40)]], [[('Sho',50)],[('Ref',25)]], [[('Dex',80)],[('Str',60)]], [[('Dex',100)],[('Str',90)]], [[('Dex',100)],[('Str',100)]], [[('Sho',1)],[('Ref',2),('Int',1)]]] #Wrist shot
]