【再掲】リクエスト:じゃんけんゲームの作成
複数のコンピュータとじゃんけんをして、1人の勝者を決めるプログラムを作成してください。
レベル2:複数のコンピュータとの勝負
参加人数が複数のジャンケンゲームを実装してください。
プレイヤーは1人で残りはコンピュータ(CPU)とします。最終的に1人の勝者が決まるまでジャンケンを続け、勝者の名前を表示するようにしてください。
(想定外の入力はないものとします)
実装例
import numpy as np
N_HAND = 3 # じゃんけんの手の種類
ROCK = 0
SCISSORS = 1
PAPER = 2
WIN = 0
LOSE = 1
AIKO = 2
class Player(object):
""" 参加者(Player、CPU)を作成するクラス
Attributes:
hand (int): じゃんけんの手(グー(0)、チョキ(1)、パー(2))
name (char): プレイヤーの名前
cpu (Bool): CPUか否か
survive (Bool): ゲームに残っているか。
"""
def __init__(self, name='cpu', cpu=True):
self.hand = np.random.randint(N_HAND)
self.name = name
self.cpu = cpu
self.survive = True
def set_hand(self, hand=None):
"""
じゃんけんの手を決める。
Args:
hand (int): じゃんけんの手(グー(0)、チョキ(1)、パー(2))
Returns:
None
"""
if hand is None:
self.hand = np.random.randint(N_HAND)
else:
self.hand = hand
def get_hand(self):
return self.hand
def set_survive(self, survive):
self.survive = survive
def get_survive(self):
return self.survive
def get_name(self):
return self.name
def cnt_survive_player(players):
"""
残っているplayer数をカウントする
Args:
players (list): Playerオブジェクト格納したリスト
Return:
cnt (int): 勝ち残っている人数
"""
cnt = 0
for player in players:
if player.get_survive():
cnt += 1
return cnt
def get_win_lose(hands):
"""
あいこ以外のジャンケン判定
0, 1 : 0 win
0, 2 : 2 win
1,2 : 1 win
1, 0 : 0 win
結論:一つ上の数字(mod 3)には勝てる
Args:
hands (set): 全Playerの手の集合。
Return:
win (int): 勝利した手
lose (int): 負けた手
"""
sum_hands = sum(hands) % 3
if sum_hands == 0: # SCISSORS and PAPER
win = SCISSORS
lose = PAPER
elif sum_hands == 1: # ROCK and SCISSORS
win = ROCK
lose = SCISSORS
elif sum_hands == 2: # Rock and PAPER
win = PAPER
lose = ROCK
return win, lose
def judge_janken_v2(players):
"""
ジャンケンの判定を行い残っている人数を返す。
Args:
players (list): Playerオブジェクト格納したリスト
Return:
勝ち残っているplayerの人数
"""
# 重複している手をまとめる
hands = []
for player in players:
if player.get_survive():
hands.append(player.get_hand())
hands = set(hands)
if (len(hands) == 3) or (len(hands) == 1):
# あいこの場合
return cnt_survive_player(players)
else:
win_hand, lose_hand = get_win_lose(hands)
for player in players:
if player.get_survive():
hand = player.get_hand()
if hand == lose_hand:
print(f"{player.get_name()}は負けました。")
player.set_survive(False) # 敗退
return cnt_survive_player(players)
def game_start():
"""
じゃんけんを開始するメイン関数
"""
print("じゃんけんをします")
print("CPUの人数を入力してください")
n_player = int(input())
n_survive_player = n_player
players = []
# playerインスタンスの作成
players.append(Player(name='Taro', cpu=False))
# cpuインスタンスの作成
for i in range(n_player):
players.append(Player(f'cpu{i+1}'))
i = 0
while n_survive_player > 1: # 勝ち残りが1人になるまで繰り返す
i += 1
print(f'{i}回戦目')
# cpus_hand = {}
for player in players:
if player.get_survive() == False:
continue
if player.cpu == False:
print("あなたの手は? (0:グー、1:チョキ、2:パー)")
my_hand = int(input())
player.set_hand(my_hand)
else:
player.set_hand()
print(f'{player.name}の手: {player.get_hand()}')
# ジャンケンの勝敗判定
n_survive_player = judge_janken_v2(players)
# 勝者を表示
for player in players:
if player.get_survive():
winner = player.get_name()
print(f'優勝は「{winner}」です')
if __name__ == "__main__":
game_start()
今回のポイント
- 12行目〜24行目:Playerクラスの実装
- Playerクラスの属性と用途
- hand:ジャンケンの手
- name:名前。勝者を表示するため。
- cpu:オブジェクトがCPUかを判定するため。
プレイヤーとの違いは手を入力できるかどうかです。 - survive:勝ち残っているか判定。
- Playerクラスの属性と用途
- 99行目〜119行目:ジャンケンの判定
- ジャンケンの判定は出された手の種類がポイントです。1種類もしくは全3種類の場合があいこで、2種類の場合が勝敗がつきます。
- 149行目:ジャンケンの終了条件
- ジャンケンが終わるのは、勝ち残っているプレイヤーが1人になったらという条件にしました。Playerクラスのsurvive属性を利用しています。
終わりに
コードを紹介しましたが、実装例と書いているようにあくまで一例です。
今回のコードはGitHubにも上げていきますので、みなさんの実装例も紹介してもらえると幸いです。
余談
リクエストを掲載してから毎回自分でもコーディングしているので、実装して思ったことを記載していきたいと思います。
今回のリクエストは前回の拡張のつもりで出したのですが、あまり流用できず作り直すところが多くなってしまいました。拡張性が足らなかったですね。特にオブジェクト周りですが、CpuオブジェクトからPlayerオブジェクトに命名変更している通り、PlayerもCPUを同じように扱っておいた方が実装が簡単でした。
アルゴリズムの考え方は、実際にジャンケンをした時に普段どうやって勝敗を判断しているかをイメージして書いています。パーの勝ち、グーの負け、と言った会話がされると思うのでその通りに、勝ち負けの手を取得してます。
コメント