【Python3】０から作るPython初心者プログラミング【03】-大人数でじゃんけんプログラム-

#【ご挨拶】こんにちは! ぬかさんエンジニアリングです。(3回目‼)
前回の投稿にまたまたありがたいことにコメント頂きまして、<font color="81C4FF">**クラス**</font>の使い方について教えて頂きました。
今回は、それらの内容も含めた上で<font color="Coral">**複数人同時にじゃんけんが出来るようにアップデート**</font>した内容になっております。
<font color="81C4FF">**クラス**</font>を使って実際に遊べる程度のプログラムを作ってみたいと思っていた初心者の方がいらっしゃいましたら是非挑戦してみてください！また、複数の<font color="OliveDrab">**インスタンス**</font>をまとめて扱う方法や特殊<font color="0C6CCC">**メソッド**</font>`__str__`など少し応用的な話もありますので、既にクラスを理解されている方も興味があれば見ていってくださいね！
<font color="LimeGreen">**LGTM**</font>も是非よろしくお願いします‼










#本シリーズ初めての方へ
<details><summary><strong>【趣旨】</strong></summary>
Python初心者プログラマーが入門書で学んだ知識を実践的なコーディングを通じて身に着けていくためのお題を提供します。
お題を基に各自コーディングに挑戦していただいた後、この記事でコーディングの過程を答え合わせします。
</details>


<details><summary><strong>【対象】</strong></summary>
Pythonの入門書を読んで理解はしたけど何か目的をもって実践的にコーディングをしたい方。
ProgateでPythonコースをLv5まで勉強したけど応用力が身に着いていないと感じている方。
</details>


<details><summary><strong>【初心者とは】</strong></summary>
この記事シリーズでの初心者は下記の項目を理解済みであることが目安となっています。
[演算子, 標準ライブラリ, 条件分岐, 繰り返し処理, 例外処理, リスト, タプル, セット, 辞書, オブジェクト指向]
</details>


<details><summary><strong>【利用ライブラリ & Python3 --version】<strong></summary><div>
・Google Colaboratory
以下のリンクからアクセスして使い方を確認した後、左上のファイルタブから「ノートブックを新規作成」を選択して自分のプログラムを作りましょう。ファイルはGoogleDriveに保存されるため、自分のGoogleアカウントと連携させるのを忘れないようにしましょう。

<a href="https://colab.research.google.com/notebooks/welcome.ipynb?hl=ja#scrollTo=2fhs6GZ4qFMx">Colaboratory へようこそ</a>  ←ここからリンクへ飛ぶ

・Python 3.7.12

</div></details>

$$$$

それではさっそく本題に入っていきましょう:muscle:

#第【03】回 -大人数でじゃんけんプログラム-
このシリーズ第三回目の今回は、前回の<font color="Coral">**「じゃんけんプログラムのクラス化」**</font>を応用して<font color="Coral">**「大人数じゃんけんプログラム」**</font>を実装します！
前回<font color="81C4FF">**クラス**</font>化した内容を更に進化させ、じゃんけんに３回勝利した人が優勝する仕様にアップデートしていきます。入力を受け取ってゲームをスタートし、一連の流れを止めずにどの順番でどう処理を実行してゴールまで行きつくのか、その中身を皆さんと一緒に作っていきたいと思います。










