Python OOP - симулятор футбола - PullRequest
3 голосов
/ 01 ноября 2019

Я новичок в ООП. Я хотел бы смоделировать футбольный матч. Как получить доступ к переменным экземпляра Play в классах Player / Offender / Defender? Если другая структура лучше, пожалуйста, помогите.

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()

Вместо классов Offender и Defender у меня есть один для каждой позиции, то есть Striker(Player), Midfielder(Player), Goalie(Player) и т. Д., Поэтому я бы хотелхранить их strategy в своем классе, а не в Play классе.

Ответы [ 3 ]

1 голос
/ 01 ноября 2019

Я просто развил идею из комментария martineau : Мы просто передаем экземпляр Play в качестве аргумента соответствующим методам Player. Я также написал самый первый черновик для метода nearest(), но вы можете улучшить его логику. Я просто готовил это, чтобы продемонстрировать, как вы можете решить вашу проблему проектирования ООП.

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)
1 голос
/ 01 ноября 2019

Не уверен, насколько это будет полезно для вас, так как реализация в C ++

Вы можете проверить мою реализацию для аналогичной постановки задачи https://github.com/rimpo/footballcpp

Для понимания аркадной игрыреализация фреймворка, для которой был написан вышеупомянутый бот, извлеките http://richard -shepherd.github.io / coding-world-cup / index.html

1 голос
/ 01 ноября 2019

Я хотел бы сделать следующее:

отслеживать состояние игры в другом классе (данных):

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

Возможно, вы даже захотите использовать python3.7 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 

Игроки затем переходят в это состояние в своей стратегиии ожидается, что они обновят свое внутреннее состояние (например, положение). nearest игрок реализуется путем определения минимального l2 расстояния между другими игроками, используя ключевой аргумент для min, который принимает функцию другого игрока, 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)      

Затем играйте в игру

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()

Затем вы можете реализовать некоторых реальных игроков

class TiernaDavidson(Defender):

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

Вы должны будете попросить ее о реализации better_strategy;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...