"""
2048 Game - Core Logic
"""
import random
import copy

class Game2048:
    """Core 2048 game logic"""
    
    def __init__(self, size=4):
        self.size = size
        self.grid = [[0] * size for _ in range(size)]
        self.score = 0
        self._add_new_tile()
        self._add_new_tile()
    
    def _add_new_tile(self):
        """Add a new tile (2 or 4) to a random empty cell"""
        empty_cells = [(r, c) for r in range(self.size) for c in range(self.size) if self.grid[r][c] == 0]
        if empty_cells:
            r, c = random.choice(empty_cells)
            self.grid[r][c] = 2 if random.random() < 0.9 else 4
    
    def _slide_row(self, row):
        """Slide and merge a row to the left"""
        # Remove zeros
        non_zero = [x for x in row if x != 0]
        
        # Merge adjacent equal tiles
        merged = []
        i = 0
        while i < len(non_zero):
            if i + 1 < len(non_zero) and non_zero[i] == non_zero[i + 1]:
                merged.append(non_zero[i] * 2)
                self.score += non_zero[i] * 2
                i += 2
            else:
                merged.append(non_zero[i])
                i += 1
        
        # Pad with zeros
        merged += [0] * (self.size - len(merged))
        return merged
    
    def _transpose(self):
        """Transpose the grid"""
        self.grid = [list(row) for row in zip(*self.grid)]
    
    def _reverse(self):
        """Reverse each row"""
        self.grid = [row[::-1] for row in self.grid]
    
    def move_left(self):
        """Move tiles left"""
        new_grid = [self._slide_row(row) for row in self.grid]
        if new_grid != self.grid:
            self.grid = new_grid
            self._add_new_tile()
            return True
        return False
    
    def move_right(self):
        """Move tiles right"""
        self._reverse()
        moved = self.move_left()
        self._reverse()
        return moved
    
    def move_up(self):
        """Move tiles up"""
        self._transpose()
        moved = self.move_left()
        self._transpose()
        return moved
    
    def move_down(self):
        """Move tiles down"""
        self._transpose()
        moved = self.move_right()
        self._transpose()
        return moved
    
    def can_move(self):
        """Check if any move is possible"""
        # Check for empty cells
        for r in range(self.size):
            for c in range(self.size):
                if self.grid[r][c] == 0:
                    return True
        
        # Check for possible merges
        for r in range(self.size):
            for c in range(self.size):
                val = self.grid[r][c]
                # Check right
                if c + 1 < self.size and self.grid[r][c + 1] == val:
                    return True
                # Check down
                if r + 1 < self.size and self.grid[r + 1][c] == val:
                    return True
        return False
    
    def has_won(self):
        """Check if player has reached 2048"""
        for row in self.grid:
            if 2048 in row:
                return True
        return False
    
    def is_game_over(self):
        """Check if game is over"""
        return not self.can_move()
    
    def get_grid(self):
        """Get current grid state"""
        return copy.deepcopy(self.grid)
    
    def get_score(self):
        """Get current score"""
        return self.score
    
    def __str__(self):
        """String representation of the grid"""
        max_width = len(str(max(max(row) for row in self.grid)))
        separator = '+' + (('-' * (max_width + 2) + '+') * self.size)
        lines = [separator]
        for row in self.grid:
            line = '|'
            for cell in row:
                if cell == 0:
                    line += ' ' * (max_width + 2) + '|'
                else:
                    line += f' {cell:>{max_width}} |'
            lines.append(line)
            lines.append(separator)
        return '\n'.join(lines)