##【お題】じゃんけんプログラムを複数人同時プレイできる様にしよう！
```py
janken()

#出力
参加人数を整数で入力してください >4
参加人数は4人です。
あなたの名前を入力してください >nukasan
nukasanさんですね。エントリー完了しました。

nukasanの現在の獲得勝利ポイント：0

コンピュータ1の現在の獲得勝利ポイント：0

コンピュータ2の現在の獲得勝利ポイント：0

コンピュータ3の現在の獲得勝利ポイント：0


じゃんけんぽん！
-------------------------------------------------------
じゃんけんの選択肢：{1: 'グー', 2: 'チョキ', 3: 'パー'}
-------------------------------------------------------
あなたの出す手を入力してください(整数：1, 2, 3) > 1
nukasanさんの手：グー
コンピュータ1さんの手：チョキ
コンピュータ2さんの手：パー
コンピュータ3さんの手：パー


あいこでしょ！
-------------------------------------------------------
じゃんけんの選択肢：{1: 'グー', 2: 'チョキ', 3: 'パー'}
-------------------------------------------------------
あなたの出す手を入力してください(整数：1, 2, 3) > 1
nukasanさんの手：グー
コンピュータ1さんの手：パー
コンピュータ2さんの手：パー
コンピュータ3さんの手：グー


コンピュータ1とコンピュータ2の勝ち！１ポイントゲット


nukasanの現在の獲得勝利ポイント：0

コンピュータ1の現在の獲得勝利ポイント：1

コンピュータ2の現在の獲得勝利ポイント：1

コンピュータ3の現在の獲得勝利ポイント：0


じゃんけんぽん！
-------------------------------------------------------
じゃんけんの選択肢：{1: 'グー', 2: 'チョキ', 3: 'パー'}
-------------------------------------------------------
あなたの出す手を入力してください(整数：1, 2, 3) > 1
nukasanさんの手：グー
コンピュータ1さんの手：パー
コンピュータ2さんの手：グー
コンピュータ3さんの手：パー


コンピュータ1とコンピュータ3の勝ち！１ポイントゲット


nukasanの現在の獲得勝利ポイント：0

コンピュータ1の現在の獲得勝利ポイント：2

コンピュータ2の現在の獲得勝利ポイント：1

コンピュータ3の現在の獲得勝利ポイント：1


じゃんけんぽん！
-------------------------------------------------------
じゃんけんの選択肢：{1: 'グー', 2: 'チョキ', 3: 'パー'}
-------------------------------------------------------
あなたの出す手を入力してください(整数：1, 2, 3) > 1
nukasanさんの手：グー
コンピュータ1さんの手：パー
コンピュータ2さんの手：チョキ
コンピュータ3さんの手：パー


                .
                .
                .
                .
                .


nukasanの現在の獲得勝利ポイント：1

コンピュータ1の現在の獲得勝利ポイント：2

コンピュータ2の現在の獲得勝利ポイント：2

コンピュータ3の現在の獲得勝利ポイント：1


じゃんけんぽん！
-------------------------------------------------------
じゃんけんの選択肢：{1: 'グー', 2: 'チョキ', 3: 'パー'}
-------------------------------------------------------
あなたの出す手を入力してください(整数：1, 2, 3) > 1
nukasanさんの手：グー
コンピュータ1さんの手：チョキ
コンピュータ2さんの手：チョキ
コンピュータ3さんの手：パー


あいこでしょ！
-------------------------------------------------------
じゃんけんの選択肢：{1: 'グー', 2: 'チョキ', 3: 'パー'}
-------------------------------------------------------
あなたの出す手を入力してください(整数：1, 2, 3) > 1
nukasanさんの手：グー
コンピュータ1さんの手：グー
コンピュータ2さんの手：グー
コンピュータ3さんの手：チョキ


nukasanとコンピュータ1とコンピュータ2の勝ち！１ポイントゲット



*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+
>>>>>よってコンピュータ1とコンピュータ2の優勝です！！<<<<<
*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+*+
```
1.３人以上の参加人数を入力してゲームに反映できるようにしてください。
2.プレイヤー名を入力してゲームに反映できるようにしてください。
3.じゃんけんの前に各参加者の現在の得点を出力してください。
4.各参加者のじゃんけんの手を出力してください。
5.じゃんけんの勝者の名前を出力してください。
6.じゃんけん勝利ポイントを３点先取した参加者の名前を出力してください。










###〔お助けヒント〕
<details><summary><font color="DarkMagenta">**ヒント１**</font></summary>
参加者の<font color="OliveDrab">**インスタンス**</font>は一つ一つ<font color="5008CC">**変数**</font>に代入せずに配列にまとめて格納し、取り出す場合はfor文を使うようにすると便利です。</details>

<details><summary><font color="DarkMagenta">**ヒント２**</font></summary>
新たに<font color="81C4FF">**クラス**</font>を作成し、初期化<font color="0C6CCC">**メソッド**</font>で<font color="OliveDrab">**インスタンス**</font>の格納された配列を<font color="5008CC">**変数**</font>に代入し、じゃんけんの一連の流れを実行できる<font color="OliveDrab">**インスタンス**</font><font color="0C6CCC">**メソッド**</font>を作成してまとめると複数人同時じゃんけんのプログラムが作りやすくなります。</details>

<details><summary><font color="DarkMagenta">**ヒント３**</font></summary>
３人以上でじゃんけんする場合、場に出ている手の種類が１種と３種である場合は必ず「あいこ」になり、２種の場合は必ずどちらかが勝ちます。</details>

