# ===== CodeLab: game-python-minesweeper =====
# 以下代码片段按文章出现顺序拼接, 共 5 段

# ----- 片段 1 (python) -----
# nums:-1 表示地雷,其余数字是周围 8 格里的雷数
# state:0 未翻开, 1 已翻开, 2 插旗
nums = [[0, -1, 1],
        [1,  1, 0],
        [0,  0, 0]]
state = [[0, 2, 1],
         [0, 0, 1],
         [0, 0, 0]]
print('雷区数据:', nums)
print('可见状态:', state)

# ----- 片段 2 (python) -----
import random

ROWS, COLS, MINES = 9, 9, 10

def init():
    nums = [[0] * COLS for _ in range(ROWS)]
    cells = [(r, c) for r in range(ROWS) for c in range(COLS)]
    for r, c in random.sample(cells, MINES):   # 一次性抽出 10 个不同位置
        nums[r][c] = -1
    for r in range(ROWS):
        for c in range(COLS):
            if nums[r][c] == -1:
                continue
            cnt = 0
            for dr in (-1, 0, 1):
                for dc in (-1, 0, 1):
                    nr, nc = r + dr, c + dc
                    if 0 <= nr < ROWS and 0 <= nc < COLS and nums[nr][nc] == -1:
                        cnt += 1
            nums[r][c] = cnt
    return nums, [[0] * COLS for _ in range(ROWS)]

nums, state = init()
print('雷数:', sum(row.count(-1) for row in nums))
print('第一行:', nums[0])

# ----- 片段 3 (python) -----
ROWS = COLS = 5

def reveal(nums, state, r, c):
    """翻开一格;0 区域自动扩散。踩雷返回 False"""
    if not (0 <= r < ROWS and 0 <= c < COLS) or state[r][c] != 0:
        return True
    if nums[r][c] == -1:
        state[r][c] = 1
        return False                      # 踩雷!
    queue = [(r, c)]
    while queue:
        cr, cc = queue.pop(0)
        if state[cr][cc] != 0:
            continue
        state[cr][cc] = 1
        if nums[cr][cc] == 0:             # 是 0 才继续扩散
            for dr in (-1, 0, 1):
                for dc in (-1, 0, 1):
                    nr, nc = cr + dr, cc + dc
                    if 0 <= nr < ROWS and 0 <= nc < COLS and state[nr][nc] == 0:
                        queue.append((nr, nc))
    return True

# 5x5 小棋盘,只有 (1,1) 一颗雷
nums = [[0, 0, 0, 0, 0],
        [0, -1, 0, 0, 0],
        [0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0]]
state = [[0] * COLS for _ in range(ROWS)]
reveal(nums, state, 0, 0)
for row in state:
    print(row)

# ----- 片段 4 (python) -----
ROWS = COLS = 5
nums = [[0, 1, 1, 1, 0],
        [0, 1, -1, 1, 0],
        [0, 1, 1, 1, 0],
        [0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0]]
state = [[0, 1, 2, 1, 1],
         [1, 1, 0, 1, 1],
         [1, 1, 1, 1, 1],
         [1, 1, 1, 1, 1],
         [1, 1, 1, 1, 1]]

def win(nums, state):
    return all(state[r][c] == 1 for r in range(ROWS) for c in range(COLS)
               if nums[r][c] != -1)

def draw(nums, state):
    import os
    os.system('cls' if os.name == 'nt' else 'clear')
    print('    ' + ' '.join(f'{c:2}' for c in range(COLS)))
    for r in range(ROWS):
        print(f'{r:2}  ', end='')
        for c in range(COLS):
            if state[r][c] == 2:
                print(' F ', end='')
            elif state[r][c] == 0:
                print(' . ', end='')
            elif nums[r][c] == -1:
                print(' * ', end='')
            else:
                print(f' {nums[r][c]} ', end='')
        print()

draw(nums, state)
print('胜利?', win(nums, state))    # (0,0) 还没翻开,所以是 False

# ----- 片段 5 (python) -----
import os
import random

ROWS, COLS, MINES = 9, 9, 10

def init():
    nums = [[0] * COLS for _ in range(ROWS)]
    cells = [(r, c) for r in range(ROWS) for c in range(COLS)]
    for r, c in random.sample(cells, MINES):
        nums[r][c] = -1
    for r in range(ROWS):
        for c in range(COLS):
            if nums[r][c] == -1:
                continue
            cnt = 0
            for dr in (-1, 0, 1):
                for dc in (-1, 0, 1):
                    nr, nc = r + dr, c + dc
                    if 0 <= nr < ROWS and 0 <= nc < COLS and nums[nr][nc] == -1:
                        cnt += 1
            nums[r][c] = cnt
    return nums, [[0] * COLS for _ in range(ROWS)]

def reveal(nums, state, r, c):
    if not (0 <= r < ROWS and 0 <= c < COLS) or state[r][c] != 0:
        return True
    if nums[r][c] == -1:
        state[r][c] = 1
        return False
    queue = [(r, c)]
    while queue:
        cr, cc = queue.pop(0)
        if state[cr][cc] != 0:
            continue
        state[cr][cc] = 1
        if nums[cr][cc] == 0:
            for dr in (-1, 0, 1):
                for dc in (-1, 0, 1):
                    nr, nc = cr + dr, cc + dc
                    if 0 <= nr < ROWS and 0 <= nc < COLS and state[nr][nc] == 0:
                        queue.append((nr, nc))
    return True

def win(nums, state):
    return all(state[r][c] == 1 for r in range(ROWS) for c in range(COLS)
               if nums[r][c] != -1)

def draw(nums, state):
    os.system('cls' if os.name == 'nt' else 'clear')
    print('    ' + ' '.join(f'{c:2}' for c in range(COLS)))
    for r in range(ROWS):
        print(f'{r:2}  ', end='')
        for c in range(COLS):
            if state[r][c] == 2:
                print(' F ', end='')
            elif state[r][c] == 0:
                print(' . ', end='')
            elif nums[r][c] == -1:
                print(' * ', end='')
            else:
                print(f' {nums[r][c]} ', end='')
        print()

def main():
    nums, state = init()
    while True:
        draw(nums, state)
        if win(nums, state):
            print('恭喜,全部排雷成功!')
            break
        try:
            cmd = input('o 行 列 翻开 / f 行 列 标记 / q 退出 > ').split()
        except EOFError:
            break
        if not cmd:
            continue
        if cmd[0] == 'q':
            break
        if len(cmd) != 3 or cmd[0] not in 'of':
            print('命令格式:o 3 5 或 f 3 5')
            continue
        try:
            op, r, c = cmd[0], int(cmd[1]), int(cmd[2])
        except ValueError:
            print('行列必须是数字')
            continue
        if op == 'f':
            if state[r][c] == 2:
                state[r][c] = 0
            elif state[r][c] == 0:
                state[r][c] = 2
        elif op == 'o':
            if not reveal(nums, state, r, c):
                draw(nums, state)
                print('踩雷了!游戏结束。')
                break

if __name__ == '__main__':
    main()
