演習 - ゲームにビヘイビアーを追加する
じゃんけんゲームへのクラスとデータの追加が済んだので、最後の部分であるビヘイビアーを追加する番です。 メソッドの形式でビヘイビアーを追加します。 クラスにメソッドを追加した最終的な結果は、動作するじゃんけんゲームになります。
ビヘイビアーを実装する
オブジェクト指向プログラミング (OOP) スタイルでプログラムを構築する場合、最初にモデルを作成してからコードを作成することを学習しました。 モデリングにより、プログラムを構成するオブジェクト、データ、ビヘイビアーが表されたテーブル出力が生成されました。 同じテーブルをもう一度示しておきます。
段階 | Actor | 動作 | Data |
---|---|---|---|
入力 | 参加者 | 手を選択する | Participant(choice) で "選択" として保存された手 |
処理中 | GameRound | 選択内容とゲーム ルールを比較する | 調べられた "結果" |
処理中 | GameRound | 結果の値に基づいてポイントを与える | 勝った Participant(point) に追加された "ポイント" |
処理中 | ゲーム | 続行の回答を確認する | 回答は true、continue、quit |
出力 | ゲーム | 新しいゲーム ラウンドまたはゲーム終了のクレジット |
ここでは、Behavior
列に注目し、クラスに追加されるメソッドをそれに設定します。 また、それらのメソッドにコードを追加し、必要な動作が実行されるようにします。
これまでのコードは次のようになります。 以下の手順でそれを拡張してみましょう。
ファイル
rock-paper-scissor.py
があるはずです。 ない場合、次の手順を実行します。ファイル
rock-paper-scissor
を作成し、エディターを開きます。touch rock-paper-scissor.py code .
そして、次のコードを追加します。
class Participant: def __init__(self): self.points = 0 self.choice = "" class GameRound: class Game: def __init__(self): self.endGame = False self.participant = Participant() self.secondParticipant = Participant()
ゲームを開始する
ゲームの最初の部分にはそのセットアップが含まれます。これは、ゲーム自体をインスタンス化し、参加者の操作を待機するポイントまでゲームを進めることを意味します。
rock-paper-scissor.py
の内容を次のコードに置き換え、ファイルを保存します。class Participant: def __init__(self, name): self.name = name self.points = 0 self.choice = "" def choose(self): self.choice = input("{name}, select rock, paper or scissor: ".format(name= self.name)) print("{name} selects {choice}".format(name=self.name, choice = self.choice)) class GameRound: def __init__(self, p1, p2): p1.choose() p2.choose() def compareChoices(self): print("implement") def awardPoints(self): print("implement") class Game: def __init__(self): self.endGame = False self.participant = Participant("Spock") self.secondParticipant = Participant("Kirk") def start(self): game_round = GameRound(self.participant, self.secondParticipant) def checkEndCondition(self): print("implement") def determineWinner(self): print("implement") game = Game() game.start()
テーブルから各オブジェクトにメソッドを追加しました。 行った変更をテーブルに表しておくと、どのビヘイビアーによってどのメソッドが追加されたのかがわかりやすくなります。
動作 メソッド Actor 手を選択する choose() 参加者 選択内容を比較する compareChoices() GameRound ポイントを与える awardPoints() GameRound 続行の回答を確認する checkEndCondition() ゲーム ゲーム終了クレジット determineWinner() ゲーム 上のテーブルのほとんどのビヘイビアーは、似た名前のメソッドに対応しています。 例外は "ゲーム終了クレジット" で、
determineWinner()
になります。 その理由は、ゲームを終了する過程で、勝者を確認してその情報を出力できるようにするためです。 このメソッドに何か別の名前を付けてもかまいません。python3
を呼び出してコードを実行します。python3 rock-paper-scissor.py
プログラムにより、次のような出力が生成されます。
Spock, select rock, paper or scissor:
この出力は、プログラムがユーザーの操作を待機していることを意味します。
rock
を選択して Enter キーを押し、プログラムが動作することを確認します。paper
を選択して、もう一度 Enter キーを押します。出力は次のテキストのようになります。
Spock, select rock, paper or scissor: rock Spock selects rock Kirk, select rock, paper or scissor: paper Kirk selects paper
Note
この演習のソリューションは、「Start a game - solution code」にあります。
ルールを実装する
問題の説明から、特定の選択が他の選択に勝つことがわかります。 たとえば、石はハサミに勝ち、ハサミは紙に勝ちます。 次のようなコードを記述するとよさそうに見えます。
if choice1 == "rock" and choice2 == "scissor":
return 1
elif choice1 == "paper" and choice2 == "scissor":
return -1
else:
# something else
# and so on
結果として大量のコードが作成され、少し扱いにくくなります。 ゲームのルール セットを拡張する必要があり、コードの保守がさらに困難になったらどうしますか。
さいわいなことに、もっと良い方法があります。 より優れたアプローチは、ルールをマトリックスとして考えることです。 マトリックスを使用すると、他の組み合わせに勝つ組み合わせを表現できます。 勝つ手には 1
を、引き分けには 0
を、負ける手には -1
を設定します。 次のマトリックスは、石、紙、ハサミについてのものです。
選択肢 | 石 | 論文 | ハサミ |
---|---|---|---|
石 | 0 | -1 | 1 |
論文 | 1 | 0 | -1 |
ハサミ | -1 | 1 | 0 |
次のような多次元配列を使用して、上記のテーブルを Python で実装できます。
rules = [
[0, -1, 1],
[1, 0, -1],
[-1, 1, 0]
]
rules[0][1] # Rock vs Paper = -1, Paper wins over Rock
Participant
クラスを見つけ、toNumericalChoice()
メソッドを追加します。def toNumericalChoice(self): switcher = { "rock": 0, "paper": 1, "scissor": 2 } return switcher[self.choice]
上記のメソッドにより、コマンド ラインの文字列入力が整数に変換されます。 そうすることで、その回の勝者を簡単に決定できるようになります。
ヒント
コードを正しくインデントするには、必ずカーソルを適切に置いてください。
GameRound
クラスを見つけ、compareChoices()
メソッドを更新します。def compareChoices(self, p1, p2): return self.rules[p1.toNumericalChoice()][p2.toNumericalChoice()]
このコードにより、2 つの選択を比較して、勝者を決定することができます。
同じクラスに、
getResultAsString()
メソッドを追加します。def getResultAsString(self, result): res = { 0: "draw", 1: "win", -1: "loss" } return res[result]
このメソッドは、結果を判断し、わかりやすいテキストを画面に出力するのに役立ちます。
引き続き同じクラスで、
__init__()
の内容を次のコードに置き換えます。def __init__(self, p1, p2): self.rules = [ [0, -1, 1], [1, 0, -1], [-1, 1, 0] ] p1.choose() p2.choose() result = self.compareChoices(p1,p2) print("Round resulted in a {result}".format(result = self.getResultAsString(result) ))
前のコードで導入された
rules
フィールドには、石、紙、ハサミのルールの実装が含まれています。 さらに、self.compareChoices()
を呼び出すことで、行われた 2 つの選択が "比較" されます。 最後に、見る人にわかりやすい結果を画面に出力する行があります。
Note
この演習のソリューションは、「Implement rules - solution code」にあります。
ゲームのスコアを付ける
ゲームのスコアを付けるには、プレイが終了した後で、適切なプレーヤーにポイントを割り当てます。 勝ったプレーヤーは 1 ポイント獲得し、引き分けと負けのときはポイントはありません。
Participant
クラスを見つけ、incrementPoint()
メソッドを追加します。def incrementPoint(self): self.points += 1
ヒント
属性を変更するメソッドの導入は、カプセル化に向けた最初のステップです。 必要であれば、
points
フィールドを__points__
に変更して、外側からメンバーを "隠ぺい" し、カプセル化を練習してください。GameRound
クラスを見つけて、__init()__
メソッドの最後に次のコードを追加します。if result > 0: p1.incrementPoint() elif result < 0: p2.incrementPoint()
Note
この演習のソリューションは、「Score game - solution code」にあります。
継続の確認を追加する
継続の確認は、ゲームの終わりにある質問で、続行するかどうかをプレーヤーにたずねます。 ユーザーが続行しないことを選択した場合は、現在の結果と勝者 (存在する場合) を出力できます。
Game
クラスを見つけ、メソッドdetermineWinner()
を更新します。def determineWinner(self): resultString = "It's a Draw" if self.participant.points > self.secondParticipant.points: resultString = "Winner is {name}".format(name=self.participant.name) elif self.participant.points < self.secondParticipant.points: resultString = "Winner is {name}".format(name=self.secondParticipant.name) print(resultString)
同じクラス内で、メソッド
checkEndCondition()
を更新します。def checkEndCondition(self): answer = input("Continue game y/n: ") if answer == 'y': GameRound(self.participant, self.secondParticipant) self.checkEndCondition() else: print("Game ended, {p1name} has {p1points}, and {p2name} has {p2points}".format(p1name = self.participant.name, p1points= self.participant.points, p2name=self.secondParticipant.name, p2points=self.secondParticipant.points)) self.determineWinner() self.endGame = True
同じクラスで、
start()
メソッドのコードを次のコードに置き換えます。def start(self): while not self.endGame: GameRound(self.participant, self.secondParticipant) self.checkEndCondition()
ファイルを保存します。
コマンド
python3 rock-paper-scissor.py
を実行して、プログラムをテストします。python3 rock-paper-scissor.py
入力として
rock
とpaper
を選択し、続行を確認するメッセージが表示されたらn
を入力します。出力は次のテキストのようになります。
Spock, select rock, paper or scissor: rock Spock selects rock Kirk, select rock, paper or scissor: paper Kirk selects paper Round resulted in a loss Continue game y/n: n Game ended, Spock has 0, and Kirk has 1 Winner is Kirk
Note
この演習のソリューションは、「Continuation query - solution code」にあります。
お疲れさまでした。 じゃんけんゲームの OOP バージョンを実装できました。