<details><summary><font color="DarkMagenta">**ヒント４**</font></summary>
<font color="OliveDrab">**インスタンス**</font><font color="0C6CCC">**メソッド**</font>内で他の<font color="OliveDrab">**インスタンス**</font><font color="0C6CCC">**メソッド**</font>を実行することで、一つの<font color="OliveDrab">**インスタンス**</font><font color="0C6CCC">**メソッド**</font>を実行するだけで様々な処理を連鎖的にさせることができます。</details>










##【解答】
解答は以下の通りです。
※この解答はあくまで私の回答です。各々の方法でお題が解けていればそれで全然かまいません。むしろ、もっと簡潔な方法があればご教示頂けると助かります:bow_tone1:

```py
import random

#コンピュータクラス(名前と勝利ポイントを保持、じゃんけんの手を選択)
class Computer:

  def __init__(self, name, point=0):
    self.name = name
    self.point = point

  def pon(self):
    self.hand = random.choice(tuple(HANDS.values()))


#ヒューマンクラス(名前と勝利ポイントを保持、じゃんけんの手を選択)
class Human:

  def __init__(self, name, point=0):
    self.name = name
    self.point = point

  def pon(self):
    while True:
      try:
        print("-"*55 + f"\nじゃんけんの選択肢：{HANDS}\n" + "-"*55)
        human_hand = int(input("あなたの出す手を入力してください(整数：1, 2, 3) > "))
        if human_hand in (1, 2, 3):
          self.hand = HANDS[human_hand]            
          return
      except:
        print("整数1, 2, 3を入力をして下さい")
      

#じゃんけんクラス(じゃんけんをする際の手の選択と出力、判定、ポイントの加算と出力)
class Janken:
  
  def __init__(self, players):
    self.players = players
  
  ##じゃんけんの一連の流れを実行
  def play(self):
    for player in self.players:
      print(f"\n{player.name}の現在の獲得勝利ポイント：{player.point}")
    print("\n\nじゃんけんぽん！")
    self.select_hand()
    while True:
      self.winners = self.judge()
      if not self.winners:
        print("\n\nあいこでしょ！")
        self.select_hand()
      else:
        break
    print(f"\n\n{'と'.join([winner.name for winner in self.winners])}の勝ち！１ポイントゲット\n")
    for winner in self.winners: 
      winner.point += 1
    return [winner.name for winner in self.winners if winner.point >= 3]
  
  ##ヒューマンクラスとコンピュータクラスのponインスタンスメソッドを実行して各参加者のじゃんけんの手を出力
  def select_hand(self):
    for player in self.players:
      player.pon()    
      print(f"{player.name}さんの手：{player.hand}")  

  ##参加者のじゃんけんの手があいこか否かを判定、あいこでなければ勝者を決定
  def judge(self):
    hands = set(player.hand for player in self.players)
    if len(hands) != 2:
      return None
    hand1, hand2 = hands
    win = hand1 if hand1.stronger_than(hand2) else hand2
    return [player for player in self.players if player.hand == win]
      
#ハンドクラス(判定で2つの手の勝敗を決定)        
class Hand:

  def __init__(self, shape, stronger_than):
    self.shape = shape
    self._stronger_than = stronger_than

  ##デバッグ時にインスタンスを指定の形で出力する用
  def __repr__(self):
    return repr(self.shape)
  
  ##インスタンスをstr型で出力する際にself.shapeを出力
  def __str__(self):
    return self.shape
  
  ##2つの手のうち、一方の手が勝つ時の相手の手と実際の相手の手が同じだという返り値を返す
  def stronger_than(self, enemy):
    return self._stronger_than == enemy.shape

#ハンドクラスのインスタンスを要素とする辞書
HANDS = {1: Hand("グー", "チョキ"),
         2: Hand("チョキ", "パー"),
         3: Hand("パー", "グー")}


#じゃんけんの実施＆出力
def janken():

  ##参加人数を選択
  while True:
    try :
      all_player_num = int(input("参加人数を整数で入力してください >"))
      if all_player_num > 0:
        break
    except:
      print("正の整数を入力してください。")    
  print(f"参加人数は{all_player_num}人です。")

  ##名前の入力
  while True:
    my_name = (input("あなたの名前を入力してください >"))
    if my_name:
      print(f"{my_name}さんですね。エントリー完了しました。")
      break
  
  ##参加者のクラスをplayer配列に格納
  players = Human(my_name), *[Computer(f"コンピュータ{n}") for n in range(1, all_player_num)]

  ##じゃんけんクラスのplayインスタンスメソッドを実行し、優勝者が出るまでじゃんけんを繰り返す
  while True:
      result = Janken(players).play() 
      if len(result) > 0:
          print("\n\n" + "*+"*30 + f"\n>>>>>よって{'と'.join(result)}の優勝です！！<<<<<\n" + "*+"*30 + "\n\n\n")
          break
  
#じゃんけんメソッドを実行
janken()
```









