import random
import os
import sys
from typing import List, Tuple, Optional

class Game2048:
    def __init__(self):
        self.board = [[0] * 4 for _ in range(4)]
        self.score = 0
        self.game_over = False
        self.add_new_tile()
        self.add_new_tile()
    
    def add_new_tile(self) -> None:
        """在随机空位置添加一个新的数字块（2或4）"""
        empty_cells = []
        for i in range(4):
            for j in range(4):
                if self.board[i][j] == 0:
                    empty_cells.append((i, j))
        
        if empty_cells:
            i, j = random.choice(empty_cells)
            self.board[i][j] = 2 if random.random() < 0.9 else 4
    
    def print_board(self) -> None:
        """打印游戏界面"""
        os.system('cls' if os.name == 'nt' else 'clear')
        print("=" * 50)
        print("2048 游戏")
        print("=" * 50)
        print(f"分数: {self.score}")
        print("使用 W/A/S/D 或方向键移动，Q退出")
        print("=" * 50)
        
        for i in range(4):
            print("|", end=" ")
            for j in range(4):
                if self.board[i][j] == 0:
                    print("    ", end=" | ")
                else:
                    print(f"{self.board[i][j]:4d}", end=" | ")
            print()
            print("-" * 50)
    
    def move_left(self) -> bool:
        """向左移动并合并"""
        moved = False
        for i in range(4):
            # 移除零
            row = [x for x in self.board[i] if x != 0]
            # 合并相同数字
            for j in range(len(row) - 1):
                if row[j] == row[j + 1]:
                    row[j] *= 2
                    self.score += row[j]
                    row[j + 1] = 0
            # 再次移除零
            row = [x for x in row if x != 0]
            # 填充到4个位置
            row.extend([0] * (4 - len(row)))
            if row != self.board[i]:
                moved = True
            self.board[i] = row
        return moved
    
    def move_right(self) -> bool:
        """向右移动并合并"""
        moved = False
        for i in range(4):
            # 移除零
            row = [x for x in self.board[i] if x != 0]
            # 合并相同数字（从右到左）
            for j in range(len(row) - 1, 0, -1):
                if row[j] == row[j - 1]:
                    row[j] *= 2
                    self.score += row[j]
                    row[j - 1] = 0
            # 再次移除零
            row = [x for x in row if x != 0]
            # 填充到4个位置
            row = [0] * (4 - len(row)) + row
            if row != self.board[i]:
                moved = True
            self.board[i] = row
        return moved
    
    def move_up(self) -> bool:
        """向上移动并合并"""
        moved = False
        for j in range(4):
            # 获取列
            col = [self.board[i][j] for i in range(4)]
            # 移除零
            col = [x for x in col if x != 0]
            # 合并相同数字
            for i in range(len(col) - 1):
                if col[i] == col[i + 1]:
                    col[i] *= 2
                    self.score += col[i]
                    col[i + 1] = 0
            # 再次移除零
            col = [x for x in col if x != 0]
            # 填充到4个位置
            col.extend([0] * (4 - len(col)))
            # 更新列
            for i in range(4):
                if self.board[i][j] != col[i]:
                    moved = True
                self.board[i][j] = col[i]
        return moved
    
    def move_down(self) -> bool:
        """向下移动并合并"""
        moved = False
        for j in range(4):
            # 获取列
            col = [self.board[i][j] for i in range(4)]
            # 移除零
            col = [x for x in col if x != 0]
            # 合并相同数字（从下到上）
            for i in range(len(col) - 1, 0, -1):
                if col[i] == col[i - 1]:
                    col[i] *= 2
                    self.score += col[i]
                    col[i - 1] = 0
            # 再次移除零
            col = [x for x in col if x != 0]
            # 填充到4个位置
            col = [0] * (4 - len(col)) + col
            # 更新列
            for i in range(4):
                if self.board[i][j] != col[i]:
                    moved = True
                self.board[i][j] = col[i]
        return moved
    
    def is_game_over(self) -> bool:
        """检查游戏是否结束"""
        # 检查是否有空格
        for i in range(4):
            for j in range(4):
                if self.board[i][j] == 0:
                    return False
        
        # 检查是否可以合并
        for i in range(4):
            for j in range(4):
                current = self.board[i][j]
                # 检查右边
                if j < 3 and self.board[i][j + 1] == current:
                    return False
                # 检查下边
                if i < 3 and self.board[i + 1][j] == current:
                    return False
        
        return True
    
    def has_won(self) -> bool:
        """检查是否达到2048"""
        for i in range(4):
            for j in range(4):
                if self.board[i][j] == 2048:
                    return True
        return False
    
    def make_move(self, direction: str) -> bool:
        """根据方向移动"""
        moved = False
        if direction in ['w', 'W', 'up']:
            moved = self.move_up()
        elif direction in ['s', 'S', 'down']:
            moved = self.move_down()
        elif direction in ['a', 'A', 'left']:
            moved = self.move_left()
        elif direction in ['d', 'D', 'right']:
            moved = self.move_right()
        
        if moved:
            self.add_new_tile()
            if self.is_game_over():
                self.game_over = True
        
        return moved

def get_key() -> str:
    """获取用户输入"""
    try:
        import msvcrt
        key = msvcrt.getch()
        # 处理特殊字符
        if key == b'\xe0':  # 方向键前缀
            key = msvcrt.getch()
            # 方向键映射
            if key == b'H': return 'w'  # 上
            elif key == b'P': return 's'  # 下
            elif key == b'K': return 'a'  # 左
            elif key == b'M': return 'd'  # 右
        else:
            try:
                return key.decode('utf-8').lower()
            except UnicodeDecodeError:
                return key.decode('latin-1').lower()
    except ImportError:
        # 对于非Windows系统，使用input
        return input("请输入移动方向 (w/a/s/d): ").lower()

def main():
    """主游戏循环"""
    game = Game2048()
    
    print("欢迎来到2048游戏！")
    print("使用 W/A/S/D 键移动方块")
    print("按 Q 退出游戏")
    print("按任意键开始...")
    input()
    
    while not game.game_over:
        game.print_board()
        
        if game.has_won():
            print("恭喜！你达到了2048！")
            choice = input("继续游戏？(y/n): ").lower()
            if choice != 'y':
                break
        
        print("移动方向: ", end="")
        key = get_key()
        
        if key == 'q':
            print("游戏结束！")
            break
        
        if key in ['w', 'a', 's', 'd']:
            game.make_move(key)
        else:
            print("无效输入！请使用 W/A/S/D 键")
    
    if game.game_over:
        game.print_board()
        print("游戏结束！最终分数:", game.score)

if __name__ == "__main__":
    main()