简体   繁体   English

Python OOP - 足球模拟

[英]Python OOP - Soccer Simulation

I'm new to OOP.我是 OOP 的新手。 I'd like to simulate a soccer match.我想模拟一场足球比赛。 How do I access Play instance variables in the Player/Offender/Defender classes?如何访问 Player/Offender/Defender 类中的 Play 实例变量? If another structure is better, please help.如果其他结构更好,请帮助。

class Player:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def move_to(self, x, y):
        self.x = (self.x + x) / 2
        self.y = (self.y + y) / 2

    ## Loop through Play.Players to find nearest. How do I access Play.Players?
    def nearest(self):
        return nearest

class Offender(Player):
    def __init__(self, x, y):
        super().__init__(x, y)

    # Move to ball.
    def strategy():
        ball_x = Play.ball_x # how do I access Play.ball_x
        ball_y = Play.ball_y # how do I access Play.ball_y
        self.move_to(ball_x, ball_y)

class Defender(Player):
    def __init__(self, x, y):
        super().__init__(x, y)

    # Move to nearest player
    def strategy(self):
        nearest = self.nearest()
        self.move_to(nearest)          

class Play:
    def __init__(self, offense_players, defense_players, ball_x, ball_y):
        self.offense = [Offender(player) for player in offense_players]
        self.defense = [Defender(player) for player in defense_players]
        self.players = self.offense + self.defense
        self.ball_x = ball_x
        self.ball_y = ball_y

    def simulate(self):
        while True:
            for player in self.players:
                player.strategy()

if __name__ == "__main__":
    Play().simulate()

Instead of having Offender and Defender classes, I have one for each position, ie Striker(Player) , Midfielder(Player) , Goalie(Player) , etc. which is why I'd like to store their respective strategy in their class and not in the Play class.我没有为每个 position 设置一个OffenderDefender类,即Striker(Player)Midfielder(Player)Goalie(Player)等,这就是为什么我想将它们各自的strategy存储在他们的 class 中而不是在Play class。

Not sure how much this will be helpful for you, as the implementation is in C++不确定这对您有多大帮助,因为实现在 C++

You can checkout my implementation for a similar problem statement https://github.com/rimpo/footballcpp您可以查看我的实现以获取类似的问题陈述https://github.com/rimpo/footballcpp

For understanding the arcade game framework implementation for which the above bot was written, checkout http://richard-shepherd.github.io/coding-world-cup/index.html要了解编写上述机器人的街机游戏框架实现, 请查看 http://richard-shepherd.github.io/coding-world-cup/index.ZFC35FDC70D5FC69D769883A82ZEC

I would do the following:我会做以下事情:

keep track of game state in another (data) class:在另一个(数据)class 中跟踪游戏 state:

class GameState:

    def __init__(self, offense_players, defense_players, ball_x, ball_y):
        self.offense = offense_players
        self.defense = defense_players
        self.players = self.offense + self.defense
        self.ball_x = ball_x
        self.ball_y = ball_y

You may even wish to use python3.7 dataclasses (and some other features) for this (although it is not at all necessary)您甚至可能希望为此使用dataclasses (和一些其他功能)(尽管这完全没有必要)

from dataclasses import dataclass
from typing import List 


@dataclass 
class GameState:

    offense: List[Offender]
    defense: List[Defender]
    ball_x: float 
    ball_y: float 

    @property 
    def players(self):
        return offense + defense 

Players then take this state in their strategy and are expected to update their internal state (like position).然后玩家在他们的策略中采用这个 state 并有望更新他们的内部 state(类似位置)。 nearest player is implemented by taking the minimum l2 distance between other players using the key argument to min that takes a function of another player, p which is written using lambda . nearest玩家是通过使用min的关键参数获取其他玩家之间的最小l2 距离来实现的,该参数采用另一个玩家的 function, p使用lambda编写。

class Player:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def move_to(self, x, y, other_players):
        self.x = (self.x + x) / 2
        self.y = (self.y + y) / 2

    def nearest(self):
        return nearest

