Python代码,M+4动态模拟,控制论

1 阅读7分钟

-- coding: utf-8 --

""" M+4动态目标版状态机【大任务4 / 小任务M+4 / 跑100万步】

本版本改动:

  1. 大任务阈值 BIG_TARGET = 4
  2. 小任务动态目标 = M + 4
  3. M >= 0 时,目标值锁定为 4
  4. M < 0 时,目标值 = M + 4
  5. 运行步数 MAX_STEPS = 1_000_000
  6. 默认只输出汇总CSV,不输出100万行明细,防止电脑卡死
  7. 保留任务后首赢 M+1 规则
  8. 主赛道每一步结束后,统一用最新pos和最新M判断 pos<M """

import csv from pathlib import Path from datetime import datetime

============================================================

参数区

============================================================

MAX_STEPS = 10_000_000

100万步建议 False;如果一定要逐步明细,可改 True

EXPORT_DETAIL = False

PI_DIGITS_TXT_NAME = "pi_digits.txt"

SUMMARY_CSV_NAME = "千万.csv" DETAIL_CSV_NAME = "m_plus_4_detail_1000000.csv"

BIG_TARGET = 4

MAIN_MODE = "主赛道" WAIT_MODE = "等待模式"

def get_desktop_path(): desktop = Path.home() / "Desktop" if desktop.exists(): return desktop

chinese_desktop = Path.home() / "桌面"
if chinese_desktop.exists():
    return chinese_desktop

return Path.cwd()

def load_pi_digits_from_desktop(): desktop_path = get_desktop_path() txt_path = desktop_path / PI_DIGITS_TXT_NAME

if not txt_path.exists():
    raise FileNotFoundError(
        f"未找到文件:{txt_path}\n"
        f"请把 {PI_DIGITS_TXT_NAME} 放到桌面。"
    )

with open(txt_path, "r", encoding="utf-8") as f:
    raw_text = f.read()

digits = "".join(ch for ch in raw_text if ch.isdigit())

# 兼容 3.14159...
if digits.startswith("314159"):
    digits = digits[1:]

if not digits.startswith("14159"):
    raise ValueError(
        "π数字文件内容错误:必须从小数点后 14159 开始。\n"
        "正确示例:14159265358979323846..."
    )

if len(digits) < MAX_STEPS:
    raise ValueError(
        f"π数字长度不足:当前只有 {len(digits)} 位,"
        f"但需要运行 {MAX_STEPS} 步。"
    )

return digits, txt_path

def is_odd_digit(digit): return digit in (1, 3, 5, 7, 9)

def calc_target(m_value): """ M+4动态目标值:

M < 0:
    target = M + 4

M >= 0:
    target = 4
"""
if m_value < 0:
    return m_value + BIG_TARGET
return BIG_TARGET

def update_m_and_target(new_m): return new_m, calc_target(new_m)

def run_state_machine(pi_digits, max_steps, keep_detail=False): pos = 0 m_value = 0 target = calc_target(m_value)

mode = MAIN_MODE

red_count = 0
green_count = 0

big_task_count = 0
small_task_count = 0

odd_count = 0
even_count = 0

m_limit = 0
pos_limit = 0

after_task_wait_confirm = False
after_task_reason = ""

detail_rows = []

start_time = datetime.now()
print(f"开始运行:{start_time}")
print(f"运行步数:{max_steps:,}")
print(f"大任务阈值:{BIG_TARGET}")
print("动态目标:M < 0 时 target=M+4;M >= 0 时 target=4")

for step_index in range(1, max_steps + 1):
    digit = ord(pi_digits[step_index - 1]) - 48
    odd_flag = is_odd_digit(digit)

    if odd_flag:
        odd_count += 1
        digit_type = "单"
    else:
        even_count += 1
        digit_type = "双"

    before_mode = mode
    before_pos = pos
    before_m = m_value
    before_target = target
    before_wait_confirm = after_task_wait_confirm
    before_wait_reason = after_task_reason

    marker = "-"
    status = ""
    operation_parts = []

    step_win_loss = ""
    step_allow_m_plus_one = False
    m_plus_one_executed = False
    wait_triggered_this_step = False
    reached_small_task = False
    reached_big_task = False

    # ====================================================
    # 1. 主赛道
    # ====================================================
    if mode == MAIN_MODE:
        status = "主赛道运行"

        if odd_flag:
            step_win_loss = "赢:主赛道单数"
            pos += 1
            operation_parts.append("主赛道遇单,判定为赢,pos+1")

            if after_task_wait_confirm:
                step_allow_m_plus_one = True

                m_value += 1
                target = calc_target(m_value)

                m_plus_one_executed = True
                operation_parts.append(
                    f"任务后首赢:执行M=M+1,重算目标值;来源={after_task_reason}"
                )

                after_task_wait_confirm = False
                after_task_reason = ""
            else:
                step_allow_m_plus_one = False
                operation_parts.append("非任务后等待确认状态,本步不执行M+1")

        else:
            step_win_loss = "输:主赛道双数"
            pos -= 1
            operation_parts.append("主赛道遇双,判定为输,pos-1")

            if after_task_wait_confirm:
                step_allow_m_plus_one = False
                operation_parts.append(
                    f"任务后遇双,判定为输:不允许M+1;来源={after_task_reason}"
                )
                after_task_wait_confirm = False
                after_task_reason = ""
            else:
                step_allow_m_plus_one = False
                operation_parts.append("非任务后等待确认状态,本步不执行M+1")

        # 主赛道本步结束后,用最新pos和最新M判断 pos<M
        if pos < m_value:
            m_value, target = update_m_and_target(pos)
            mode = WAIT_MODE
            status = "触发等待模式"
            wait_triggered_this_step = True
            operation_parts.append(
                "主赛道本步结束后:pos<M,M=pos,重算目标值,进入等待模式"
            )

    # ====================================================
    # 2. 等待模式
    # ====================================================
    elif mode == WAIT_MODE:
        status = "等待模式"
        step_win_loss = "不判输赢:等待模式只统计红绿点"
        step_allow_m_plus_one = False

        if odd_flag:
            green_count += 1
            marker = "绿点"

            mode = MAIN_MODE
            after_task_wait_confirm = True
            after_task_reason = "等待模式解锁"

            operation_parts.append(
                "等待模式遇单,绿点+1,pos不变,退出等待;进入任务后等待确认"
            )

        else:
            red_count += 1
            marker = "红点"

            operation_parts.append(
                "等待模式遇双,红点+1,pos不变,继续等待"
            )

    else:
        raise RuntimeError(f"未知模式:{mode}")

    # ====================================================
    # 3. 实时状态:任务结算前
    # ====================================================
    realtime_mode = mode
    realtime_pos = pos
    realtime_m = m_value
    realtime_target = target

    if realtime_m < m_limit:
        m_limit = realtime_m

    if realtime_pos < pos_limit:
        pos_limit = realtime_pos

    # ====================================================
    # 4. 大任务优先判定
    # ====================================================
    if pos == BIG_TARGET:
        reached_big_task = True
        big_task_count += 1

        operation_parts.append(
            "pos=4,完成大任务;本轮小任务自动终止;重置pos=0、M=0、target=4;进入任务后等待确认"
        )

        pos = 0
        m_value = 0
        target = calc_target(m_value)

        mode = MAIN_MODE

        after_task_wait_confirm = True
        after_task_reason = "完成大任务"

    else:
        # ====================================================
        # 5. 小任务判定
        # ====================================================
        if pos == target:
            reached_small_task = True
            small_task_count += 1

            m_value, target = update_m_and_target(pos)

            after_task_wait_confirm = True
            after_task_reason = "完成小任务"

            operation_parts.append(
                "pos=当前动态目标值,完成小任务;不重置pos;M=当前pos,重算目标值;进入任务后等待确认"
            )

    settled_mode = mode
    settled_pos = pos
    settled_m = m_value
    settled_target = target

    if settled_pos > BIG_TARGET:
        raise RuntimeError(
            f"全局约束错误:第 {step_index} 步 pos={settled_pos} > {BIG_TARGET}"
        )

    if keep_detail:
        detail_rows.append({
            "步数": step_index,
            "数字": digit,
            "单双": digit_type,

            "步前模式": before_mode,
            "步前pos": before_pos,
            "步前M": before_m,
            "步前目标值": before_target,
            "步前任务后等待确认": before_wait_confirm,
            "步前等待确认来源": before_wait_reason,

            "当前状态": status,
            "本步输赢判定": step_win_loss,
            "本步是否允许M+1": step_allow_m_plus_one,
            "本步是否执行M+1": m_plus_one_executed,
            "本步是否触发等待": wait_triggered_this_step,

            "实时模式": realtime_mode,
            "实时pos": realtime_pos,
            "实时M": realtime_m,
            "实时目标值": realtime_target,

            "标记": marker,
            "红点累计": red_count,
            "绿点累计": green_count,

            "是否完成小任务": reached_small_task,
            "是否完成大任务": reached_big_task,

            "小任务完成数": small_task_count,
            "大任务完成数": big_task_count,

            "结算后模式": settled_mode,
            "结算后pos": settled_pos,
            "结算后M": settled_m,
            "结算后目标值": settled_target,
            "结算后任务后等待确认": after_task_wait_confirm,
            "结算后等待确认来源": after_task_reason,

            "核心合规操作": ";".join(operation_parts),
        })

    if step_index % 100_000 == 0:
        print(
            f"已运行 {step_index:,} 步 | "
            f"红点={red_count:,} | 绿点={green_count:,} | "
            f"大任务={big_task_count:,} | 小任务={small_task_count:,} | "
            f"pos={pos} | M={m_value} | target={target}"
        )

