# ===== CodeLab: Python 小游戏⑥:记忆翻牌(pygame) =====
# 来源: https://aoerliang.dpdns.org/articles/game-python-memory
# 以下代码片段按文章出现顺序拼接, 共 4 段

# ----- 片段 1 (python) -----
import random, pygame

COLS = ROWS = 4
N = COLS * ROWS
pairs = list(range(N // 2)) * 2      # 0~7 各两次
random.shuffle(pairs)                 # 洗牌
state = ['closed'] * N                # closed / open / matched

# ----- 片段 2 (python) -----
flipped = -1   # 当前翻开的第一张下标

def on_click(card):
    global flipped
    if state[card] != 'closed':
        return
    if flipped == -1:
        state[card] = 'open'
        flipped = card
    else:
        state[card] = 'open'
        if pairs[flipped] == pairs[card]:   # 配对成功
            state[flipped] = state[card] = 'matched'
        else:                                # 失败:短暂展示后翻回
            state[flipped] = state[card] = 'closed'
        flipped = -1

# ----- 片段 3 (python) -----
CELL = 100
GAP = 12
W = H = COLS * CELL + (COLS + 1) * GAP
screen = pygame.display.set_mode((W, H))

def draw():
    screen.fill((30, 30, 45))
    for i in range(N):
        x = GAP + (i % COLS) * (CELL + GAP)
        y = GAP + (i // COLS) * (CELL + GAP)
        rect = (x, y, CELL, CELL)
        if state[i] == 'closed':
            pygame.draw.rect(screen, (70, 90, 140), rect, border_radius=10)
        elif state[i] == 'open':
            pygame.draw.rect(screen, (220, 180, 90), rect, border_radius=10)
            color = [(220,60,60),(60,160,220),(90,200,90),(220,150,50),
                     (180,90,220),(60,200,200),(230,90,120),(160,160,60)][pairs[i]]
            pygame.draw.circle(screen, color, (x+CELL//2, y+CELL//2), 22)
        else:
            pygame.draw.rect(screen, (60, 200, 120), rect, border_radius=10)
    pygame.display.flip()

# ----- 片段 4 (python) -----
import random, pygame

COLS = ROWS = 4
N = COLS * ROWS
CELL = 100
GAP = 12
W = H = COLS * CELL + (COLS + 1) * GAP

pygame.init()
screen = pygame.display.set_mode((W, H))
pygame.display.set_caption('记忆翻牌')
clock = pygame.time.Clock()

pairs = list(range(N // 2)) * 2
random.shuffle(pairs)
state = ['closed'] * N
flipped = -1
moves = 0
won = False

def draw():
    screen.fill((30, 30, 45))
    for i in range(N):
        x = GAP + (i % COLS) * (CELL + GAP)
        y = GAP + (i // COLS) * (CELL + GAP)
        rect = (x, y, CELL, CELL)
        if state[i] == 'closed':
            pygame.draw.rect(screen, (70, 90, 140), rect, border_radius=10)
        elif state[i] == 'open':
            pygame.draw.rect(screen, (220, 180, 90), rect, border_radius=10)
            color = [(220,60,60),(60,160,220),(90,200,90),(220,150,50),
                     (180,90,220),(60,200,200),(230,90,120),(160,160,60)][pairs[i]]
            pygame.draw.circle(screen, color, (x+CELL//2, y+CELL//2), 22)
        else:
            pygame.draw.rect(screen, (60, 200, 120), rect, border_radius=10)
    pygame.display.set_caption('记忆翻牌 · 步数 %d' % moves)
    pygame.display.flip()

while not won:
    for e in pygame.event.get():
        if e.type == pygame.QUIT:
            pygame.quit(); raise SystemExit
        if e.type == pygame.MOUSEBUTTONDOWN and e.button == 1:
            mx, my = pygame.mouse.get_pos()
            c = (my - GAP) // (CELL + GAP)
            r = (mx - GAP) // (CELL + GAP)
            if 0 <= c < COLS and 0 <= r < ROWS:
                card = c * COLS + r
                if state[card] == 'closed':
                    moves += 1
                    if flipped == -1:
                        state[card] = 'open'
                        flipped = card
                    else:
                        state[card] = 'open'
                        if pairs[flipped] == pairs[card]:
                            state[flipped] = state[card] = 'matched'
                        else:
                            state[flipped] = state[card] = 'closed'
                        flipped = -1
    won = all(s == 'matched' for s in state)
    draw()
    clock.tick(30)
print('通关!用了 %d 步' % moves)
