import random # Define the basic movements def move_left(grid): new_grid = [[0]*4 for _ in range(4)] for i in range(4): position = 0 for j in range(4): if grid[i][j] != 0: if new_grid[i][position] == 0: new_grid[i][position] = grid[i][j] elif new_grid[i][position] == grid[i][j]: new_grid[i][position] *= 2 position += 1 else: position += 1 new_grid[i][position] = grid[i][j] return new_grid def move_right(grid): new_grid = [[0]*4 for _ in range(4)] for i in range(4): position = 3 for j in range(3, -1, -1): if grid[i][j] != 0: if new_grid[i][position] == 0: new_grid[i][position] = grid[i][j] elif new_grid[i][position] == grid[i][j]: new_grid[i][position] *= 2 position -= 1 else: position -= 1 new_grid[i][position] = grid[i][j] return new_grid def move_up(grid): new_grid = [[0]*4 for _ in range(4)] for j in range(4): position = 0 for i in range(4): if grid[i][j] != 0: if new_grid[position][j] == 0: new_grid[position][j] = grid[i][j] elif new_grid[position][j] == grid[i][j]: new_grid[position][j] *= 2 position += 1 else: position += 1 new_grid[position][j] = grid[i][j] return new_grid def move_down(grid): new_grid = [[0]*4 for _ in range(4)] for j in range(4): position = 3 for i in range(3, -1, -1): if grid[i][j] != 0: if new_grid[position][j] == 0: new_grid[position][j] = grid[i][j] elif new_grid[position][j] == grid[i][j]: new_grid[position][j] *= 2 position -= 1 else: position -= 1 new_grid[position][j] = grid[i][j] return new_grid def is_game_over(grid): if any(0 in row for row in grid): return False for i in range(4): for j in range(3): if grid[i][j] == grid[i][j + 1] or grid[j][i] == grid[j + 1][i]: return False return True def get_available_moves(grid): moves = [move_left, move_right, move_up, move_down] available_moves = [] for move in moves: new_grid = move(grid) if new_grid != grid: available_moves.append(move) return available_moves def expectimax(grid, depth): if depth == 0 or is_game_over(grid): return evaluate(grid) available_moves = get_available_moves(grid) if not available_moves: return evaluate(grid) if depth % 2 == 0: # Max node return max(expectimax(move(grid), depth - 1) for move in available_moves) else: # Expectation node total_score = 0 empty_tiles = [(i, j) for i in range(4) for j in range(4) if grid[i][j] == 0] if not empty_tiles: return evaluate(grid) for tile in empty_tiles: grid[tile[0]][tile[1]] = 2 total_score += 0.9 * expectimax(grid, depth - 1) grid[tile[0]][tile[1]] = 4 total_score += 0.1 * expectimax(grid, depth - 1) grid[tile[0]][tile[1]] = 0 return total_score / len(empty_tiles) def evaluate(grid): return sum(sum(row) for row in grid) def input_grid(): grid = [] for i in range(4): row = list(map(int, input(f"Enter row {i+1} (space-separated values): ").split())) grid.append(row) return grid def input_new_tile(): i, j = map(int, input("Enter the position of the new tile (row and column): ").split()) value = int(input("Enter the value of the new tile (2 or 4): ")) return (i, j, value) def play_2048_with_manual_input(): grid = input_grid() print("Initial Grid:") print_grid(grid) while not is_game_over(grid): move_func = get_best_move(grid) grid = move_func(grid) print(f"Best move: {move_func.__name__[5:]}") new_tile = input_new_tile() grid[new_tile[0] - 1][new_tile[1] - 1] = new_tile[2] print("Updated Grid:") print_grid(grid) print("Game over!") def get_best_move(grid): moves = [move_left, move_right, move_up, move_down] best_move = None best_score = float('-inf') for move in moves: new_grid = move(grid) score = expectimax(new_grid, 3) # Adjust depth as needed if score > best_score: best_score = score best_move = move return best_move def print_grid(grid): for row in grid: print(" ".join(map(str, row))) if __name__ == "__main__": play_2048_with_manual_input() app.mainloop()