##【解説】
今回は、じゃんけんプログラムの応用編と言うことで人間一人とコンピュータ複数人でじゃんけんが出来るプログラムにアップデートしてみたいと思います。

主な変更点は3つあります。
一つ目。各プレイヤーの名前と勝利ポイントを<font color="OliveDrab">**インスタンス**</font><font color="5008CC">**変数**</font>に保持できるように<font color="81C4FF">**クラス**</font>を変更します。
二つ目。複数人で同時にじゃんけんをして誰が勝利したか判定できるように変更します。
三つ目。各プレイヤーの勝利ポイントを記録し、3点先取した人が優勝する仕組みに変更します。

この変更点を満たす形で<font color="81C4FF">**クラス**</font>や<font color="OliveDrab">**インスタンス**</font><font color="0C6CCC">**メソッド**</font>を作っていきたいと思います。

どんな<font color="81C4FF">**クラス**</font>を作るのか、どんな<font color="OliveDrab">**インスタンス**</font><font color="0C6CCC">**メソッド**</font>を作るのかは自由度が高すぎてむやみに作ってもこんがらがります。まずは、どんな機能が必要でどんな<font color="OliveDrab">**インスタンス**</font><font color="0C6CCC">**メソッド**</font>を<font color="81C4FF">**クラス**</font>にまとめると分かりやすくて効率の良いコードになるのか自分で仮説を立てて作ってみます。たいていはエラーを吐くのでそこから試行錯誤と情報収集を繰り返しながら自分なりの解法を見つけていきます。その過程で得る知見は実践経験と結びついてしっかりと身に着いていきます。今回の解説も情報収集として使っていただくために書いておりますが、なるべく自力で作ってみるのをおすすめします。










###〔作り方〕










####<font color="DarkMagenta">**①プレイ人数とプレイヤー名を入力できる機構を作成**</font>
⑴プレイ人数の入力機構を作成

```py
##参加人数を選択
  while True:
    try :
      all_player_num = int(input("参加人数を整数で入力してください >"))
      if all_player_num > 0:
        break
    except:
      print("正の整数を入力してください。")    
  print(f"参加人数は{all_player_num}人です。")
```

⑵プレイヤーの名前の入力機構を作成

```py
##名前の入力
  while True:
    my_name = (input("あなたの名前を入力してください >"))
    if my_name:
      print(f"{my_name}さんですね。エントリー完了しました。")
      break
```










####<font color="DarkMagenta">**②ヒューマンクラスとコンピュータクラスに名前と勝利ポイントを受け取る初期化メソッドを追加**</font>
⑴<font color="OliveDrab">**インスタンス**</font>作成時に名前を代入する`self.name`を追加

```py
#コンピュータクラス(名前と勝利ポイントを保持、じゃんけんの手を選択)
class Computer:

  def __init__(self, name):
    self.name = name #<<<<<<<<<

#ヒューマンクラス(名前と勝利ポイントを保持、じゃんけんの手を選択)
class Human:

  def __init__(self, name):
    self.name = name #<<<<<<<<<
```

⑵勝利ポイントを代入する`self.point`を追加

```py
#コンピュータクラス(名前と勝利ポイントを保持、じゃんけんの手を選択)
class Computer:

  def __init__(self, name, point=0):
    self.name = name
    self.point = point #<<<<<<<<<

#ヒューマンクラス(名前と勝利ポイントを保持、じゃんけんの手を選択)
class Human:

  def __init__(self, name, point=0):
    self.name = name
    self.point = point #<<<<<<<<<
```

<font color="OliveDrab">**インスタンス**</font>生成時にはポイントは0なので、引数に初期値として0を設定しておきます。










