---
# System prepended metadata

title: Python Ability Check 2020

---

# Python Ability Check 2020

Last Updated: 2020/08/20 18:45

- [問題 / Problem](#問題--problem)
  - [初期仕様 / First Problem](#初期仕様--first-problem)
  - [追加仕様 / Additional Problem](#追加仕様--additional-problem)
    - [1. 鈴木、鹿島田からのフィードバックを極力反映せよ](#1-鈴木鹿島田からのフィードバックを極力反映せよ)
      - [for 前田](#for-前田)
        - [from 鹿島田](#from-鹿島田)
        - [from 鈴木](#from-鈴木)
      - [フィードバック for 渡邉](#フィードバック-for-渡邉)
        - [from 鹿島田](#from-鹿島田-1)
        - [from 鈴木](#from-鈴木-1)
    - [2. `ドラミ` を追加せよ](#2-ドラミ-を追加せよ)
    - [3. `源静香` が「グー、チョキ、パーをちょうど1/3の確率ずつ出す」か確認せよ](#3-源静香-がグーチョキパーをちょうど13の確率ずつ出すか確認せよ)
- [質疑応答 / Questions & Answers](#質疑応答--questions--answers)
- [制約 / Constraints](#制約--constraints)
- [評価方法 / Evaluation Point](#評価方法--evaluation-point)
- [最終評価 / Evaluations](#最終評価--evaluations)
  - [from 鹿島田](#from-鹿島田-2)
    - [to 前田: 総合得点: 75 点](#to-前田-総合得点-75-点)
      - [完成度 (仕様充足度; 最大20点): 15 点](#完成度-仕様充足度-最大20点-15-点)
      - [可読性 (PEP8に準拠してなければ0点; 最大30点): 25 点](#可読性-pep8に準拠してなければ0点-最大30点-25-点)
      - [拡張可能性(仕様追加への対応コスト; 最大20点): 15 点](#拡張可能性仕様追加への対応コスト-最大20点-15-点)
      - [実行時間( `trials=1000` x 16通り(= 16,000試行)で30分を超えたら0点; 最大10点): 10 点](#実行時間-trials1000-x-16通り-16000試行で30分を超えたら0点-最大10点-10-点)
      - [芸術点 (審査員の主観; 最大20点): 10 点](#芸術点-審査員の主観-最大20点-10-点)
    - [to 渡邉: 総合得点: 33 点](#to-渡邉-総合得点-33-点)
      - [完成度 (仕様充足度; 最大20点): 5 点](#完成度-仕様充足度-最大20点-5-点-1)
      - [可読性 (PEP8に準拠してなければ0点; 最大30点): 3 点](#可読性-pep8に準拠してなければ0点-最大30点-3-点-1)
      - [拡張可能性(仕様追加への対応コスト; 最大20点): 5 点](#拡張可能性仕様追加への対応コスト-最大20点-5-点-1)
      - [実行時間( `trials=1000` x 16通り(= 16,000試行)で30分を超えたら0点; 最大10点): 10 点](#実行時間-trials1000-x-16通り-16000試行で30分を超えたら0点-最大10点-10-点-1)
      - [芸術点 (審査員の主観; 最大20点) (審査員の主観; 最大20点): 10 点](#芸術点-審査員の主観-最大20点-審査員の主観-最大20点-10-点)
  - [from 鈴木](#from-鈴木-2)
    - [to 前田: 総合得点: 50 点](#to-前田-総合得点-50-点)
      - [完成度 (仕様充足度; 最大20点): 10 点](#完成度-仕様充足度-最大20点-10-点)
      - [可読性 (PEP8に準拠してなければ0点; 最大30点): 15 点](#可読性-pep8に準拠してなければ0点-最大30点-15-点)
      - [拡張可能性(仕様追加への対応コスト; 最大20点): 5 点](#拡張可能性仕様追加への対応コスト-最大20点-5-点)
      - [実行時間( `trials=1000` x 16通り(= 16,000試行)で30分を超えたら0点; 最大10点): 10 点](#実行時間-trials1000-x-16通り-16000試行で30分を超えたら0点-最大10点-10-点)
      - [芸術点 (審査員の主観; 最大20点): 10 点](#芸術点-審査員の主観-最大20点-10-点)
    - [to 渡邉: 総合得点: 20 点](#to-渡邉-総合得点-20-点)
      - [完成度 (仕様充足度; 最大20点): 0 点](#完成度-仕様充足度-最大20点-0-点)
      - [可読性 (PEP8に準拠してなければ0点; 最大30点): 0 点](#可読性-pep8に準拠してなければ0点-最大30点-0-点)
      - [拡張可能性(仕様追加への対応コスト; 最大20点): 5 点](#拡張可能性仕様追加への対応コスト-最大20点-5-点-1)
      - [実行時間( `trials=1000` x 16通り(= 16,000試行)で30分を超えたら0点; 最大10点): 10 点](#実行時間-trials1000-x-16通り-16000試行で30分を超えたら0点-最大10点-10-点-1)
      - [芸術点 (審査員の主観; 最大20点): 5 点](#芸術点-審査員の主観-最大20点-5-点)
- [総評](#総評)
  - [from 鹿島田](#from-鹿島田-3)
    - [to 前田](#to-前田-1)
    - [to 渡邉](#to-渡邉-1)
  - [from 鈴木](#from-鈴木-3)
    - [to 前田](#to-前田-2)
    - [to 渡邉](#to-渡邉-2)
- [備考 / Miscellaneous](#備考--miscellaneous)
  - [改訂履歴 / Revision History](#改訂履歴--revision-history)

## 問題 / Problem

### 初期仕様 / First Problem

**2020年8月19日02:00(JST)** までに、下記の仕様で **「じゃんけんプログラム」** を作成してください。

`main.py`

```main.py
#!/usr/bin/env python3

def main(first: str, second: str, trials: int):
    """
    Parameters
    --------
    first, second: string
        源静香: グー、チョキ、パーをちょうど1/3の確率ずつ出す。
        野比のび太: 最初はランダム、勝ったら次も同じ手を出す。
        ドラえもん: グーしか出せない。
        骨川スネ夫: チョキとパーしか出せない。
    trials: int
        試行回数（max: 10000）

    Returns
    --------
    要素数=試行回数の配列と勝率
    配列の要素はタプル
        [("<firstが出した手 {"グー" | "チョキ" | "パー"}>", "<secondが出した手 {"グー" | "チョキ" | "パー"}>", "<firstから見た勝敗 {"Win" | "Draw" | "Lose"}>"), ..., ()] <firstの勝率(小数点下2桁)> %

    Raises
    --------
    ValueError
        引数の文字列や試行回数がおかしい場合

    Examples
    --------
    >>> main("ドラえもん", "野比のび太", 10)
    [("グー", "チョキ", "Win"), ("グー", "グー", "Draw"), ("グー", "パー", "Lose"), ("グー", "パー", "Lose"), ("グー", "パー", "Lose"), ("グー", "パー", "Lose"), ("グー", "パー", "Lose"), ("グー", "パー", "Lose"), ("グー", "パー", "Lose"), ("グー", "パー", "Lose")] 10.00 %
    >>> main("源静香", "骨川スネ夫", 10)
    [("グー", "パー", "Lose"), ("パー", "チョキ", "Lose"), ("パー", "チョキ", "Lose"), ("グー", "パー", "Lose"), ("パー", "チョキ", "Lose"), ("グー", "パー", "Lose"), ("チョキ", "チョキ", "Draw"), ("グー", "パー", "Lose"), ("チョキ", "パー", "Lose"), ("チョキ", "チョキ", "Lose")] 0.00 %
    """
    pass

if __name__ == "__main__":
    main()
```

`README.md`

```markdown:README.md
# Python Ability Check 2020 - <提出者名>

## How to Run

## Refrences

- [Qiita:foobar]()

## Miscellaneous

備考
```

ファイル一式を `PAC2020_<提出者名>_<提出日時: YYYYMMDD>.zip` に固めて提出してください。

### 追加仕様 / Additional Problem

下記3つの仕様を追加します。
締め切りは **2020年8月20日12:00(JST)** です。
ファイル一式を `PAC2020_<提出者名>_<提出日時: YYYYMMDD>.zip` に固めて提出してください。

#### 1. 鈴木、鹿島田からのフィードバックを極力反映せよ

##### for 前田

###### from 鹿島田

> # Feedback from 鹿島田 to 前田
>
> ## Before 仕様追加
> 
> 総合得点: 40 点 （ `拡張可能性` と `芸術点` は仕様追加後のみなので60点満点）
> 
> ### 完成度 (仕様充足度; 最大20点): 10 点
>
> - スネ夫の出し手の仕様が違っています
> - 配列への参照はmethodの呼び出しでなくて良いです
> 
> ### 可読性 ([PEP8](https://pep8-ja.readthedocs.io/ja/latest/)に準拠してなければ0点; 最大30点): 20 点
>
> - 順を追って読んでいけるので読むことに苦労しないと思いました
> - コメントもつけてもらえているので読み手として助かります
> 
> ### 実行時間 ( `trials=1000` x 16通り(= 16,000試行)で30分を超えたら0点; 最大10点): 10 点
>
> - 条件を満たしているので満点としました

###### from 鈴木

> # Feedback from 鈴木 to 前田
>
> ## Before 仕様追加
>
> 総合得点: 35 点 （ `拡張可能性` と `芸術点` は仕様追加後のみなので60点満点）
>
> ### 完成度 (仕様充足度; 最大20点): 15 点
>
> 概ね仕様は満たしているが `骨川スネ夫` の挙動がおかしいので `-5` 点。
>
> ### 可読性 ([PEP8](https://pep8-ja.readthedocs.io/ja/latest/)に準拠してなければ0点; 最大30点): 10 点
>
> エラー & 警告 **4** 箇所なので `0` 点。しかし、コメントをちゃんと書いているので `+10` 点。
>
> ```plain
> ./family.py:2:1: F401 'janken.jankenpon' imported but unused
> from janken import pats, jankenpon, judge_result
> ^
> ./main.py:2:1: F401 'janken.pats' imported but unused
> from janken import judge_result, jankenpon, pats, win_rate
> ^
> ./main.py:9:5: F841 local variable 'lose' is assigned to but never used
>     lose = judge_result()[1]
>     ^
> ./main.py:10:5: F841 local variable 'draw' is assigned to but never used
>     draw = judge_result()[2]
>     ^
> 2     F401 'janken.jankenpon' imported but unused
> 2     F841 local variable 'lose' is assigned to but never used
> 4
> ```
> 
> ### 実行時間 ( `trials=1000` x 16通り(= 16,000試行)で30分を超えたら0点; 最大10点): 10 点
>
> ```shell
> python main.py  0.24s user 0.02s system 59% cpu 0.429 total
> ```
>
> 16,000回実行して `0.24s` なので `+10` 点。

##### フィードバック for 渡邉

###### from 鹿島田

> # Feedback from 鹿島田 to 渡邉
>
> ## Before 仕様追加
> 
> 総合得点: 18 点 （ `拡張可能性` と `芸術点` は仕様追加後のみなので60点満点）
> 
> ### 完成度 (仕様充足度; 最大20点): 5 点
>
> - のび太の仕様が完成していない点で大きく点数が下がりました
> - `main.py` の実行結果が仕様書と異なっています
> 
> ### 可読性 ([PEP8](https://pep8-ja.readthedocs.io/ja/latest/)に準拠してなければ0点; 最大30点): 3 点
>
> - 変数が多いことが可読性を下げていると思います
> - Classを定義毎にファイルを分けるなど、整理してもらいたいです
> 
> ### 実行時間 ( `trials=1000` x 16通り(= 16,000試行)で30分を超えたら0点; 最大10点): 10 点
>
> - 条件を満たしているので満点としました

###### from 鈴木

> # Feedback from 鈴木 to 渡邉
>
> ## Before 仕様追加
>
> 総合得点: 5 点 （ `拡張可能性` と `芸術点` は仕様追加後のみなので60点満点）
>
> ### 完成度 (仕様充足度; 最大20点): 0 点
>
> 「野比のび太」が実装できてないので `-10` 点。
> `main.py` が標準入力を受け付けるのは好感触だが、その入力受付コードが汚いので `±0` 点。
> 例外の処理が実装されてないので、 `-10` 点。
> 出力結果が仕様から大きく外れているので、 `0` 点。
>
> ### 可読性 ([PEP8](https://pep8-ja.readthedocs.io/ja/latest/)に準拠してなければ0点; 最大30点): 5 点
>
> エラー & 警告 **94** 箇所なので `0` 点。しかし、コメントを少し書いているので `+5` 点。
>
> ```plain
> ./strategy.py:7:1: E302 expected 2 blank lines, found 1
> class JankenStrategy:
> ^
> ./strategy.py:12:1: E302 expected 2 blank lines, found 1
> class RandomStrategy(JankenStrategy):
> ^
> ./strategy.py:19:1: E302 expected 2 blank lines, found 1
> class Suneo_Strategy(JankenStrategy):
> ^
> ./strategy.py:20:1: W191 indentation contains tabs
> 	# チョキかパー
> ^
> ./strategy.py:20:1: E101 indentation contains mixed spaces and tabs
> 	# チョキかパー
> ^
> ./strategy.py:20:2: E117 over-indented (comment)
> 	# チョキかパー
> 	^
> ./strategy.py:21:1: W191 indentation contains tabs
> 	def next_hand(self):
> ^
> ./strategy.py:21:1: E101 indentation contains mixed spaces and tabs
> 	def next_hand(self):
> ^
> ./strategy.py:21:2: E117 over-indented
> 	def next_hand(self):
> 	^
> ./strategy.py:22:1: W191 indentation contains tabs
> 		# 乱数の初期化
> ^
> ./strategy.py:22:1: E101 indentation contains mixed spaces and tabs
> 		# 乱数の初期化
> ^
> ./strategy.py:22:3: E117 over-indented (comment)
> 		# 乱数の初期化
> 		^
> ./strategy.py:23:1: W191 indentation contains tabs
> 		random.seed()
> ^
> ./strategy.py:23:1: E101 indentation contains mixed spaces and tabs
> 		random.seed()
> ^
> ./strategy.py:23:3: E117 over-indented
> 		random.seed()
> 		^
> ./strategy.py:24:1: W191 indentation contains tabs
> 		n = random.randint(1, 2)
> ^
> ./strategy.py:24:1: E101 indentation contains mixed spaces and tabs
> 		n = random.randint(1, 2)
> ^
> ./strategy.py:25:1: W191 indentation contains tabs
> 		return JankenHand(n)
> ^
> ./strategy.py:25:1: E101 indentation contains mixed spaces and tabs
> 		return JankenHand(n)
> ^
> ./strategy.py:27:1: E302 expected 2 blank lines, found 1
> class Nobita_Strategy(JankenStrategy):
> ^
> ./strategy.py:28:1: W191 indentation contains tabs
> 	def next_hand(self):
> ^
> ./strategy.py:28:1: E101 indentation contains mixed spaces and tabs
> 	def next_hand(self):
> ^
> ./strategy.py:28:2: E117 over-indented
> 	def next_hand(self):
> 	^
> ./strategy.py:29:1: W191 indentation contains tabs
> 		# 乱数の初期化
> ^
> ./strategy.py:29:1: E101 indentation contains mixed spaces and tabs
> 		# 乱数の初期化
> ^
> ./strategy.py:29:3: E117 over-indented (comment)
> 		# 乱数の初期化
> 		^
> ./strategy.py:30:1: W191 indentation contains tabs
> 		random.seed()
> ^
> ./strategy.py:30:1: E101 indentation contains mixed spaces and tabs
> 		random.seed()
> ^
> ./strategy.py:30:3: E117 over-indented
> 		random.seed()
> 		^
> ./strategy.py:31:1: W191 indentation contains tabs
> 		n = random.randint(0, 2)
> ^
> ./strategy.py:31:1: E101 indentation contains mixed spaces and tabs
> 		n = random.randint(0, 2)
> ^
> ./strategy.py:32:1: W191 indentation contains tabs
> 		return JankenHand(n)
> ^
> ./strategy.py:32:1: E101 indentation contains mixed spaces and tabs
> 		return JankenHand(n)
> ^
> ./strategy.py:34:1: E302 expected 2 blank lines, found 1
> class Doraemon_Strategy(JankenStrategy):
> ^
> ./strategy.py:35:1: W191 indentation contains tabs
> 	# グー
> ^
> ./strategy.py:35:1: E101 indentation contains mixed spaces and tabs
> 	# グー
> ^
> ./strategy.py:35:2: E117 over-indented (comment)
> 	# グー
> 	^
> ./strategy.py:36:1: W191 indentation contains tabs
> 	def next_hand(self):
> ^
> ./strategy.py:36:1: E101 indentation contains mixed spaces and tabs
> 	def next_hand(self):
> ^
> ./strategy.py:36:2: E117 over-indented
> 	def next_hand(self):
> 	^
> ./strategy.py:37:1: W191 indentation contains tabs
> 		return JankenHand.goo
> ^
> ./strategy.py:37:1: E101 indentation contains mixed spaces and tabs
> 		return JankenHand.goo
> ^
> ./strategy.py:37:3: E117 over-indented
> 		return JankenHand.goo
> 		^
> ./strategy.py:39:1: E302 expected 2 blank lines, found 1
> class Sizuka_Strategy(JankenStrategy):
> ^
> ./strategy.py:40:1: W191 indentation contains tabs
> 	def next_hand(self):
> ^
> ./strategy.py:40:1: E101 indentation contains mixed spaces and tabs
> 	def next_hand(self):
> ^
> ./strategy.py:40:2: E117 over-indented
> 	def next_hand(self):
> 	^
> ./strategy.py:41:1: W191 indentation contains tabs
> 		# 乱数の初期化
> ^
> ./strategy.py:41:1: E101 indentation contains mixed spaces and tabs
> 		# 乱数の初期化
> ^
> ./strategy.py:41:3: E117 over-indented (comment)
> 		# 乱数の初期化
> 		^
> ./strategy.py:42:1: W191 indentation contains tabs
> 		random.seed()
> ^
> ./strategy.py:42:1: E101 indentation contains mixed spaces and tabs
> 		random.seed()
> ^
> ./strategy.py:42:3: E117 over-indented
> 		random.seed()
> 		^
> ./strategy.py:43:1: W191 indentation contains tabs
> 		n = random.randint(0, 2)
> ^
> ./strategy.py:43:1: E101 indentation contains mixed spaces and tabs
> 		n = random.randint(0, 2)
> ^
> ./strategy.py:44:23: W292 no newline at end of file
> 		return JankenHand(n)		                    ^
> ./hand.py:6:1: E302 expected 2 blank lines, found 1
> class JankenHand(Enum):
> ^
> ./hand.py:29:1: W391 blank line at end of file
>
> ^
> ./main.py:4:1: F401 'random' imported but unused
> import random
> ^
> ./main.py:6:1: F403 'from strategy import *' used; unable to detect undefined names
> from strategy import *
> ^
> ./main.py:9:1: E302 expected 2 blank lines, found 1
> class Player:
> ^
> ./main.py:14:25: F405 'JankenStrategy' may be undefined, or defined from star imports: strategy
>         self.strategy = JankenStrategy()
>                         ^
> ./main.py:24:1: C901 'main' is too complex (18)
> def main(first,second,trials):
> ^
> ./main.py:24:15: E231 missing whitespace after ','
> def main(first,second,trials):
>               ^
> ./main.py:24:22: E231 missing whitespace after ','
> def main(first,second,trials):
>                      ^
> ./main.py:38:32: F405 'Doraemon_Strategy' may be undefined, or defined from star imports: strategy
>             player1.strategy = Doraemon_Strategy()
>                                ^
> ./main.py:41:32: F405 'Nobita_Strategy' may be undefined, or defined from star imports: strategy
>             player1.strategy = Nobita_Strategy()
>                                ^
> ./main.py:42:23: F405 'Nobita_Strategy' may be undefined, or defined from star imports: strategy
>             nobita1 = Nobita_Strategy()
>                       ^
> ./main.py:47:32: F405 'Sizuka_Strategy' may be undefined, or defined from star imports: strategy
>             player1.strategy = Sizuka_Strategy()
>                                ^
> ./main.py:49:9: E115 expected an indented block (comment)
>         # 二人目のストラテジ判定
>         ^
> ./main.py:50:32: F405 'Suneo_Strategy' may be undefined, or defined from star imports: strategy
>             player1.strategy = Suneo_Strategy()
>                                ^
> ./main.py:52:32: F405 'Doraemon_Strategy' may be undefined, or defined from star imports: strategy
>             player2.strategy = Doraemon_Strategy()
>                                ^
> ./main.py:54:32: F405 'Nobita_Strategy' may be undefined, or defined from star imports: strategy
>             player2.strategy = Nobita_Strategy()
>                                ^
> ./main.py:55:23: F405 'Nobita_Strategy' may be undefined, or defined from star imports: strategy
>             nobita2 = Nobita_Strategy()
>                       ^
> ./main.py:61:32: F405 'Sizuka_Strategy' may be undefined, or defined from star imports: strategy
>             player2.strategy = Sizuka_Strategy()
>                                ^
> ./main.py:63:32: F405 'Suneo_Strategy' may be undefined, or defined from star imports: strategy
>             player2.strategy = Suneo_Strategy()
>                                ^
> ./main.py:94:1: W293 blank line contains whitespace
>
> ^
> ./main.py:106:12: E225 missing whitespace around operator
>         res=[(first_hand,second_hand,result)]
>            ^
> ./main.py:106:25: E231 missing whitespace after ','
>         res=[(first_hand,second_hand,result)]
>                         ^
> ./main.py:106:37: E231 missing whitespace after ','
>         res=[(first_hand,second_hand,result)]
>                                     ^
> ./main.py:118:9: E225 missing whitespace around operator
>     char=("源静香","野比のび太","ドラえもん","骨川スネ夫")
>         ^
> ./main.py:118:16: E231 missing whitespace after ','
>     char=("源静香","野比のび太","ドラえもん","骨川スネ夫")
>                ^
> ./main.py:118:24: E231 missing whitespace after ','
>     char=("源静香","野比のび太","ドラえもん","骨川スネ夫")
>                        ^
> ./main.py:118:32: E231 missing whitespace after ','
>     char=("源静香","野比のび太","ドラえもん","骨川スネ夫")
>                                ^
> ./main.py:119:24: E231 missing whitespace after ','
>     print("誰と誰を戦わせる?\n",char)
>                        ^
> ./main.py:120:12: E225 missing whitespace around operator
>     first =input("一人目 :")
>            ^
> ./main.py:121:15: E231 missing whitespace after ','
>     print(char,"\n")#
>               ^
> ./main.py:121:21: E261 at least two spaces before inline comment
>     print(char,"\n")#
>                     ^
> ./main.py:121:22: W291 trailing whitespace
>     print(char,"\n")#
>                      ^
> ./main.py:122:13: E225 missing whitespace around operator
>     second =input("二人目 :")
>             ^
> ./main.py:124:11: E225 missing whitespace around operator
>     trials=int(input("cnt:"))
>           ^
> ./main.py:126:43: E231 missing whitespace after ','
>     print("プレイヤー: {} VS {} !".format(first,second))
>                                           ^
> ./main.py:127:15: E231 missing whitespace after ','
>     main(first,second,trials)
>               ^
> ./main.py:127:22: E231 missing whitespace after ','
>     main(first,second,trials)
>                      ^
> 1     C901 'main' is too complex (18)
> 18    E101 indentation contains mixed spaces and tabs
> 1     E115 expected an indented block (comment)
> 13    E117 over-indented (comment)
> 5     E225 missing whitespace around operator
> 12    E231 missing whitespace after ','
> 1     E261 at least two spaces before inline comment
> 8     E302 expected 2 blank lines, found 1
> 1     F401 'random' imported but unused
> 1     F403 'from strategy import *' used; unable to detect undefined names
> 11    F405 'JankenStrategy' may be undefined, or defined from star imports: strategy
> 18    W191 indentation contains tabs
> 1     W291 trailing whitespace
> 1     W292 no newline at end of file
> 1     W293 blank line contains whitespace
> 1     W391 blank line at end of file
> 94
> ```
>
> ### 実行時間 ( `trials=1000` x 16通り(= 16,000試行)で30分を超えたら0点; 最大10点): 10 点
>
> ```shell
> python3 main.py  0.52s user 0.17s system 74% cpu 0.917 total
> ```
>
> 16,000回実行して `0.52s` なので `+10` 点。

#### 2. `ドラミ` を追加せよ

`ドラミ` を「グーを50%、チョキとパーを25%の確率で出す」キャラクターとして追加してください。

#### 3. `源静香` が「グー、チョキ、パーをちょうど1/3の確率ずつ出す」か確認せよ

`pytest` , `doctest` など、なんらかのテストツールを使って、 `源静香` が本当に「グー、チョキ、パーをちょうど1/3の確率ずつ出す」か確認してください。

上記、 `2. ドラミを追加せよ` も含めて、計算機に完全な乱数を求めるのは難しいので、10,000回実行して誤差 `±10%` までは許容範囲とします。

## 質疑応答 / Questions & Answers

- [x] `源静香` vs `源静香` のような同じ人同士の対決はありえますか？
  - ありえます、つまり、4人 x 4人で16通りの組み合わせがあります

## 制約 / Constraints

1. 本稿は随時更新される場合があるので、本稿冒頭の `Last Updated` に注意してください
1. 実行方法等に関する説明を `README.md` の `## How to Run` に纏めてください
3. 実行環境はは `Python 3.8` とする
    - ファイル数や使用ライブラリに制約はない
4. どんなサイトや書籍を参照しても良い
    - 参照した情報を箇条書きで `README.md` の `## References` に残してください
5. 公平を期すため、質疑応答は上記 `## Questions & Answers` で行う
    - 未回答が `[ ]` 、回答済みが `[x]`
6. **2020年8月19日02:00(JST)** に実行チェックし、その後で何らかの仕様が追加されます
    - ex. 「 `チョキ` を `チー` に変えてください」「3人対決できるようにしてください」「 `出木杉英才` (その時点で最も勝率の高い手を出す)を追加してください」など

## 評価方法 / Evaluation Point

審査員は鈴木、鹿島田の2名。
下記配点で100点満点で採点し、2名の平均を取る。
目標点数は *60点* とする。

- 完成度 (仕様充足度; 最大20点)
- 可読性 ([PEP8](https://pep8-ja.readthedocs.io/ja/latest/)に準拠してなければ0点; 最大30点)
- 拡張可能性 (仕様追加への対応コスト; 最大20点)
- 実行時間 ( `trials=1000` x 16通り(= 16,000試行)で30分を超えたら0点; 最大10点)
- 芸術点 (審査員の主観; 最大20点)

## 最終評価 / Evaluations

### from 鹿島田

#### to 前田: 総合得点 75 点

##### 完成度 (仕様充足度; 最大20点): 15 点

###### README.md

- `venv` フォルダも共有されていますが、通例では共有しないフォルダになります
  - 関連して、`$ cd doraemon/ && python3 -m venv doraemon` という順番になると思います
- `$ pip install pytest` の記述は必要です
  - `pytest`モジュールのインストールがないと、テストが実行できません
- テストの実行方法も記載してください

###### family.py

`members()` は単純にタプルで良い気がします。

###### janken.py

`judge_result()` および `pats()` もタプルで良いと思います

###### main.py

for文の中で、毎回 `Doraemon_family` をインスタンス化しているのが気になります。
一案ですが、 `Doraemon_family` クラスでは `members` それぞれの出し手の定義に止めておいて、実際に何を出したかは `main.py` でのメソッド呼び出して、、とか、何か工夫ができそうです。
その場合、 `nobita_hand()` の引数に、`before_time` , `first_before` , `second_before` を渡せるようにするとか、、

###### test_family.py

- 上記、他ファイルへのコメントを、 `dora = Doraemon_family("", "", "", "", "")` のところを見て思いました。
- 現状のテストでは、 `import pytest` は不要です

##### 可読性 ([PEP8](https://pep8-ja.readthedocs.io/ja/latest/)に準拠してなければ0点; 最大30点): 25 点

- クラスに分けていることでの見通しの良さが良いと思います
- 変数や関数の命名は、あまり頭文字だけ使うような短縮はしなくて良いです
  - そのほうが読みやすく、書くときにもエディタのコード補完機能で長くても問題にならないと思います
- `README.md` での手順については、シェルコマンドを実行順に書くことで、書くのも読むのも楽になると思いました

##### 拡張可能性(仕様追加への対応コスト; 最大20点): 15 点

`family.py` にて、`def dorami_hand(self)` の追加によって、対応できていると思います。

##### 実行時間( `trials=1000` x 16通り(= 16,000試行)で30分を超えたら0点; 最大10点): 10 点

特に問題になるレベルではないと思います。

##### 芸術点 (審査員の主観; 最大20点): 10 点

- PEP8に準拠することで、コードの見た目の美しさは担保されるのかなと思います
- なので、命名や配列の参照とか、どう判定処理しているのかとかに目がいくのですが、上記の指摘を加味した主観としての点数です

#### to 渡邉: 総合得点 33 点

##### 完成度 (仕様充足度; 最大20点): 5 点

###### README.md

- 実行環境について書いてほしいです
- 'How to Run'ではない情報も同じところに書かれています
- `pytest` モジュールをインストールする必要があることを記述してください
- Markdownの記法に問題ありです↓

```
README.md:3 MD022/blanks-around-headings/blanks-around-headers Headings should be surrounded by blank lines [Expected: 1; Actual: 0; Below] [Context: "## How to Run"]
README.md:7 MD032/blanks-around-lists Lists should be surrounded by blank lines [Context: "- `main.py`"]
README.md:13 MD032/blanks-around-lists Lists should be surrounded by blank lines [Context: "- 静香ちゃんの各手の出現確率が全体の40％以上なら、エラー..."]
README.md:14 MD032/blanks-around-lists Lists should be surrounded by blank lines [Context: "- `pytest -v test_main.py` で実行..."]
README.md:15 MD022/blanks-around-headings/blanks-around-headers Headings should be surrounded by blank lines [Expected: 1; Actual: 0; Above] [Context: "## Refrences"]  
README.md:16 MD032/blanks-around-lists Lists should be surrounded by blank lines [Context: "- [Python 3.8.5 ドキュメント](https:..."]
README.md:19 MD022/blanks-around-headings/blanks-around-headers Headings should be surrounded by blank lines [Expected: 1; Actual: 0; Below] [Context: "## Miscellaneous"]
README.md:20:25 MD009/no-trailing-spaces Trailing spaces [Expected: 0 or 2; Actual: 1]
README.md:20 MD032/blanks-around-lists Lists should be surrounded by blank lines [Context: "- エラーチェックおよびPEP8に準拠しました。"]
```

###### main.py

- for文の中で毎回ストラテジーのインスタンス化を行なっているのが気になります
  - → `player1` , `player2` へのインスタンス化は、for文の直前とかで実行するのではどうでしょうか
- フラグの変数を作ってしまうのは、基本的に悪手です
  - 状態（の変化）を管理するのは、気をつけないといけないところが多く、扱いが難しいです
  - なので、都度計算して得られる状態ならば、変数に格納しない方が良いです
- `res` に入るべきは、配列ないしタプルであると思う
    - `main.py` の実行結果を現状のようなしようと違うものにしたためなのか、それとも、、?

###### test.py

- `main.py` のほぼコピペで、 `return` を用意している形ですが、それは `main.py` の方での書き方を変更するのが正解です
- その上で現状のテストコードで必要になるのは、以下のみとなると思います ↓

```
from main import main

def test_1():
    result = main("源静香", "野比のび太", 100)
    assert result[0] < 0.4
    assert result[1] < 0.4
    assert result[2] < 0.4
```

##### 可読性 ([PEP8](https://pep8-ja.readthedocs.io/ja/latest/)に準拠してなければ0点; 最大30点): 3 点

- ストラテジーに関するクラスを `main.py` に持ってきてしまったのですね
  - → 19日時点でのように `strategy.py` に分けられている方が見通しがよかったように思います
- `Player` クラスも別のファイルに分けてもらった方が良いです
- → クラス（モジュール）はそれ単体でファイルを分けるのが基本
  - > モジュールは Pythonの定義や文が入ったファイルです
  - → つまり、モジュール毎にファイルがあることが読み取れます
  - cf. [6. モジュール — Python 3.8.5 ドキュメント](https://docs.python.org/ja/3/tutorial/modules.html)
- `flug` → `flag` ですね
  - VS Codeにスペルチェックの拡張機能を追加しておくと良いです
  - [streetsidesoftware/vscode-spell-checker: A simple source code spell checker for code](https://github.com/streetsidesoftware/vscode-spell-checker)

- `nobita1`, `nobita2` がだれがplayerでも登場してきているのが気になりました
  - のび太用の処理はそれだけでまとまっている方が読みやすく、処理も無駄にしなくてよくなります
- `main()`は、その中から処理を切り分けて別メソッドにするともう少し書きやすくなると思うし、読みやすくもなると思います

##### 拡張可能性(仕様追加への対応コスト; 最大20点): 5 点

のび太の出し手を決める処理だけでもまとまってない時点で、同じような特別な出し方をする人が多くなればなるほど苦労するのが目に見えています。

##### 実行時間( `trials=1000` x 16通り(= 16,000試行)で30分を超えたら0点; 最大10点): 10 点

特に問題になるレベルではないと思います。

##### 芸術点 (審査員の主観; 最大20点) (審査員の主観; 最大20点): 10 点

- `main.py` の実行結果にはこだわりを感じるし、個人的には好感なのですが、仕様としてはそれを求めれていないのが残念です
- クラスの継承を使っているのは良いと思います（が、このくらいの内容だとちょっと大袈裟で逆に読み辛さが目立ってしまったかもですね）

### from 鈴木

#### to 前田: 総合得点: 50 点

##### 完成度 (仕様充足度; 最大20点): 10 点

まず、 `README.md` で、大嘘。 `python3 -m venv venv` でなければいけない。
実際に実行した結果はこちら。

```
$ python3 venv -m doraemon
/Users/suzuki/Downloads/PAC2020_maeda_20200820/venv/bin/python3: can't find '__main__' module in 'venv'
```

`venv` を作った後に「`main.py`, `family.py`, `janken.py` を 作成した `doraemon` ディレクトリに移動」する必要などない。
`venv` の勉強、やり直してください。

`README.md` に `pytest` のインストール方法およびテスト実行方法についての記述なし。

`README.md` に嘘が書かれている、または何も書かれていないと、何もできなくなるので、大きく減点。

`test_family.py` で `import pytest` しているが使われていない。

`dora = Doraemon_family("", "", "", "", "")` というインスタンス化はありえない。
クラスと `self` の勉強、やり直してください。

##### 可読性 ([PEP8](https://pep8-ja.readthedocs.io/ja/latest/)に準拠してなければ0点; 最大30点): 15 点

悪くはない、が全体的に場当たり的に命名しながらやってるんだろうな、と言う印象。

PyLintの結果はこちら。

```
************* Module family
family.py:7:4: W0622: Redefining built-in 'all' (redefined-builtin)
family.py:12:0: C0103: Class name "Doraemon_family" doesn't conform to PascalCase naming style (invalid-name)
family.py:13:4: R0913: Too many arguments (6/5) (too-many-arguments)
family.py:23:4: R0201: Method could be a function (no-self-use)
family.py:36:8: R1705: Unnecessary "elif" after "return" (no-else-return)
family.py:50:4: R0201: Method could be a function (no-self-use)
family.py:57:8: C0103: Variable name "h" doesn't conform to snake_case naming style (invalid-name)
family.py:58:8: C0103: Variable name "ha" doesn't conform to snake_case naming style (invalid-name)
family.py:56:4: R0201: Method could be a function (no-self-use)
family.py:65:8: C0103: Variable name "h" doesn't conform to snake_case naming style (invalid-name)
family.py:67:8: C0103: Variable name "ha" doesn't conform to snake_case naming style (invalid-name)
family.py:64:4: R0201: Method could be a function (no-self-use)
************* Module janken
janken.py:23:4: R1705: Unnecessary "else" after "return" (no-else-return)
************* Module main
main.py:6:0: R0914: Too many local variables (16/15) (too-many-locals)
main.py:25:7: C0123: Using type() instead of isinstance() for a typecheck. (unidiomatic-typecheck)
main.py:27:7: C0122: Comparison should be trials > 10000 (misplaced-comparison-constant)
main.py:29:8: C0123: Using type() instead of isinstance() for a typecheck. (unidiomatic-typecheck)
main.py:29:32: C0123: Using type() instead of isinstance() for a typecheck. (unidiomatic-typecheck)
main.py:35:8: W0612: Unused variable 'i' (unused-variable)
************* Module test_family
test_family.py:6:0: C0103: Constant name "guu" doesn't conform to UPPER_CASE naming style (invalid-name)
test_family.py:7:0: C0103: Constant name "cho" doesn't conform to UPPER_CASE naming style (invalid-name)
test_family.py:8:0: C0103: Constant name "paa" doesn't conform to UPPER_CASE naming style (invalid-name)
test_family.py:10:0: C0103: Constant name "sanbun" doesn't conform to UPPER_CASE naming style (invalid-name)
test_family.py:12:0: C0103: Constant name "san_zen" doesn't conform to UPPER_CASE naming style (invalid-name)
test_family.py:13:0: C0103: Constant name "san_go" doesn't conform to UPPER_CASE naming style (invalid-name)
test_family.py:21:8: W0612: Unused variable 'i' (unused-variable)
test_family.py:36:8: W0612: Unused variable 'i' (unused-variable)
test_family.py:51:8: W0612: Unused variable 'i' (unused-variable)
test_family.py:66:8: W0612: Unused variable 'i' (unused-variable)
test_family.py:81:8: W0612: Unused variable 'i' (unused-variable)
test_family.py:96:8: W0612: Unused variable 'i' (unused-variable)
```

「 `ha` って何？」「 `san_zen` `pats()` って何？」と変数名がわかりにくい。
`hand` と `san_` のように変数名の言語が英語日本語混用なのもわかりにくい。
cf. [リーダブルコード（1/3）『命名』](http://kubokubokun.hatenablog.com/entry/2018/06/08/230205)

`win_rate(win, trials)` など、関数の名前には処理に応じて `get_` や `set_` 、 `test_` 、 `delete_` など英語の動詞を添えて処理内容をわかりやすくする。

たとえば `janken.py` の `judge_result` を

```py
def judge_result():
    return["Win", "Lose", "Draw"]
```

`main.py` で関数のように呼び出して参照しているが、

```py
    # 勝った時の文字を判別
    win = judge_result()[0]
```

ただのリストならそのまま参照した方が良い。

```py
jusge_result = ["Win", "Lose", "Draw"]
win = judge_result[0]
```

そうしないなら、せめて関数名は `get_judge_results()` 。

さらに `all_member = members()` と書くぐらいなら、最初から `members()` を `all_members = ["源静香", ..., ] ` で用意すれば良い。
`members()` が `class Doraemon_family` 内に定義されてないのも不思議。

また、配列のように複数入るのが前提の変数には `all_members` や `all_matches` など複数形を使う。

つまり、ソースコードに出てくる変数名を見るだけで「これは何かを取得(get)する関数で、ここは何か複数の値が入ってる変数か（じゃ、深読みしなくても良いな）」と把握できるように書かれていない。

細かいところでは、Python 3.6以降では `format()` の代わりに `f-strings` を使う方が便利です。
cf. [2.4.3. フォーマット済み文字列リテラル](https://docs.python.org/ja/3/reference/lexical_analysis.html#formatted-string-literals)

```py
    # 勝率計算したものを追加
    print("{} {}".format(all_match, win_rate(win_counter, trials)))
    # ⇒ print(f"{all_match} {win_rate(win_counter, trials)}")
```

##### 拡張可能性(仕様追加への対応コスト; 最大20点): 5 点

正直、ひどい。前述の通り、変数名が何を意味するか分からない上に、マジックナンバーのハードコーディングが多すぎる。
cf. [マジックナンバー (プログラム) - Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%9E%E3%82%B8%E3%83%83%E3%82%AF%E3%83%8A%E3%83%B3%E3%83%90%E3%83%BC_(%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0))

```py
# 1/3の計算
sanbun = 1 / 3
```

```py
    def suneo_hand(self):
        h = random.randint(0, 1)
        ha = [1, 2]
        h = random.randint(0, len(ha) - 1)
```

クラス構文を `family.py` だけ中途半端に使われていて、しかも、そのインスタンスに5人分の処理が全て書かれているので、オブジェクト指向にした意味がない。
ゆえに、テストも極めて冗長な書き振りになっている。

```py
# 静香ちゃんがグーを出す時の確率チェック
def test_shizuka_guu():
    # カウントする変数
    count = 0
    # 10000回実行した時のグーの結果をカウントする
    for i in range(10000):
        dora = Doraemon_family("", "", "", "", "")
        shizuka = dora.shizuka_hand()
        if shizuka == guu:
            count += 1
    per = count / 10000
    # 1/3の前後10%ならOK
    assert san_zen <= per <= san_go

# ドラミちゃんがグーを出す時の確率チェック
def test_dorami_guu():
    # カウントする変数
    count = 0
    # 10000回実行した時のパーの結果をカウントする
    for i in range(10000):
        dora = Doraemon_family("", "", "", "", "")
        dorami = dora.dorami_hand()
        if dorami == guu:
            count += 1
    per = count / 10000
    # 50%の前後10%ならOK
    assert 0.4 <= per <= 0.6
```

##### 実行時間( `trials=1000` x 16通り(= 16,000試行)で30分を超えたら0点; 最大10点): 10 点

250,000回実行して、*3.6* 秒だったので問題なし。

##### 芸術点 (審査員の主観; 最大20点): 10 点

王道的な仕様に素直な実装。
`main.py` の書き換えが必要な実行や、テスト自動化などで工夫が見られれば尚良かった。

#### to 渡邉: 総合得点: 20 点

##### 完成度 (仕様充足度; 最大20点): 0 点

`README.md` に「コマンドラインから `python main.py` で実行出来ます。」とあるが大嘘。
MacOSで `python` だけならPython2系で動くので、エラーで動きません。

```shell
$ python main.py
Traceback (most recent call last):
  File "main.py", line 5, in <module>
    from hand import JankenHand
  File "/Users/suzuki/Downloads/PAC2020_watanabe_20200820/hand.py", line 4, in <module>
    from enum import Enum
ImportError: No module named enum
```

「`pytest -v test_main.py` で実行できます。」、大嘘。 `pytest` は標準ライブラリではありません。

```shell
$ pytest                                                                                                                      ✘ 1
zsh: command not found: pytest
```

そして、 `README.md` にあいかわらず警告 *10* 個。22行の `README.md` で10個って、直す気あるんですか？レベル。
この時点で0点。

```shell
MD022/blanks-around-headings/blanks-around-headers: Headings should be surrounded by blank lines [Expected: 1; Actual: 0; Below]
MD032/blanks-around-lists: Lists should be surrounded by blank lines
MD009/no-trailing-spaces: Trailing spaces [Expected: 0 or 2; Actual: 1]
(多すぎるので割愛)
```

各ソースコード冒頭に `# coding: utf_8` と書いてますが、UTF-8で動かす前提のPython3では非推奨です。
cf. [ソースファイルのエンコーディング](https://pep8-ja.readthedocs.io/ja/latest/#id12)

`(first in char) & (second in char)` 、Pythonでは `&` は論理演算子ではなくビット演算子です。
たまたま `first in char` がビット表現可能な結果になるから成立しているだけなので `and` を使った方が良いです。

`print("==== ValueError!!! ===\n==== Try Again ====")` 、ちゃんと例外を出してください。
`trials` の上限に対する例外を検出できていません。
cf. [8.4. 例外を送出する](https://docs.python.org/ja/3/tutorial/errors.html#raising-exceptions)

`野比のび太` が実装されていません。
`ドラミ` の実装が割合変えるだけで8行追加はダサすぎます。

```py
class Dorami_Strategy(JankenStrategy):
    def next_hand(self):
        # 乱数の初期化
        random.seed()
        n = random.randint(0, 3)
        if n == 0:
            return JankenHand(0)

        if n == 1:
            return JankenHand(0)

        if n == 2:
            return JankenHand(1)

        if n == 3:
            return JankenHand(2)
```

`RandomStrategy`と `Shizuka_Strategy` の違いってなんですか？
そもそも、 `next_hand()` を全ての子クラスで実装するなら `JankenStrategy` を親に持つ意味ってなんですか？
`super` も使えないならオブジェクト指向諦めた方がいいですよ。

```py
class JankenStrategy:
    # とりあえず固定の手を返す
    def next_hand(self):
        return JankenHand.chii

class RandomStrategy(JankenStrategy):
    def next_hand(self):

        # 乱数の初期化
        random.seed()
        n = random.randint(0, 2)
        return JankenHand(n)

class Sizuka_Strategy(JankenStrategy):
    def next_hand(self):
        # 乱数の初期化
        random.seed()
        n = random.randint(0, 2)
        return JankenHand(n)
```

##### 可読性 ([PEP8](https://pep8-ja.readthedocs.io/ja/latest/)に準拠してなければ0点; 最大30点): 0 点

可読性だけの問題ではないが、 `__str__` への追加など、やらなくて良いことをやっているせいで読みにくい。
反面、 `cnt` など昭和時代かのような3文字変数を使ってたりハードコーディングしてたりと、はっきり言ってひどい。
`RandomStrategy`と `Shizuka_Strategy` のようにパスカルケースとスネークケースの混用は、マジでひどい。

```py
    print("ドラミがグーを出す確率", cnt_1 / cnt)
    print("ドラミがチョキを出す確率", cnt_2 / cnt)
    print("ドラミがパーを出す確率", cnt_3 / cnt)
    print("全ての確率の和", (cnt_1 + cnt_2 + cnt_3) / cnt)
```

PyLintの結果。

```
************* Module hand
hand.py:13:8: R1705: Unnecessary "elif" after "return" (no-else-return)
hand.py:21:8: C0103: Variable name "n" doesn't conform to snake_case naming style (invalid-name)
hand.py:25:16: W0143: Comparing against a callable, did you omit the parenthesis? (comparison-with-callable)
************* Module main
main.py:13:4: R0201: Method could be a function (no-self-use)
main.py:11:0: R0903: Too few public methods (1/2) (too-few-public-methods)
main.py:22:8: C0103: Variable name "n" doesn't conform to snake_case naming style (invalid-name)
main.py:17:0: R0903: Too few public methods (1/2) (too-few-public-methods)
main.py:26:0: C0103: Class name "Suneo_Strategy" doesn't conform to PascalCase naming style (invalid-name)
main.py:31:8: C0103: Variable name "n" doesn't conform to snake_case naming style (invalid-name)
main.py:26:0: R0903: Too few public methods (1/2) (too-few-public-methods)
main.py:35:0: C0103: Class name "Nobita_Strategy" doesn't conform to PascalCase naming style (invalid-name)
main.py:39:8: C0103: Variable name "n" doesn't conform to snake_case naming style (invalid-name)
main.py:35:0: R0903: Too few public methods (1/2) (too-few-public-methods)
main.py:43:0: C0103: Class name "Doraemon_Strategy" doesn't conform to PascalCase naming style (invalid-name)
main.py:43:0: R0903: Too few public methods (1/2) (too-few-public-methods)
main.py:49:0: C0103: Class name "Sizuka_Strategy" doesn't conform to PascalCase naming style (invalid-name)
main.py:53:8: C0103: Variable name "n" doesn't conform to snake_case naming style (invalid-name)
main.py:49:0: R0903: Too few public methods (1/2) (too-few-public-methods)
main.py:57:0: C0103: Class name "Dorami_Strategy" doesn't conform to PascalCase naming style (invalid-name)
main.py:61:8: C0103: Variable name "n" doesn't conform to snake_case naming style (invalid-name)
main.py:58:4: R1710: Either all return statements in a function should return an expression, or none of them should. (inconsistent-return-statements)
main.py:57:0: R0903: Too few public methods (1/2) (too-few-public-methods)
main.py:89:9: W0621: Redefining name 'first' from outer scope (line 226) (redefined-outer-name)
main.py:89:16: W0621: Redefining name 'second' from outer scope (line 227) (redefined-outer-name)
main.py:89:24: W0621: Redefining name 'trials' from outer scope (line 228) (redefined-outer-name)
main.py:105:8: W0621: Redefining name 'i' from outer scope (line 255) (redefined-outer-name)
main.py:89:0: R0914: Too many local variables (19/15) (too-many-locals)
main.py:152:8: W0105: String statement has no effect (pointless-string-statement)
main.py:105:8: W0612: Unused variable 'i' (unused-variable)
main.py:89:0: R0912: Too many branches (29/12) (too-many-branches)
main.py:89:0: R0915: Too many statements (83/50) (too-many-statements)
main.py:226:4: C0103: Constant name "first" doesn't conform to UPPER_CASE naming style (invalid-name)
main.py:227:4: C0103: Constant name "second" doesn't conform to UPPER_CASE naming style (invalid-name)
main.py:228:4: C0103: Constant name "trials" doesn't conform to UPPER_CASE naming style (invalid-name)
main.py:239:8: C0103: Variable name "n" doesn't conform to snake_case naming style (invalid-name)
main.py:237:4: R1710: Either all return statements in a function should return an expression, or none of them should. (inconsistent-return-statements)
main.py:249:4: C0103: Constant name "cnt_1" doesn't conform to UPPER_CASE naming style (invalid-name)
main.py:250:4: C0103: Constant name "cnt_2" doesn't conform to UPPER_CASE naming style (invalid-name)
main.py:251:4: C0103: Constant name "cnt_3" doesn't conform to UPPER_CASE naming style (invalid-name)
main.py:252:4: C0103: Constant name "cnt" doesn't conform to UPPER_CASE naming style (invalid-name)
main.py:256:8: C0103: Constant name "t" doesn't conform to UPPER_CASE naming style (invalid-name)
************* Module test_main
test_main.py:13:4: R0201: Method could be a function (no-self-use)
test_main.py:11:0: R0903: Too few public methods (1/2) (too-few-public-methods)
test_main.py:22:8: C0103: Variable name "n" doesn't conform to snake_case naming style (invalid-name)
test_main.py:17:0: R0903: Too few public methods (1/2) (too-few-public-methods)
test_main.py:26:0: C0103: Class name "Suneo_Strategy" doesn't conform to PascalCase naming style (invalid-name)
test_main.py:31:8: C0103: Variable name "n" doesn't conform to snake_case naming style (invalid-name)
test_main.py:26:0: R0903: Too few public methods (1/2) (too-few-public-methods)
test_main.py:35:0: C0103: Class name "Nobita_Strategy" doesn't conform to PascalCase naming style (invalid-name)
test_main.py:39:8: C0103: Variable name "n" doesn't conform to snake_case naming style (invalid-name)
test_main.py:35:0: R0903: Too few public methods (1/2) (too-few-public-methods)
test_main.py:43:0: C0103: Class name "Doraemon_Strategy" doesn't conform to PascalCase naming style (invalid-name)
test_main.py:43:0: R0903: Too few public methods (1/2) (too-few-public-methods)
test_main.py:49:0: C0103: Class name "Sizuka_Strategy" doesn't conform to PascalCase naming style (invalid-name)
test_main.py:53:8: C0103: Variable name "n" doesn't conform to snake_case naming style (invalid-name)
test_main.py:49:0: R0903: Too few public methods (1/2) (too-few-public-methods)
test_main.py:57:0: C0103: Class name "Dorami_Strategy" doesn't conform to PascalCase naming style (invalid-name)
test_main.py:61:8: C0103: Variable name "n" doesn't conform to snake_case naming style (invalid-name)
test_main.py:58:4: R1710: Either all return statements in a function should return an expression, or none of them should. (inconsistent-return-statements)
test_main.py:57:0: R0903: Too few public methods (1/2) (too-few-public-methods)
test_main.py:89:9: W0621: Redefining name 'first' from outer scope (line 242) (redefined-outer-name)
test_main.py:89:16: W0621: Redefining name 'second' from outer scope (line 243) (redefined-outer-name)
test_main.py:89:24: W0621: Redefining name 'trials' from outer scope (line 244) (redefined-outer-name)
test_main.py:89:0: R0914: Too many local variables (24/15) (too-many-locals)
test_main.py:156:8: W0105: String statement has no effect (pointless-string-statement)
test_main.py:109:8: W0612: Unused variable 'i' (unused-variable)
test_main.py:89:0: R0912: Too many branches (32/12) (too-many-branches)
test_main.py:89:0: R0915: Too many statements (93/50) (too-many-statements)
test_main.py:242:4: C0103: Constant name "first" doesn't conform to UPPER_CASE naming style (invalid-name)
test_main.py:243:4: C0103: Constant name "second" doesn't conform to UPPER_CASE naming style (invalid-name)
test_main.py:244:4: C0103: Constant name "trials" doesn't conform to UPPER_CASE naming style (invalid-name)
test_main.py:254:4: W0621: Redefining name 'first' from outer scope (line 242) (redefined-outer-name)
test_main.py:255:4: W0621: Redefining name 'second' from outer scope (line 243) (redefined-outer-name)
test_main.py:256:4: W0621: Redefining name 'trials' from outer scope (line 244) (redefined-outer-name)
test_main.py:1:0: R0801: Similar lines in 2 files
==main:101
==test_main:105
    player1 = Player(first)
    player2 = Player(second)

    for i in range(trials):

        # 一人目のストラテジ判定
        if first == str("ドラえもん"):
            player1.strategy = Doraemon_Strategy()

        if first == str("源静香"):
            player1.strategy = Sizuka_Strategy()

        if first == str("骨川スネ夫"):
            player1.strategy = Suneo_Strategy()

        if first == str("ドラミ"):
            player1.strategy = Dorami_Strategy()

        if first == str("野比のび太"):
            player1.strategy = Nobita_Strategy()

            # 一人目のび太が一回前のジャンケンで勝ってた場合
            if first_flug == 1 and second_flug == -1:
                # splayer1.strategy = nobita1
                # 問題のコード
                # print("firstのび太の勝ち！")
                # nobita1 = player1.next_hand()
                pass
        # 二人目のストラテジ判定
        if second == str("ドラえもん"):
            player2.strategy = Doraemon_Strategy()

        if second == str("ドラミ"):
            player2.strategy = Dorami_Strategy()

        if second == str("野比のび太"):
            player2.strategy = Nobita_Strategy()
            # 二人目のび太が一回前のジャンケンで勝ってた場合
            if second_flug == 1 and first_flug == -1:
                # player2.strategy = nobita2
                # 問題のコード
                # print("secondのび太の勝ち！")
                # nobita2 = player2.next_hand()
                pass
        if second == str("源静香"):
            player2.strategy = Sizuka_Strategy()
        if second == str("骨川スネ夫"):
            player2.strategy = Suneo_Strategy()

        # ハンド判定
        """
        hand1 = player1.next_hand()
        hand2 = player2.next_hand()
        """

        # 次のハンドを決定
        hand1 = player1.next_hand()
        nobita1 = hand1
        if hand1 == JankenHand.goo:
            first_hand = "グー"

        elif hand1 == JankenHand.chii:
            first_hand = "チョキ"

        else:
            first_hand = "パー"

        if first_flug == 1 and second_flug == -1:
            hand1 = nobita1
            if hand1 == JankenHand.goo:
                second_hand = "グー"

            elif hand1 == JankenHand.chii:
                second_hand = "チョキ"

            else:
                second_hand = "パー"

        hand2 = player2.next_hand()
        nobita2 = hand2
        if hand2 == JankenHand.goo:
            second_hand = "グー"

        elif hand2 == JankenHand.chii:
            second_hand = "チョキ"

        else:
            second_hand = "パー"

        if first_flug == -1 and second_flug == 1:
            hand2 = nobita2

            if hand2 == JankenHand.goo:
                second_hand = "グー"

            elif hand2 == JankenHand.chii:
                second_hand = "チョキ"

            else:
                second_hand = "パー"

        result = "Draw"
        first_flug = 0
        second_flug = 0

        if hand1.win_to(hand2):
            result = "Win"
            first_flug = 1
            second_flug = -1
            win_cnt += 1

        elif hand1.lose_to(hand2):
            result = "Lose"
            first_flug = -1
            second_flug = 1

        res = [(first_hand, second_hand, result)]
        print(res) (duplicate-code)
test_main.py:1:0: R0801: Similar lines in 2 files
==main:3
==test_main:3
import random
from hand import JankenHand


# ストラテジ定義


class JankenStrategy:
    # とりあえず固定の手を返す
    def next_hand(self):
        return JankenHand.chii


class RandomStrategy(JankenStrategy):
    def next_hand(self):

        # 乱数の初期化
        random.seed()
        n = random.randint(0, 2)
        return JankenHand(n)


class Suneo_Strategy(JankenStrategy):
    def next_hand(self):

        # 乱数の初期化
        random.seed()
        n = random.randint(1, 2)
        return JankenHand(n)


class Nobita_Strategy(JankenStrategy):
    def next_hand(self):
        # 乱数の初期化
        random.seed()
        n = random.randint(0, 2)
        return JankenHand(n)


class Doraemon_Strategy(JankenStrategy):
    def next_hand(self):
        # グー
        return JankenHand.goo


class Sizuka_Strategy(JankenStrategy):
    def next_hand(self):
        # 乱数の初期化
        random.seed()
        n = random.randint(0, 2)
        return JankenHand(n)


class Dorami_Strategy(JankenStrategy):
    def next_hand(self):
        # 乱数の初期化
        random.seed()
        n = random.randint(0, 3)
        if n == 0:
            return JankenHand(0)

        if n == 1:
            return JankenHand(0)

        if n == 2:
            return JankenHand(1)

        if n == 3:
            return JankenHand(2)


class Player:
    def __init__(self, name):
        self._name = name
        # デフォルトではJankenStrategyを使う
        self.strategy = JankenStrategy()

    @property
    def name(self):
        return str("Player" + self._name)

    def next_hand(self):
        return self.strategy.next_hand()


def main(first, second, trials): (duplicate-code)
test_main.py:1:0: R0801: Similar lines in 2 files
==main:91
==test_main:90
    win_cnt = 0  # firstプレイヤーが勝った数

    nobita1 = 0  # firstのび太の一回前の手

    nobita2 = 0  # secondのび太の一回前の手

    first_flug = 0  # firstプレイヤーが一回前に勝ったかどうかのフラグ

    second_flug = 0  # secondプレイヤーが一回前に勝ったかどうかのフラグ
 (duplicate-code)
test_main.py:1:0: R0801: Similar lines in 2 files
==main:227
==test_main:243
    trials = 10
    char = ["源静香", "野比のび太", "ドラえもん", "骨川スネ夫", "ドラミ"]
    if (first in char) & (second in char):
        print("プレイヤー: {} VS {} !\n".format(first, second))
        main(first, second, trials)
    else:
        print("==== ValueError!!! ===\n==== Try Again ====")

 (duplicate-code)
```

##### 拡張可能性(仕様追加への対応コスト; 最大20点): 5 点

Strategyパターンを採用して、拡張可能性を狙った気持ちはわかりますが、ちゃんと適応できてないせいで全然メリットがないですね。
cf. [Strategy パターン - Wikipedia](https://ja.wikipedia.org/wiki/Strategy_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3)
こんなにif文重ねなきゃいけないんじゃ…しかも順番揃ってないし。

```py
        # 一人目のストラテジ判定
        if first == str("ドラえもん"):
            player1.strategy = Doraemon_Strategy()

        if first == str("源静香"):
            player1.strategy = Sizuka_Strategy()

        if first == str("骨川スネ夫"):
            player1.strategy = Suneo_Strategy()

        if first == str("ドラミ"):
            player1.strategy = Dorami_Strategy()

        if first == str("野比のび太"):
            player1.strategy = Nobita_Strategy()

        # 二人目のストラテジ判定
        if second == str("ドラえもん"):
            player2.strategy = Doraemon_Strategy()

        if second == str("ドラミ"):
            player2.strategy = Dorami_Strategy()

        if second == str("野比のび太"):
            player2.strategy = Nobita_Strategy()
            # 二人目のび太が一回前のジャンケンで勝ってた場合
            if second_flug == 1 and first_flug == -1:
                # player2.strategy = nobita2
                # 問題のコード
                # print("secondのび太の勝ち！")
                # nobita2 = player2.next_hand()
                pass
        if second == str("源静香"):
            player2.strategy = Sizuka_Strategy()
        if second == str("骨川スネ夫"):
            player2.strategy = Suneo_Strategy()
```

##### 実行時間( `trials=1000` x 16通り(= 16,000試行)で30分を超えたら0点; 最大10点): 10 点

250,000回実行して、*7.26* 秒だったので問題なし。
（しかし、仕様を満たせてないのに、前田さんより2倍遅いってことに注目してください）

##### 芸術点 (審査員の主観; 最大20点): 5 点

チャレンジ精神は認めるけど、仕様を満たせてない時点で芸術点なんてつけてる場合じゃないですし、
とりあえず、プログラムというより「何かを書く」ことのセンスを磨いた方がいいですね。
基本を疎かにしてるダサさがにじみ出てます。

## 総評

### from 鹿島田

(T. B. D.: 2人に対して)

#### to 前田

前田さんの可読性に25点を付けましたが、レビューしていて、可読性について30/100と設定されていて、そもそものウェイトが高い点に納得しました。
変数の命名に慣れていったり、コード設計を学んでいくことで、よくなっていくことが見えている気がします。

#### to 渡邉

フラグを不用意に使ってしまったり、それゆえどんな状態になってしまっているかコードを書いている自分自身が迷子になってしまっているなど、過去の（今も？）の鹿島田自身を見ているようです。
親近感、というよりこのままだと苦労することがわかっているので、迷子にならない書き方を身につけていきましょう。
まずは関数をなるべくコンパクトにすることを心掛けてみる、フラグを使うのではなく都度処理で得たい状態が得られないかを考えてみる、とか、からでしょうか。

### from 鈴木

(T. B. D.: 2人に対して)

#### to 前田

(T. B. D.)

#### to 渡邉

(T. B. D.)

## 備考 / Miscellaneous

### 改訂履歴 / Revision History

- **(2020/08/18 04:38)** 入力: `剛田武` を仕様から削除しました
- **(2020/08/19 00:23)** 締め切りを延長しました
- **(2020/08/19 00:23)** 提出ファイル名を変更しました
- **(2020/08/19 03:51)** 追加仕様を公開しました
- **(2020/08/19 04:12)** フィードバックコメントを追加しました
- **(2020/08/20 18:45)** フィードバックコメントを追加しました
