
"""
learnstock.py
帰納的学習による10桁のパターン探索
パターンA・B・C・Dの比較
"""

import random

# グローバル変数
SETSIZE = 100       # 学習データの数
CNO = 10            # パターンの桁数
GENMAX = 10000      # 解候補を生成する回数
SEED = 7            # 乱数の初期値


# 学習データと教師データを読み込む関数
def readdata(data, teacher):
    for i in range(SETSIZE):
        line = input()
        data[i] = [int(num) for num in line.split()]
        teacher[i] = data[i][CNO]


# 解候補のスコアを計算する関数
def calcscore(data, teacher, answer):
    score = 0

    for i in range(SETSIZE):
        point = 0

        # 学習データと解候補の一致度を調べる
        for j in range(CNO):
            if answer[j] == 2:
                point += 1
            elif answer[j] == data[i][j]:
                point += 1

        # 教師データに対する正解数を数える
        if point == CNO and teacher[i] == 1:
            score += 1
        elif point != CNO and teacher[i] == 0:
            score += 1

    return score


# パターンを検査データに適用する関数
def predict(pattern, testdata):
    result = []

    for row in testdata:
        point = 0

        for j in range(CNO):
            if pattern[j] == 2:
                point += 1
            elif pattern[j] == row[j]:
                point += 1

        # 10桁すべてが一致すれば1、そうでなければ0
        if point == CNO:
            result.append(1)
        else:
            result.append(0)

    return result


# 表2.2の検査データ
testdata = [
    [0, 0, 0, 1, 0, 1, 0, 0, 0, 0],
    [0, 0, 1, 0, 1, 0, 0, 1, 0, 0],
    [0, 0, 1, 0, 0, 1, 0, 0, 1, 1],
    [1, 1, 1, 1, 0, 1, 0, 1, 0, 1],
    [1, 0, 1, 0, 0, 1, 0, 1, 0, 1],
    [1, 0, 1, 1, 1, 1, 0, 1, 0, 1],
    [0, 1, 0, 1, 1, 1, 1, 1, 0, 1],
    [0, 1, 1, 0, 1, 0, 1, 1, 1, 1],
    [0, 0, 1, 0, 1, 0, 1, 0, 1, 1],
    [1, 1, 1, 0, 1, 0, 1, 0, 1, 1]
]

# 表2.2に記載された正しい結果
correct = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0]


# メイン処理
data = [[] for i in range(SETSIZE)]
teacher = [0 for i in range(SETSIZE)]

bestscore = 0
bestanswer = [0 for i in range(CNO)]

# パターンA・Bを設定する
patternA = [2, 2, 0, 2, 2, 2, 0, 2, 0, 2]
patternB = [2, 2, 0, 2, 2, 2, 2, 2, 0, 2]

# パターンC・Dの候補を保存する
candidate_patterns = {}

# 乱数を初期化する
random.seed(SEED)

# 学習データを読み込む
readdata(data, teacher)

# パターンA・Bの学習データに対するスコア
scoreA = calcscore(data, teacher, patternA)
scoreB = calcscore(data, teacher, patternB)

print("パターンAのスコア =", scoreA)
print("パターンBのスコア =", scoreB)

# 解候補を生成して評価する
for i in range(GENMAX):
    answer = [random.randint(0, 2) for j in range(CNO)]

    score = calcscore(data, teacher, answer)

    # 全体の最良解を更新する
    if score > bestscore:
        bestscore = score
        bestanswer = answer.copy()

    # スコア84点・100点以外の候補を記録する
    if score != 84 and score != 100:
        pattern = tuple(answer)

        # 同じパターンを重複して登録しない
        if pattern not in candidate_patterns:
            candidate_patterns[pattern] = score

# スコアの高い順に並べる
sorted_patterns = sorted(
    candidate_patterns.items(),
    key=lambda item: item[1],
    reverse=True
)

# A・Bと同じパターンは候補から除く
patternA_tuple = tuple(patternA)
patternB_tuple = tuple(patternB)

sorted_patterns = [
    item for item in sorted_patterns
    if item[0] != patternA_tuple
    and item[0] != patternB_tuple
]

# C・Dを選ぶ
patterns = {
    "A": patternA,
    "B": patternB
}

if len(sorted_patterns) >= 1:
    patterns["C"] = list(sorted_patterns[0][0])

if len(sorted_patterns) >= 2:
    patterns["D"] = list(sorted_patterns[1][0])

# A・B・C・Dの予測結果を表示する
print("\n表2.2 検査データの予測結果")
print("番号  正解  A予測  B予測  C予測  D予測")

predictions = {}

for name, pattern in patterns.items():
    predictions[name] = predict(pattern, testdata)

for i in range(len(testdata)):
    values = []

    for name in ["A", "B", "C", "D"]:
        if name in predictions:
            values.append(str(predictions[name][i]))
        else:
            values.append("-")

    print(
        i + 1, correct[i],
        values[0], values[1], values[2], values[3]
    )

# 各パターンの正解数を表示する
print("\n検査データ10例の正解数")

for name in ["A", "B", "C", "D"]:
    if name in predictions:
        count = 0

        for i in range(len(correct)):
            if predictions[name][i] == correct[i]:
                count += 1

        print(name, ":", count, "/ 10")

# 探索全体の最良解を表示する
print("\n探索全体の最良解")
print(bestanswer, ":score=", bestscore)
# your code goes here