2
2

More than 3 years have passed since last update.

Python学習型じゃんけん

Last updated at Posted at 2021-01-23

はじめに

  • Python を少し囓った素人が、「学習型じゃんけん」を作ってみました。 (⇒ SQL版)
  • 学習型といっても、強化学習とかではありません。単純な統計です。
  • 「こう書いた方がスマートだ」など、突っ込み大歓迎です。

環境

  • Jupyter Notebook 6.1.4
  • Python 3.8.5 (default, Sep 3 2020, 21:29:08) [MSC v.1916 64 bit (AMD64)]

アルゴリズム

  • 人間は、単純な選択を短時間に繰り返したときに、無意識に癖が出ます。
  • 直近4回の手の並びの出現頻度を記録して、直近3回の並びから最も頻度の高い次の手を予測します。
  • 初期化時に出現履歴と頻度表を適当な乱数で埋めてあります。

使い方

  • 人間が手を入力する前に、プログラムは手の内を見せます。
    • 見たくない場合は、firstOutFalseにしてください。
  • 人間側の手を13の数字で入力します。
    • 機械側の手を見ずに入力するとフェアです。
    • 0を入力するとゲームを終了します。
  • 人間が手を選ぶと、勝敗を判定し、結果と戦績を表示します。

コード

janken.py
import random as rnd

# 初期化
log = [rnd.randrange(3) for _ in range(4)] # 履歴
frequency = [[[[rnd.randrange(3) for _ in range(3)] for _ in range(3)] for _ in range(3)] for _ in range(3)] # 頻度
handName = { 0:'Goo', 1:'Choki', 2:'Par' } # 手の名前
prompt = "[1:Goo, 2:Choki, 3:Par, 0:End]? " # プロンプト
human = 0 # 人間の勝利数
computer = 0 # 機械の勝利数
draw = 0 # 引き分け数
firstOut = True # 先出し

# 手の表示
def printHand(hand, isHuman = False, secret = False):
    print(f"{'Human' if isHuman else 'Computer'} hand: {handName[hand]}{(' (secret)' if secret else '')}")

# 結果と戦績の表示
def printResult(comHand, humHand):
    global human, computer, draw
    if comHand == humHand:
        result = 'draw'
        draw += 1
    elif comHand == humHand - 1 or comHand == humHand + 2:
        result = 'Human lose!'
        computer += 1
    else:
        result = 'Human win!!'
        human += 1
    print(f"{result} (computer:{computer} human:{human} draw:{draw})")

# 次の手の取得
def getNextHand(isHuman = False):
    if isHuman:
        while True:
            try:
                hand = int(input(prompt))
            except:
                pass
            else:
                if hand >= 0 and hand <= 3:
                    return hand - 1
            print('input error')
    else:
        f = frequency[log[1]][log[2]][log[3]] # 人間の次の手の出現頻度
        return (f.index(max(f)) + 2) % 3 # 最頻手に勝てる手

# 履歴と頻度の更新
def updateLog(hand):
    global log, frequency
    log.append(hand)
    log = log[-4:]
    frequency[log[0]][log[1]][log[2]][log[3]] += 1

# メインループ
while True:
    print(f"--- {human + computer + draw + 1} ---") # ゲーム数表示
    com = getNextHand() # 機械の次の手の算出
    if firstOut: printHand(com, secret = True) # COMの手表示 先に見せてしまう
    hand = getNextHand(isHuman = True) # 人間の次の手の取得
    if hand < 0: break # 終了
    printHand(hand, isHuman = True) # HUMの手表示
    if not firstOut: printHand(com) # COMの手表示  後で見せる
    printResult(com, hand) # 結果表示
    updateLog(hand) # 記録
result
--- 1 ---
Computer hand: Par (secret)
[1:Goo, 2:Choki, 3:Par, 0:End]? 1
Human hand: Goo
Human lose! (computer:1 human:0 draw:0)
--- 2 ---
Computer hand: Par (secret)
[1:Goo, 2:Choki, 3:Par, 0:End]? 2
Human hand: Choki
Human win!! (computer:1 human:1 draw:0)
--- 3 ---
Computer hand: Par (secret)
[1:Goo, 2:Choki, 3:Par, 0:End]? 3
Human hand: Par
draw (computer:1 human:1 draw:1)
--- 4 ---
Computer hand: Choki (secret)
[1:Goo, 2:Choki, 3:Par, 0:End]? 0
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2