class Offender(Player):
    def __init__(self, x, y):
        super().__init__(x, y)

    # Move to ball.
    def strategy(self, game_state):
        ball_x = game_sate.ball_x # how do I access Play.ball_x
        ball_y = game_state.ball_y # how do I access Play.ball_y
        self.move_to(ball_x, ball_y)

class Defender(Player):
    def __init__(self, x, y):
        super().__init__(x, y)

    # Move to nearest player
    def strategy(self, game_state):
        # we assume you are moving to offensive players - which 
        # you will not be apart of 
        nearest = min(
            game_state.offense
            key=lambda p: (
                (self.x - p.x) **2 + (self.y - p.y) ** 2
            ) ** (1/2)  # take the l2 norm to find the "closest" player to you
        )
        self.move_to(nearest.x, nearest.y)      

Then, play the game然后,玩游戏

class Play:

    def __init__(self, game_state):
        self.game_state = game_state

    def simulate(self):
        while True:
            for player in self.game_state.players:
                player.strategy(self.game_state)

if __name__ == "__main__":
    Play(GameState(
        [Offender(-1, 0), Offender(-1, -1), ...]
        [Defender(1, 0), Offender(1, -1), ...]
    )).simulate()

You could then implement some actual players然后你可以实现一些实际的播放器

class TiernaDavidson(Defender):

    def strategy(self, *args, **kwargs):
        return better_strategy(*args, **kwargs)

You will have to ask her for the implementation of better_strategy ;)您将不得不请执行better_strategy ;)

I just elaborate the idea from the comment of martineau : We just pass the Play instance as argument to the relevant methods of Player .我只是从martineau的评论中详细阐述了这个想法:我们只是将Play实例作为参数传递给Player的相关方法。 I also wrote out a very first draft for the nearest() method, but you might want to improve its logic.我还为nearest()方法写了一个初稿,但你可能想改进它的逻辑。 I was just drafting this to demonstrate how you could solve your OOP design problem.我只是起草这个来演示如何解决您的 OOP 设计问题。

import typing


class Player:
    def __init__(self, x: float, y: float):
        self.x = x
        self.y = y

    def move_to(self, x: float, y: float) -> None:
        self.x = (self.x + x) / 2
        self.y = (self.y + y) / 2

    def nearest(self, play: "Play") -> "Player":
    # This must yet be adapted to handle the edge case of two players 
# having equal distance to the current player. You didn't specify the 
# desired output for that case, hence I just ignored that scenario for now.
        return min([
            p for p in play.players 
            if p.x != self.x or p.y != self.y, # this is to 
# exclude the player itself. 
# This is a buggy logic, because it relies on an assumption that is not  
# validated in the code (the assumption that two different players never 
# have identical coordinates). You might want to introduce a uniqe `id` 
# instance variable to the Player class, to handle this identification in a 
# clean way.
            ],
            key=lambda p: (self.x - p.x)**2 + (self.y - p.y)**2
        ) 


class Offender(Player):
    def __init__(self, x: float, y: float):
        super().__init__(x, y)

    # Move to ball.
    def strategy(self, play: "Play") -> None:
        self.move_to(play.ball_x, play.ball_y)


class Defender(Player):
    def __init__(self, x: float, y: float):
        super().__init__(x, y)

    # Move to nearest player
    def strategy(self, play: "Play") -> None:
        self.move_to(self.nearest(play=play)          


class Play:
    def __init__(
    self, 
    offense_players: typing.List["Offender"], 
    defense_players: typing.List["Defender"],
    ball_x: float, 
    ball_y: float,
):
        self.offense = offense_players
        self.defense = defense_players
        self.players = self.offense + self.defense
        self.ball_x = ball_x
        self.ball_y = ball_y

    def simulate(self) -> None:
        while True:  # this is still a bad condition, you might want to change this. However you didn't specify your desired logic, so I didn't change it.
            for player in self.players:
                player.strategy(self, play=self)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM