├── .gitignore
├── Img
└── default_regions.jpeg
├── loganalyzer
├── __pycache__
│ ├── Game.cpython-36.pyc
│ ├── Team.cpython-36.pyc
│ ├── Agent.cpython-36.pyc
│ ├── Parser.cpython-36.pyc
│ └── Analyzer.cpython-36.pyc
├── __init__.py
├── Team.py
├── Game.py
├── Testcase.py
├── __main__.py
├── Parser.py
├── Agent.py
└── Analyzer.py
├── setup.py
├── LICENSE.txt
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | build/
2 | dist/
3 | __pycache__/
4 | loganalyzer.egg-info/
--------------------------------------------------------------------------------
/Img/default_regions.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Farzin-Negahbani/Namira-LogAnalyzer/HEAD/Img/default_regions.jpeg
--------------------------------------------------------------------------------
/loganalyzer/__pycache__/Game.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Farzin-Negahbani/Namira-LogAnalyzer/HEAD/loganalyzer/__pycache__/Game.cpython-36.pyc
--------------------------------------------------------------------------------
/loganalyzer/__pycache__/Team.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Farzin-Negahbani/Namira-LogAnalyzer/HEAD/loganalyzer/__pycache__/Team.cpython-36.pyc
--------------------------------------------------------------------------------
/loganalyzer/__pycache__/Agent.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Farzin-Negahbani/Namira-LogAnalyzer/HEAD/loganalyzer/__pycache__/Agent.cpython-36.pyc
--------------------------------------------------------------------------------
/loganalyzer/__pycache__/Parser.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Farzin-Negahbani/Namira-LogAnalyzer/HEAD/loganalyzer/__pycache__/Parser.cpython-36.pyc
--------------------------------------------------------------------------------
/loganalyzer/__init__.py:
--------------------------------------------------------------------------------
1 | from .Game import Game
2 | from .Parser import Parser
3 | from .Analyzer import Analyzer
4 | from .Agent import Agent
5 | from .Team import Team
--------------------------------------------------------------------------------
/loganalyzer/__pycache__/Analyzer.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Farzin-Negahbani/Namira-LogAnalyzer/HEAD/loganalyzer/__pycache__/Analyzer.cpython-36.pyc
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import platform
4 | import shutil
5 | from setuptools import setup
6 | setup(
7 | name="loganalyzer",
8 | version='1.0.1',
9 | description='Python Script for parsing and analyzing agent2D socer simulation rcl and rcg logs',
10 | long_description=open("README.md").read(),
11 | author='Shahryar Bhm & Farzin Negahbani',
12 | author_email='shahryarbahmeie@gmail.com , farzin.negahbani@gmail.comh',
13 | url='https://github.com/Farzin-Negahbani/Namira_LogAnalyzer',
14 | packages=['loganalyzer', ],
15 | entry_points={ # Optional
16 | 'console_scripts': [
17 | 'loganalyzer=loganalyzer.__main__:main',
18 | ],
19 | },
20 | )
21 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Farzin Negahbani, Shahryar Bahmaei and Ehsan Asali.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/loganalyzer/Team.py:
--------------------------------------------------------------------------------
1 | from loganalyzer.Agent import *
2 |
3 |
4 | class Team:
5 |
6 | def __init__(self,name,side):
7 | self.name = name
8 | self.side = side
9 | self.agents = self.generate_agents()
10 |
11 |
12 |
13 | def get_result(self):
14 | result = {"all_kick":[],"all_tackle":[],"true_kick":[],"true_tackle":[]}
15 | for agent in self.agents:
16 | result["all_kick"]+=agent.result["all_kick"]
17 | result["all_tackle"]+=agent.result["all_tackle"]
18 | result["true_kick"]+=agent.result["true_kick"]
19 | result["true_tackle"]+=agent.result["true_tackle"]
20 | return result
21 |
22 | def generate_agents(self):
23 | agents=[]
24 | for i in range (11):
25 | agents+=[Agent(i+1,self)]
26 | return agents
27 |
28 | def set_agents_data(self,cycle, game):
29 | for i in range(3,len(cycle)):
30 | if cycle[i][0][0]==self.side:
31 | self.agents[cycle[i][0][1]-1].parse_data(cycle[1],cycle[i],game)
32 |
33 | def get_agent_data(self,number):
34 | return self.agents[number-1].get_data()
35 |
--------------------------------------------------------------------------------
/loganalyzer/Game.py:
--------------------------------------------------------------------------------
1 | from loganalyzer.Team import *
2 |
3 |
4 | class Game:
5 |
6 | def __init__(self, parser):
7 | self.parser = parser
8 | self.right_goal = 0
9 | self.left_goal = 0
10 | self.server_param = {}
11 | self.right_team = Team(parser.right_team, 'r')
12 | self.left_team = Team(parser.left_team, 'l')
13 | self.agent_types = {}
14 | self.play_modes = {}
15 | self.ball_pos = {}
16 | self.play_on_cycles = []
17 | self.set_game_result()
18 | self.set_teams_data()
19 |
20 | def set_play_modes(self, cycle, playMode):
21 | self.play_modes[cycle] = playMode
22 |
23 | def set_ball_position(self, cycle, ball_data):
24 | self.ball_pos[cycle] = {
25 | 'x': ball_data[1], 'y': ball_data[2], 'Vx': ball_data[3], 'Vy': ball_data[4]}
26 |
27 | def set_game_result(self):
28 | self.left_goal, self.right_goal = self.parser.data_rcg[-1][0][4:]
29 |
30 |
31 | def set_teams_data(self):
32 | current_play_mode = False
33 | for cycle in self.parser.data_rcg:
34 | if cycle[0][0] == 'show':
35 | if current_play_mode == 'play_on':
36 | self.play_on_cycles += [cycle[0][1]]
37 | self.set_ball_position(cycle[0][1], cycle[0][2])
38 | self.left_team.set_agents_data(cycle[0], self)
39 | self.right_team.set_agents_data(cycle[0], self)
40 |
41 | elif cycle[0][0] == 'playmode':
42 | current_play_mode = cycle[0][2]
43 | self.set_play_modes(cycle[0][1], cycle[0][2])
44 |
45 | elif cycle[0][0] == 'server_param':
46 | for i in range(1, len(cycle[0])):
47 | self.server_param[cycle[0][i][0]] = cycle[0][i][1]
48 |
49 | elif cycle[0][0] == 'player_type':
50 | data = {}
51 | for i in range(2, len(cycle[0])):
52 | data[cycle[0][i][0]] = cycle[0][i][1]
53 | self.agent_types[cycle[0][1][1]] = data
54 |
55 | def get_agent_data(self, side, number):
56 |
57 | if side == 'l':
58 | return self.left_team.agents[number-1].get_data()
59 | else:
60 | return self.right_team.agents[number-1].get_data()
61 |
62 | def get_kickers(self, cycle):
63 | kickers = []
64 | for agent in self.left_team.agents+self.right_team.agents:
65 | if(agent.data[cycle]['is_tackled'] or agent.data[cycle]['is_kicked']):
66 | kickers.append(agent)
67 | return kickers
68 |
69 | def get_last_kickers(self, cycle):
70 | m = 0
71 | kickers = []
72 | for agent in (self.left_team.agents+self.right_team.agents):
73 | if cycle in agent.data:
74 | if(agent.data[cycle]['last_tackle_cycle'] > m or agent.data[cycle]['lastkickCycle'] > m):
75 | if(agent.data[cycle]['last_tackle_cycle'] > agent.data[cycle]['lastkickCycle']):
76 | m = agent.data[cycle]['last_tackle_cycle']
77 | else:
78 | m = agent.data[cycle]['lastkickCycle']
79 | kickers.clear()
80 | kickers.append(agent)
81 | elif(agent.data[cycle]['last_tackle_cycle'] == m or agent.data[cycle]['lastkickCycle'] == m):
82 | kickers.append(agent)
83 | return kickers
84 |
85 | def get_play_on_cycles(self):
86 | return self.play_on_cycles
87 |
--------------------------------------------------------------------------------
/loganalyzer/Testcase.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | from loganalyzer.Parser import *
4 | from loganalyzer.Game import *
5 | from loganalyzer.Analyzer import *
6 |
7 |
8 | parser = Parser('Data/20190213193824-Namira_4-vs-CYRUS2018_312')
9 |
10 | game = Game(parser)
11 |
12 | analyzer = Analyzer(game)
13 | analyzer.analyze()
14 |
15 | print("Right Team :"+analyzer.game.right_team.name + "\n")
16 | print("Game result :"+analyzer.status_r)
17 | print("Goals :"+str(analyzer.game.right_goal))
18 | print("True Pass:"+str(analyzer.pass_r))
19 | print("Wrong Pass:"+str(analyzer.intercept_l))
20 | print("Pass in Lenght:"+str(analyzer.pass_in_length_r))
21 | print("Pass in Width:"+str(analyzer.pass_in_width_r))
22 | print("Pass Accuracy:"+str(analyzer.pass_accuracy_r))
23 | print("on_target_shoot:"+str(analyzer.on_target_shoot_r))
24 | print("off_target_shoot:"+str(analyzer.off_target_shoot_r))
25 | print("Shoot in Lenght:"+str(analyzer.shoot_in_length_r))
26 | print("Shoot in Width:"+str(analyzer.shoot_in_width_r))
27 | print("Shoot Accuracy:"+str(analyzer.shoot_accuracy_r))
28 | print("Possession:"+str(analyzer.possession_r))
29 | print("Stamina Usage:"+str(analyzer.used_stamina_agents_r))
30 | print("moved Distance:"+str(analyzer.team_moved_distance_r))
31 | print("Average Distance 10 Player: "+str(analyzer.average_distance_10p_r))
32 | print("Average Stamina 10 Player: "+str(analyzer.average_stamina_10p_r))
33 | print("Average Stamina Per distance 10 Player: " +
34 | str(analyzer.av_st_per_dist_10p_r))
35 | print("Stamina per Distance:"+str(analyzer.used_per_distance_r)+"\n"+"\n")
36 |
37 |
38 | print("Left Team :"+analyzer.game.left_team.name+"\n")
39 | print("Game result :"+analyzer.status_l)
40 | print("Goals :"+str(analyzer.game.left_goal))
41 | print("Wrong Pass:"+str(analyzer.intercept_r))
42 | print("Pass in Lenght:"+str(analyzer.pass_in_length_l))
43 | print("Pass in Width:"+str(analyzer.pass_in_width_l))
44 | print("Pass Accuracy:"+str(analyzer.pass_accuracy_l))
45 | print("on_target_shoot:"+str(analyzer.on_target_shoot_l))
46 | print("off_target_shoot:"+str(analyzer.off_target_shoot_l))
47 | print("Shoot in Lenght:"+str(analyzer.shoot_in_length_l))
48 | print("Shoot in Width:"+str(analyzer.shoot_in_width_l))
49 | print("Shoot Accuracy:"+str(analyzer.shoot_accuracy_l))
50 | print("Possession:"+str(analyzer.possession_l))
51 | print("Stamina Usage:"+str(analyzer.used_stamina_agents_l))
52 | print("moved Distance:"+str(analyzer.team_moved_distance_l))
53 | print("Average Distance 10 Player: "+str(analyzer.average_distance_10p_l))
54 | print("Average Stamina 10 Player: "+str(analyzer.average_stamina_10p_l))
55 | print("Average Stamina Per distance 10 Player: " +
56 | str(analyzer.av_st_per_dist_10p_l))
57 | print("Stamina per Distance:"+str(analyzer.used_per_distance_l)+"\n")
58 |
59 |
60 | for region in analyzer.regions:
61 | print("Ball in Region Percentage", region.name,
62 | " ", region.ball_in_region_cycles)
63 |
64 | print("\nRight Team Regions Data")
65 |
66 | # Agent_regions
67 | # owner_cycles : cycles player is ball owner in the region
68 | # position_cycles : cycles player is in the region
69 | for agent in game.right_team.agents:
70 | for region in agent.regions:
71 | print(region.name+" "+"Agent number "+str(agent.number)+" owner_cycles: " +
72 | str(region.owner_cycles) + " " + "position_cycles: "+str(region.position_cycles))
73 |
74 | print("\nLeft Team Regions Data")
75 | for agent in game.left_team.agents:
76 | for region in agent.regions:
77 | print(region.name+" "+"Agent number "+str(agent.number)+" owner_cycles: " +
78 | str(region.owner_cycles) + " " + "position_cycles: "+str(region.position_cycles))
79 |
80 | # Drawing Heatmap of the game
81 | heatmap = analyzer.draw_heatmap(right_team=True, left_team=True)
82 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Namira Log-Analyzer
2 |
3 | Python Script for parsing and analyzing agent2D soccer simulation rcl and rcg log files. This has been used in [NAMIRA TPAS](https://github.com/Farzin-Negahbani/Namira_TPAS),
4 | a Tournament Planning and Analyzer Software.
5 |
6 | ## Why is this useful?
7 |
8 | - Generating comprehensive data about your team performance on different matches.
9 | - Evaluating different capabilities of your team .
10 | - Using extracted data to train machine learning algorithm.
11 |
12 | ## Getting Started
13 |
14 | You just need python 3.x! and setuptools running on any OS.
15 |
16 | ### Pre Installation
17 |
18 | ##### Ubuntu
19 |
20 | sudo apt-get update
21 | sudo apt-get install python3 python3-pip python3-setuptools python3-numpy python3-matplotlib
22 |
23 | ### Installation
24 | git clone https://github.com/Farzin-Negahbani/Namira_LogAnalyzer.git
25 | cd Namira_LogAnalyzer
26 | Then you can do one of the following methods:
27 | #### Method 1
28 | sudo python3 ./setup.py install
29 | #### Method 2
30 | pip install .
31 |
32 | ### Uninstall
33 | pip uninstall loganalyzer
34 |
35 | ## Capabilities of this analyzer
36 |
37 | This analyzer can report following match facts and information:
38 |
39 | - Pass
40 | - Pass Counting
41 | - In Width
42 | - In Length
43 | - In 9 determined regions (A, B, ... I)
44 | - True Passes
45 | - Pass Interception
46 | - Pass Accuracy
47 | - Shoot
48 | - Shoot Counting
49 | - In Width
50 | - In Length
51 | - In 9 determined regions (A, B, ... I)
52 | - On Target Shoots
53 | - Off Target Shoots
54 | - Shoot Accuracy
55 | - Possession
56 | - Possession in 9 determined regions (A, B, ... I) for the teams
57 | - Possession in 9 determined regions for each player (A, B, ... I)
58 | - Possession of any team or player in any custom region
59 | - Position
60 | - Cycles each player is in 9 determined regions (A, B, ... I)
61 | - Cycles each player is in any of custom regions (A, B, ... I)
62 | - Players' moved distance
63 | - Players' stamina usage
64 | - Players' stamina used per distance
65 | - Game Heatmap of teams
66 | - Kick count
67 | - Tackle count
68 | - Say count
69 | #### Default Regions
70 |
71 |
72 |
73 |
74 | ### How to Use
75 |
76 | To check how to retrieve data, take a look at **Testcase.py** file.
77 |
78 | #### As a Script
79 |
80 | loganalyzer --path
81 |
82 | #### As a Module
83 |
84 | import loganalyzer
85 | from loganalyzer import Parser
86 | from loganalyzer import Game
87 | from loganalyzer import Analyzer
88 | parser = Parser('path to log file without .rcl or .rcg')
89 | game = Game(parser)
90 | analyzer = Analyzer(game)
91 | analyzer.analyze()
92 | left_team_pass = analyzer.pass_l
93 | left_team_in_target_shoot = analyzer.in_target_shoot_l
94 | left_team_agent_1 = game.left_team.agents[0].data
95 |
96 | ## Publication
97 |
98 | If you found this work useful in your research, please give credits to the authors by citing:
99 |
100 | - Asali, E., Negahbani, F., Tafazzol, S., Maghareh, M.S., Bahmeie, S., Barazandeh, S., Mirian, S., & Moshkelgosha, M. (2018). Namira Soccer 2 D Simulation Team Description Paper 2018. [PDF](https://archive.robocup.info/Soccer/Simulation/2D/TDPs/RoboCup/2018/Namira_SS2D_RC2018_TDP.pdf)
101 | - Asali, E., Moravej, A., Akbarpoor, S., Asali, O., Katebzadeh, M., Tafazol, S., ... & Haghighi, A. B. (2017). Persian Gulf Soccer 2D Simulation Team Description Paper 2017. In The 21th annual RoboCup International Symposium, Japan, Nagoya. [PDF](https://www.robocup2017.org/file/symposium/soccer_sim_2D/TDP_PersianGulf.pdf)
102 |
103 | ### Todo
104 |
105 | - [ ] Adding pass and shoot lenght attributes
106 |
--------------------------------------------------------------------------------
/loganalyzer/__main__.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import os
3 | import argparse
4 | import json
5 | from loganalyzer.Game import *
6 | from loganalyzer.Parser import *
7 | from loganalyzer.Analyzer import *
8 | # from Parser import *
9 | # from Game import *
10 | # from Analyzer import *
11 |
12 |
13 | def parse_args():
14 | parser = argparse.ArgumentParser()
15 | parser.add_argument("--path", help="Input file path", metavar='',
16 | required=True, dest='path')
17 | parser.add_argument(
18 | "--save_path", help="Output saving path.", metavar='', dest='save_path')
19 | parser.add_argument("--heatmap", help="Show Heatmap of Selected Side", metavar='TEAM_SIDE',
20 | dest='heat_map')
21 | parser.add_argument('--version', action='version', version='1.0.1')
22 | args = parser.parse_args()
23 | if args.save_path is None:
24 | args.save_path = args.path+".log.json"
25 | return args
26 |
27 |
28 | def write_to_file(save_path, analyzer):
29 | # right TEAM
30 | right_team_data = {
31 | "rightTeam": analyzer.game.right_team.name,
32 | "truePass": analyzer.pass_r,
33 | "intercept": analyzer.intercept_r,
34 | "onTargetShoot": analyzer.on_target_shoot_r,
35 | "offTarget": analyzer.off_target_shoot_r,
36 | "goals": analyzer.game.right_goal,
37 | "wrongPass": analyzer.intercept_l,
38 | "passInLength": analyzer.pass_in_length_r,
39 | "passInWidth": analyzer.pass_in_width_r,
40 | "passAccuracy": analyzer.pass_accuracy_r,
41 | "onTargetShoot": analyzer.on_target_shoot_r,
42 | "shootInLength": analyzer.shoot_in_length_r,
43 | "shootInWidth": analyzer.shoot_in_width_r,
44 | "shootAccuracy": analyzer.shoot_accuracy_r,
45 | "possession": analyzer.possession_r,
46 | "stamina": analyzer.used_stamina_agents_r,
47 | "moved": analyzer.team_moved_distance_r,
48 | "averageDistance10": analyzer.average_distance_10p_r,
49 | "averageStamina10": analyzer.average_stamina_10p_r,
50 | "averageStaminaPerDistance10": analyzer.av_st_per_dist_10p_r,
51 | "staminaPerDistance": analyzer.used_per_distance_r
52 | }
53 | # left TEAM
54 | left_team_data = {
55 | "leftTeam": analyzer.game.left_team.name,
56 | "truePass": analyzer.pass_l,
57 | "Intercept": analyzer.intercept_l,
58 | "onTargetShoot": analyzer.on_target_shoot_l,
59 | "offTarget": analyzer.off_target_shoot_l,
60 | "goals": analyzer.game.left_goal,
61 | "wrongPass": analyzer.intercept_r,
62 | "passinLength": analyzer.pass_in_length_l,
63 | "passInWidth": analyzer.pass_in_width_l,
64 | "passAccuracy": analyzer.pass_accuracy_l,
65 | "onTargetShoot": analyzer.on_target_shoot_l,
66 | "shootInLength": analyzer.shoot_in_length_l,
67 | "shootInWidth": analyzer.shoot_in_width_l,
68 | "shootAccuracy": analyzer.shoot_accuracy_l,
69 | "possession": analyzer.possession_l,
70 | "stamina": analyzer.used_stamina_agents_l,
71 | "moved": analyzer.team_moved_distance_l,
72 | "averageDistance10": analyzer.average_distance_10p_l,
73 | "averageStamina10": analyzer.average_stamina_10p_l,
74 | "averageStaminaPerDistance10": analyzer.av_st_per_dist_10p_l,
75 | "staminaPerDistance": analyzer.used_per_distance_r
76 | }
77 |
78 | ball_in_region_percentage = {}
79 | for region in analyzer.regions:
80 | ball_in_region_percentage[region.name] = region.ball_in_region_cycles
81 |
82 | # Agent_regions
83 | # owner_cycles : cycles player is ball owner in the region
84 | # position_cycles : cycles player is in the region
85 | right_team_regions_data = {}
86 | for agent in analyzer.game.right_team.agents:
87 | agent_data = {}
88 | for region in agent.regions:
89 | agent_data[region.name] = {
90 | "ownerCycles": region.owner_cycles, "positionCycles": region.position_cycles}
91 | right_team_regions_data[agent.number] = agent_data
92 | left_team_regions_data = {}
93 | for agent in analyzer.game.left_team.agents:
94 | agent_data = {}
95 | for region in agent.regions:
96 | agent_data[region.name] = {
97 | "ownerCycles": region.owner_cycles, "positionCycles": region.position_cycles}
98 | left_team_regions_data[agent.number] = agent_data
99 | right_team_data['regionData'] = right_team_regions_data
100 | left_team_data['regionData'] = left_team_regions_data
101 |
102 | data = {
103 | "gameResult": {analyzer.game.left_team.name: analyzer.game.left_goal,
104 | analyzer.game.right_team.name: analyzer.game.right_goal},
105 | "rightTeam": right_team_data,
106 | "leftTeam": left_team_data
107 | }
108 |
109 | with open(save_path, 'w') as outfile:
110 | json.dump(data, outfile)
111 |
112 |
113 | def main():
114 | args = parse_args()
115 | path = args.path
116 | save_path = args.save_path
117 | parser = Parser(path)
118 | game = Game(parser)
119 | analyzer = Analyzer(game)
120 | analyzer.analyze()
121 | write_to_file(save_path, analyzer)
122 |
123 | # Drawing Heatmap of the game
124 |
125 | if args.heat_map is not None:
126 | analyzer.draw_heatmap(right_team=True, left_team=True)
127 |
--------------------------------------------------------------------------------
/loganalyzer/Parser.py:
--------------------------------------------------------------------------------
1 |
2 | class Parser:
3 | def __init__(self, path):
4 | self.path = path
5 | self.set_data_rcg()
6 | self.set_data_rcl()
7 | self.right_team
8 | self.left_team
9 |
10 | def set_data_rcg(self):
11 | try:
12 | f = open(self.path+'.rcg', 'r')
13 | except:
14 | print("RCG file does not exist")
15 | exit(1)
16 | data_rcg = []
17 |
18 | def parse(expr):
19 | def _helper(iter):
20 | items = []
21 | for item in iter:
22 | if item == '(':
23 | result, closeparen = _helper(iter)
24 | if not closeparen:
25 | return [], False
26 | items.append(result)
27 | elif item == ')':
28 | return items, True
29 | else:
30 | items.append(item)
31 | return items, False
32 | return _helper(iter(expr))[0]
33 |
34 | def cleaner(lis):
35 |
36 | def isfloat(value):
37 | try:
38 | float(value)
39 | return True
40 | except ValueError:
41 | return False
42 | arr = []
43 | string = ''
44 | for i in range(len(lis)):
45 | if type(lis[i]) is list:
46 | if string != '':
47 | if string.isdigit():
48 | arr += [int(string)]
49 | elif isfloat(string):
50 | arr += [float(string)]
51 | else:
52 | arr += [string]
53 | string = ''
54 | arr += [cleaner(lis[i])]
55 | elif type(lis[i]) is str:
56 | if lis[i] == ' ':
57 | if string != '':
58 | if string.isdigit():
59 | arr += [int(string)]
60 | elif isfloat(string):
61 | arr += [float(string)]
62 | else:
63 | arr += [string]
64 | string = ''
65 | else:
66 | string += lis[i]
67 | if string != '':
68 | if string.isdigit():
69 | arr += [int(string)]
70 | elif isfloat(string):
71 | arr += [float(string)]
72 | else:
73 | arr += [string]
74 | return arr
75 | lines = f.readlines()
76 | for i in range(len(lines)):
77 | lines[i] = lines[i].replace("\n", '')
78 | for line in lines:
79 | p = parse(line)
80 | if p != []:
81 | data_rcg += [cleaner(p)]
82 | f.close()
83 | self.data_rcg = data_rcg
84 |
85 | def get_data_rcg(self):
86 | return self.data_rcg
87 |
88 | def set_data_rcl(self):
89 | try:
90 | f = open(self.path+'.rcl', 'r')
91 | except:
92 | print("RCL file does not exist")
93 | exit(1)
94 | self.set_teams_name()
95 | self.data_rcl = {}
96 | lines = f.readlines()
97 | kick_tackle = {}
98 | for line in lines:
99 | if ("kick" in line or "tackle" in line)and ("kick_" not in line) and ("_kick" not in line):
100 | cycle = int(line.split(',')[0])
101 | temp = line.split(':')
102 | temp2 = temp[0].split('_')
103 | number = temp2[len(temp2)-1]
104 | team = temp[0].split(' ')[1].replace("_"+number, '')
105 | words = line.split(':')[1].split(')')
106 | for word in words:
107 | if '(kick' in word:
108 | action = 'kick'
109 | try:
110 | degree = word.split(' ')[3]
111 | degree = float(degree)
112 | cycle_data = {'team': team, 'number': int(
113 | number), 'action': action, 'degree': degree}
114 | break
115 | except:
116 | print("error")
117 | elif 'tackle' in word:
118 | action = 'tackle'
119 | cycle_data = {'team': team, 'number': int(
120 | number), 'action': action}
121 | break
122 | if cycle in kick_tackle:
123 | if self.left_team in line:
124 | kick_tackle[cycle] = [cycle_data] + kick_tackle[cycle]
125 | elif self.right_team in line:
126 | kick_tackle[cycle] += [cycle_data]
127 |
128 | else:
129 | kick_tackle[cycle] = [cycle_data]
130 | for cycle in kick_tackle:
131 | if len(kick_tackle[cycle]) > 1:
132 | self.data_rcl[cycle] = kick_tackle[cycle]
133 | f.close()
134 |
135 | def get_data_rcl(self):
136 | return self.data_rcl
137 |
138 | def set_teams_name(self):
139 | for cycle in self.data_rcg:
140 | if cycle[0][0] == 'team':
141 | self.left_team = cycle[0][2]
142 | self.right_team = cycle[0][3]
143 |
144 | return
145 |
--------------------------------------------------------------------------------
/loganalyzer/Agent.py:
--------------------------------------------------------------------------------
1 |
2 | from math import degrees,atan
3 |
4 | class Agent_Region:
5 |
6 | def __init__(self, top_left, bottom_right, name="Unnamed"):
7 |
8 | self.top_left = top_left
9 | self.bottom_right = bottom_right
10 | self.name = name
11 | self.owner_cycles = 0
12 | self.position_cycles = 0
13 |
14 | def in_region(self, x,y):
15 | '''check if a point (x,y) lies in a rectangle
16 | with upper left corner (x1,y1) and bottom right corner (x2,y2)'''
17 | if (x > self.top_left[0] and x < self.bottom_right[0] and y > self.top_left[1] and y < self.bottom_right[1]) :
18 | return True
19 | else :
20 | return False
21 |
22 | class Agent:
23 |
24 | def __init__(self, number, team):
25 | self.team = team
26 | self.number = number
27 | self.kick_count = 0
28 | self.last_tackle_cycle = 0
29 | self.last_tackle_cycle = 0
30 | self.tackle_count = 0
31 | self.data = {}
32 | self.result = {"all_kick":[],"all_tackle":[],"true_kick":[],"true_tackle":[]}
33 | self.moved_distance = 0
34 | self.used_stamina = 0
35 | self.regions =[]
36 | self.regions.append(Agent_Region((-52.5,-34),(-17.5,-11),"A"))
37 | self.regions.append(Agent_Region((-52.5,-11),(-17.5,11),"B"))
38 | self.regions.append(Agent_Region((-52.5,11),(-17.5,34),"C"))
39 | self.regions.append(Agent_Region((-17.5,-34),(17.5,-11),"D"))
40 | self.regions.append(Agent_Region((-17.5,-11),(17.5,11),"E"))
41 | self.regions.append(Agent_Region((-17.5,11),(17.5,34),"F"))
42 | self.regions.append(Agent_Region((17.5,-34),(52.5,-11),"G"))
43 | self.regions.append(Agent_Region((17.5,-11),(52.5,11),"H"))
44 | self.regions.append(Agent_Region((17.5,11),(52.5,34),"I"))
45 |
46 |
47 | def get_data(self):
48 | return self.data
49 |
50 | def set_data(self,\
51 | cycle,\
52 | is_kicked,\
53 | is_tackled,\
54 | is_in_tackle_area,\
55 | is_in_kick_area,\
56 | is_true_tackle,\
57 | is_true_kick,\
58 | x,y,Vx,Vy,\
59 | body,\
60 | neck,\
61 | agent_type,\
62 | view_quality,\
63 | view_width,\
64 | effort,\
65 | stamina,\
66 | recovery,\
67 | stamina_capacity,\
68 | focus_side,\
69 | focus_num,\
70 | turn_count,\
71 | catch_count,\
72 | move_counte,\
73 | dash_count,\
74 | turn_neck_count,\
75 | change_view_count,\
76 | say_count,\
77 | point_to_count,\
78 | attention_to_count,\
79 | point_to_x,\
80 | point_to_y):
81 | self.data[cycle] = {\
82 | 'view_quality':view_quality,\
83 | 'view_width':view_width,\
84 | 'is_in_tackle_area':is_in_tackle_area,\
85 | 'is_in_kick_area':is_in_kick_area,\
86 | 'is_true_kick':is_true_kick,\
87 | 'is_true_tackle':is_true_tackle,\
88 | 'effort':effort,\
89 | 'stamina':stamina,\
90 | 'recovery':recovery,\
91 | 'stamina_capacity':stamina_capacity,\
92 | 'focus_side':focus_side,
93 | 'focus_num':focus_num,\
94 | 'turn_count':turn_count,\
95 | 'catch_count':catch_count,\
96 | 'move_counte':move_counte,\
97 | 'dash_count':dash_count,\
98 | 'turn_neck_count':turn_neck_count,\
99 | 'change_view_count':change_view_count,\
100 | 'say_count':say_count,\
101 | 'point_to_count':point_to_count,\
102 | 'attention_to_count':attention_to_count,\
103 | 'point_to_x':point_to_x,\
104 | 'point_to_y':point_to_y,\
105 | 'is_kicked':is_kicked,\
106 | 'is_tackled':is_tackled,\
107 | 'x':x,'y':y,'Vx':Vx,'Vy':Vy,\
108 | 'body':body,\
109 | 'neck':neck,\
110 | 'agent_type':agent_type,\
111 | 'lastkickCycle':self.last_tackle_cycle,\
112 | 'last_tackle_cycle':self.last_tackle_cycle\
113 | }
114 |
115 | def is_in_tackle_area(self, game,agent_pos,ball_pos, agent_type):
116 |
117 | agent_type = game.agent_types[agent_type]
118 | kick_radius = agent_type['player_size']+agent_type['kickable_margin']
119 | dist = (pow((agent_pos[0]- ball_pos[0]),2) + pow((agent_pos[1]- ball_pos[1]),2) )** 0.5
120 | if(kick_radius >= dist-1.60):
121 | return True
122 | else:
123 | return False
124 | def is_in_kick_area(self, game,agent_pos,ball_pos, agent_type):
125 | agent_type = game.agent_types[agent_type]
126 | kick_radius = agent_type['player_size']+agent_type['kickable_margin']
127 | dist = (pow((agent_pos[0]- ball_pos[0]),2) + pow((agent_pos[1]- ball_pos[1]),2) )** 0.5
128 | if(kick_radius >= dist-0.35):
129 | return True
130 | else:
131 | return False
132 |
133 | def parse_data(self,cycle,agent_data, game):
134 |
135 | def degree(ball , body):
136 |
137 | if(ball[0]-body[0] == 0):
138 | deg = 90
139 | else:
140 | deg = degrees(atan((ball[1]-body[1])/(ball[0]-body[0])))
141 |
142 | if(ball[1] body[0]:
144 | return 360+deg
145 | else:
146 | return 360-(180-deg)
147 | else:
148 | if ball[0]>body[0]:
149 | return deg
150 | else:
151 | return 180 +deg
152 |
153 | agent_type = agent_data[1]
154 | x = agent_data[3]
155 | y = agent_data[4]
156 | Vx = agent_data[5]
157 | Vy = agent_data[6]
158 | body = agent_data[7]
159 | neck = agent_data[8]
160 | view_quality ='not'
161 | view_width='not'
162 | effort='not'
163 | stamina='not'
164 | recovery='not'
165 | stamina_capacity='not'
166 | focus_side='not'
167 | focus_num='not'
168 | dash_count='not'
169 | turn_count='not'
170 | catch_count='not'
171 | move_counte='not'
172 | turn_neck_count='not'
173 | change_view_count='not'
174 | say_count='not'
175 | point_to_count='not'
176 | attention_to_count='not'
177 | point_to_x='not'
178 | point_to_y= 'not'
179 | for i in range(len(agent_data)):
180 | if type(agent_data[i])==list:
181 | if agent_data[i][0]=='v':
182 | view_quality = agent_data[i][1]
183 | view_width =agent_data[i][2]
184 |
185 | elif agent_data[i][0]=='s':
186 | stamina = agent_data[i][1]
187 | effort = agent_data[i][2]
188 | recovery = agent_data[i][3]
189 | stamina_capacity = agent_data[i][4]
190 |
191 | elif agent_data[i][0] =='f':
192 | focus_side= agent_data[i][1]
193 | focus_num = agent_data[i][2]
194 |
195 | elif agent_data[i][0] == 'c':
196 | kick_count = agent_data[i][1]
197 | dash_count = agent_data[i][2]
198 | turn_count = agent_data[i][3]
199 | catch_count = agent_data[i][4]
200 | move_counte = agent_data[i][5]
201 | turn_neck_count = agent_data[i][6]
202 | change_view_count = agent_data[i][7]
203 | say_count = agent_data[i][8]
204 | tackle_count = agent_data[i][9]
205 | point_to_count = agent_data[i][10]
206 | attention_to_count = agent_data[i][11]
207 |
208 | elif (i >8 and i <11) and (type(agent_data[i])!=list):
209 | if i ==9:
210 | point_to_x = agent_data[i]
211 | elif i ==10:
212 | point_to_y = agent_data[i]
213 |
214 | is_kicked = self.is_kicked(kick_count,cycle)
215 | if is_kicked:
216 | self.result['all_kick']+=[[x,y]]
217 | is_tackled = self.is_tackled(tackle_count,cycle)
218 | if is_tackled:
219 | self.result['all_tackle']+=[[x,y]]
220 | is_in_kick_area = self.is_in_kick_area(game,(x,y),(game.ball_pos[cycle]['x'],game.ball_pos[cycle]['y']),agent_type)
221 | is_in_tackle_area = self.is_in_tackle_area(game,(x,y),(game.ball_pos[cycle]['x'],game.ball_pos[cycle]['y']),agent_type)
222 | agent_pos = [x,y]
223 |
224 | is_true_kick = False
225 | is_true_tackle = False
226 | if body<0:
227 | bodyDegree = 360 +body
228 | else :
229 | bodyDegree = body
230 |
231 | ball_pos = [game.ball_pos[cycle]['x'],game.ball_pos[cycle]['y']]
232 | if cycle-1 in self.data:
233 | if cycle-1 in game.parser.data_rcl :
234 | if self.team.side == 'l' and self.number == game.parser.data_rcl[cycle-1][0]['number']:
235 | if('tackle' ==game.parser.data_rcl[cycle-1][0]['action']):
236 | if(body-degree(ball_pos,agent_pos)<30):
237 | is_true_tackle = True
238 | self.result["true_tackle"]+=[[x,y]]
239 | elif( 'kick' == game.parser.data_rcl[cycle-1][0]['action']):
240 | if(game.parser.data_rcl[cycle-1][0]['degree']-(degree(ball_pos,agent_pos)-bodyDegree)<30):
241 | self.result["true_kick"]+=[[x,y]]
242 | is_true_kick = True
243 | elif self.team.side=='r' and self.number == game.parser.data_rcl[cycle-1][1]['number']:
244 | if( 'tackle'==game.parser.data_rcl[cycle-1][1]['action']):
245 | if(body-degree(ball_pos,agent_pos)<30):
246 | self.result["true_tackle"]+=[[x,y]]
247 | is_true_tackle = True
248 | elif( 'kick' ==game.parser.data_rcl[cycle-1][1]['action']):
249 | if(game.parser.data_rcl[cycle-1][1]['degree']-(degree(ball_pos,agent_pos)-bodyDegree)<30):
250 | self.result["true_kick"]+=[[x,y]]
251 | is_true_kick = True
252 | else:
253 | if self.data[cycle-1]['is_in_kick_area']==True and is_kicked== True:
254 | is_true_kick = True
255 | self.result["true_kick"]+=[[x,y]]
256 | else:
257 | is_true_kick = False
258 | if self.data[cycle-1]['is_in_tackle_area']==True and is_tackled ==True:
259 | is_true_tackle = True
260 | self.result["true_tackle"]+=[[x,y]]
261 | else:
262 | is_true_tackle =False
263 |
264 | self.set_data(
265 | cycle,\
266 | is_kicked,\
267 | is_tackled,\
268 | is_in_tackle_area,\
269 | is_in_kick_area,\
270 | is_true_tackle,\
271 | is_true_kick,\
272 | x,y,Vx,Vy,\
273 | body,\
274 | neck,\
275 | agent_type,\
276 | view_quality,\
277 | view_width,
278 | effort,\
279 | stamina,\
280 | recovery,\
281 | stamina_capacity,\
282 | focus_side,\
283 | focus_num,\
284 | turn_count,\
285 | catch_count,\
286 | move_counte,\
287 | dash_count,\
288 | turn_neck_count,\
289 | change_view_count,\
290 | say_count,\
291 | point_to_count,\
292 | attention_to_count,\
293 | point_to_x,\
294 | point_to_y\
295 | )
296 |
297 | def is_kicked(self, kick_count,cycle):
298 | if(self.kick_count self.top_left[0] and x < self.bottom_right[0] and y > self.top_left[1] and y < self.bottom_right[1]):
17 | return True
18 | else:
19 | return False
20 |
21 |
22 | class Analyzer:
23 |
24 | def __init__(self, game):
25 |
26 | self.game = game
27 | self.play_on_cycles = game.get_play_on_cycles()
28 | self.pass_status = 0 # 0 --> no kick, 1 --> one kicker detected
29 | self.shoot_status = 0
30 | self.pass_last_kicker = -1
31 | self.pass_last_kick_cycle = -1
32 | self.i = 0
33 | self.ball_owner = 0
34 |
35 | # Special Regions
36 | self.regions = []
37 | self.regions.append(Region((-52.5, -34), (-17.5, -11), "A"))
38 | self.regions.append(Region((-52.5, -11), (-17.5, 11), "B"))
39 | self.regions.append(Region((-52.5, 11), (-17.5, 34), "C"))
40 | self.regions.append(Region((-17.5, -34), (17.5, -11), "D"))
41 | self.regions.append(Region((-17.5, -11), (17.5, 11), "E"))
42 | self.regions.append(Region((-17.5, 11), (17.5, 34), "F"))
43 | self.regions.append(Region((17.5, -34), (52.5, -11), "G"))
44 | self.regions.append(Region((17.5, -11), (52.5, 11), "H"))
45 | self.regions.append(Region((17.5, 11), (52.5, 34), "I"))
46 |
47 | # Right TEAM
48 | self.status_r = 0 # Winner' 'Loser' 'Draw'
49 | self.pass_r = 0
50 | self.intercept_r = 0
51 | self.pass_in_length_r = 0
52 | self.pass_in_width_r = 0
53 | self.pass_accuracy_r = 0
54 | self.shoot_in_length_r = 0
55 | self.shoot_in_width_r = 0
56 | self.on_target_shoot_r = 0
57 | self.off_target_shoot_r = 0
58 | self.shoot_accuracy_r = 0
59 | self.possession_r = 0
60 | self.used_stamina_agents_r = []
61 | self.team_moved_distance_r = []
62 | self.used_per_distance_r = []
63 | self.average_stamina_10p_r = 0
64 | self.average_distance_10p_r = 0
65 | self.av_st_per_dist_10p_r = 0
66 |
67 | # Left TEAM
68 | self.status_l = 0 # Winner' 'Loser' 'Draw'
69 | self.pass_l = 0
70 | self.intercept_l = 0
71 | self.pass_in_length_l = 0
72 | self.pass_in_width_l = 0
73 | self.pass_accuracy_l = 0
74 | self.shoot_in_length_l = 0
75 | self.shoot_in_width_l = 0
76 | self.on_target_shoot_l = 0
77 | self.off_target_shoot_l = 0
78 | self.shoot_accuracy_l = 0
79 | self.possession_l = 0
80 | self.used_stamina_agents_l = []
81 | self.team_moved_distance_l = []
82 | self.used_per_distance_l = []
83 | self.average_stamina_10p_l = 0
84 | self.average_distance_10p_l = 0
85 | self.av_st_per_dist_10p_l = 0
86 |
87 | def draw_heatmap(self, right_team=False, left_team=True):
88 | import numpy as np
89 | import matplotlib.pyplot as plt
90 |
91 | world = np.zeros((110, 75))
92 |
93 | if(right_team ):
94 | team =self.game.right_team.agents
95 | elif(left_team):
96 | team =self.game.left_team.agents
97 | # for cycle in self.play_on_cycles:
98 | for cycle in self.play_on_cycles:
99 | for agent in team:
100 | if(agent.number != 1):
101 | x = int(round(agent.data[cycle]['x'], 1))+52
102 | y = int(round(agent.data[cycle]['y'], 1))+33
103 | for i in range(-4,5):
104 | for j in range(-4,5):
105 | try:
106 | world[x+i][y+j] += 5 - abs(j)
107 | except:
108 | continue
109 | fig, ax = plt.subplots()
110 | ax.set_xticks(np.arange(len([])))
111 | ax.set_yticks(np.arange(len([])))
112 | ax.set_xticklabels([])
113 | ax.set_yticklabels([])
114 | cbarlabel="Relative Frequency"
115 |
116 | im = ax.imshow(np.fliplr(world).T, interpolation='gaussian')
117 | cbar = ax.figure.colorbar(im, ax=ax )
118 | cbar.ax.set_ylabel(cbarlabel, rotation=-90, va="bottom")
119 | plt.show()
120 |
121 |
122 | def line_intersection(self,line1, line2):
123 | def det(a, b):
124 | return a[0] * b[1] - a[1] * b[0]
125 |
126 | xdiff = (line1[0][0] - line1[1][0], line2[0][0] - line2[1][0])
127 | ydiff = (line1[0][1] - line1[1][1], line2[0][1] - line2[1][1]) #Typo was here
128 | div = det(xdiff, ydiff)
129 | if div == 0:
130 | raise Exception('lines do not intersect!')
131 | d = (det(*line1), det(*line2))
132 | x = det(d, xdiff) / div
133 | y = det(d, ydiff) / div
134 | return x, y
135 |
136 | def update_distance(self, key):
137 |
138 | def distance(p1,p2):
139 | return ((p1[0]-p2[0])**2+(p1[1]-p2[1])**2)**0.5
140 |
141 | if(key in self.play_on_cycles and (key-1) in self.play_on_cycles):
142 | for agent in (self.game.right_team.agents + self.game.left_team.agents):
143 | p1 = (agent.data[key-1]['x'],agent.data[key-1]['y'])
144 | p2 = (agent.data[key]['x'],agent.data[key]['y'])
145 | if( distance(p1,p2) < 1.6):
146 | agent.moved_distance = agent.moved_distance +distance(p1,p2)
147 |
148 |
149 | def update_parameters(self):
150 |
151 | if(self.game.left_goal == self.game.right_goal ):
152 | self.status_l = "Draw"
153 | self.status_r = "Draw"
154 | elif(self.game.left_goal > self.game.right_goal ):
155 | self.status_l = "Winner"
156 | self.status_r = "Loser"
157 | else:
158 | self.status_r = "Winner"
159 | self.status_l = "Loser"
160 |
161 | for agent in self.game.right_team.agents:
162 |
163 | agent.used_stamina = self.game.server_param['stamina_max']+self.game.server_param['stamina_capacity']-agent.data[self.game.get_play_on_cycles()[-1]]['stamina_capacity']-agent.data[self.game.get_play_on_cycles()[-1]]['stamina']
164 | self.used_stamina_agents_r.append((round(agent.used_stamina,2),agent.number))
165 |
166 | self.team_moved_distance_r.append((round(agent.moved_distance,2),agent.number))
167 | if(agent.moved_distance !=0):
168 | self.used_per_distance_r.append((round(agent.used_stamina/agent.moved_distance,1),agent.number))
169 |
170 |
171 | for agent in self.game.left_team.agents:
172 |
173 | agent.used_stamina = self.game.server_param['stamina_max']+self.game.server_param['stamina_capacity']-agent.data[self.game.get_play_on_cycles()[-1]]['stamina_capacity']-agent.data[self.game.get_play_on_cycles()[-1]]['stamina']
174 | self.used_stamina_agents_l.append((round(agent.used_stamina,2),agent.number))
175 |
176 | self.team_moved_distance_l.append((round(agent.moved_distance,2),agent.number))
177 | if(agent.moved_distance !=0):
178 | self.used_per_distance_l.append((round(agent.used_stamina/agent.moved_distance,1),agent.number))
179 |
180 | if(self.pass_r+self.intercept_l != 0):
181 | self.pass_accuracy_r = round(self.pass_r * 100/(self.pass_r+self.intercept_l),1)
182 | else:
183 | self.pass_accuracy_r = 0
184 |
185 | if(self.pass_l+self.intercept_r != 0):
186 | self.pass_accuracy_l = round(self.pass_l * 100/(self.pass_l+self.intercept_r),1)
187 | else:
188 | self.pass_accuracy_l = 0
189 |
190 | if(self.on_target_shoot_l+self.off_target_shoot_l != 0):
191 | self.shoot_accuracy_l = round(self.on_target_shoot_l *100/(self.on_target_shoot_l+self.off_target_shoot_l),1)
192 | else:
193 | self.shoot_accuracy_l = 0
194 |
195 | if(self.on_target_shoot_r+self.off_target_shoot_r != 0):
196 | self.shoot_accuracy_r = round(self.on_target_shoot_r *100/(self.on_target_shoot_r+self.off_target_shoot_r),1)
197 | else:
198 | self.shoot_accuracy_r = 0
199 |
200 | total = self.possession_r+self.possession_l
201 | if(total!=0):
202 | self.possession_r = round(self.possession_r * 100 /(total) ,1)
203 | self.possession_l = round(self.possession_l * 100 /(total) ,1)
204 | else:
205 | self.possession_r = 0
206 | self.possession_l = 0
207 |
208 | s = sum([d.ball_in_region_cycles for d in self.regions])
209 | for region in self.regions:
210 | region.ball_in_region_cycles = round(region.ball_in_region_cycles*100/s,1)
211 |
212 | self.average_distance_10p_r = round(sum([d[0] for d in self.team_moved_distance_r if d[1]!=1])/10,1)
213 | self.average_distance_10p_l = round(sum([d[0] for d in self.team_moved_distance_l if d[1]!=1])/10,1)
214 | self.average_stamina_10p_r = round(sum([d[0] for d in self.used_stamina_agents_r if d[1]!=1])/10,1)
215 | self.average_stamina_10p_l = round(sum([d[0] for d in self.used_stamina_agents_l if d[1]!=1])/10,1)
216 |
217 | if(self.average_distance_10p_r !=0):
218 | self.av_st_per_dist_10p_r = round(self.average_stamina_10p_r/self.average_distance_10p_r,1)
219 |
220 | if(self.average_distance_10p_l !=0):
221 | self.av_st_per_dist_10p_l = round(self.average_stamina_10p_l/self.average_distance_10p_l,1)
222 |
223 | def update_possession(self, key):
224 |
225 | if(key in self.play_on_cycles and len(self.game.get_last_kickers(key))>0):
226 |
227 | for region in self.regions:
228 | if(region.in_region(self.game.ball_pos[key]['x'],self.game.ball_pos[key]['y'])):
229 | region.ball_in_region_cycles +=1
230 | break
231 |
232 | for agent in (self.game.right_team.agents +self.game.left_team.agents ):
233 | for region in agent.regions:
234 | if(region.in_region(agent.data[key]['x'],agent.data[key]['y'])):
235 | region.position_cycles +=1
236 | if(self.game.get_last_kickers(key)[0] == agent):
237 | region.owner_cycles +=1
238 | break
239 |
240 |
241 | if(self.game.get_last_kickers(key)[0].team.name == self.game.left_team.name ):
242 | self.possession_l +=1
243 | # print("Left Team is ball Owner cycle ",key)
244 | else:
245 | # print("Right Team is ball Owner cycle ",key)
246 | self.possession_r +=1
247 |
248 |
249 | def check_shoot(self, key):
250 |
251 | if key in self.game.ball_pos:
252 | if(key not in self.play_on_cycles):
253 | self.shoot_status = 0
254 |
255 | elif( self.shoot_status == 0 and (self.game.ball_pos[key]['Vx']**2 + self.game.ball_pos[key]['Vy']**2)** 0.5 > 2.0 ):
256 | kickers = self.game.get_kickers(key)
257 | if(len(kickers)>0 and kickers[0].team.name == self.game.right_team.name and math.hypot(kickers[0].data[key]['x']+51.6,kickers[0].data[key]['y'] )< 20 and self.game.ball_pos[key]['Vx'] ):
258 | ball1 = (self.game.ball_pos[key-1]['x'], self.game.ball_pos[key-1]['y'])
259 | ball2 = (self.game.ball_pos[key]['x'], self.game.ball_pos[key]['y'])
260 | if ball1[0]-ball2[0]>0:
261 | (x,y) = self.line_intersection((ball1,ball2) , ((-52.6,1),(-52.6,0)) )
262 |
263 | if(abs(y)<7.5 ):
264 | if(abs(y-ball1[1])> abs(x-ball1[0])):
265 | self.shoot_in_width_r +=1
266 | else:
267 | self.shoot_in_length_r +=1
268 | # print( "On-Target Shoot", key , kickers[0].number , self.game.right_team.name)
269 | self.on_target_shoot_r +=1
270 | self.shoot_status =1
271 |
272 | elif(abs(y)<16 and abs(y)>9):
273 | if(abs(y-ball1[1])> abs(x-ball1[0])):
274 | self.shoot_in_width_r +=1
275 | else:
276 | self.shoot_in_length_r +=1
277 | # print( "Off-Target Shoot", key ,kickers[0].number , self.game.right_team.name)
278 | self.off_target_shoot_r +=1
279 | self.shoot_status =1
280 |
281 |
282 | elif(len(kickers)>0 and kickers[0].team.name == self.game.left_team.name and math.hypot(kickers[0].data[key]['x']-51.6,kickers[0].data[key]['y'] ) < 20 and self.game.ball_pos[key]['Vx']):
283 | ball1= (self.game.ball_pos[key-1]['x'], self.game.ball_pos[key-1]['y'])
284 | ball2= (self.game.ball_pos[key]['x'], self.game.ball_pos[key]['y'])
285 | if ball2[0]-ball1[0]>0:
286 | (x,y) = self.line_intersection( (ball1,ball2), ((52.6,1),(52.6,0)) )
287 |
288 | if(abs(y)<7.5 ):
289 | if(abs(y-ball1[1])> abs(x-ball1[0])):
290 | self.shoot_in_width_l +=1
291 | else:
292 | self.shoot_in_length_l +=1
293 | # print( "On-Target Shoot",key, kickers[0].number , self.game.left_team.name)
294 | self.on_target_shoot_l +=1
295 | self.shoot_status =1
296 |
297 | elif(abs(y)<16 and abs(y)>9):
298 | if(abs(y-ball1[1])> abs(x-ball1[0])):
299 | self.shoot_in_width_l +=1
300 | else:
301 | self.shoot_in_length_l +=1
302 | # print( "Off-Target Shooet",key, kickers[0].number , self.game.left_team.name)
303 | self.off_target_shoot_l+=1
304 | self.shoot_status =1
305 |
306 |
307 | def check_pass(self, key):
308 | if len(self.game.get_last_kickers(key))>0:
309 | if(key not in self.play_on_cycles):
310 | self.pass_status = 0
311 |
312 | elif(self.pass_status == 0):
313 | self.pass_last_kicker = self.game.get_last_kickers(key)[0]
314 | self.pass_last_kick_cycle = key
315 | self.pass_status = 1
316 |
317 | elif(self.pass_status == 1 ):
318 |
319 | if(self.pass_last_kicker == self.game.get_last_kickers(key)[0] and self.game.get_last_kickers(key)[0].data[key]['is_kicked']):
320 | self.pass_status = 1
321 | self.pass_last_kick_cycle = key
322 |
323 | elif(self.pass_last_kicker != self.game.get_last_kickers(key)[0] and self.pass_last_kicker.team == self.game.get_last_kickers(key)[0].team ):
324 | self.i = self.i+1
325 | ball1 = (self.game.ball_pos[self.pass_last_kick_cycle]['x'], self.game.ball_pos[self.pass_last_kick_cycle]['y'])
326 | ball2 = (self.game.ball_pos[key]['x'], self.game.ball_pos[key]['y'])
327 | if(self.pass_last_kicker.team.name == self.game.right_team.name):
328 | self.pass_r += 1
329 | if(abs(ball1[0]-ball2[0])>abs(ball1[1]-ball2[1])):
330 | self.pass_in_width_r +=1
331 | else:
332 | self.pass_in_length_r +=1
333 | else:
334 | self.pass_l += 1
335 | if(abs(ball1[0]-ball2[0])>abs(ball1[1]-ball2[1])):
336 | self.pass_in_width_l +=1
337 | else:
338 | self.pass_in_length_l +=1
339 |
340 |
341 | self.pass_status = 1
342 | self.pass_last_kicker = self.game.get_last_kickers(key)[0]
343 | self.pass_last_kick_cycle = key
344 |
345 | elif(self.pass_last_kicker.team != self.game.get_last_kickers(key)[0].team):
346 | if(self.game.get_last_kickers(key)[0].team.name == self.game.right_team.name):
347 | self.intercept_r += 1
348 | else:
349 | self.intercept_l += 1
350 | ball1 = (self.game.ball_pos[self.pass_last_kick_cycle]['x'], self.game.ball_pos[self.pass_last_kick_cycle]['y'])
351 | ball2 = (self.game.ball_pos[key]['x'], self.game.ball_pos[key]['y'])
352 |
353 |
354 | self.pass_status = 1
355 | self.pass_last_kicker = self.game.get_last_kickers(key)[0]
356 | self.pass_last_kick_cycle = key
357 |
358 |
359 | def analyze(self):
360 | ''' pass, shoot, pass intercept, shot intercept, possesion , '''
361 |
362 | for key in range(1,self.play_on_cycles[-1]+1):
363 | self.check_pass(key)
364 | self.check_shoot(key)
365 | self.update_possession(key)
366 | self.update_distance(key)
367 | self.update_parameters()
--------------------------------------------------------------------------------