# -*- coding: utf-8 -*-
"""
重力付き四目並べ（プログラム）
"""
# これは，難易度２を達成するプログラムのソースコードです．


BOARD_SIZE_H = 7  # 盤面横サイズ
BOARD_SIZE_V = 6  # 盤面縦サイズ
WINCON_LEN   = 4  # 勝利条件：四目
STONE_STR = ["[ ]", " X ", " O "]  # 石の文字
# 盤面を初期化した状態でグローバル変数として生成
board   = [[0 for j in range(BOARD_SIZE_H)] for i in range(BOARD_SIZE_V)]
TICKS_H = "".join([f"{i+1:2d} " for i in range(BOARD_SIZE_H)])  # 横軸目盛

# 盤面の表示
def print_board():
    # print("\x1b[2J", end="")  # 画面のクリア
    print(TICKS_H)  # 横軸目盛
    j = 1
    for board_raw in board:
        # １行分の盤面の要素をそれぞれ文字列化
        str_raw = [STONE_STR[i] for i in board_raw]
        # 縦軸目盛とともに１行分の盤面を表示
        print("".join(str_raw))
        j += 1
    print(TICKS_H)  # 横軸目盛


# 位置が盤面の外かどうかを判定
def is_out_of_board(num_v, num_h):
    return not ((0 <= num_v < BOARD_SIZE_V) and (0 <= num_h < BOARD_SIZE_H))


# 盤面に空きがないか確認
def is_board_full():
    for j in range(BOARD_SIZE_H):
        # 重力付きなので上辺だけ確認すればよい
        if board[0][j] == 0:
            return False
    return True


# 縦横斜めのいずれかの方向に指定の石が並んでいるか確認
# 再帰処理を利用する場合のコード
def check_line(num_side, num_v, num_h, dv, dh):
    # 石の種類が異なったら探索から復帰（０個目）
    # そうでなければ次を探索し，その結果に１を加算
    if is_out_of_board(num_v, num_h) or (board[num_v][num_h] != num_side):
        return 0
    else:
        return check_line(num_side, num_v+dv, num_h+dh, dv, dh) + 1


def main():
    num_side = 1      # どちらの手番か
    num_move = 1      # 何手目か
    flag_win = False  # 勝敗フラグ

    print_board()
    # 盤面に空きがあれば継続
    while not is_board_full():
        # 手番の出力
        print(STONE_STR[num_side] + "の番です")
        # 位置の入力　listのインデックスと対応させるため -1
        num_h = int(input(f"どこに置きますか？（{num_move}手目）：")) - 1
        print()  # 改行のみ

        # 位置が 0 以下の場合は終了
        if num_h < 0:
            break

        # 位置が盤面の外の場合や上限に達していた場合はやり直し
        if is_out_of_board(0, num_h) or (board[0][num_h] != 0):
            print("そこには置けません")
            continue

        # 一番下まで落ちたところに石を置く
        num_v = BOARD_SIZE_V - 1
        while board[num_v][num_h] != 0:
            num_v -= 1
        board[num_v][num_h] = num_side

        # 各方向について同じ種類の石がどれだけ並んでいるかチェック
        flag_win = False
        for dv in range(-1, 2):
            for dh in range(2):
                # 置いたところと対向は省略（左上，上，右，右下を確認）
                if (dv <= 0) and (dh <= 0):
                    continue

                # 自分＋指示した方向＋その対向　で数え上げて合計
                num_stone = 1 + check_line(num_side, num_v+dv, num_h+dh, dv, dh) \
                            + check_line(num_side, num_v-dv, num_h-dh, -dv, -dh)
                
                # 指定の数以上なら勝ち
                if  num_stone >= WINCON_LEN:
                    flag_win = True

        # 盤面を表示
        print_board()
        # 勝敗がついた場合（石を置いた側が勝ち）は終了
        if flag_win:
            print(STONE_STR[num_side] + "の勝ちです")
            break
        # 攻守交替
        num_side = (num_side % 2) + 1
        num_move += 1

    else:
        print("引き分けです")
    
    input("\nEnterを押してプログラムを完全終了")


if __name__ == "__main__":
    main()