####<font color="DarkMagenta">**③参加者が何人でも処理しやすいようにインスタンスを配列(タプル)に格納**</font>
⑴ヒューマン<font color="81C4FF">**クラス**</font>はプレイヤーの名前を、コンピュータは番号を受け取りplayersに格納

```py
  ##参加者のクラスをplayer配列に格納
  players = Human(my_name), *[Computer(f"コンピュータ{n}") for n in range(1, all_player_num)]

  print(players)
  #出力(参加人数４人の場合)
  '''
  (<__main__.Human object at 0x7f842fe0a3d0>, <__main__.Computer object at 0x7f842fe98e90>, 
   <__main__.Computer object at 0x7f842fe98f90>, <__main__.Computer object at 0x7f84330fa410>)
  '''

```

プレイヤー名入力機構で入力した名前が`my_name`に代入されているので、ヒューマン<font color="81C4FF">**クラス**</font>作成時に受け取ります。
コンピュータの数は参加人数からプレイヤー数１人を除いた分になるので、参加人数が代入されている`all_player_num`を使ってリスト内包表記で人数分の<font color="OliveDrab">**インスタンス**</font>を作成します。配列に代入する際には、「＊」を使いリストから順番に要素を取り出す方法を使います。
実際にplayersの中身を見ると<font color="81C4FF">**クラス**</font>型のオブジェクト(<font color="OliveDrab">**インスタンス**</font>)が格納されているのが分かります。
ここで疑問に思う方がいるかもしれません。<font color="81C4FF">**クラス**</font>を作成するときは
`インスタンス名 = クラス名()`
と書きますよね？？と。
私もそう思っていました。
だた、実は<font color="OliveDrab">**インスタンス**</font>を作成する際に<font color="5008CC">**変数**</font>に代入する必要はありません。
通例で<font color="5008CC">**変数**</font>に代入しているのは、<font color="OliveDrab">**インスタンス**</font>を作成した際にその<font color="OliveDrab">**インスタンス**</font>を分かりやすく識別するという理由があるからです。<font color="5008CC">**変数**</font>に代入しなければむき出しの<font color="81C4FF">**クラス**</font>型オブジェクトが出力されてしまい、同じ<font color="81C4FF">**クラス**</font>から作った<font color="OliveDrab">**インスタンス**</font>を瞬時に識別するのは難しいのです。上記のコードを見ると変数に代入する理由がよくわかると思います。
今回の様に<font color="OliveDrab">**インスタンス**</font>をまとめて扱いたい場合は、<font color="5008CC">**変数**</font>への代入が要らないことを理解していればわざわざ
<font color="OliveDrab">**インスタンス**</font>作成→<font color="5008CC">**変数**</font>に代入→リストを作成→<font color="5008CC">**変数**</font>をリストに追加
せずとも
<font color="OliveDrab">**インスタンス**</font>作成→配列へ代入
とコードを省略できます。是非覚えておいてください。










####<font color="DarkMagenta">**④参加者のインスタンス配列を受け取りじゃんけんを実行するJankenクラスを作成**</font>
⑴初期化<font color="0C6CCC">**メソッド**</font>を作成

```py
#じゃんけんクラス(じゃんけんをする際の手の選択と出力、判定、ポイントの加算と出力)
class Janken:
  
  def __init__(self, players):
    self.players = players
```

⑵じゃんけんの一連の流れを実行するplay<font color="OliveDrab">**インスタンス**</font><font color="0C6CCC">**メソッド**</font>を作成

```py
##じゃんけんの一連の流れを実行
  def play(self):
    ###現在の参加者全員のそれぞれの勝利ポイントを出力
    for player in self.players:
      print(f"\n{player.name}の現在の獲得勝利ポイント：{player.point}")
    ###じゃんけんスタート
    print("\n\nじゃんけんぽん！")
    ###ヒューマンクラスとコンピュータクラスのponインスタンスメソッドを実行して各参加者のじゃんけんの手の記録と出力
    self.select_hand()
    ###各参加者の手からjudgeインスタンスメソッドであいこか否か判別。あいこを抜け出すまでじゃんけんを繰り返す
    while True:
      self.winners = self.judge()
      if not self.winners:
        print("\n\nあいこでしょ！")
        self.select_hand()
      else:
        break
    ###じゃんけんの勝者の名前を出力
    print(f"\n\n{'と'.join([winner.name for winner in self.winners])}の勝ち！１ポイントゲット\n")
    ###じゃんけんの勝者に勝利ポイントを加算し、もし３ポイント獲得した参加者がいれば名前を返り値として返す
    for winner in self.winners: 
      winner.point += 1
    return [winner.name for winner in self.winners if winner.point >= 3]
```

