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

# ----- 片段 1 (python) -----
SIZE = 4

# board[r][c] 存数字,0 表示空格
board = [[0] * SIZE for _ in range(SIZE)]
board[0][0] = 2
board[1][1] = 4
for row in board:
    print(row)

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

SIZE = 4

def new_board():
    return [[0] * SIZE for _ in range(SIZE)]

def spawn(board):
    empty = [(r, c) for r in range(SIZE) for c in range(SIZE)
             if board[r][c] == 0]
    if not empty:
        return False
    r, c = random.choice(empty)
    board[r][c] = 2 if random.random() < 0.9 else 4
    return True

board = new_board()
spawn(board)
spawn(board)
for row in board:
    print(row)

# ----- 片段 3 (python) -----
SIZE = 4

def merge_row(row):
    nums = [x for x in row if x != 0]      # 压缩:去掉 0
    out = []
    gain = 0
    i = 0
    while i < len(nums):
        if i + 1 < len(nums) and nums[i] == nums[i + 1]:
            out.append(nums[i] * 2)        # 合并一次
            gain += nums[i] * 2
            i += 2                         # 跳过已合并的一对
        else:
            out.append(nums[i])
            i += 1
    return out + [0] * (SIZE - len(out)), gain

for row in ([2, 2, 2, 2], [2, 0, 2, 4], [4, 4, 8, 0], [0, 0, 0, 0]):
    print(row, '->', merge_row(row))

# ----- 片段 4 (python) -----
SIZE = 4

def merge_row(row):
    nums = [x for x in row if x != 0]
    out = []
    gain = 0
    i = 0
    while i < len(nums):
        if i + 1 < len(nums) and nums[i] == nums[i + 1]:
            out.append(nums[i] * 2)
            gain += nums[i] * 2
            i += 2
        else:
            out.append(nums[i])
            i += 1
    return out + [0] * (SIZE - len(out)), gain

def move(board, d):
    """d: 0左 1下 2右 3上"""
    b = [list(row) for row in board]
    for _ in range(d):                     # 顺时针旋转 d 次
        b = [list(row) for row in zip(*b[::-1])]
    rows, gain = [], 0
    for row in b:
        new_row, g = merge_row(row)
        rows.append(new_row)
        gain += g
    for _ in range(d):                     # 逆时针转回去
        rows = [list(row) for row in zip(*rows)][::-1]
    return rows, gain, rows != board

board = [[2, 2, 0, 0],
         [0, 0, 0, 0],
         [0, 0, 0, 0],
         [0, 0, 0, 0]]
print('向左:', move(board, 0))
print('向下:', move(board, 1))

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

SIZE = 4

def game_over(board):
    if any(0 in row for row in board):
        return False
    for r in range(SIZE):
        for c in range(SIZE):
            v = board[r][c]
            if (r + 1 < SIZE and board[r + 1][c] == v) or \
               (c + 1 < SIZE and board[r][c + 1] == v):
                return False
    return True

def draw(board, score):
    os.system('cls' if os.name == 'nt' else 'clear')
    print('得分:', score)
    for row in board:
        print('+----' * SIZE + '+')
        print(''.join(f'|{v:^4}' if v else '|    ' for v in row) + '|')
    print('+----' * SIZE + '+')

demo = [[2, 4, 8, 16], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
draw(demo, 30)
full = [[2, 4, 8, 16], [4, 8, 16, 32], [8, 16, 32, 64], [16, 32, 64, 128]]
print('有空格时结束吗?', game_over(demo))      # False
print('满盘且无相邻相等时结束吗?', game_over(full))  # True

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

SIZE = 4

def new_board():
    return [[0] * SIZE for _ in range(SIZE)]

def spawn(board):
    empty = [(r, c) for r in range(SIZE) for c in range(SIZE)
             if board[r][c] == 0]
    if not empty:
        return False
    r, c = random.choice(empty)
    board[r][c] = 2 if random.random() < 0.9 else 4
    return True

def merge_row(row):
    nums = [x for x in row if x != 0]
    out = []
    gain = 0
    i = 0
    while i < len(nums):
        if i + 1 < len(nums) and nums[i] == nums[i + 1]:
            out.append(nums[i] * 2)
            gain += nums[i] * 2
            i += 2
        else:
            out.append(nums[i])
            i += 1
    return out + [0] * (SIZE - len(out)), gain

def move(board, d):
    b = [list(row) for row in board]
    for _ in range(d):
        b = [list(row) for row in zip(*b[::-1])]
    rows, gain = [], 0
    for row in b:
        new_row, g = merge_row(row)
        rows.append(new_row)
        gain += g
    for _ in range(d):
        rows = [list(row) for row in zip(*rows)][::-1]
    return rows, gain, rows != board

def game_over(board):
    if any(0 in row for row in board):
        return False
    for r in range(SIZE):
        for c in range(SIZE):
            v = board[r][c]
            if (r + 1 < SIZE and board[r + 1][c] == v) or \
               (c + 1 < SIZE and board[r][c + 1] == v):
                return False
    return True

def draw(board, score):
    os.system('cls' if os.name == 'nt' else 'clear')
    print('得分:', score)
    for row in board:
        print('+----' * SIZE + '+')
        print(''.join(f'|{v:^4}' if v else '|    ' for v in row) + '|')
    print('+----' * SIZE + '+')

def main():
    board = new_board()
    spawn(board)
    spawn(board)
    score = 0
    keys = {'a': 0, 's': 1, 'd': 2, 'w': 3}
    while True:
        draw(board, score)
        if game_over(board):
            print('游戏结束,最终得分:', score)
            break
        try:
            cmd = input('w/a/s/d 移动,q 退出 > ').strip().lower()
        except EOFError:
            break
        if cmd == 'q':
            break
        if cmd not in keys:
            continue
        board, gain, changed = move(board, keys[cmd])
        if changed:
            score += gain
            spawn(board)

if __name__ == '__main__':
    main()
