我有 C# 背景,具有相当扎实的 OOP 技能。在学习任何 OOP 语言时,我通常会参考曾经被问到的一个旧的 Smalltalk 面试问题。
如何制作一个没有任何条件语句的石头剪刀布游戏?
这是我的想法:
game_piece.py
"""Game Piece Class represenets the base game piece"""
from __future__ import annotations
class GamePiece:
"""Base class for all game pieces"""
def __init__(self) -> None:
pass
def __repr__(self) -> str:
return "<GamePiece>"
def play(self, game_piece: GamePiece) -> bool:
"""Play method from base class for all game pieces to override.
This method will call the game piece's specific 'do you beat' method
:param game_piece: The user's chosen game piece.
:return: bool
"""
return \
game_piece.do_you_beat_paper() | \
game_piece.do_you_beat_rock() | \
game_piece.do_you_beat_scissors()
def do_you_beat_rock(self) -> bool:
"""Every game piece is asked if they can beat a other game pieces.
Returns a true if it can. Otherwise, returns a false.
:return: bool
"""
return False
def do_you_beat_paper(self) -> bool:
"""Every game piece is asked if they can beat a other game pieces.
Returns a true if it can. Otherwise, returns a false.
:return: bool
"""
return False
def do_you_beat_scissors(self) -> bool:
"""Every game piece is asked if they can beat a other game pieces.
Returns a true if it can. Otherwise, returns a false.
:return: bool
"""
return False
摇滚.py
"""Represents the Rock Game Piece"""
from game_piece import GamePiece
class Rock(GamePiece):
"""This class represents the Rock Game Piece"""
def __repr__(self) -> str:
return "<Rock>"
def play(self, game_piece: GamePiece) -> bool:
"""Call this method to have the game pieces play each other.
It'll return a true if the game piece is a Paper.
Otherwise return false.
:param game_piece: Represents the game piece that it's playing against
:returns: bool
"""
return game_piece.do_you_beat_rock()
def do_you_beat_scissors(self) -> bool:
"""When the opponent game piece is a pair of scissors
it will call this method on the Rock opponent piece and
return true to demonstrate that it can beat a pair
of scissors.
:return: bool
"""
return True
纸.py
"""Represents the Paper Game Piece"""
from game_piece import GamePiece
class Paper(GamePiece):
"""This class represents the Paper Game Piece"""
def __repr__(self) -> str:
return "<Paper>"
def play(self, game_piece: GamePiece) -> bool:
"""Call this method to have the game pieces play each other.
It'll return a true if the game piece is Scissors.
Otherwise return false.
:param game_piece: Represents the game piece that it's playing against
:returns: bool
"""
return game_piece.do_you_beat_paper()
def do_you_beat_rock(self) -> bool:
"""When the opponent game piece is a rock
it will call this method on the Paper opponent piece and
return true to demonstrate that it can beat a rock.
:return: bool
"""
return True
剪刀.py
"""Represents Scissors Game Piece"""
from game_piece import GamePiece
class Scissors(GamePiece):
"""This class represents the Paper Game Piece"""
def __repr__(self) -> str:
return "<Scissors>"
def play(self, game_piece: GamePiece) -> bool:
"""Call this method to have the game pieces play each other.
It'll return a true if the game piece is Paper.
Otherwise return false.
:param game_piece: Represents the game piece that it's playing against
:returns: bool
"""
return game_piece.do_you_beat_scissors()
def do_you_beat_paper(self) -> bool:
"""When the opponent game piece is a Paper
it will call this method on the Scissors opponent piece and
return true to demonstrate that it can beat a Paper.
:return: bool
"""
return True
主.py
"""The main calling program for the game Rock, Paper, Scissors"""
import random
from typing import Any
import click
from game_piece import GamePiece
from paper import Paper
from rock import Rock
from scissors import Scissors
@click.group()
def cli():
"""Required by click"""
@click.command()
@click.option("--selection",
prompt="Please select: [R]ock, [P]aper or [S]cissors",
help="The user's selection of either \
[R]ock, [P]aper or [S]cissors.")
def shoot(selection: str) -> None:
"""The call to 'Shoot' based on the rules
:param selection: The user's choice
:return: None
"""
game_piece_list = {"R": Rock, "P": Paper, "S": Scissors}
user_selected_game_piece = game_piece_list[selection.upper()]
mach_selected_game_piece: Any = random.choice(
list(game_piece_list.items()))
print(f"You selected {selection} which is {user_selected_game_piece}")
does_user_win = user_selected_game_piece.play(mach_selected_game_piece)
print(f"Can {user_selected_game_piece} beat {mach_selected_game_piece}")
cli.add_command(shoot)
if __name__ == "__main__":
cli()
我收到的错误是:
TypeError: Rock.play() missing 1 required positional argument: 'game_piece'
由于游戏片段是由人类和机器随机选择的,我认为这会起作用。
有人可以解释我如何将类型推断为基本类型并接受任何子类型作为参数吗?
问题出在线路上
game_piece_list = {"R": Rock, "P": Paper, "S": Scissors}
你的字典中的项目是类而不是这些类的对象。
play()
函数需要一个 GamePiece
类型的对象。
所以使用
game_piece_list = {"R": Rock(), "P": Paper(), "S": Scissors()}
应该可以工作,因为它创建每个游戏块类的对象。
虽然这应该可行,但您的游戏逻辑并不真正需要游戏片段的对象,而只需要它们背后的逻辑。正如@提议的 jasonharper,在这里使用静态方法可能是有意义的。