⑶各参加者のじゃんけんの手を記録し出力する`select_hand`<font color="OliveDrab">**インスタンス**</font><font color="0C6CCC">**メソッド**</font>を作成

```py
  ##ヒューマンクラスとコンピュータクラスのponインスタンスメソッドを実行して各参加者のじゃんけんの手を出力
  def select_hand(self):
    for player in self.players:
      player.pon()    
      print(f"{player.name}さんの手：{player.hand}")  
```

`pon`<font color="OliveDrab">**インスタンス**</font><font color="0C6CCC">**メソッド**</font>を実行すると`self.hand`に3種のHand<font color="OliveDrab">**インスタンス**</font>のどれかが代入される様にヒューマン<font color="81C4FF">**クラス**</font>とコンピュータ<font color="81C4FF">**クラス**</font>を一部変更します。
（`print(self.hand)`を実行すると、特殊<font color="0C6CCC">**メソッド**</font>`＿＿str＿＿`の効果で"グーチョキパー"の文字列が出力されますが、`type(self.hand)`では`<class '__main__.Hand'>`が出力されるためHand<font color="81C4FF">**クラス**</font>の<font color="OliveDrab">**インスタンス**</font>が代入されていると分かります。）

⑷参加者のじゃんけんの手からあいこと勝敗を判定

```py
  ##参加者のじゃんけんの手があいこか否かを判定、あいこでなければ勝者を決定
  def judge(self):
    ###参加者のじゃんけんの手をセットにまとめると場に出ている手の種類が分かる
    hands = set(player.hand for player in self.players)
    ###手が１種、３種の場合は必ずあいこになるので返り値でNoneを返す
    if len(hands) != 2:
      return None
    ###手が２種の場合は、一方の手でstronger_thanインスタンスメソッドを実行し、強い手を判別する
    hand1, hand2 = hands
    win = hand1 if hand1.stronger_than(hand2) else hand2
    ###強い手を出していた参加者を勝者として返り値で返す
    return [player for player in self.players if player.hand == win]
```

⑤の⑵で詳しく説明










####<font color="DarkMagenta">**⑤複数人の勝敗判定に対応するためじゃんけんの手の辞書を変更しHandクラスを作成**</font>
⑴じゃんけんの手の辞書をJudge<font color="OliveDrab">**インスタンス**</font><font color="0C6CCC">**メソッド**</font>の判定に使いやすいように変更

```py
#ハンドクラスのインスタンスを要素とする辞書
HANDS = {1: Hand("グー", "チョキ"),
         2: Hand("チョキ", "パー"),
         3: Hand("パー", "グー")}
```

⑤の⑵で詳しく説明

⑵Hand<font color="81C4FF">**クラス**</font>を作成する

```py
#ハンドクラス(判定で2つの手の勝敗を決定)        
class Hand:

  def __init__(self, shape, stronger_than):
    self.shape = shape
    self._stronger_than = stronger_than
  
  ##デバッグ時にインスタンスを指定の形で出力する用
  def __repr__(self):
    return repr(self.shape)
  
  ##インスタンスをstr型で出力する際にself.shapeを出力
  def __str__(self):
    return self.shape
  
  ##2つの手のうち、一方の手が勝つ時の相手の手と実際の相手の手が同じだという返り値を返す
  def stronger_than(self, enemy):
    return self._stronger_than == enemy.shape
```

初期化<font color="0C6CCC">**メソッド**</font>では、`self.shape`に選んだ手、`self._stronger_than`に選んだ手が勝てる相手の手（グーに対するチョキ）を代入します。

