├── .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() --------------------------------------------------------------------------------