# -*- coding: utf-8 -*-
"""
二分探索（基本，最初に見つけた結果のみ）
"""


import random


# 整数の単調増加listを作成（増分0-2）
def make_ints_s(n):
    x = []
    sum = 0
    for i in range(n):
        sum += int((random.random() ** 2) * 3)
        x.append(sum)
    return x


# ランダムな英数文字列（２文字）のlistを作成
def make_strs(n):
    c_map = list("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
    c_len = len(c_map)
    s = []

    for i in range(n):
        c_tmp = ""
        for j in range(2):
            c_tmp += c_map[random.randrange(c_len)]
        s.append(str(c_tmp))
    return s


# データ列（整数）を文字列化
# 分かりやすさのため，一部を色付け（ターミナル上）
def ints_to_str(x, m=[]):
    x_strs = []  # 文字列化されたデータ列を保持するlist
    for i in range(len(x)):
        # インデックスがmに含まれていれば背景を赤色に
        if i in m:
            x_strs.append(f"\x1b[4;101m{x[i]:2d}\x1b[0m")
        else:
            x_strs.append(f"{x[i]:2d}")
    # 結合して戻す
    return ",".join(x_strs)


# 目盛を表示
# 分かりやすさのため，全て色付け（ターミナル上）
def print_index(n):
    # 目盛をlistで準備
    tics = [f"{i:2d}" for i in range(n)]
    # 背景を青色にしつつ結合し表示
    print("index\x1b[4;104m " + ",".join(tics) + "\x1b[0m")


# 二分探索
# 探索する値の配列中の位置を返す（途中経過も出力）
# sv: 探索する値（整数）
# x:  list（整数）
def binary_search(sv, x):
    cnt = 0           # 探索ステップ数
    fi  = -1          # 発見位置を負の値で初期化
    li  = 0           # 左端の位置
    ri  = len(x) - 1  # 右端の位置

    while li <= ri:  # 左端と右端が入れ替わったら終了
        i = (li + ri) // 2
        cnt += 1
        if x[i] == sv:  # 発見したら
            # 位置を赤色で表示
            print(f"[{cnt:03d}] " + "   "*i + "\x1b[4;101m++\x1b[0m")
            fi = i      # 位置を記録して
            break       # ループ脱出
        else:
            # 位置を緑色で表示
            print(f"[{cnt:03d}] " + "   "*i + "\x1b[4;102m--\x1b[0m")
            if x[i] < sv:   # svの方が大きいなら
                li = i + 1  # 範囲を右に狭める
            else:           # そうでないなら
                ri = i - 1  # 範囲を左に狭める
        
    return fi


def main():
    # 乱数を準備
    try:
        # 整数が入力された場合は，それを種とする
        rnd_seed = int(input("乱数の種（入力が整数以外なら自動設定）："))
        random.seed(rnd_seed)
    except ValueError:
        # 整数でなかった場合は，デフォルト（自動設定）
        pass

    # 各データの準備
    n = 30
    x = make_ints_s(n)  # 整数のデータ列
    s = make_strs(n)    # 対応する文字列の列

    # 探索値を設定（0-9）
    try:
        sv = int(input("探索値（入力が整数以外なら自動設定）："))
    except TypeError:
        sv = random.randrange(9)
    print()  # 採点の都合上の空行 

    # ヘッダー部を表示
    print(sv, "を探します")
    print_index(n)
    print("val_1", ints_to_str(x))
    print("val_2", ",".join(s))

    # 二分探索を実施
    fi = binary_search(sv, x)

    # 結果を表示
    print("val_1", ints_to_str(x))
    print("val_2", ",".join(s))
    print_index(n)

    """ 指示ここから """
    # 条件式を適切に補いなさい．
    # また，プログラムの挙動を確認し，アルゴリズムを理解しなさい．
    if fi < 0:  # 位置の情報が負にならないことを利用
        print(sv, "は見つかりませんでした")
    else:
        print(sv, "は", fi, "番目にあります")
        print("対応する文字列は", s[fi], "です")
    """ 指示ここまで """


if __name__ == "__main__":
    main()