Handの<font color="OliveDrab">**インスタンス**</font>は`__str__`という特殊<font color="0C6CCC">**メソッド**</font>によって、str型(文字列型)で表示するときに`self.shape`、つまり選んだ手に対応する文字列"グーチョキパー"のどれかを出力します。
この特殊<font color="0C6CCC">**メソッド**</font>`__str__`についてはTechAcademyマガジンの[Pythonの__str__と__repr__の違いを現役エンジニアが解説【初心者向け】](https://techacademy.jp/magazine/46504)をご覧ください。

`stronger_than`<font color="OliveDrab">**インスタンス**</font><font color="0C6CCC">**メソッド**</font>は、`judge`<font color="OliveDrab">**インスタンス**</font><font color="0C6CCC">**メソッド**</font>で２種の手から勝ち手を判別する際に用いられます。
まず２種の手の集合を`hand1`と`hand2`に分けます。
次に`hand1.stronger_than(hand2)`で実行し、`hand1`が選んだ手(グー)が勝てる相手の手(チョキ)である`self._stronger_than`と相手の手である`enemy.shape`が同じだという返り値を返します。

あとは`judge`<font color="OliveDrab">**インスタンス**</font><font color="0C6CCC">**メソッド**</font>で返り値が`True`の場合は`hand1`を`win`に代入、返り値が`False`の場合は`hand2`を`win`に代入します。
`win`に代入した手の種が勝ち手なので、各プレイヤーの手と照らし合わせ、同じ手を選んでいた場合はそのプレイヤーを勝者として返り値を返します。

ちなみに、それぞれの手の種は`print`で出力してもただの文字列に見えますが`type`を見るとHand<font color="81C4FF">**クラス**</font>の<font color="OliveDrab">**インスタンス**</font>だと分かります。これは特殊<font color="0C6CCC">**メソッド**</font>`＿＿str＿＿`の効果で文字列が出力されているだけで本質は`<class '__main__.Hand'>`だからと言うことです。だから、引数`enemy`に`hand2`を渡して`enemy.shape`を書いてもエラーにならずに処理することができます。










####<font color="DarkMagenta">**⑥プレイヤーの誰かが３ポイントを取るまでじゃんけんを繰り返す機構を作成**</font>
⑴`Janken`<font color="81C4FF">**クラス**</font>の`play`<font color="OliveDrab">**インスタンス**</font><font color="0C6CCC">**メソッド**</font>の返り値が０以上なら優勝者を出力

```py
  ##じゃんけんクラスのplayインスタンスメソッドを実行し、優勝者が出るまでじゃんけんを繰り返す
  while True:
      result = Janken(players).play() 
      if len(result) > 0:
          print("\n\n" + "*+"*30 + f"\n>>>>>よって{'と'.join(result)}の優勝です！！<<<<<\n" + "*+"*30 + "\n\n\n")
          break
```

`Janken(players).play()`によって`Janken`<font color="81C4FF">**クラス**</font>の「属性」として参加者の<font color="OliveDrab">**インスタンス**</font>の配列が代入され、同時に`play`<font color="OliveDrab">**インスタンス**</font><font color="0C6CCC">**メソッド**</font>が実行されることで誰かが勝つまでじゃんけんをしてくれます。たった一文ですがほぼすべての処理が実行されます。
`play`<font color="OliveDrab">**インスタンス**</font><font color="0C6CCC">**メソッド**</font>は返り値として３ポイント以上勝利ポイントを獲得した人の名前が帰ってきます。ですので、返り値を`result`に代入して`len()`で要素数が０より多くなった瞬間じゃんけんを終わりにして名前を出力することで優勝者を出力出来ます。










#【終わりに】
今回は、前回のじゃんけんプログラムを応用して<font color="Coral">**複数人同時にじゃんけんできるプログラム**</font>を作ってきました。いかがだったでしょうか。
何も見ずに作るのは結構難しかったのではないでしょうか。特に<font color="OliveDrab">**インスタンス**</font>を変数に代入せずに使う感覚を掴むまでには時間を要したのではないでしょうか。次回はもっと難易度は上がりますが一緒に頑張っていきましょう！反対に今回の課題をすらすらと作ることが出来た方はもう中級者に手がかかり始めていると言ってもいいかもしれません。どちらにせよ今回の課題で何か成長を感じてくださったのであれば嬉しいです。

もしもコーディングの部分で間違いなどありましたらコメントでご指摘いただけると幸いです。
また、その他質問などございましたらコメントをお願い致します。

次回は、今回作った大人数じゃんけんプログラムを応用して<font color="Coral">**「あっち向いてほいプログラム」**</font>を作りたいと思います。下記リンクからどうぞ！
→[鋭意制作中]()

この記事が良かったと感じたら<font color="LimeGreen">**LGTM**</font>を宜しくお願いします！それではまた次回！:wave: