import os
import re
import random

# EVOLVE-BLOCK-START
def solve(capacity, items):
    """
    使用随机顺序的 Next-Fit 算法解决装箱问题.
    物品将先被随机打乱顺序, 然后再进行装箱.
    """
    # bins 是一个列表的列表, 每个内部列表代表一个箱子
    if not items:
        return []
    
    bins = [[]] # 从第一个空箱子开始
    
    # 【关键修改】设置随机种子以保证结果可复现, 并随机打乱物品顺序
    random.seed(42)
    random.shuffle(items)

    for item in items:
        # Next-Fit 的核心: 只尝试放入最后一个(当前)箱子
        if (capacity - sum(bins[-1])) >= item:
            # 如果能放下, 就放入当前箱子
            bins[-1].append(item)
        else:
            # 如果放不下, 则开启一个新箱子, 并将物品放入
            # 旧的箱子将不再被考虑
            bins.append([item])
            
    # 返回包含详细方案的列表
    return bins
# EVOLVE-BLOCK-END

def solve_bpp_files(directory):
    """
    读取目录中的 BPP 文件, 使用随机顺序的 Next-Fit 算法求解, 并与最优解对比.
    """
    total_relative_error = 0
    file_count = 0

    print(f"正在从文件夹 '{directory}' 读取文件...")
    print("将使用 Next-Fit (随机顺序) 算法进行求解.\n")

    if not os.path.isdir(directory):
        print(f"错误: 目录 '{directory}' 不存在或不是一个有效的目录.")
        return

    for filename in os.listdir(directory):
        if not filename.endswith(".txt"):
            continue

        file_path = os.path.join(directory, filename)
        
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                full_content = f.read()

            # 1. 从文件内容中提取最优解
            optimal_match = re.search(r"Total bins used:\s*(\d+)", full_content)
            if not optimal_match:
                print(f"警告: 在文件 '{filename}' 中未找到 'Total bins used: ...', 已跳过.")
                print("-" * 25)
                continue
            optimal_bins = int(optimal_match.group(1))

            # 2. 从文件中提取容量和物品列表 (遵循正确的格式)
            numeric_lines = [int(line.strip()) for line in full_content.splitlines() if line.strip().isdigit()]
            
            if len(numeric_lines) < 3:
                print(f"警告: 在文件 '{filename}' 中未找到足够的有效数据，已跳过.")
                print("-" * 25)
                continue
            
            # 文件格式: 第一个数字是物品数, 第二个是容量, 其余是物品
            capacity = numeric_lines[1]
            items = numeric_lines[2:]
            
            # 3. 运行算法并计算
            solution = solve(capacity, items)
            next_fit_bins = len(solution) # 从返回的方案中获取箱子数
            relative_error = (next_fit_bins - optimal_bins) / optimal_bins
            
            print(f"文件: {filename}")
            print(f"  - 物品容量: {capacity}")
            print(f"  - Next-Fit (随机) 算法结果: {next_fit_bins} 个箱子")
            print(f"  - 从该文件读入的最优解: {optimal_bins} 个箱子")
            print(f"  - 相对误差: {relative_error:+.4f}")
            print("-" * 25)
            
            total_relative_error += relative_error
            file_count += 1
        
        except Exception as e:
            print(f"处理文件 '{filename}' 时发生错误: {e}")
            print("-" * 25)
            continue

    if file_count > 0:
        average_relative_error = total_relative_error / file_count
        print(f"\n成功处理了 {file_count} 个文件.")
        print(f"所有文件的总平均相对误差: {average_relative_error:.4f}")
    else:
        print("在指定目录中没有找到任何可处理的文件.")

# --- 主程序入口 ---
if __name__ == "__main__":
    # 请确保这里的路径是您存放 BPP 数据文件的正确目录
    INPUT_DIRECTORY = "/home/liuyihong/openevolve/examples/BPP/input" 
    solve_bpp_files(INPUT_DIRECTORY)
