implemented default rink graph
This commit is contained in:
parent
cc0487469a
commit
1c6a5400a5
1260
Rinks/Graphs/defaultedges.nx
Normal file
1260
Rinks/Graphs/defaultedges.nx
Normal file
File diff suppressed because it is too large
Load diff
36
Rinks/Graphs/defaultnodesnamed.nx
Normal file
36
Rinks/Graphs/defaultnodesnamed.nx
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
LDLW
|
||||||
|
LDHW
|
||||||
|
LDNW
|
||||||
|
LONW
|
||||||
|
LOHW
|
||||||
|
LOLW
|
||||||
|
LDC
|
||||||
|
LDL
|
||||||
|
LDH
|
||||||
|
LDN
|
||||||
|
LON
|
||||||
|
LOH
|
||||||
|
LOL
|
||||||
|
LOC
|
||||||
|
DT
|
||||||
|
DLS
|
||||||
|
DHS
|
||||||
|
CD
|
||||||
|
CO
|
||||||
|
OHS
|
||||||
|
OLS
|
||||||
|
OT
|
||||||
|
RDC
|
||||||
|
RDL
|
||||||
|
RDH
|
||||||
|
RDN
|
||||||
|
RON
|
||||||
|
ROH
|
||||||
|
ROL
|
||||||
|
ROC
|
||||||
|
RDLW
|
||||||
|
RDHW
|
||||||
|
RDNW
|
||||||
|
RONW
|
||||||
|
ROHW
|
||||||
|
ROLW
|
36
Rinks/Graphs/defaultnodesnumbered.nx
Normal file
36
Rinks/Graphs/defaultnodesnumbered.nx
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
01
|
||||||
|
02
|
||||||
|
03
|
||||||
|
04
|
||||||
|
05
|
||||||
|
06
|
||||||
|
10
|
||||||
|
11
|
||||||
|
12
|
||||||
|
13
|
||||||
|
14
|
||||||
|
15
|
||||||
|
16
|
||||||
|
17
|
||||||
|
20
|
||||||
|
21
|
||||||
|
22
|
||||||
|
23
|
||||||
|
24
|
||||||
|
25
|
||||||
|
26
|
||||||
|
27
|
||||||
|
30
|
||||||
|
31
|
||||||
|
32
|
||||||
|
33
|
||||||
|
34
|
||||||
|
35
|
||||||
|
36
|
||||||
|
37
|
||||||
|
41
|
||||||
|
42
|
||||||
|
43
|
||||||
|
44
|
||||||
|
45
|
||||||
|
46
|
11
SimHoc.py
11
SimHoc.py
|
@ -1,6 +1,10 @@
|
||||||
import os, player, tweepy, twitHandler, time, skillContests, random
|
import os, player, tweepy, twitHandler, time, skillContests, random, itertools
|
||||||
from attributes import normalDis
|
from attributes import normalDis
|
||||||
from hocTests import AttributeTest
|
from hocTests import AttributeTest
|
||||||
|
from hocUtils import RinkGraph
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
#for name in ["Vivi", "Artemis", "Laika", "Sharks", "Dragons", "Melua", "Sabriina", "Jorts (Buttered)", "Jorts (Unbuttered)"]:
|
#for name in ["Vivi", "Artemis", "Laika", "Sharks", "Dragons", "Melua", "Sabriina", "Jorts (Buttered)", "Jorts (Unbuttered)"]:
|
||||||
|
@ -10,8 +14,9 @@ if __name__ == "__main__":
|
||||||
# print(atr)
|
# print(atr)
|
||||||
# print("----------")
|
# print("----------")
|
||||||
|
|
||||||
test = AttributeTest()
|
g = RinkGraph(edgeFilename="defaultedges.nx")
|
||||||
test.allTests()
|
g.getNodeDebug('25')
|
||||||
|
|
||||||
|
|
||||||
#twitter = twitHandler.TwitHandler()
|
#twitter = twitHandler.TwitHandler()
|
||||||
#if os.path.exists(os.path.join("Data", "lastID.twt")):
|
#if os.path.exists(os.path.join("Data", "lastID.twt")):
|
||||||
|
|
|
@ -29,6 +29,9 @@
|
||||||
<Compile Include="hocTests.py">
|
<Compile Include="hocTests.py">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="hocUtils.py">
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
<Compile Include="skillContests.py">
|
<Compile Include="skillContests.py">
|
||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
@ -59,6 +62,9 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Data\" />
|
<Folder Include="Data\" />
|
||||||
|
<Folder Include="Rinks\" />
|
||||||
|
<Folder Include="Rinks\Backgrounds\" />
|
||||||
|
<Folder Include="Rinks\Graphs\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="Data\s options.txt" />
|
<Content Include="Data\s options.txt" />
|
||||||
|
|
43
game.py
43
game.py
|
@ -1,8 +1,14 @@
|
||||||
import random, team, player
|
import random, team, player, os
|
||||||
from team import Team
|
from team import Team
|
||||||
from player import Player, AtkAction, DefAction
|
from player import Player, AtkAction, DefAction
|
||||||
from skillContests import SkillContestParams, Situations
|
from skillContests import SkillContestParams, Situations
|
||||||
from attributes import normalDis
|
from attributes import normalDis
|
||||||
|
from hocUtils import RinkGraph
|
||||||
|
from enum import Enum
|
||||||
|
import networkx as nx
|
||||||
|
|
||||||
|
RINKDIRPATH = os.path.join("Rinks","Graphs")
|
||||||
|
DEFAULTRINKFILENAME = "defaultedges.nx"
|
||||||
|
|
||||||
class Game(object):
|
class Game(object):
|
||||||
"""A game of hockey!"""
|
"""A game of hockey!"""
|
||||||
|
@ -12,6 +18,11 @@ class Game(object):
|
||||||
self.away = awayTeam
|
self.away = awayTeam
|
||||||
self.home = homeTeam
|
self.home = homeTeam
|
||||||
|
|
||||||
|
self.awayZones = RinkGraph(edgeFilename=DEFAULTRINKFILENAME)
|
||||||
|
self.homeZones = RinkGraph(edgeFilename=DEFAULTRINKFILENAME)
|
||||||
|
self.currentZone = None
|
||||||
|
self.faceoff = FaceoffDot.Center
|
||||||
|
|
||||||
self.lineSize = 5
|
self.lineSize = 5
|
||||||
if len(awayTeam.roster) != 10 or len(homeTeam.roster) != 10 or threes:
|
if len(awayTeam.roster) != 10 or len(homeTeam.roster) != 10 or threes:
|
||||||
self.lineSize = 3
|
self.lineSize = 3
|
||||||
|
@ -19,10 +30,10 @@ class Game(object):
|
||||||
self.goalieHome = self.home.chooseGoalie()
|
self.goalieHome = self.home.chooseGoalie()
|
||||||
self.goalieAway = self.away.chooseGoalie()
|
self.goalieAway = self.away.chooseGoalie()
|
||||||
|
|
||||||
self.playerInPossession = None
|
self.positionInPossession = None
|
||||||
self.teamInPossession = None
|
self.teamInPossession = None
|
||||||
|
|
||||||
self.skatersHome = [] #LW LD C RD RW
|
self.skatersHome = [] #LW LD C RD RW, use the SkaterPosition enum for indexing.
|
||||||
self.skatersAway = []
|
self.skatersAway = []
|
||||||
|
|
||||||
self.penaltyBoxAway = []
|
self.penaltyBoxAway = []
|
||||||
|
@ -41,6 +52,10 @@ class Game(object):
|
||||||
else:
|
else:
|
||||||
return self.home
|
return self.home
|
||||||
|
|
||||||
|
def attackingTeam(self):
|
||||||
|
"""Alias for teamInPossession, to match defendingTeam()"""
|
||||||
|
return teamInPossession
|
||||||
|
|
||||||
def homeAttacking(self):
|
def homeAttacking(self):
|
||||||
return teamInPossession == self.home
|
return teamInPossession == self.home
|
||||||
|
|
||||||
|
@ -66,4 +81,24 @@ class Game(object):
|
||||||
|
|
||||||
atkRoll = normalDis(atkValue, atkValue/2, 0)
|
atkRoll = normalDis(atkValue, atkValue/2, 0)
|
||||||
defRoll = normalDis(defValue, defValue/2, 0)
|
defRoll = normalDis(defValue, defValue/2, 0)
|
||||||
return atkRoll-defRoll > 0
|
return atkRoll-defRoll > 0
|
||||||
|
|
||||||
|
class FaceoffDot(Enum):
|
||||||
|
"""All orientations are given from the perspective of the defending team."""
|
||||||
|
AwayZoneLeft = -4
|
||||||
|
AwayZoneRight = -3
|
||||||
|
AwayNeutralLeft = -2
|
||||||
|
AwayNeutralRight = -1
|
||||||
|
Center = 0
|
||||||
|
HomeNeutralRight = 1
|
||||||
|
HomeNeutralLeft = 2
|
||||||
|
HomeZoneRight = 3
|
||||||
|
HomeZoneLeft = 4
|
||||||
|
|
||||||
|
class SkaterPosition(Enum):
|
||||||
|
"""Allows easy indexing to the active skaters lists for each team."""
|
||||||
|
LW = 0
|
||||||
|
LD = 1
|
||||||
|
C = 2
|
||||||
|
RD = 3
|
||||||
|
RW = 4
|
|
@ -1,4 +1,5 @@
|
||||||
import skillContests, player, team, game, attributes
|
import skillContests, player, team, game, attributes, os
|
||||||
|
|
||||||
|
|
||||||
class AttributeTest(object):
|
class AttributeTest(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
131
hocUtils.py
Normal file
131
hocUtils.py
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
import os, itertools
|
||||||
|
import networkx as nx
|
||||||
|
|
||||||
|
class RinkGraph(object):
|
||||||
|
"""Base class for a graph of nodes representing a hockey rink. Description of nodes found in design documents."""
|
||||||
|
G = nx.empty_graph()
|
||||||
|
|
||||||
|
def __init__(self, nodeFilename:str=None, edgeFilename:str=None):
|
||||||
|
if nodeFilename is not None:
|
||||||
|
with open(os.path.join("Rinks","Graphs",nodeFilename)) as nodeFile:
|
||||||
|
nodeListS = [node.strip() for node in nodeFile.readlines()]
|
||||||
|
self.G = nx.empty_graph(create_using=nx.DiGraph)
|
||||||
|
edges = itertools.permutations(nodeListS,2)
|
||||||
|
self.G.add_edges_from(edges)
|
||||||
|
elif edgeFilename is not None:
|
||||||
|
self.G = nx.readwrite.edgelist.read_edgelist(os.path.join("Rinks","Graphs", edgeFilename), create_using=nx.DiGraph)
|
||||||
|
|
||||||
|
def writeGraph(self, writeFilename:str):
|
||||||
|
nx.readwrite.edgelist.write_edgelist(self.G, os.path.join("Rinks","Graphs",writeFilename))
|
||||||
|
|
||||||
|
def nameToZones(self, name:str):
|
||||||
|
column = int(name[1])
|
||||||
|
row = int(name[0])
|
||||||
|
|
||||||
|
def adjacencyRule(self):
|
||||||
|
for node1, node2 in list(self.G.edges):
|
||||||
|
self.G.edges[node1, node2]['actions'] = []
|
||||||
|
if (abs(int(node1[0]) - int(node2[0])) <= 1 and abs(int(node1[1]) - int(node2[1])) <= 0) or (abs(int(node1[0]) - int(node2[0])) <= 0 and abs(int(node1[1]) - int(node2[1])) <= 1):
|
||||||
|
self.G.edges[node1, node2]['adjacent'] = 1
|
||||||
|
elif node1 == "01" and node2 == "10" or node1 == "10" and node2 == "01" or node1 == "06" and node2 == "17" or node1 == "17" and node2 == "06":
|
||||||
|
self.G.edges[node1, node2]['adjacent'] = 1
|
||||||
|
elif node1 == "41" and node2 == "30" or node1 == "30" and node2 == "41" or node1 == "46" and node2 == "37" or node1 == "37" and node2 == "46":
|
||||||
|
self.G.edges[node1, node2]['adjacent'] = 1
|
||||||
|
else:
|
||||||
|
self.G.edges[node1, node2]['adjacent'] = 0
|
||||||
|
|
||||||
|
def backSkateRule(self):
|
||||||
|
for node1, node2 in list(self.G.edges):
|
||||||
|
if node1[1] in ['1','2','3','4','6']:
|
||||||
|
if abs(int(node1[0]) - int(node2[0])) <= 1 and int(node2[1]) == int(node1[1])-1:
|
||||||
|
self.G.edges[node1, node2]['actions'].append('SkateB')
|
||||||
|
|
||||||
|
def forwardSkateRule(self):
|
||||||
|
for node1, node2 in list(self.G.edges):
|
||||||
|
access = False
|
||||||
|
if node1[1] in ['0','1','2']:
|
||||||
|
access = True
|
||||||
|
distance = 2
|
||||||
|
elif node1[1] in ['3','4']:
|
||||||
|
access = True
|
||||||
|
distance = 1
|
||||||
|
|
||||||
|
if access and node2[1] >= node1[1]:
|
||||||
|
atkDistance = int(node2[1]) - int(node1[1])
|
||||||
|
horzDistance = abs(int(node2[0]) - int(node1[0]))
|
||||||
|
if (atkDistance+horzDistance) <= distance:
|
||||||
|
self.G.edges[node1, node2]['actions'].append('SkateF')
|
||||||
|
|
||||||
|
def throughSkateRule(self):
|
||||||
|
for node1, node2 in list(self.G.edges):
|
||||||
|
if node1[1] in ['5','6','7']:
|
||||||
|
if node1[0] not in ['0','4']:
|
||||||
|
if node2 == '26':
|
||||||
|
self.G.edges[node1, node2]['actions'].append('SkateT')
|
||||||
|
else:
|
||||||
|
if node1[0] == '0' and node2 == '16' or node1[0] == '4' and node2 == '36':
|
||||||
|
self.G.edges[node1, node2]['actions'].append('SkateT')
|
||||||
|
|
||||||
|
def aroundSkateRule(self):
|
||||||
|
for node1, node2 in list(self.G.edges):
|
||||||
|
if node1[1] in ['5','6'] and node1[0] != '2' and node2 == '27':
|
||||||
|
self.appendAction(node1, node2, 'SkateA')
|
||||||
|
|
||||||
|
def stretchPassRule(self):
|
||||||
|
for node1, node2 in list(self.G.edges):
|
||||||
|
if node1[1] in ['1','2'] and node2[1] == '5':
|
||||||
|
self.appendAction(node1, node2, "PassS")
|
||||||
|
|
||||||
|
def forwardPassRule(self):
|
||||||
|
for node1, node2 in list(self.G.edges):
|
||||||
|
if node1[1] in ['1','2', '3', '5', '6']:
|
||||||
|
if int(node2[1]) >= int(node1[1]) and int(node2[1]) - int(node1[1]) <= 2:
|
||||||
|
self.appendAction(node1, node2, 'PassF')
|
||||||
|
elif node1[1] == '4' and node2[1] in ['4','5']:
|
||||||
|
self.appendAction(node1, node2, 'PassF')
|
||||||
|
elif node1[1] == '7' and node2[1] in ['5','6']:
|
||||||
|
self.appendAction(node1, node2, 'PassF')
|
||||||
|
|
||||||
|
def backwardPassRule(self):
|
||||||
|
for node1, node2 in list(self.G.edges):
|
||||||
|
if node1[1] not in ['0','5','7']: #back pass from column 7 is treated as forward pass for difficulty
|
||||||
|
if int(node1[1]) - int(node2[1]) == 1 and node1[0] == node2[0]:
|
||||||
|
self.appendAction(node1, node2, 'PassB')
|
||||||
|
|
||||||
|
|
||||||
|
def appendAction(self, node1, node2, actionString):
|
||||||
|
self.G.edges[node1, node2]['actions'].append(actionString)
|
||||||
|
|
||||||
|
|
||||||
|
def allRules(self):
|
||||||
|
self.adjacencyRule()
|
||||||
|
self.backSkateRule()
|
||||||
|
self.forwardSkateRule()
|
||||||
|
self.throughSkateRule()
|
||||||
|
self.aroundSkateRule()
|
||||||
|
self.stretchPassRule()
|
||||||
|
self.forwardPassRule()
|
||||||
|
self.backwardPassRule()
|
||||||
|
self.writeGraph("defaultedges.nx")
|
||||||
|
|
||||||
|
def getAllReachableFrom(self, nodeName):
|
||||||
|
"""Returns a dictionary where the keys are all reachable nodes, and the values are the list of actions that can reach the key node."""
|
||||||
|
if isinstance(nodeName, int):
|
||||||
|
nodeName = str(nodeName)
|
||||||
|
allConnected = dict(self.G[nodeName])
|
||||||
|
possibleReachable = {}
|
||||||
|
for otherNode in allConnected:
|
||||||
|
if allConnected[otherNode]['actions'] != []:
|
||||||
|
possibleReachable[otherNode] = allConnected[otherNode]['actions']
|
||||||
|
return possibleReachable
|
||||||
|
|
||||||
|
def getAdjacentNodes(self, nodeName):
|
||||||
|
"""Returns a list of all nodes marked as adjacent by the current map."""
|
||||||
|
if isinstance(nodeName, int):
|
||||||
|
nodeName = str(nodeName)
|
||||||
|
allConnected = dict(self.G[nodeName])
|
||||||
|
adjacents = []
|
||||||
|
for otherNodeName, nodeDic in allConnected.items():
|
||||||
|
if nodeDic['adjacent']:
|
||||||
|
adjacents.append(otherNodeName)
|
||||||
|
return adjacents
|
Loading…
Reference in a new issue