Implemented basic action matrix, set weights to initial values
This commit is contained in:
parent
de46f85dfe
commit
cc0487469a
40
SimHoc.py
40
SimHoc.py
|
@ -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")):
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
10
game.py
|
@ -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
88
hocTests.py
Normal 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("-------")
|
15
player.py
15
player.py
|
@ -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
|
||||
|
|
|
@ -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
|
||||
]
|
Loading…
Reference in a new issue