red_green_diff = red_count - green_count
theoretical_red_green_diff = big_task_count * BIG_TARGET + pos
conservation_error = abs(red_green_diff - theoretical_red_green_diff)
odd_even_abs_diff = abs(odd_count - even_count)
conservation_pass = odd_even_abs_diff == conservation_error

end_time = datetime.now()

result = {
    "max_steps": max_steps,

    "odd_count": odd_count,
    "even_count": even_count,
    "odd_even_abs_diff": odd_even_abs_diff,

    "red_count": red_count,
    "green_count": green_count,
    "red_green_diff": red_green_diff,

    "small_task_count": small_task_count,
    "big_task_count": big_task_count,

    "final_pos": pos,
    "final_m": m_value,
    "final_target": target,
    "final_mode": mode,
    "final_after_task_wait_confirm": after_task_wait_confirm,
    "final_after_task_reason": after_task_reason,

    "m_limit": m_limit,
    "pos_limit": pos_limit,

    "theoretical_red_green_diff": theoretical_red_green_diff,
    "conservation_error": conservation_error,
    "conservation_pass": conservation_pass,

    "start_time": str(start_time),
    "end_time": str(end_time),
    "elapsed_time": str(end_time - start_time),

    "detail_rows": detail_rows,
}

return result

def export_summary_csv(result, output_path, pi_source_path): rows = [ ["项目", "数值"], ["π数字文件", str(pi_source_path)], ["运行开始时间", result["start_time"]], ["运行结束时间", result["end_time"]], ["运行耗时", result["elapsed_time"]],

    ["总步数", result["max_steps"]],
    ["大任务阈值", BIG_TARGET],
    ["动态目标规则", "M<0时 target=M+4;M>=0时 target=4"],

    ["单数数量", result["odd_count"]],
    ["双数数量", result["even_count"]],
    ["单双计数绝对差", result["odd_even_abs_diff"]],

    ["红点累计总数", result["red_count"]],
    ["绿点累计总数", result["green_count"]],
    ["红绿点差值=红点-绿点", result["red_green_diff"]],

    ["小任务完成总数", result["small_task_count"]],
    ["完成大任务总次数", result["big_task_count"]],

    ["最终pos", result["final_pos"]],
    ["最终M", result["final_m"]],
    ["最终动态目标值", result["final_target"]],
    ["最终模式", result["final_mode"]],
    ["最终任务后等待确认", result["final_after_task_wait_confirm"]],
    ["最终等待确认来源", result["final_after_task_reason"]],

    ["全程M极限最小值", result["m_limit"]],
    ["全程pos极限最小值", result["pos_limit"]],

    ["", ""],
    ["守恒总账校验", ""],
    ["理论红绿点差=完成大任务次数×4+最终pos", result["theoretical_red_green_diff"]],
    ["实际红绿点差=红点-绿点", result["red_green_diff"]],
    ["守恒误差", result["conservation_error"]],
    ["单双计数绝对差", result["odd_even_abs_diff"]],
    ["守恒公式是否通过", result["conservation_pass"]],
]

with open(output_path, "w", newline="", encoding="utf-8-sig") as f:
    writer = csv.writer(f)
    writer.writerows(rows)

def export_detail_csv(detail_rows, output_path): if not detail_rows: return

fieldnames = list(detail_rows[0].keys())

with open(output_path, "w", newline="", encoding="utf-8-sig") as f:
    writer = csv.DictWriter(f, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerows(detail_rows)

def print_summary(result, pi_source_path): print() print("========== M+4动态目标版统计结果 ==========") print(f"π数字文件: {pi_source_path}") print(f"总步数: {result['max_steps']:,}") print(f"运行耗时: {result['elapsed_time']}") print() print(f"单数数量: {result['odd_count']:,}") print(f"双数数量: {result['even_count']:,}") print(f"单双计数绝对差: {result['odd_even_abs_diff']:,}") print() print(f"红点累计总数: {result['red_count']:,}") print(f"绿点累计总数: {result['green_count']:,}") print(f"红绿点差值: {result['red_green_diff']:,}") print() print(f"小任务完成总数: {result['small_task_count']:,}") print(f"完成大任务总次数: {result['big_task_count']:,}") print() print(f"最终pos: {result['final_pos']}") print(f"最终M: {result['final_m']}") print(f"最终动态目标值: {result['final_target']}") print(f"最终模式: {result['final_mode']}") print(f"最终任务后等待确认: {result['final_after_task_wait_confirm']}") print(f"最终等待确认来源: {result['final_after_task_reason']}") print(f"全程M极限最小值: {result['m_limit']}") print(f"全程pos极限最小值: {result['pos_limit']}") print() print("========== 守恒总账校验 ==========") print(f"理论红绿点差: {result['theoretical_red_green_diff']}") print(f"实际红绿点差: {result['red_green_diff']}") print(f"守恒误差: {result['conservation_error']}") print(f"单双计数绝对差: {result['odd_even_abs_diff']}") print(f"守恒公式是否通过: {result['conservation_pass']}")

def main(): desktop_path = get_desktop_path()

summary_csv_path = desktop_path / SUMMARY_CSV_NAME
detail_csv_path = desktop_path / DETAIL_CSV_NAME

pi_digits, pi_source_path = load_pi_digits_from_desktop()

result = run_state_machine(
    pi_digits=pi_digits,
    max_steps=MAX_STEPS,
    keep_detail=EXPORT_DETAIL,
)

export_summary_csv(result, summary_csv_path, pi_source_path)

if EXPORT_DETAIL:
    export_detail_csv(result["detail_rows"], detail_csv_path)

print_summary(result, pi_source_path)

print()
print("========== CSV文件已生成 ==========")
print(f"汇总CSV: {summary_csv_path}")

if EXPORT_DETAIL:
    print(f"明细CSV: {detail_csv_path}")

if name == "main": main()