链式反应网页源码
<!DOCTYPE html>
<html lang="zh-CN">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>链式反应</title>
    <link rel="stylesheet" href="https://unpkg.com/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
    <!--
        本地存储工具类 - rotaryChainLocalStorageUtil.js
        功能:封装游戏配置、历史记录、关卡进度的本地存储操作
    -->
    <script src="https://ltda.wdfiles.com/local--code/ry-rotating-localstorageutil/1"></script>
    <!-- 引入Vue 2 -->
    <script src="https://unpkg.com/vue@2.6.14/dist/vue.min.js"></script>
    <!-- 链式反应-装置组件 -->
    <script src="https://ltda.wdfiles.com/local--code/ry-rotating-device/1"></script>
    <!-- pako压缩库 -->
    <script src="https://ltda.wdfiles.com/local--code/ry-rotating-pako/1"></script>
    <!-- fonts-style对应的style会在图标库字体加载完成之后被删除 -->
    <style id="fonts-style">
        .bi::before,
        [class^="bi-"]::before,
        [class*=" bi-"]::before {
            content: '☒' !important;
            font-family: unset !important;
        }
    </style>
    <style>
        [v-cloak] {
            display: none !important;
            /* vue2未挂载时隐藏元素 */
        }
    </style>
    <style>
        /* 页面css */
        @import url("https://ltda.wikidot.com/ry-rotating-device/code/2");
    </style>
</head>
 
<body>
    <div id="app" v-cloak
        style="display: flex;flex-direction: column;justify-content: flex-start;align-items: center;align-content: center;">
        <!-- minScreenDimension这里“+20”和“+120”是因为getMinDimension方法中“-20”和“-120” -->
        <div style="display: flex;flex-direction: column;justify-content: flex-start;align-items: center;align-content: center;"
            :style="{width: (minScreenDimension+20) + 'px', height: (minScreenDimension+120) + 'px'}">
            <!-- 顶部UI -->
            <div class="ui-container" :style="{width: minScreenDimension + 'px'}">
                <div class="ui-section">
                    <i class="bi bi-lightning-charge-fill"></i>
                    <span>{{ actionPoints }}</span>
                </div>
                <div class="ui-section">
                    <i class="bi bi-circle-fill"></i>
                    <span>×&nbsp;{{ zeroRotationDevicesCount + 1 }}</span>
                </div>
                <div class="ui-section">
                    <i class="bi bi-star-fill"></i>
                    <span>{{ operationLog.score }}</span>
                </div>
                <div class="ui-section">
                    <i class="bi bi-hash"></i>
                    <span>{{ operationLog.time }}</span>
                </div>
            </div>
            <!-- 游戏主体、内容遮罩 -->
            <div class="devices-container-wrapper"
                :style="{width: minScreenDimension + 'px', height: minScreenDimension + 'px'}">
                <!-- 带坐标的网格容器 -->
                <div class="grid-with-coordinates" v-if="devicesGrid.length > 0">
                    <!-- 网格 -->
                    <div class="coordinates-and-grid">
                        <!-- 装置网格 -->
                        <div class="devices-container">
                            <div class="device-row" v-for="(row, rowIndex) in devicesGrid" :key="rowIndex">
                                <template v-for="(device, colIndex) in row">
                                    <div :key="rowIndex+'_'+colIndex" style="position: relative;">
                                        <rotating-device :ref="'device_' + rowIndex + '_' + colIndex"
                                            :width="deviceSize" :height="deviceSize"
                                            :max-rotation-times="device.maxRotationTimes" :speed="speed"
                                            :flash-enabled="flashEnabled"
                                            :init-rotation-angle="device.initRotationAngle"
                                            :title="'('+rowIndex+', '+colIndex+')'" :style="{
                                                pointerEvents: isDeviceClickable ? 'auto' : 'none',
                                                border: (currentClick.rowIndex !== null && currentClick.colIndex !== null
                                                        && currentClick.rowIndex===rowIndex && currentClick.colIndex===colIndex)
                                                        ? 'solid 1px red'
                                                        : ''
                                                }" :class="[device.t ? 'specialDevice' : '']" @rotated="handleDeviceRotated(rowIndex, colIndex, $event)"
                                            @reset-color="resetDeviceColor(rowIndex, colIndex)">
                                        </rotating-device>
                                        <div style="position: absolute;z-index: -1;left: 0;right: 0;top: 0;bottom: 0;"
                                            :style="isInChainReaction ? {} : assistPredictStyle[rowIndex + '_' + colIndex]">
                                        </div>
                                    </div>
                                </template>
                            </div>
                            <div
                                style="position: absolute;top: 0px;right: 0px;bottom: 0px;left: 0px;z-index: -2;pointer-events: none;display: flex;flex-direction: column;justify-content: center;align-items: center;color:#aaa;font-weight: bold;">
                                <!-- 执行历史记录状态提示 -->
                                <div v-show="isExecutingHistory" :style="{'font-size': minScreenDimension / 18 + 'px'}">
                                    执行历史记录中... {{ currentExecutionStep }}/{{ totalExecutionSteps }}
                                </div>
                                <!-- 游戏当前状态:运行/备战 -->
                                <div :style="{
                                    'font-size': minScreenDimension / 12 + 'px',
                                    'color': gameState === '运行' ? '#22C55E' : '#EF4444'
                                }">
                                    {{ gameState }}
                                </div>
                                <!-- 游戏当前分数 -->
                                <div :style="{'font-size': minScreenDimension / 6 + 'px'}">
                                    {{ operationLog.score }}
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                <div v-else>
                    正在生成装置网格...
                </div>
            </div>
            <div v-show="!autoSaveHistory" style="font-size: 12px;color: red;">
                自动保存暂不可用,重置即可重新开启
            </div>
            <!-- 底部UI -->
            <div class="ui-container" :style="{width: minScreenDimension + 'px'}">
                <div class="ui-section">
                    <button @click="toggleGameState" :disabled="isExecutingHistory || isInChainReaction">
                        切换状态
                    </button>
                </div>
                <div class="ui-section">
                    <button @click="undoLastOperation" :disabled="!canUndo || isExecutingHistory || isInChainReaction">
                        撤回
                    </button>
                </div>
                <div class="ui-section">
                    <button @click="regenerateGrid">重置</button>
                </div>
                <div class="ui-section">
                    <button @click="showSettings" :disabled="isExecutingHistory || isInChainReaction">设置</button>
                </div>
            </div>
        </div>
        <!-- 设置面板 -->
        <div v-show="settingsDialog" class="overlay-container settings-overlay"
            @click="(e) => { if (e.target === e.currentTarget) settingsDialog = false; }">
            <div class="panel settings-panel">
                <!-- 面板头部:返回按钮 + 标题 + 分割线 -->
                <div class="panel__header">
                    <i class="bi bi-arrow-left" @click="settingsDialog = false;"></i>
                    <div>
                        <h3 class="panel__title">系统设置</h3>
                        <div class="panel__divider"></div>
                    </div>
                    <!-- 占位,保持头部布局对称 -->
                    <i></i>
                </div>
                <!-- 面板内容区:滚动容器 -->
                <div class="panel__content">
                    <div class="settings-li">
                        <button class="settings-panel__btn settings-panel__btn--action"
                            @click="instructionsDialog = true;">
                            <i class="bi bi-book"></i>
                            <div>游戏说明</div>
                        </button>
                    </div>
                    <div class="settings-li">
                        <button class="settings-panel__btn settings-panel__btn--action"
                            @click="predictStoreDialog = true;" :disabled="isExecutingHistory">
                            <i class="bi bi-star-fill"></i>今日评级
                        </button>
                    </div>
                    <div class="settings-li">
                        <button class="settings-panel__btn settings-panel__btn--action"
                            @click="executeRecordDialog = true;" :disabled="isExecutingHistory">
                            <i class="bi bi-play-circle"></i>录入操作
                        </button>
                    </div>
                    <div class="settings-li">
                        <button class="settings-panel__btn settings-panel__btn--action" @click="logOperationDetails"
                            :disabled="isExecutingHistory">
                            <i class="bi bi-list-check"></i>
                            <div>操作日志</div>
                        </button>
                    </div>
                    <div class="settings-li">
                        <button class="settings-panel__btn settings-panel__btn--action" @click="showHistoryRecords"
                            :disabled="isExecutingHistory">
                            <i class="bi bi-clock-history"></i>历史记录
                        </button>
                    </div>
                    <div class="settings-li">
                        <button class="settings-panel__btn settings-panel__btn--action" @click="importExportRecordDialog = true;" :disabled="isExecutingHistory">
                            <i class="bi bi-download"></i>
                            <div>导入/导出记录</div>
                        </button>
                    </div>
                    <div class="settings-li">
                        <button class="settings-panel__btn settings-panel__btn--action"
                            @click="assistPredictDialog = true;" :disabled="isExecutingHistory">
                            <i class="bi bi-lightbulb"></i>
                            <div>辅助预测</div>
                        </button>
                    </div>
                    <div class="settings-li">
                        <button class="settings-panel__btn settings-panel__btn--action" @click="toggleSpeed">
                            <i class="bi bi-speedometer"></i>切至{{speed===0.5?'2倍速':'1倍速'}}
                        </button>
                    </div>
                    <div class="settings-li">
                        <button class="settings-panel__btn settings-panel__btn--action" @click="toggleFlashEnabled">
                            <i class="bi bi-eye"></i>{{flashEnabled?'关闭闪烁动画':'开启闪烁动画'}}
                        </button>
                    </div>
                </div>
            </div>
        </div>
        <!-- 游戏说明面板 -->
        <div v-show="instructionsDialog" class="overlay-container instructions-overlay"
            @click="(e) => { if (e.target === e.currentTarget) instructionsDialog = false; }">
            <div class="panel instructions-panel">
                <!-- 面板头部:返回按钮 + 标题 + 分割线 -->
                <div class="panel__header">
                    <i class="bi bi-arrow-left" @click="instructionsDialog = false;"></i>
                    <div>
                        <h3 class="panel__title">游戏说明</h3>
                        <div class="panel__divider"></div>
                    </div>
                    <!-- 关闭所有遮罩 -->
                    <i class="bi bi-x-circle" style="cursor: pointer;"
                        @click="instructionsDialog = false;settingsDialog = false;"></i>
                </div>
                <!-- 面板内容区:滚动容器 -->
                <div class="panel__content">
                    <div class="instructions-content">
                        <!-- 核心图标说明(新增,同步顶部UI) -->
                        <div class="instructions-section">
                            <div class="section-heading">一、核心图标说明</div>
                            <div class="section-list"
                                style="display: flex; flex-wrap: wrap; gap: 15px; padding-left: 0;">
                                <div style="display: flex; align-items: center;">
                                    <i class="bi bi-lightning-charge-fill"
                                        style="color: #2196F3; margin-right: 0.5em;"></i>
                                    <span>行动点数:每次点击消耗1点,初始10点</span>
                                </div>
                                <div style="display: flex; align-items: center;">
                                    <i class="bi bi-circle-fill" style="color: #f44336; margin-right: 0.5em;"></i>
                                    <span>耗尽装置数:变红装置越多,得分倍数越高</span>
                                </div>
                                <div style="display: flex; align-items: center;">
                                    <i class="bi bi-star-fill" style="color: #FFC107; margin-right: 0.5em;"></i>
                                    <span>当前分数:旋转装置可累积,连锁反应得分更高</span>
                                </div>
                                <div style="display: flex; align-items: center;">
                                    <i class="bi bi-hash" style="color: #4CAF50; margin-right: 0.5em;"></i>
                                    <span>随机种子:相同种子可生成完全一致的装置网格</span>
                                </div>
                            </div>
                        </div>
 
                        <!-- 游戏规则(细化描述+示例) -->
                        <div class="instructions-section">
                            <div class="section-heading">二、核心游戏规则</div>
                            <ul class="section-list">
                                <li>1. 装置操作:点击网格中的装置,装置会顺时针旋转90度。
                                </li>
                                <li>2. 行动点限制:每次点击消耗1点行动点,点数为0时无法点击;点击「重置」可恢复10点并生成新网格。</li>
                                <li>3. 装置旋转次数:
                                    <ul style="padding-left: 2rem; margin-top: 4px;">
                                        <li>有限次数:装置上显示数字,代表剩余旋转次数,数字为0时装置变红、不可再转;</li>
                                        <li>无限次数:无数字显示的装置,可无限次旋转。</li>
                                    </ul>
                                </li>
                                <li>4. 两种游戏状态(点击底部「切换状态」按钮切换):
                                    <ul style="padding-left: 2rem; margin-top: 4px;">
                                        <li>备战状态:仅当前点击的装置旋转,不触发相邻装置连锁反应(适合规划布局);</li>
                                        <li>运行状态:点击后,相邻装置角度匹配时自动连锁旋转(如当前装置朝上、上方装置朝下)。</li>
                                    </ul>
                                </li>
                                <li>5. 得分规则(倍数=1+耗尽装置数):
                                    <ul style="padding-left: 2rem; margin-top: 4px;">
                                        <li>基础得分:点击旋转后该装置未变0,得1×倍数分;</li>
                                        <li>高额得分:点击旋转后该装置变0(耗尽次数),得10×倍数分;</li>
                                        <li>连锁得分:运行状态下,每连锁旋转1个装置,额外得1×倍数分。</li>
                                    </ul>
                                </li>
                            </ul>
                        </div>
 
                        <!-- 功能操作(补充细节+关联图标) -->
                        <div class="instructions-section">
                            <div class="section-heading">三、实用功能操作</div>
                            <ul class="section-list">
                                <li>1. 状态切换:底部「切换状态」按钮,在“备战/运行”间切换(连锁反应中不可点击);
                                    <br>&nbsp;&nbsp;&nbsp;&nbsp;提示:规划初期建议用“备战”调整布局,调整完成后切“运行”触发连锁。
                                </li>
                                <li>2. 撤回操作:底部「撤回」按钮,可回到上一步操作(最多保留最近10步,连锁/历史执行中不可用)。</li>
                                <li>3. 重置网格:底部「重置」按钮,生成新装置网格,同时恢复10点行动点、清空当前分数。</li>
                                <li>4. 历史记录(设置面板中「历史记录」按钮 <i class="bi bi-clock-history" style="color: #4CAF50;"></i>):
                                    <ul style="padding-left: 2rem; margin-top: 4px;">
                                        <li>运行历史:选择历史记录,自动复现操作流程(适合学习高分策略);</li>
                                        <li>挑战种子:可生成与历史记录完全一致的网格,重试优化操作。</li>
                                    </ul>
                                </li>
                                <li>5. 速度调节:设置面板中「切至X倍速」按钮 <i class="bi bi-speedometer" style="color: #dc3545;"></i>,
                                    可切换1倍速(0.5秒/旋转)或2倍速(0.25秒/旋转),不影响实际得分。
                                </li>
                                <li>6. 辅助预测(设置面板中「辅助预测」按钮 <i class="bi bi-lightbulb" style="color: #2ecc71;"></i>):
                                    <ul style="padding-left: 2rem; margin-top: 4px;">
                                        <li>分数优先:推荐单次点击得分最高的装置(绿色提示圈);</li>
                                        <li>乘数优先:推荐能快速增加耗尽装置数的装置(红色提示圈);</li>
                                        <li>提示:辅助仅提供单步参考,长期策略需结合自身判断。</li>
                                    </ul>
                                </li>
                            </ul>
                        </div>
 
                        <!-- 常见问题(新增,解决高频疑问) -->
                        <div class="instructions-section">
                            <div class="section-heading">四、常见问题解答</div>
                            <ul class="section-list">
                                <li>Q1:为什么有的装置点击后没反应?
                                    <br>&nbsp;&nbsp;&nbsp;&nbsp;A:可能是行动点耗尽、装置已变红(次数为0),或处于连锁反应/历史执行状态。
                                </li>
                                <li>Q2:如何让连锁反应触发更多装置?
                                    <br>&nbsp;&nbsp;&nbsp;&nbsp;A:用“备战”状态调整相邻装置角度(如让横向装置朝左/右、纵向装置朝上/下),再切“运行”点击。
                                </li>
                                <li>Q3:历史记录会保存多久?
                                    <br>&nbsp;&nbsp;&nbsp;&nbsp;A:保存在浏览器本地,清除浏览器缓存前不会丢失;同一种子保留前3名得分,全局保留前20名高分。
                                </li>
                            </ul>
                        </div>
                    </div>
                </div>
            </div>
        </div>
 
        <!-- 录入操作面板 -->
        <div v-show="executeRecordDialog" class="overlay-container history-overlay"
            @click="(e) => { if (e.target === e.currentTarget) executeRecordDialog = false; }">
            <div class="panel instructions-panel">
                <!-- 面板头部 -->
                <div class="panel__header">
                    <i class="bi bi-arrow-left" @click="executeRecordDialog = false;"></i>
                    <div>
                        <h3 class="panel__title">录入操作</h3>
                        <div class="panel__divider"></div>
                    </div>
                    <!-- 关闭所有遮罩 -->
                    <i class="bi bi-x-circle" style="cursor: pointer;"
                        @click="executeRecordDialog = false;settingsDialog = false;"></i>
                </div>
                <!-- 面板内容区 -->
                <div class="panel__content">
                    <!-- 自定义JSON输入框 -->
                    <div class="custom-json-input">
                        <textarea class="json-textarea"
                            placeholder='{"time":20241001,"records":["1_0_0"],"score":0,"date":1622505600000}'
                            v-model="customRecordJson" :disabled="isExecutingHistory"></textarea>
                    </div>
                    <!-- 功能按钮组 -->
                    <div class="custom-json-buttons">
                        <button @click="executeCustomRecord" :disabled="isExecutingHistory">运行此操作</button>
                        <button class="challenge-btn" @click="challengeCustomRecord(customRecordJson)"
                            :disabled="isExecutingHistory">挑战相同种子</button>
                    </div>
                    <!-- 自定义JSON输入框 -->
                    <div class="custom-json-input">
                        <textarea class="json-textarea" placeholder='请输入种子(仅支持数字)' v-model="customRecordSeed"
                            :disabled="isExecutingHistory"></textarea>
                    </div>
                    <!-- 功能按钮组 -->
                    <div class="custom-json-buttons">
                        <button class="challenge-btn"
                            @click="challengeCustomRecord(JSON.stringify({time: parseInt(customRecordSeed)}))"
                            :disabled="isExecutingHistory">挑战种子</button>
                    </div>
                </div>
            </div>
        </div>
 
        <!-- 今日评级面板 -->
        <div v-show="predictStoreDialog" class="overlay-container predict-store-overlay"
            @click="(e) => { if (e.target === e.currentTarget) predictStoreDialog = false; }">
            <div class="panel predict-store-panel">
                <!-- 面板头部 -->
                <div class="panel__header">
                    <i class="bi bi-arrow-left" @click="predictStoreDialog = false;"></i>
                    <div>
                        <h3 class="panel__title">今日评级</h3>
                        <div class="panel__divider"></div>
                    </div>
                    <!-- 关闭所有遮罩 -->
                    <i class="bi bi-x-circle" style="cursor: pointer;"
                        @click="predictStoreDialog = false;settingsDialog = false;"></i>
                </div>
                <!-- 面板内容区 -->
                <div class="panel__content">
                    <!-- 2.1 今日种子提示(新增,让用户明确当前评级的种子) -->
                    <div
                        style="background-color: #f8f9fa; padding: 12px 15px; border-radius: 8px; border-left: 4px solid #4CAF50;">
                        <div style="display: flex; align-items: center; gap: 8px; font-size: 14px; color: #333;">
                            <i class="bi bi-hash" style="color: #4CAF50; font-size: 16px;"></i>
                            <span><strong>当前评级种子</strong>:{{ getTodaySeed() }}</span>
                        </div>
                        <div style="font-size: 12px; color: #666; margin-top: 4px;">
                            提示:仅基于今日种子生成的网格进行评级,每日种子唯一
                        </div>
                    </div>
 
                    <!-- 2.2 评级操作与结果区(核心模块,居中突出) -->
                    <div
                        style="display: flex; flex-direction: column; align-items: center; gap: 1rem;margin-top: 1rem;">
                        <!-- 评级按钮(优化样式,增加交互反馈) -->
                        <button @click="handlePredictStore"
                            :disabled="isExecutingHistory || predictProgress.isActive || predictStoreStar !== 0"
                            style="padding: 6px 15px; font-size: 16px; font-weight: 600; border-radius: 8px; background-color: #2196F3; color: white; border: none; transition: all 0.3s; display: flex; align-items: center; gap: 8px;"
                            :style="{
                                backgroundColor: (isExecutingHistory || predictProgress.isActive || predictStoreStar !== 0) ? '#cccccc' : '#2196F3',
                                boxShadow: (isExecutingHistory || predictProgress.isActive || predictStoreStar !== 0) ? 'none' : '0 4px 12px rgba(33, 150, 243, 0.2)'
                            }" onmouseover="!this.disabled && (this.style.backgroundColor='#0b7dda', this.style.transform='translateY(-2px)')"
                            onmouseout="!this.disabled && (this.style.backgroundColor='#2196F3', this.style.transform='translateY(0)')">
                            <i class="bi bi-star-half" style="font-size: 18px;"></i>
                            生成今日评级
                        </button>
 
                        <!-- 进度条容器(仅计算中显示) -->
                        <div v-show="predictProgress.isActive && predictStoreStar === 0"
                            style="width: 100%; margin-top: 1rem;">
                            <!-- 步骤文本提示 -->
                            <div style="font-size: 12px; color: #666; text-align: center; margin-bottom: 4px;">
                                {{ predictProgress.stepText }}
                            </div>
                        </div>
 
                        <!-- 星级结果展示(放大字体,增加星级图标,突出视觉) -->
                        <div v-show="predictStoreStar !== 0"
                            style="display: flex; flex-direction: column; align-items: center; gap: 1rem;">
                            <div style="font-size: 15px; color: #666;">今日评级结果</div>
                            <div style="display: flex; align-items: center;">
                                <!-- 星级图标(动态显示,与评级结果联动) -->
                                <div style="display: flex; gap: 0.25rem;">
                                    <i class="bi bi-star-fill" style="color: #FFC107; font-size: 1rem;"
                                        v-for="(star, idx) in Math.min(predictStoreStar, 5)" :key="idx"></i>
                                    <!-- 10星特殊处理(显示2组5星) -->
                                    <template v-if="predictStoreStar === 10">
                                        <i class="bi bi-star-fill" style="color: #FFC107; font-size: 1rem;"
                                            v-for="idx in 5" :key="idx+5"></i>
                                    </template>
                                </div>
                            </div>
                            <!-- 结果说明(未评级时提示,已评级时显示分数范围) -->
                            <div style="font-size: 12px; color: #666; text-align: center;">
                                <span v-if="predictStoreStar === 0">点击上方按钮生成评级</span>
                                <span v-else>
                                    对应分数范围:{{ getStarScoreRange(predictStoreStar) }}
                                </span>
                            </div>
                        </div>
                        <div v-show="predictStoreStar === 0" style="font-size: 12px; color: #666; text-align: center;">
                            <span>点击上方按钮生成评级</span>
                        </div>
                    </div>
 
                    <!-- 2.3 注意事项说明区(优化排版,增加分隔线) -->
                    <div style="padding-top: 15px; border-top: 1px solid #eee; margin-top: 1rem;">
                        <div
                            style="font-size: 14px; font-weight: 600; color: #333; margin-bottom: 8px; display: flex; align-items: center; gap: 6px;">
                            <i class="bi bi-info-circle" style="color: #ff9800;"></i>
                            评级规则与说明
                        </div>
                        <div style="font-size: 12px; color: #666; line-height: 1.8; padding-left: 22px;">
                            <!-- 新增:先说明“预测逻辑”,让用户理解评级依据 -->
                            <p>1. 评级核心逻辑:基于今日种子生成独立网格,通过多轮智能预测(模拟最优点击策略【伪】)计算“参考最高得分”,最终按得分匹配星级,结果反映网格的潜力上限。</p>
 
                            <!-- 优化:补充分数区间的“衔接关系”,消除“≤5万是1星,>5万是否算2星”的歧义 -->
                            <p>2. 星级判定标准(按预测最高分划分):</p>
                            <ul style="padding-left: 20px; margin: 8px 0; list-style-type: disc;">
                                <li>1星:0 ~ 50,000分(基础潜力)</li>
                                <li>2星:50,001 ~ 70,000分(中等潜力)</li>
                                <li>3星:70,001 ~ 100,000分(良好潜力)</li>
                                <li>4星:100,001 ~ 150,000分(优秀潜力)</li>
                                <li>5星:150,001 ~ 200,000分(极佳潜力)</li>
                                <li>10星:>200,000分(满分评级,网格潜力天花板)</li>
                            </ul>
 
                            <!-- 优化:补充“种子时效性”的原因,增加用户理解 -->
                            <p>3. 评级时效性:每日仅支持“当日种子”评级(种子由系统按日期自动生成,每日唯一),历史日期的种子无法回溯计算,建议每日尽早完成评级。</p>
 
                            <!-- 优化:强化“理论与实际的差异”,给出实用提示 -->
                            <p>4. 结果参考价值:评级是“理论最优得分”的参考,实际游戏中得分会受您的操作策略(如点击顺序、连锁反应触发时机)影响,建议结合“辅助预测”功能提升实际得分。</p>
 
                            <!-- 优化:将“卡顿提示”改为“体验说明+应对建议”,降低用户焦虑 -->
                            <p>5. 计算体验说明:预测过程中若出现短暂卡顿,是因系统在多轮迭代计算最优路径(网格尺寸越大、迭代轮次越多,耗时略长)</p>
                            <ul style="padding-left: 20px; margin: 6px 0; list-style-type: disc; font-size: 11px;">
                                <li>计算时避免频繁切换页面或操作其他功能;</li>
                                <li>若卡顿超过30秒,或影响到了浏览器正常运行,可关闭或刷新页面。</li>
                            </ul>
                            <p style="font-size: 11px; color: #888; margin-top: 6px;">注:算法优化已在规划中,未来将进一步提升计算速度与准确性。</p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
 
        <!-- 操作日志面板 -->
        <div v-show="operationLogDialog" class="overlay-container history-overlay"
            @click="(e) => { if (e.target === e.currentTarget) operationLogDialog = false; }">
            <div class="panel history-panel">
                <!-- 面板头部:返回按钮 + 标题 + 分割线 -->
                <div class="panel__header">
                    <i class="bi bi-arrow-left" @click="operationLogDialog = false;"></i>
                    <div>
                        <h3 class="panel__title">当前操作日志</h3>
                        <div class="panel__divider"></div>
                    </div>
                    <!-- 关闭所有遮罩 -->
                    <i class="bi bi-x-circle" style="cursor: pointer;"
                        @click="operationLogDialog = false;settingsDialog = false;"></i>
                </div>
                <!-- 面板内容区:滚动容器 -->
                <div class="panel__content">
                    <!-- 无操作日志提示 -->
                    <div class="no-history" v-if="operationLog.records.length === 0">
                        暂无操作记录
                    </div>
                    <!-- 有操作日志时显示详情 -->
                    <div v-else>
                        <!-- 日志基础信息 -->
                        <div class="history-item" style="margin-bottom: 15px;">
                            <div class="history-item-header">
                                <span>当前游戏日志</span>
                                <span><i class="bi bi-star-fill" style="color: #FFC107; margin-right: 0.5em;"></i>{{
                                    operationLog.score }}</span>
                            </div>
                            <div class="history-item-date">
                                日期: {{ formatDate(operationLog.date) }} | <i class="bi bi-hash"
                                    style="color: #4CAF50;"></i>随机种子:
                                {{ operationLog.time }}
                            </div>
                            <!-- 操作记录列表 -->
                            <div class="operation-records" style="margin: 10px 0;">
                                <p style="margin: 0 0 5px; font-size: 14px;">操作序列【第x行第y列表示为(x,
                                    y)】:</p>
                                <div v-for="(record, idx) in operationLog.records" :key="idx">
                                    {{ idx + 1 }}. {{ formatOperationRecord(record) }}
                                </div>
                            </div>
                            <!-- 完整JSON数据 -->
                            <p style="margin: 10px 0 5px; font-size: 14px;">
                                完整数据【复制内容后,可以在“录入操作”中粘贴后执行】:</p>
                            <textarea class="json-textarea" :value="JSON.stringify(operationLog)" readonly></textarea>
                            <!-- 功能按钮组 -->
                            <div class="history-item-btns" style="margin-top: 15px;">
                                <button @click="executeHistory(operationLog)"
                                    :disabled="isExecutingHistory">运行该日志</button>
                                <button class="challenge-btn" @click="createChallengeWithSeed(operationLog.time)"
                                    :disabled="isExecutingHistory">挑战相同种子</button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
 
        <!-- 历史记录面板 -->
        <div v-show="historyDialog" class="overlay-container history-overlay"
            @click="(e) => { if (e.target === e.currentTarget) historyDialog = false; }">
            <div class="panel history-panel">
                <!-- 面板头部:返回按钮 + 标题 + 分割线 -->
                <div class="panel__header">
                    <i class="bi bi-arrow-left" @click="historyDialog = false;"></i>
                    <div>
                        <h3 class="panel__title">历史记录</h3>
                        <div class="panel__divider"></div>
                    </div>
                    <!-- 关闭所有遮罩 -->
                    <i class="bi bi-x-circle" style="cursor: pointer;"
                        @click="historyDialog = false;settingsDialog = false;"></i>
                </div>
 
                <!-- 面板内容区:滚动容器 -->
                <div class="panel__content">
                    <!-- 清空所有记录按钮 -->
                    <button class="clear-history-btn" @click="clearAllHistoryRecords" :disabled="isExecutingHistory">
                        清空所有历史记录
                    </button>
 
                    <!-- 种子搜索区域 -->
                    <div class="history-search">
                        <input type="text" placeholder="输入随机种子搜索记录" v-model="historySearchSeed"
                            :disabled="isExecutingHistory">
                        <div>
                            <button class="search-btn" @click="searchHistoryBySeed"
                                :disabled="isExecutingHistory">搜索</button>
                            <button class="search-btn"
                                @click="historySearchSeed = ''+getTodaySeed();searchHistoryBySeed();"
                                :disabled="isExecutingHistory">今日记录</button>
                            <button class="delete-btn" @click="historySearchSeed = '';searchHistoryBySeed();"
                                :disabled="isExecutingHistory">清除</button>
                        </div>
                    </div>
                    <div class="search-results-info">
                        显示 {{filteredHistoryRecords.length}} 条记录(共 {{totalHistoryRecords}} 条)
                    </div>
 
                    <!-- 历史记录列表 -->
                    <ul class="history-list" v-if="filteredHistoryRecords.length > 0">
                        <li class="history-item" v-for="(record, index) in filteredHistoryRecords" :key="index"
                            :data-seed="record.time">
                            <div class="history-item-header">
                                <span>记录 #{{index + 1}}</span>
                                <span><i class="bi bi-star-fill"
                                        style="color: #FFC107; margin-right: 0.5em;"></i>{{record.score}}</span>
                            </div>
                            <div class="history-item-date">
                                日期: {{formatDate(record.date)}} | <i class="bi bi-hash"
                                    style="color: #4CAF50;"></i>随机种子:
                                {{record.time}}
                            </div>
                            <textarea class="json-textarea" :value="JSON.stringify(record)" readonly></textarea>
                            <div class="history-item-btns">
                                <button @click="executeHistory(record)" :disabled="isExecutingHistory">运行该记录</button>
                                <button class="challenge-btn" @click="createChallengeWithSeed(record.time)"
                                    :disabled="isExecutingHistory">挑战相同种子</button>
                                <button class="delete-btn" @click="deleteHistoryRecord(index, record.$index)"
                                    :disabled="isExecutingHistory">删除</button>
                            </div>
                        </li>
                    </ul>
                    <div class="no-history" v-else>
                        暂无历史记录
                    </div>
                </div>
            </div>
        </div>
 
        <!-- 导入/导出记录面板 -->
        <div v-show="importExportRecordDialog" class="overlay-container history-overlay"
            @click="(e) => { if (e.target === e.currentTarget) importExportRecordDialog = false; }">
            <div class="panel instructions-panel">
                <!-- 面板头部:返回按钮 + 标题 + 分割线 -->
                <div class="panel__header">
                    <i class="bi bi-arrow-left" @click="importExportRecordDialog = false;"></i>
                    <div>
                        <h3 class="panel__title">导入/导出记录</h3>
                        <div class="panel__divider"></div>
                    </div>
                    <!-- 关闭所有遮罩 -->
                    <i class="bi bi-x-circle" style="cursor: pointer;"
                        @click="importExportRecordDialog = false;settingsDialog = false;"></i>
                </div>
                <!-- 面板内容区:文本框 + 按钮 -->
                <div class="panel__content" style="padding: 20px;">
                    <!-- 固定高度带滚动条的textarea -->
                    <textarea 
                        class="json-textarea" 
                        placeholder="导入:粘贴数据后点击「导入记录」按钮;
导出:点击「导出记录」按钮后复制文本框中的数据"
                        v-model="importExportText"
                        :disabled="isExecutingHistory"
                        style="height: 200px;resize: none;overflow-y: auto;margin-bottom: 15px;"></textarea>
 
                    <!-- 第一个按钮:导入记录(空事件) -->
                    <button 
                        class="settings-panel__btn settings-panel__btn--action"
                        @click="handleImportRecord"
                        :disabled="isExecutingHistory"
                        style="width: 100%; margin-bottom: 10px; padding: 8px 0;">
                        <i class="bi bi-upload"></i> 导入记录
                    </button>
 
                    <!-- 第二个按钮:导出记录(空事件) -->
                    <button 
                        class="settings-panel__btn settings-panel__btn--action"
                        @click="handleExportRecord"
                        :disabled="isExecutingHistory"
                        style="width: 100%; padding: 8px 0;">
                        <i class="bi bi-download"></i> 导出记录
                    </button>
                </div>
            </div>
        </div>
 
        <!-- 辅助预测面板 -->
        <div v-show="assistPredictDialog" class="overlay-container history-overlay"
            @click="(e) => { if (e.target === e.currentTarget) assistPredictDialog = false; }">
            <div class="panel instructions-panel">
                <!-- 面板头部:返回按钮 + 标题 + 分割线 -->
                <div class="panel__header">
                    <i class="bi bi-arrow-left" @click="assistPredictDialog = false;"></i>
                    <div>
                        <h3 class="panel__title">辅助预测设置</h3>
                        <div class="panel__divider"></div>
                    </div>
                    <!-- 关闭所有遮罩 -->
                    <i class="bi bi-x-circle" style="cursor: pointer;"
                        @click="assistPredictDialog = false;settingsDialog = false;"></i>
                </div>
                <!-- 面板内容区:表单布局 -->
                <div class="panel__content">
                    <!-- 1. 是否启用辅助 -->
                    <div
                        style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 25px;">
                        <!-- 开关 -->
                        <div style="display: flex; align-items: center; gap: 8px;">
                            <span style="font-size: 13px; color: #ff4949;"
                                :style="{color: assistEnabled ? '#999' : '#ff4949'}">关闭辅助</span>
                            <div style="width: 50px; height: 24px; border-radius: 12px; background-color: #eee; cursor: pointer; position: relative; transition: background-color 0.3s;"
                                :style="{backgroundColor: assistEnabled ? '#13ce66' : '#ff4949'}"
                                @click="assistEnabled = !assistEnabled">
                                <div style="width: 20px; height: 20px; border-radius: 50%; background-color: white; position: absolute; top: 2px; left: 2px; transition: left 0.3s;"
                                    :style="{left: assistEnabled ? '28px' : '2px'}"></div>
                            </div>
                            <span style="font-size: 13px; color: #13ce66;"
                                :style="{color: assistEnabled ? '#13ce66' : '#999'}">启用辅助</span>
                        </div>
                    </div>
 
                    <!-- 2. 选择优先级 -->
                    <div
                        style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 25px;">
                        <!-- 开关 -->
                        <div style="display: flex; align-items: center; gap: 8px;">
                            <span style="font-size: 13px; color: #ff4949;"
                                :style="{color: selectedScore ? '#999' : '#ff4949'}">乘数优先</span>
                            <div style="width: 50px; height: 24px; border-radius: 12px; background-color: #eee; cursor: pointer; position: relative; transition: background-color 0.3s;"
                                :style="{backgroundColor: selectedScore ? '#13ce66' : '#ff4949'}"
                                @click="selectedScore = !selectedScore">
                                <div style="width: 20px; height: 20px; border-radius: 50%; background-color: white; position: absolute; top: 2px; left: 2px; transition: left 0.3s;"
                                    :style="{left: selectedScore ? '28px' : '2px'}"></div>
                            </div>
                            <span style="font-size: 13px; color: #13ce66;"
                                :style="{color: selectedScore ? '#13ce66' : '#999'}">分数优先</span>
                        </div>
                    </div>
 
                    <!-- 3. 开启/关闭全局预测 -->
                    <div
                        style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 25px;">
                        <!-- 开关 -->
                        <div style="display: flex; align-items: center; gap: 8px;">
                            <span style="font-size: 13px; color: #ff4949;"
                                :style="{color: assistPredictGlobal ? '#999' : '#ff4949'}">关闭全局预测</span>
                            <div style="width: 50px; height: 24px; border-radius: 12px; background-color: #eee; cursor: pointer; position: relative; transition: background-color 0.3s;"
                                :style="{backgroundColor: assistPredictGlobal ? '#13ce66' : '#ff4949'}"
                                @click="assistPredictGlobal = !assistPredictGlobal">
                                <div style="width: 20px; height: 20px; border-radius: 50%; background-color: white; position: absolute; top: 2px; left: 2px; transition: left 0.3s;"
                                    :style="{left: assistPredictGlobal ? '28px' : '2px'}"></div>
                            </div>
                            <span style="font-size: 13px; color: #13ce66;"
                                :style="{color: assistPredictGlobal ? '#13ce66' : '#999'}">启用全局预测</span>
                        </div>
                    </div>
 
                    <!-- 注意事项说明区域 -->
                    <div style="margin-top: 30px; padding-top: 15px; border-top: 1px solid #eee;">
                        <div style="font-size: 14px; font-weight: 600; color: #333; margin-bottom: 8px;">
                            注意事项
                        </div>
                        <div style="font-size: 12px; color: #666; line-height: 1.5;">
                            1. 辅助预测仅基于当前网格状态计算<span
                                style="font-weight: bold;">单步最优解</span>,不考虑后续多步操作的连锁收益,长期策略需结合玩家自主判断,结果仅供参考;<br>
                            2. 优先级选择(分数优先/乘数优先)仅影响预测推荐的排序规则,不改变实际游戏得分逻辑(乘数=预测耗尽装置数,分数=预测总分);<br>
                            3. 启用辅助后,仅筛选并显示前20个最优推荐位置(未指明具体排名);<br>
                            4. 全局预测功能:会将所有位置按排名的前20%、前40%、前60%、前80%、前100%分别置为红色、黄色、绿色、蓝色、灰色;<br>
                            5. 辅助配置(含启用状态、优先级选择)会自动保存到本地存储,刷新页面、重新打开游戏后仍保持当前设置,无需重复调整;<br>
                            6. 行动点数耗尽(≤0)、装置已耗尽旋转次数(显示红色),或处于连锁反应、历史记录执行状态时,辅助推荐会自动隐藏或暂停,待状态恢复后重新计算。
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    </div>
 
    <script>
        // 监听 bootstrap-icons 字体加载状态
        if (document.fonts) {
            // 检查字体是否已加载
            document.fonts.check('1em "bootstrap-icons"') ?
                markAsLoaded() :
                document.fonts.load('1em "bootstrap-icons"').then(markAsLoaded);
        } else {
            // 兼容不支持 FontFaceSet 的浏览器(延迟 500ms 强制移除占位符)
            setTimeout(markAsLoaded, 500);
        }
 
        // 移除占位符样式的函数
        function markAsLoaded() {
            document.getElementById('fonts-style').remove();
        }
 let URL = window.location.href;
    window.key = URL.split('=')[1] ? URL.split('=')[1] : null;
 
        // 主应用
        new Vue({
            el: '#app',
            data() {
                return {
                    // 屏幕和布局相关配置
                    minScreenDimension: 1000, // 游戏容器的最大尺寸限制(取屏幕宽高最小值)
                    sizeMin: 16, // 网格尺寸最小值最小值(行数和列数的最小值)
                    sizeMax: 24, // 网格尺寸尺寸上限(行数和列数的最大值)
                    speed: 0.5, // 装置旋转速度
                    flashEnabled: true, // 开启/关闭闪烁动画
 
                    // 游戏配置参数
                    infinityProbability: 0.33, // 装置有无穷旋转次数的概率(33%)
                    numMin: 4, // 装置有限旋转次数的最小值
                    numMax: 16, // 装置有限旋转次数的最大值
 
                    // 游戏状态数据
                    devicesGrid: [], // 存储所有装置的二维数组,每个元素代表一个装置的配置
                    actionPoints: 10, // 玩家当前的行动点数,每次点击装置消耗1点
                    zeroRotationDevicesCount: 0, // 记录已耗尽旋转次数的装置数量
                    gameState: '运行', // 游戏当前状态('运行'或'备战')
                    operationLog: { // 记录游戏操作日志的数据对象
                        time: null, // 随机种子(基于日期生成)
                        records: [], // 存储操作记录的数组,格式为"状态_行_列"
                        score: 0, // 当前游戏的总分数
                        date: null // 游戏开始的时间戳
                    },
                    currentClick: {
                        rowIndex: null,
                        colIndex: null,
                    }, // 当前最后一次点击的坐标
                    autoSaveHistory: true, // 是否自动保存(执行历史记录时将值变成false,重置时变成true)
 
                    // 连锁反应相关状态
                    chainReactionTimerId: -1, // 连锁反应定时器ID,-1表示无活跃定时器
 
                    // 撤回功能
                    operationSnapshotStack: [], // 操作快照栈,存储每次点击前的游戏状态
                    canUndo: false, // 是否可撤回(控制按钮禁用状态)
                    isUndoing: false, // 标记是否正在执行撤回操作(避免并发问题)
 
                    // 设置面板
                    settingsDialog: false,
 
                    // 游戏说明面板
                    instructionsDialog: false,
 
                    // 今日评级面板
                    isCalculatingRating: false, // 今日评级计算锁(防止并发)
                    predictStoreStar: 0, // 今日评级结果(默认0星)
                    predictStoreDialog: false, // 原有面板显示控制变量
                    // 今日评级进度条相关状态
                    predictProgress: {
                        currentStep: 0, // 当前步骤(从0开始)
                        totalSteps: 0, // 总步骤数(初始为0,计算前初始化)
                        isActive: false, // 进度条是否显示(计算中为true)
                        stepText: "准备计算..." // 步骤文本提示(如“预测第1轮/共5轮”)
                    },
 
                    // 录入操作面板
                    executeRecordDialog: false,
                    // 自定义JSON输入值
                    customRecordJson: '',
                    customRecordSeed: '',
 
                    // 操作日志面板
                    operationLogDialog: false,
 
                    // 历史记录面板 -- begin
                    historyDialog: false, // 历史记录面板显示控制
                    historySearchSeed: '', // 历史记录搜索输入
                    filteredHistoryRecords: [], // 过滤后的历史记录
                    totalHistoryRecords: 0, // 总历史记录数
                    // 历史记录执行相关状态
                    isExecutingHistory: false, // 是否正在执行历史记录
                    currentExecutionStep: 0, // 当前执行到历史记录的第几步
                    totalExecutionSteps: 0, // 历史记录的总步骤数
                    executionQueue: [], // 待执行的历史操作队列
                    executionTimer: null, // 历史记录执行的定时器ID
                    // 历史记录面板 -- end
 
                    // 导入/导出记录面板
                    importExportRecordDialog: false, // 面板显示控制
                    importExportText: '', // textarea绑定值
 
                    // 辅助预测面板 --begin
                    assistPredictDialog: false, // 辅助预测面板显示控制
                    assistEnabled: false, // 是否启用辅助(开关绑定值)
                    selectedScore: true, // 选中的优先级(复选框绑定值,数组存value)
                    assistPredictGlobal: false, // 是否全局预测
                    assistPredictStyle: {}, // 预测面板的样式二维数组(和网格一一对应)
                    // 辅助预测面板 --end
                }
            },
            watch: {
                // 监听自定义JSON输入变化,实时调整高度
                customRecordJson() {
                    this.$nextTick(() => {
                        this._adjustTextareaHeight('.custom-json-input .json-textarea');
                    });
                },
                customRecordSeed() {
                    this.$nextTick(() => {
                        this._adjustTextareaHeight('.custom-json-input .json-textarea');
                    });
                },
                // 监听辅助功能
                assistContent() {
                    this.assistEnabled ? this.startAssist() : this.stopAssist();
                },
                // 监听辅助启用状态变化
                assistEnabled(newVal) {
                    // 状态变了就保存
                    this.saveSettingsToLocalStorage();
                },
 
                // 监听辅助优先级变化
                selectedScore(newVal) {
                    // 状态变了就保存
                    this.saveSettingsToLocalStorage();
                },
 
                // 监听辅助全局启用状态变化
                assistPredictGlobal(newVal) {
                    // 状态变了就保存
                    this.saveSettingsToLocalStorage();
                }
            },
            computed: {
                // 计算装置尺寸
                deviceSize() {
                    if (this.devicesGrid.length === 0) return 40;
                    const size = this.minScreenDimension / this.devicesGrid.length / 0.9;
                    return Math.max(10, Math.min(80, size));
                },
                // 格式化装置高度(用于坐标显示)
                formattedDeviceHeight() {
                    return Math.floor(this.deviceSize * 10 * 0.85) / 10;
                },
                // 格式化装置宽度(用于坐标显示)
                formattedDeviceWidth() {
                    return Math.floor(this.deviceSize * 10 * 0.85) / 10;
                },
                // 判断是否可以进行自动点击
                canAutoClick() {
                    return this.devicesGrid.length > 0;
                },
                // 判断装置是否可点击
                isDeviceClickable() {
                    return !(this.isExecutingHistory || this.isInChainReaction || this.actionPoints <= 0);
                },
                // 判断是否正在连锁反应中
                isInChainReaction() {
                    return this.chainReactionTimerId !== -1;
                },
                // 当assistEnabledselectedScoreassistPredictGlobal发生改变时,该变量改变,从而触发监听器中的方法
                assistContent() {
                    return {
                        isDeviceClickable: this.isDeviceClickable,
                        assistEnabled: this.assistEnabled,
                        selectedScore: this.selectedScore,
                        assistPredictGlobal: this.assistPredictGlobal
                    }
                }
            },
            created() {
                // 1. 从本地存储加载配置(优先读取,无配置则用默认)
                this.loadSettingsFromLocalStorage();
 
                // 初始化屏幕尺寸
                this.minScreenDimension = this.getMinDimension();
                window.addEventListener('resize', () => {
                    this.minScreenDimension = this.getMinDimension();
                });
                // 生成初始装置网格
                this.generateDevicesGrid();
            },
            methods: {
                // 1.本地存储操作 --begin
                /**
                 * 从本地存储加载配置信息
                 */
                loadSettingsFromLocalStorage() {
                    const savedSettings = localStorageUtil.loadGameSettings();
                    this.speed = savedSettings.speed;
                    this.flashEnabled = savedSettings.flashEnabled;
                    this.assistEnabled = savedSettings.assistEnabled;
                    this.selectedScore = savedSettings.selectedScore;
                    this.assistPredictGlobal = savedSettings.assistPredictGlobal;
                },
 
                /**
                 * 将当前配置信息保存到本地存储
                 */
                saveSettingsToLocalStorage() {
                    const settings = {
                        speed: this.speed,
                        flashEnabled: this.flashEnabled,
                        assistEnabled: this.assistEnabled, // 辅助启用状态
                        selectedScore: this.selectedScore, // 辅助优先级
                        assistPredictGlobal: this.assistPredictGlobal, // 辅助全局启用状态
                    };
                    localStorageUtil.saveGameSettings(settings);
                },
 
                // 1.本地存储操作 --end
 
                // 2.屏幕与布局适配 --begin
 
                // 获取屏幕最小尺寸
                getMinDimension() {
                    return Math.min(window.innerWidth - 20, window.innerHeight - 120);
                },
 
                /**
                 * 自动调整 textarea 高度以适配内容(无滚动条全显示)
                 * @param {String} textareaSelector - textarea 的选择器(如 '.json-textarea')
                 */
                _adjustTextareaHeight(textareaSelector) {
                    // 获取所有目标 textarea 元素(历史记录列表中可能有多个)
                    const textareas = document.querySelectorAll(textareaSelector);
                    textareas.forEach(textarea => {
                        // 1. 先重置高度为最小高度,避免计算偏差
                        textarea.style.height = 40;
                        // 2. 计算文本实际高度(scrollHeight 包含所有内容高度,不包括滚动条)
                        const contentHeight = textarea.scrollHeight;
                        // 3. 限制高度大于minHeight
                        const minHeight = parseInt(textarea.style.minHeight) || 40;
                        const finalHeight = Math.max(contentHeight, minHeight);
                        // 4. 设置最终高度
                        textarea.style.height = `${finalHeight}px`;
                    });
                },
 
                // 2.屏幕与布局适配 --end
 
                // 3.游戏基础状态控制 --begin
 
                // 切换游戏状态
                toggleGameState() {
                    if (!this.isInChainReaction) {
                        this.gameState = this.gameState === '备战' ? '运行' : '备战';
                    }
                },
 
                // 切换游戏运行速度
                toggleSpeed() {
                    // 1. 切换速度
                    this.speed = this.speed === 0.5 ? 0.25 : 0.5;
                    // 2. 同步保存到本地存储
                    this.saveSettingsToLocalStorage();
                },
 
                toggleFlashEnabled() {
                    this.flashEnabled = !this.flashEnabled;
                    this.saveSettingsToLocalStorage();
                },
 
                // 打开设置面板
                showSettings() {
                    this.settingsDialog = true;
                },
 
                // 格式化日期
                formatDate(timestamp) {
                    if (!timestamp) return '';
                    const date = new Date(timestamp);
                    return `${date.getFullYear()}-${(date.getMonth() + 1).toString().padStart(2, '0')
                        }-${date.getDate().toString().padStart(2, '0')
                        } ${date.getHours().toString().padStart(2, '0')
                        }:${date.getMinutes().toString().padStart(2, '0')
                        }`;
                },
 
                // 3.游戏基础状态控制 --end
 
                // 4.历史记录与日志管理 --begin
 
                // 查看历史记录
                showHistoryRecords() {
                    this.searchHistoryBySeed();
                    this.historyDialog = true;
                },
 
                // 搜索历史记录(根据种子)
                searchHistoryBySeed() {
                    const historyRecords = localStorageUtil.getHistoryRecords();
                    this.totalHistoryRecords = historyRecords.length;
                    if (!this.historySearchSeed.trim()) {
                        this.filteredHistoryRecords = historyRecords;
                        return;
                    }
                    this.filteredHistoryRecords = historyRecords.filter(record =>
                        record.time.toString().includes(this.historySearchSeed.trim())
                    );
 
                    // 搜索结果更新后,重新调整 textarea 高度
                    this.$nextTick(() => {
                        this._adjustTextareaHeight('.json-textarea');
                    });
                },
 
                // 删除指定的历史记录
                deleteHistoryRecord(index, $index) {
                    if (confirm('确定要删除这条历史记录吗?此操作不可恢复。')) {
                        this.filteredHistoryRecords.splice(index, 1);
                        localStorageUtil.deleteHistoryRecord($index);
 
                        // 删除记录后,重新调整剩余 textarea 高度
                        this.$nextTick(() => {
                            this._adjustTextareaHeight('.json-textarea');
                        });
                    }
                },
 
                // 清空所有历史记录
                clearAllHistoryRecords() {
                    if (confirm('确定要删除所有历史记录吗?此操作不可恢复。')) {
                        localStorageUtil.clearAllHistoryRecords();
 
                        this.searchHistoryBySeed();
                    }
                },
 
                // 打开操作日志面板
                logOperationDetails() {
                    // 直接显示操作日志面板,无需拼接弹窗
                    this.operationLogDialog = true;
                    // 面板显示后调整 JSON 文本框高度
                    this.$nextTick(() => {
                        this._adjustTextareaHeight('.json-textarea');
                    });
                },
 
                /**
                 * 格式化操作记录(如 "1_0_0" → "运行-坐标(1,1)")
                 * @param {string} record 原始操作记录(格式:状态_行_列)
                 * @returns {string} 格式化后的字符串
                 */
                formatOperationRecord(record) {
                    const [stateCode, rowIndex, colIndex] = record.split('_').map(Number);
                    const stateText = stateCode === 1 ? '运行' : '备战';
                    // 坐标转换为「人类习惯的1开始计数」
                    const humanRow = rowIndex + 1;
                    const humanCol = colIndex + 1;
                    return `${stateText}-坐标(${humanRow}, ${humanCol})`;
                },
 
                // 4.历史记录与日志管理 --end
 
                // 5.历史记录执行逻辑 --begin
 
                // 执行历史记录
                executeHistory(record) {
                    if (this.historyDialog) {
                        // 关闭历史记录面板和设置面板
                        this.historyDialog = false;
                        this.settingsDialog = false;
                    } else if (this.executeRecordDialog) {
                        // 关闭录入操作面板和设置面板
                        this.executeRecordDialog = false;
                        this.settingsDialog = false;
                    } else if (this.operationLogDialog) {
                        // 关闭操作日志面板和设置面板
                        this.operationLogDialog = false;
                        this.settingsDialog = false;
                    }
 
                    // 停止连锁反应
                    if (this.isInChainReaction) {
                        clearInterval(this.chainReactionTimerId);
                        this.chainReactionTimerId = -1;
                    }
 
                    // 初始化执行状态
                    this.isExecutingHistory = true;
                    this.executionQueue = [...record.records];
                    this.totalExecutionSteps = this.executionQueue.length;
                    this.currentExecutionStep = 0;
 
                    // 使用相同的随机种子生成相同的网格
                    this.operationLog = {
                        time: record.time,
                        date: record.date || Date.now(),
                        records: [],
                        score: 0
                    };
                    this.actionPoints = 10;
                    this.zeroRotationDevicesCount = 0;
 
                    // 生成与历史记录相同的网格
                    this.devicesGrid = [];
                    this.$nextTick(() => {
                        this.devicesGrid = this._generateRandom2DArray({
                            sizeMin: this.sizeMin,
                            sizeMax: this.sizeMax,
                            infinityProbability: this.infinityProbability,
                            numMin: this.numMin,
                            numMax: this.numMax,
                            seed: this.operationLog.time
                        });
 
                        // 网格生成后开始执行操作
                        this.$nextTick(() => {
                            this.autoSaveHistory = false;
 
                            this._executeNextStep();
                        });
                    });
                },
 
                // 执行下一步操作
                _executeNextStep() {
                    if (!this.isExecutingHistory || this.executionQueue.length === 0) {
                        this._finishExecution();
                        return;
                    }
 
                    // 等待连锁反应结束
                    if (this.isInChainReaction) {
                        setTimeout(() => this._executeNextStep(), 100);
                        return;
                    }
 
                    // 执行下一步操作
                    const operation = this.executionQueue.shift();
                    this.currentExecutionStep++;
 
                    const [stateCode, rowIndex, colIndex] = operation.split('_').map(Number);
                    this.gameState = stateCode === 1 ? '运行' : '备战';
 
                    // 执行点击操作
                    const deviceRef = this._getDeviceRef(rowIndex, colIndex);
                    if (deviceRef && deviceRef.remainingRotationTimes > 0) {
                        deviceRef.rotate90Degrees('history');
                        this.executionTimer = setTimeout(() => this._executeNextStep(), 1000);
                    } else {
                        this._executeNextStep();
                    }
                },
 
                // 完成历史记录执行
                _finishExecution() {
                    if (this.executionTimer) {
                        clearTimeout(this.executionTimer);
                        this.executionTimer = null;
                    }
                    this.isExecutingHistory = false;
                    this.currentExecutionStep = 0;
                    this.totalExecutionSteps = 0;
                    this.executionQueue = [];
                },
 
                /**
                 * 运行自定义录入操作
                 */
                executeCustomRecord() {
                    // 校验输入不为空
                    if (!this.customRecordJson.trim()) {
                        alert('请输入符合格式的 operationLog JSON 字符串');
                        return;
                    }
                    try {
                        // 解析JSON字符串
                        const customRecord = JSON.parse(this.customRecordJson);
                        // 校验必填字段
                        if (!customRecord.time || !customRecord.records || !Array.isArray(customRecord
                                .records)) {
                            throw new Error('JSON格式错误!需包含 "time"(随机种子)和 "records"(操作记录数组)字段');
                        }
                        // 关闭录入操作面板
                        this.executeRecordDialog = false;
                        this.settingsDialog = false;
                        // 复用历史记录的执行逻辑
                        this.executeHistory(customRecord);
                    } catch (e) {
                        alert('操作失败:' + e.message);
                    }
                },
 
                /**
                 * 挑战自定义录入操作
                 */
                challengeCustomRecord(customRecordJson) {
                    // 校验输入不为空
                    if (!customRecordJson.trim()) {
                        alert('请输入符合格式的 operationLog JSON 字符串');
                        return;
                    }
                    try {
                        // 解析JSON字符串
                        const customRecord = JSON.parse(customRecordJson);
                        // 挑战仅需校验种子字段
                        if (!customRecord.time && customRecord.time !== 0) {
                            throw new Error('JSON格式错误!需包含 "time"(随机种子)字段');
                        }
                        // 关闭录入操作面板
                        this.executeRecordDialog = false;
                        this.settingsDialog = false;
                        // 复用历史记录的挑战逻辑
                        this.createChallengeWithSeed(customRecord.time);
                    } catch (e) {
                        alert('挑战失败:' + e.message);
                    }
                },
 
                // 使用指定种子创建挑战(生成相同网格但不执行历史操作)
                createChallengeWithSeed(seed) {
                    if (this.historyDialog) {
                        // 关闭历史记录面板和设置面板
                        this.historyDialog = false;
                        this.settingsDialog = false;
                    } else if (this.executeRecordDialog) {
                        // 关闭录入操作面板和设置面板
                        this.executeRecordDialog = false;
                        this.settingsDialog = false;
                    } else if (this.operationLogDialog) {
                        // 关闭操作日志面板和设置面板
                        this.operationLogDialog = false;
                        this.settingsDialog = false;
                    }
 
                    // 停止连锁反应
                    if (this.isInChainReaction) {
                        clearInterval(this.chainReactionTimerId);
                        this.chainReactionTimerId = -1;
                    }
 
                    // 停止历史执行
                    if (this.isExecutingHistory) this._finishExecution();
 
                    // 初始化日志
                    this.operationLog = {
                        time: seed,
                        date: Date.now(),
                        records: [],
                        score: 0
                    };
 
                    // 重置游戏状态
                    this.actionPoints = 10;
                    this.zeroRotationDevicesCount = 0;
                    this.gameState = '运行';
 
                    // 清空快照栈和可撤回状态
                    this.operationSnapshotStack = [];
                    this.canUndo = false;
 
                    // 重置网格时,清除最后点击标记
                    this.currentClick = {
                        rowIndex: null,
                        colIndex: null
                    };
 
                    // 生成网格
                    this.devicesGrid = [];
                    this.$nextTick(() => {
                        this.devicesGrid = this._generateRandom2DArray({
                            sizeMin: this.sizeMin,
                            sizeMax: this.sizeMax,
                            infinityProbability: this.infinityProbability,
                            numMin: this.numMin,
                            numMax: this.numMax,
                            seed: this.operationLog.time
                        });
                        this.$nextTick(() => {
                            this.startAssist();
                        });
                    });
                },
 
                // 5.历史记录执行逻辑 --end
 
                // 6.网格与装置核心逻辑 --begin
 
                // 获取今日种子
                getTodaySeed() {
                    const today = new Date();
                    return (today.getFullYear() * 10000 + (today.getMonth() + 1) * 100 + today.getDate());
                },
 
                /**
                 * 生成装置网格(支持自定义初始状态)
                 * @param {Array} [devicesGrid] 自定义装置二维数组(可选)
                 * @param {number} [actionPoints=10] 自定义剩余行动数(可选,默认10)
                 * @param {number} [zeroRotationDevicesCount=0] 自定义耗尽装置数(可选,默认0)
                 * @param {number} [score=0] 自定义初始分数(可选,默认0)
                 * @param {number} [seed] 自定义随机种子(可选,仅当未传入devicesGrid时生效)
                 */
                generateDevicesGrid(devicesGrid, actionPoints = 10, zeroRotationDevicesCount = 0, score = 0,
                    seed) {
                    // 初始化操作日志(优先使用传入的种子,否则生成基于当天的种子)
                    const currentSeed = seed || this.getTodaySeed(); // 当前种子
                    this.operationLog = {
                        time: currentSeed,
                        date: Date.now(),
                        records: [],
                        score: score // 初始分数:优先使用传入值
                    };
 
                    // 重置游戏状态(优先使用传入的参数)
                    this.actionPoints = actionPoints;
                    this.zeroRotationDevicesCount = zeroRotationDevicesCount;
                    this.gameState = '运行'; // 默认状态为“运行”
 
                    // 判断是否使用传入的自定义网格
                    if (devicesGrid && Array.isArray(devicesGrid) && devicesGrid.length > 0) {
                        // 校验传入的网格格式是否合法(二维数组且每行元素为对象)
                        const isGridValid = devicesGrid.every(row =>
                            Array.isArray(row) && row.every(device =>
                                device && typeof device === 'object' &&
                                'maxRotationTimes' in device && 'initRotationAngle' in device
                            )
                        );
                        if (isGridValid) {
                            this.devicesGrid = devicesGrid.map(row =>
                                row.map(device => ({
                                    ...device
                                })) // 深拷贝传入的网格,避免外部修改影响内部状态
                            );
                            return; // 直接使用自定义网格,终止后续随机生成逻辑
                        }
                    }
 
                    // 未传入有效网格时,按原逻辑随机生成(使用传入的seed或默认种子)
                    this.devicesGrid = this._generateRandom2DArray({
                        sizeMin: this.sizeMin,
                        sizeMax: this.sizeMax,
                        infinityProbability: this.infinityProbability,
                        numMin: this.numMin,
                        numMax: this.numMax,
                        seed: currentSeed
                    });
                },
 
                // 重新生成网格(重置功能)
                regenerateGrid() {
                    // 1. 清理连锁反应与历史执行
                    if (this.isExecutingHistory) this._finishExecution();
                    if (this.isInChainReaction) this._stopChainReaction();
 
                    // 2. 重置快照栈与可撤回状态
                    this.operationSnapshotStack = [];
                    this.canUndo = false;
                    this.currentClick = {
                        rowIndex: null,
                        colIndex: null
                    };
 
                    // 生成随机网格
                    this.devicesGrid = [];
                    this.$nextTick(() => {
                        this.generateDevicesGrid()
                        this.$nextTick(() => {
                            this.autoSaveHistory = true;
                            this.startAssist()
                        });
                    });
                },
 
                /**
                 * 特殊初始化方法:种子为特定值时,手动设置固定网格
                 * @returns {Array} 手动定义的装置网格(二维数组)
                 */
                specialInitGrid(seed, devicesGrid) {
                    if (seed === 20251001) {
                        devicesGrid = [[{"maxRotationTimes":1,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":1,"initRotationAngle":270,"currentRotationAngle":90,"t":true},{"maxRotationTimes":3,"initRotationAngle":90,"currentRotationAngle":0,"t":true},{"maxRotationTimes":3,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":2,"initRotationAngle":180,"currentRotationAngle":0,"t":true},{"maxRotationTimes":2,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":1,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":2,"initRotationAngle":180,"currentRotationAngle":0,"t":true},{"maxRotationTimes":1,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":3,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":5,"initRotationAngle":270,"currentRotationAngle":90,"t":true},{"maxRotationTimes":5,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":8,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":6,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":5,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":6,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":5,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":4,"initRotationAngle":0,"currentRotationAngle":180,"t":true},{"maxRotationTimes":6,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":7,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":5,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":4,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":3,"initRotationAngle":270,"currentRotationAngle":270}],[{"maxRotationTimes":2,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":3,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":4,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":2,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":6,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":5,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":2,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":5,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":4,"initRotationAngle":180,"currentRotationAngle":270},{"maxRotationTimes":9,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":7,"initRotationAngle":180,"currentRotationAngle":270,"t":true},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":11,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":9,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":10,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":10,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":8,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":8,"initRotationAngle":0,"currentRotationAngle":180,"t":true},{"maxRotationTimes":8,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":9,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":9,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":7,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":1,"initRotationAngle":0,"currentRotationAngle":0,"t":true}],[{"maxRotationTimes":3,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":5,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":4,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":6,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":8,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":9,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":5,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":8,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":7,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":10,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":0},{"maxRotationTimes":15,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":13,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":13,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":11,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":11,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":15,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":15,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":13,"initRotationAngle":0,"currentRotationAngle":180},{"maxRotationTimes":6,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":2,"initRotationAngle":0,"currentRotationAngle":0}],[{"maxRotationTimes":5,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":8,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":7,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":8,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":9,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":9,"initRotationAngle":270,"currentRotationAngle":0,"t":true},{"maxRotationTimes":7,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":6,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":9,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":15,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":14,"initRotationAngle":270,"currentRotationAngle":90},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":15,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":14,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":13,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":12,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":9,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":13,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":13,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":8,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":4,"initRotationAngle":180,"currentRotationAngle":180}],[{"maxRotationTimes":5,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":9,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":8,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":8,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":7,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":7,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":14,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":12,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":16,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":13,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":270,"t":true},{"maxRotationTimes":16,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":16,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":15,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":13,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":12,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":12,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":8,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":10,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":3,"initRotationAngle":0,"currentRotationAngle":180}],[{"maxRotationTimes":6,"initRotationAngle":90,"currentRotationAngle":270,"t":true},{"maxRotationTimes":10,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":9,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":6,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":1,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":2,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":270,"t":true},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":14,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":16,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":10,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":12,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":13,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270,"t":true},
                        {"maxRotationTimes":13,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":10,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":8,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":9,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":7,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":2,"initRotationAngle":90,"currentRotationAngle":90}],[{"maxRotationTimes":6,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":15,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":13,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":7,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":6,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":12,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":13,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":15,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":16,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":12,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":12,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":11,"initRotationAngle":0,"currentRotationAngle":90},{"maxRotationTimes":13,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":14,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":9,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":11,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":11,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":2,"initRotationAngle":90,"currentRotationAngle":90}],[{"maxRotationTimes":5,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":12,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":12,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":13,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":8,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":8,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":14,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":17,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":14,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":10,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":12,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":14,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":16,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":15,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":12,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":8,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":2,"initRotationAngle":90,"currentRotationAngle":90}],[{"maxRotationTimes":6,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":12,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":8,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":7,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":10,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":15,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":10,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":16,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":15,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":10,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":17,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":16,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":15,"initRotationAngle":0,"currentRotationAngle":180},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":14,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":9,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":5,"initRotationAngle":180,"currentRotationAngle":180}],[{"maxRotationTimes":6,"initRotationAngle":90,"currentRotationAngle":270,"t":true},{"maxRotationTimes":9,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":9,"initRotationAngle":180,"currentRotationAngle":0},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":15,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":16,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":14,"initRotationAngle":90,"currentRotationAngle":270},{"maxRotationTimes":17,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":18,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":18,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":10,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":18,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":14,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":19,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":14,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":11,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":13,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":9,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":9,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":4,"initRotationAngle":270,"currentRotationAngle":270}],[{"maxRotationTimes":7,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":7,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":10,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":10,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":10,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":20,"initRotationAngle":270,"currentRotationAngle":90},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":15,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":15,"initRotationAngle":180,"currentRotationAngle":90},{"maxRotationTimes":11,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":12,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":11,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":6,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":4,"initRotationAngle":180,"currentRotationAngle":180,"t":true}],[{"maxRotationTimes":7,"initRotationAngle":90,"currentRotationAngle":270},{"maxRotationTimes":11,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":12,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":14,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":16,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":16,"initRotationAngle":0,"currentRotationAngle":0},
                        {"maxRotationTimes":17,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":15,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":13,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":15,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":19,"initRotationAngle":90,"currentRotationAngle":0},{"maxRotationTimes":27,"initRotationAngle":90,"currentRotationAngle":270},{"maxRotationTimes":20,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":20,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":22,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":21,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":19,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":15,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":16,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":13,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":12,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":6,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":5,"initRotationAngle":180,"currentRotationAngle":180}],[{"maxRotationTimes":7,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":14,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":17,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":17,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":10,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":13,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":14,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":15,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":17,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":24,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":24,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":20,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":20,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":19,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":19,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":15,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":10,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":10,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":10,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":8,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":4,"initRotationAngle":270,"currentRotationAngle":90}],[{"maxRotationTimes":5,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":4,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":3,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":14,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":15,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":15,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":14,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":16,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":15,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":20,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":21,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":13,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":14,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":15,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":3,"initRotationAngle":0,"currentRotationAngle":0}],[{"maxRotationTimes":4,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":3,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":2,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":12,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":10,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":11,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":13,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":17,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":13,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":12,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":14,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":14,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":13,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":15,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":14,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":11,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":5,"initRotationAngle":180,"currentRotationAngle":180}],[{"maxRotationTimes":5,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":4,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":6,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":9,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":13,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":14,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":13,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":14,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":16,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":180,"t":true},{"maxRotationTimes":12,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":15,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":15,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":11,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":12,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":12,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":9,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":5,"initRotationAngle":180,"currentRotationAngle":180}],[{"maxRotationTimes":4,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":11,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":9,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":9,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":11,"initRotationAngle":0,"currentRotationAngle":180},{"maxRotationTimes":11,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":9,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":13,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":13,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":12,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":18,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":17,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":14,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":15,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":13,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":0,"t":true},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":11,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":13,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":6,"initRotationAngle":0,"currentRotationAngle":90},
                        {"maxRotationTimes":4,"initRotationAngle":270,"currentRotationAngle":270}],[{"maxRotationTimes":5,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":12,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":10,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":9,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":9,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":10,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":18,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":22,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":10,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":9,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":9,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":9,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":6,"initRotationAngle":270,"currentRotationAngle":270,"t":true},{"maxRotationTimes":2,"initRotationAngle":90,"currentRotationAngle":90}],[{"maxRotationTimes":4,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":13,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":11,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":11,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":11,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":14,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":7,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":6,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":6,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":12,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":17,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":4,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":4,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":4,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":7,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":9,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":11,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":11,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":8,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":4,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":2,"initRotationAngle":90,"currentRotationAngle":90}],[{"maxRotationTimes":3,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":12,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":9,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":13,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":13,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":11,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":10,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":11,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":11,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":11,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":9,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":12,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":9,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":6,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":6,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":6,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":6,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":9,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":6,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":6,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":6,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":4,"initRotationAngle":270,"currentRotationAngle":270}],[{"maxRotationTimes":2,"initRotationAngle":180,"currentRotationAngle":270},{"maxRotationTimes":8,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":8,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":9,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":11,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":10,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":10,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":12,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":12,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":11,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":9,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":8,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":8,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":8,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":6,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":8,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":4,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":5,"initRotationAngle":180,"currentRotationAngle":270},{"maxRotationTimes":5,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":6,"initRotationAngle":90,"currentRotationAngle":270},{"maxRotationTimes":6,"initRotationAngle":270,"currentRotationAngle":180,"t":true},{"maxRotationTimes":3,"initRotationAngle":0,"currentRotationAngle":90}],[{"maxRotationTimes":3,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":5,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":4,"initRotationAngle":180,"currentRotationAngle":180,"t":true},{"maxRotationTimes":6,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":5,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":4,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":6,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":7,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":5,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":7,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":5,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":8,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":6,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":9,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":9,"initRotationAngle":0,"currentRotationAngle":90},{"maxRotationTimes":6,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":9,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":5,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":5,"initRotationAngle":180,"currentRotationAngle":180},{"maxRotationTimes":6,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":6,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":5,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":2,"initRotationAngle":0,"currentRotationAngle":0,"t":true}],[{"maxRotationTimes":2,"initRotationAngle":90,"currentRotationAngle":270},{"maxRotationTimes":3,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":2,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":5,"initRotationAngle":90,"currentRotationAngle":90,"t":true},{"maxRotationTimes":5,"initRotationAngle":270,"currentRotationAngle":180},{"maxRotationTimes":3,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":4,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":3,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":3,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":3,"initRotationAngle":0,"currentRotationAngle":180,"t":true},{"maxRotationTimes":3,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":4,"initRotationAngle":0,"currentRotationAngle":0},{"maxRotationTimes":6,"initRotationAngle":90,"currentRotationAngle":180},{"maxRotationTimes":6,"initRotationAngle":90,"currentRotationAngle":90},{"maxRotationTimes":6,"initRotationAngle":90,"currentRotationAngle":180},{"maxRotationTimes":5,"initRotationAngle":90,"currentRotationAngle":180,"t":true},{"maxRotationTimes":6,"initRotationAngle":0,"currentRotationAngle":0,"t":true},{"maxRotationTimes":5,"initRotationAngle":90,"currentRotationAngle":180},{"maxRotationTimes":4,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":4,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":6,"initRotationAngle":90,"currentRotationAngle":180},{"maxRotationTimes":4,"initRotationAngle":270,"currentRotationAngle":270},{"maxRotationTimes":4,"initRotationAngle":270,"currentRotationAngle":270}]];
                    }
                    return devicesGrid;
                },
 
                // 生成随机的二维装置数组
                _generateRandom2DArray(options) {
                    // 是否属于特殊种子
                    const isSpecial = options.seed === 20251001
 
                    const {
                        sizeMin = 10, sizeMax = 20, infinityProbability = 0.3, numMin = 3, numMax = 10, seed =
                            this.getTodaySeed()
                    } = !isSpecial ? options : {
                        ...options,
                        sizeMin: 23,
                        sizeMax: 23,
                        numMin: 10,
                        numMax: 20,
                        seed: options.seed
                    };
 
                    // 随机数生成器
                    const rand = this._mulberry32(seed);
                    const size = Math.floor(rand() * (sizeMax - sizeMin + 1)) + sizeMin;
                    let result = [];
                    const initialRotationAngles = [0, 90, 180, 270];
 
                    // 生成二维数组
                    for (let i = 0; i < size; i++) {
                        const row = [];
                        for (let j = 0; j < size; j++) {
                            // 随机决定是否为无限次旋转
                            const maxRotationTimes = rand() < infinityProbability ?
                                Infinity :
                                Math.floor(rand() * (numMax - numMin + 1)) + numMin;
 
                            // 随机初始旋转角度
                            const initRotationAngle = initialRotationAngles[
                                Math.floor(rand() * initialRotationAngles.length)
                            ];
 
                            row.push({
                                maxRotationTimes,
                                initRotationAngle,
                                currentRotationAngle: initRotationAngle
                            });
                        }
                        result.push(row);
                    }
 
                    if (isSpecial)
                        result = this.specialInitGrid(seed, result)
                    return result;
                },
 
                // 随机数生成算法
                _mulberry32(seed) {
                    return function () {
                        seed += 0x6D2B79F5;
                        let t = seed;
                        t = Math.imul(t ^ t >>> 15, t | 1);
                        t ^= t + Math.imul(t ^ t >>> 7, t | 61);
                        return ((t ^ t >>> 14) >>> 0) / 4294967296;
                    };
                },
 
                // 获取装置引用
                _getDeviceRef(rowIndex, colIndex) {
                    const refs = this.$refs[`device_${rowIndex}_${colIndex}`];
                    return refs && Array.isArray(refs) ? refs[0] : null;
                },
 
                // 6.网格与装置核心逻辑 --end
 
                // 7.连锁反应与得分计算 --begin
 
                // 处理装置旋转事件
                handleDeviceRotated(rowIndex, colIndex, eventData) {
                    const {
                        oldDevice,
                        triggerSource,
                        becameZero,
                        remainingRotations
                    } = eventData;
                    // 仅当玩家主动点击/自动点击时,在操作前生成快照(排除连锁反应自动触发和历史执行)
                    if (['click', 'auto'].includes(triggerSource) && !this.isExecutingHistory && !this
                        .isInChainReaction && !this.isUndoing) {
                        const snapshot = this._createGameSnapshot(rowIndex, colIndex, oldDevice);
                        this.operationSnapshotStack.push(snapshot);
 
                        // 更新可撤回状态(有快照则可撤回)
                        this.canUndo = this.operationSnapshotStack.length > 0;
 
                        // 暂时停止预测
                        this.stopAssist();
                    }
 
                    // 更新已耗尽装置计数
                    if (becameZero) {
                        this.zeroRotationDevicesCount++;
                    }
 
                    // 计算分数
                    if (['click', 'auto', 'history'].includes(triggerSource)) {
                        this.currentClick = {
                            rowIndex: rowIndex,
                            colIndex: colIndex
                        }
                        const multiplier = 1 + this.zeroRotationDevicesCount;
                        this.operationLog.score += remainingRotations === 0 ?
                            10 * multiplier :
                            1 * multiplier;
                    }
 
                    // 处理不同触发来源的逻辑
                    switch (triggerSource) {
                        case 'click':
                        case 'auto':
                        case 'history':
                            // 记录操作日志
                            const stateCode = this.gameState === '备战' ? 0 : 1;
                            this.operationLog.records.push(`${stateCode}_${rowIndex}_${colIndex}`);
 
                            // 消耗行动点 - 这是触发颜色重置的关键位置
                            const previousActionPoints = this.actionPoints;
                            this.actionPoints--;
 
                            // 当行动点数减少时,重置所有装置颜色为原蓝色
                            if (previousActionPoints > this.actionPoints) {
                                this._resetAllDeviceColors();
                            }
 
                            // 反应状态下触发连锁反应
                            if (this.gameState === '运行' && !this.isInChainReaction) {
                                // 记录当前触发旋转的装置坐标集合
                                this._startChainReaction(rowIndex, colIndex, oldDevice);
                            }
                            break;
 
                        case 'force':
                            break;
                    }
                },
 
                // 开始连锁反应
                _startChainReaction(i, j, oldDevice) {
                    // 预测点击后的结果
                    const currentState = {
                        devicesGrid: this.devicesGrid.map((row, r) =>
                            row.map((device, c) => {
                                if (i === r && c === j) {
                                    // 触发连锁反应的装置需要用oldDevice的角度和剩余次数
                                    return {
                                        maxRotationTimes: device.maxRotationTimes,
                                        initRotationAngle: device.initRotationAngle,
                                        currentRotationAngle: oldDevice.currentRotationAngle,
                                        remainingRotationTimes: oldDevice.remainingRotationTimes,
                                    };
                                } else {
                                    let deviceRef = this._getDeviceRef(r, c);
                                    return {
                                        maxRotationTimes: device.maxRotationTimes,
                                        initRotationAngle: device.initRotationAngle,
                                        currentRotationAngle: deviceRef.currentRotationAngle,
                                        remainingRotationTimes: deviceRef.remainingRotationTimes,
                                    };
                                }
                            })
                        ),
                        actionPoints: this.actionPoints + 1,
                        // 如果oldDevice的剩余次数是1,则zeroRotationDevicesCount需要+1
                        // (因为oldDevice执行完旋转后,剩余次数会变成0,此时装置消耗总数+1)
                        zeroRotationDevicesCount: this.zeroRotationDevicesCount + (oldDevice
                            .remainingRotationTimes === 1 ? 1 : 0),
                        score: 0, // 此处分数错误,但不会影响操作
                    };
                    const predictedState = this._predictChainReaction(currentState, i, j);
                    // 计时器的次数
                    let num = 1;
                    // 设置连锁反应定时器
                    this.chainReactionTimerId = setInterval(() => {
                        if (num < predictedState.rotationBatches.length) {
                            const currentRotationRowColArray = predictedState.rotationBatches[
                                num]; // 本轮连锁反应的旋转装置坐标集合
                            // 汇总待旋转的旋转装置列表
                            // 存储待旋转的装置的rowIndex_colIndex,主要用于去重判断
                            let pendingRotationCoordsSet = new Set();
                            // 存储待旋转的装置组件列表
                            let deviceRefList = [];
                            currentRotationRowColArray.forEach((rowColIndex) => {
                                const rowColArray = rowColIndex.split('_');
                                const rowIndex = parseInt(rowColArray[0]);
                                const colIndex = parseInt(rowColArray[1]);
                                const rotatingDevice = this._getDeviceRef(rowIndex, colIndex);
 
                                if (!rotatingDevice) return;
 
                                deviceRefList.push(rotatingDevice);
                            });
 
                            // 没有待处理装置时结束连锁反应
                            if (deviceRefList.length === 0) {
                                this._stopChainReaction();
                                return;
                            }
 
                            // 计算并添加连锁反应分数
                            const multiplier = 1 + this.zeroRotationDevicesCount;
                            this.operationLog.score += deviceRefList.length * multiplier;
 
                            // 处理当前批次的旋转
                            deviceRefList.forEach(deviceRef => {
                                if (deviceRef) {
                                    deviceRef.forceRotate('force');
                                }
                            });
                            num++;
                        } else {
                            this._stopChainReaction();
                            return;
                        }
                    }, this.speed * 1000);
                },
 
                // 停止连锁反应的定时器
                _stopChainReaction() {
                    clearInterval(this.chainReactionTimerId);
                    this.chainReactionTimerId = -1;
 
                    // 继续执行历史记录(如果正在执行)
                    if (this.isExecutingHistory) {
                        this._executeNextStep();
                    } else {
                        // 不是执行记录,则保存记录并预测
                        this.saveHistoryRecord();
                        this.startAssist();
                    }
                },
 
                // 重置指定装置的颜色为原蓝色
                resetDeviceColor(rowIndex, colIndex) {
                    const deviceRef = this._getDeviceRef(rowIndex, colIndex);
                    if (deviceRef) {
                        deviceRef.resetToNormalColor();
                    }
                },
 
                // 重置所有装置的颜色为原蓝色
                _resetAllDeviceColors() {
                    this.devicesGrid.forEach((row, rowIndex) => {
                        row.forEach((_, colIndex) => this.resetDeviceColor(rowIndex, colIndex));
                    });
                },
 
                // 7.连锁反应与得分计算 --end
 
                // 8.撤回与状态快照 --begin
 
                /**
                 * 生成游戏状态快照(深拷贝,避免状态引用污染)
                 * @returns {Object} 包含所有关键状态的快照对象
                 */
                _createGameSnapshot(rowIndex, colIndex, oldDevice) {
                    // 1. 从组件实例中读取装置状态(旋转角度、剩余旋转次数)
                    const devicesGridSnapshot = [];
                    for (let i = 0; i < this.devicesGrid.length; i++) {
                        const row = [];
                        for (let j = 0; j < this.devicesGrid[i].length; j++) {
                            const deviceRef = this._getDeviceRef(i, j);
                            if (i === rowIndex && j === colIndex) {
                                row.push({
                                    maxRotationTimes: this.devicesGrid[i][j]
                                        .maxRotationTimes, // 基础配置仍来自devicesGrid
                                    initRotationAngle: this.devicesGrid[i][j].initRotationAngle,
                                    currentRotationAngle: oldDevice
                                        .currentRotationAngle, // 此时组件已执行完旋转操作,所以快照中需要保留执行前的数据
                                    remainingRotationTimes: oldDevice
                                        .remainingRotationTimes, // 此时组件已执行完旋转操作,所以快照中需要保留执行前的数据
                                    t: this.devicesGrid[i][j].t,
                                });
                            } else {
                                row.push({
                                    maxRotationTimes: this.devicesGrid[i][j]
                                        .maxRotationTimes, // 基础配置仍来自devicesGrid
                                    initRotationAngle: this.devicesGrid[i][j].initRotationAngle,
                                    currentRotationAngle: deviceRef.currentRotationAngle, // 存储组件当前数据
                                    remainingRotationTimes: deviceRef
                                        .remainingRotationTimes, // 存储组件当前数据
                                    t: this.devicesGrid[i][j].t,
                                });
                            }
                        }
                        devicesGridSnapshot.push(row);
                    }
 
                    // 2. 深拷贝操作日志
                    const operationLogSnapshot = JSON.parse(JSON.stringify(this.operationLog));
 
                    // 3. 返回完整快照
                    return {
                        devicesGrid: devicesGridSnapshot,
                        actionPoints: this.actionPoints,
                        zeroRotationDevicesCount: this.zeroRotationDevicesCount,
                        operationLog: operationLogSnapshot,
                        currentClick: {
                            ...this.currentClick
                        },
                        timestamp: Date.now()
                    };
                },
 
                // 撤回上一步操作(恢复到最近一次点击前的状态)
                undoLastOperation() {
                    // 撤回边界校验:无快照/连锁反应中/执行历史中,禁止撤回
                    if (this.operationSnapshotStack.length === 0 || this.isInChainReaction || this
                        .isExecutingHistory) {
                        this.canUndo = this.operationSnapshotStack.length > 0;
                        return;
                    }
 
                    // 撤回前停止连锁反应
                    if (this.isInChainReaction) {
                        this._stopChainReaction();
                    }
 
                    this.isUndoing = true; // 标记正在撤回,避免并发操作
 
                    try {
                        // 1. 弹出最近的快照(无需清空网格,直接覆盖状态)
                        const lastSnapshot = this.operationSnapshotStack.pop();
 
                        // 2. 恢复基础状态(分数、行动点等)
                        this.actionPoints = lastSnapshot.actionPoints;
                        this.zeroRotationDevicesCount = lastSnapshot.zeroRotationDevicesCount;
                        this.operationLog = JSON.parse(JSON.stringify(lastSnapshot.operationLog));
                        this.currentClick = {
                            ...lastSnapshot.currentClick
                        };
 
                        // 3. 恢复网格结构(若尺寸不变,直接更新;若尺寸变化,才需要重新渲染)
                        this.devicesGrid = JSON.parse(JSON.stringify(lastSnapshot.devicesGrid));
 
                        // 4. 等待网格更新后,同步组件状态(仅需一次 $nextTick)
                        this.$nextTick(() => {
                            for (let rowIndex = 0; rowIndex < this.devicesGrid.length; rowIndex++) {
                                for (let colIndex = 0; colIndex < this.devicesGrid[rowIndex]
                                    .length; colIndex++) {
                                    const deviceRef = this._getDeviceRef(rowIndex, colIndex);
                                    const snapshotDevice = lastSnapshot.devicesGrid[rowIndex][colIndex];
                                    if (deviceRef && snapshotDevice) {
                                        // 恢复组件的旋转角度和剩余次数(直接操作组件实例)
                                        deviceRef.currentRotationAngle = snapshotDevice
                                            .currentRotationAngle;
                                        deviceRef.remainingRotationTimes = snapshotDevice
                                            .remainingRotationTimes;
                                        // 恢复颜色并强制更新(确保视图同步)
                                        deviceRef.resetToNormalColor();
                                        deviceRef.$forceUpdate(); // 兼容非响应式属性的组件
                                    }
                                }
                            }
 
                            // 5. 更新可撤回状态
                            this.canUndo = this.operationSnapshotStack.length > 0;
 
                            this.startAssist();
                        });
 
                    } catch (error) {
                        alert("撤回失败,请重试");
                    } finally {
                        this.isUndoing = false; // 解除撤回标记
                    }
                },
 
                /**
                 * 保存记录到本地存储
                 * 规则:
                 * 1. 每个随机种子的得分前三名必然保留
                 * 2. 所有种子的全部记录中,分数排名前20名必然保留
                 * 最终历史记录数量可能超过20条
                 */
                saveHistoryRecord() {
                    if (this.operationLog.records.length === 0) return;
                    if (this.autoSaveHistory)
                        localStorageUtil.saveHistoryRecord(this.operationLog);
 
                    // 清理快照栈(保留最近10次)
                    const MAX_SNAPSHOTS = 10;
                    if (this.operationSnapshotStack.length > MAX_SNAPSHOTS) {
                        this.operationSnapshotStack = this.operationSnapshotStack.slice(-MAX_SNAPSHOTS);
                        this.canUndo = this.operationSnapshotStack.length > 0;
                    }
                },
 
                /**
                 * 导入记录按钮点击事件(空实现,后续可扩展)
                 */
                handleImportRecord() {
                    if(!this.importExportText) {
                        alert('请输入想导入的数据!')
                        return;
                    }
                    if(!window.key) {
                        alert('请先登录!')
                        return;
                    }
                    let result = localStorageUtil.mergeCiphertextToHistory(this.importExportText);
                    if(!result)
                        alert('请核对导入的数据!仅可导入自己账号登录时点击“导出记录”生成的数据!')
                    else {
                        alert('导入成功!')
                        this.importExportText = '';
                    }
                },
 
                /**
                 * 导出记录按钮点击事件(空实现,后续可扩展)
                 */
                handleExportRecord() {
                    if(!window.key) {
                        alert('请先登录!')
                        return;
                    }
                    this.importExportText = localStorageUtil.exportStorageData();
                    if(!this.importExportText)
                        alert('为什么没有数据捏?也许是还没有数据吧')
                    else
                        alert('数据已导出!复制上方文本后,在另一个浏览器中点击“导入记录”即可!ps:另一个浏览器也要记得登录本人账号哦!')
                },
                // 8.撤回与状态快照 --end
 
                // 9.预测与辅助计算 --begin
 
                /**
                 * 预测点击指定装置后,连锁反应结束的最终状态
                 * @param {Object} initialState 初始状态数据
                 * @param {Array} initialState.devicesGrid 初始装置网格(二维数组)
                 * @param {number} initialState.actionPoints 初始行动点数
                 * @param {number} initialState.zeroRotationDevicesCount 初始耗尽装置数
                 * @param {number} initialState.score 初始分数
                 * @param {number} rowIndex 触发装置的行坐标
                 * @param {number} colIndex 触发装置的列坐标
                 * @returns {Object} 连锁反应结束后的最终状态
                 */
                _predictChainReaction(initialState, rowIndex, colIndex) {
                    // 1. 深拷贝初始状态,避免污染原数据
                    const state = {
                        devicesGrid: this._deepCloneWithInfinity(initialState.devicesGrid),
                        actionPoints: initialState.actionPoints,
                        zeroRotationDevicesCount: initialState.zeroRotationDevicesCount,
                        score: initialState.score
                    };
 
                    // 用于记录每一批次的队列(连锁反应的批次历史)
                    const rotationBatches = [];
                    const size = state.devicesGrid.length;
                    if (size === 0) {
                        return {
                            ...state,
                            rotationBatches: [],
                        };
                    }
 
                    // 2. 检查初始条件(是否可点击)
                    const maxRowIndex = size - 1;
                    const maxColIndex = state.devicesGrid[0].length - 1;
                    if (
                        state.actionPoints <= 0 ||
                        rowIndex < 0 || rowIndex > maxRowIndex ||
                        colIndex < 0 || colIndex > maxColIndex ||
                        state.devicesGrid[rowIndex][colIndex].remainingRotationTimes <= 0
                    ) {
                        // 不可点击时直接返回初始状态
                        return {
                            ...state,
                            rotationBatches: [] // 无连锁反应,队列历史为空
                        };
                    }
 
                    // 3. 模拟首次点击(消耗行动点+旋转装置)
                    let firstDevice = state.devicesGrid[rowIndex][colIndex];
                    state.actionPoints--; // 消耗1点行动点
 
                    // 计算首次旋转得分
                    const firstRotationScore = firstDevice.remainingRotationTimes === 1 ? 10 * (1 + state
                        .zeroRotationDevicesCount) : 1 * (1 + state.zeroRotationDevicesCount);
                    state.score += firstRotationScore;
 
                    // 更新装置状态(旋转90度+减少剩余次数)
                    firstDevice.currentRotationAngle = (firstDevice.currentRotationAngle + 90) % 360;
                    firstDevice.remainingRotationTimes--;
 
                    // 检查是否变为耗尽状态
                    if (firstDevice.remainingRotationTimes === 0) {
                        state.zeroRotationDevicesCount++;
                    }
 
                    // 4. 模拟连锁反应(使用队列处理批量旋转)
                    const rotationQueue = new Set(); // 存储待旋转装置坐标(格式:"row_col"rotationQueue.add(`${rowIndex}_${colIndex}`); // 初始加入首次点击的装置
 
                    // 朝上朝左的方法
                    const isTopFunc = (angle) => [0, 90].includes(angle);
                    const isLeftFunc = (angle) => [270, 0].includes(angle);
 
                    // 循环处理连锁反应,直到无新装置需要旋转
                    while (rotationQueue.size > 0) {
                        const currentBatch = Array.from(rotationQueue);
                        // 记录当前批次的队列(转换为坐标数组格式,如 [[r1,c1], [r2,c2]])
                        rotationBatches.push(currentBatch);
 
                        rotationQueue.clear(); // 清空队列,准备接收新的待旋转装置
 
                        // 处理当前批次的所有装置旋转
                        currentBatch.forEach(coord => {
                            const [r, c] = coord.split('_').map(Number);
                            const device = state.devicesGrid[r][c];
 
                            // 检查装置是否还能旋转(防御性判断)
                            // if (device.remainingRotationTimes <= 0) return;
 
                            // 根据装置当前朝向,检查相邻装置是否需要旋转
                            const angle = device.currentRotationAngle % 360;
                            const isTop = isTopFunc(angle); // 朝上状态
                            const isLeft = isLeftFunc(angle); // 朝左状态
 
                            // 检查上方装置(当前朝上时,上方装置需朝下)
                            if (isTop && r > 0) {
                                const topDevice = state.devicesGrid[r - 1][c];
                                const topAngle = topDevice.currentRotationAngle % 360;
                                if (!isTopFunc(topAngle) && topDevice.remainingRotationTimes > 0) {
                                    const key = `${r - 1}_${c}`;
                                    if (!rotationQueue.has(key)) rotationQueue.add(key);
                                }
                            }
 
                            // 检查下方装置(当前朝下时,下方装置需朝上)
                            if (!isTop && r < size - 1) {
                                const bottomDevice = state.devicesGrid[r + 1][c];
                                const bottomAngle = bottomDevice.currentRotationAngle % 360;
                                if (isTopFunc(bottomAngle) && bottomDevice.remainingRotationTimes > 0) {
                                    const key = `${r + 1}_${c}`;
                                    if (!rotationQueue.has(key)) rotationQueue.add(key);
                                }
                            }
 
                            // 检查左侧装置(当前朝左时,左侧装置需朝右)
                            if (isLeft && c > 0) {
                                const leftDevice = state.devicesGrid[r][c - 1];
                                const leftAngle = leftDevice.currentRotationAngle % 360;
                                if (!isLeftFunc(leftAngle) && leftDevice.remainingRotationTimes > 0) {
                                    const key = `${r}_${c - 1}`;
                                    if (!rotationQueue.has(key)) rotationQueue.add(key);
                                }
                            }
 
                            // 检查右侧装置(当前朝右时,右侧装置需朝左)
                            if (!isLeft && c < size - 1) {
                                const rightDevice = state.devicesGrid[r][c + 1];
                                const rightAngle = rightDevice.currentRotationAngle % 360;
                                if (isLeftFunc(rightAngle) && rightDevice.remainingRotationTimes > 0) {
                                    const key = `${r}_${c + 1}`;
                                    if (!rotationQueue.has(key)) rotationQueue.add(key);
                                }
                            }
                        });
 
                        // 计算当前批次的连锁得分
                        const chainScore = rotationQueue.size * (1 + state.zeroRotationDevicesCount);
                        state.score += chainScore;
 
                        // 执行当前批次的旋转(更新角度和剩余次数)
                        rotationQueue.forEach(coord => {
                            const [r, c] = coord.split('_').map(Number);
                            const device = state.devicesGrid[r][c];
 
                            // 旋转90度
                            device.currentRotationAngle = (device.currentRotationAngle + 90) % 360;
                            // 减少剩余次数
                            if (device.remainingRotationTimes !== Infinity) {
                                device.remainingRotationTimes--;
                                // 检查是否变为耗尽状态
                                if (device.remainingRotationTimes === 0) {
                                    state.zeroRotationDevicesCount++;
                                }
                            }
                        });
                    }
 
                    // 5. 返回连锁反应结束后的最终状态
                    return {
                        devicesGrid: state.devicesGrid,
                        actionPoints: state.actionPoints,
                        zeroRotationDevicesCount: state.zeroRotationDevicesCount,
                        score: state.score,
                        rotationBatches: rotationBatches // 新增:所有批次的队列历史
                    };
                },
 
                /**
                 * 深克隆函数,高效保留 Infinity 类型
                 * @param {any} value 要克隆的值
                 * @returns {any} 克隆后的新值
                 */
                _deepCloneWithInfinity(value) {
                    // 基本类型直接返回(含null,因为typeof null === 'object')
                    if (value === null || typeof value !== 'object') {
                        // 对于Infinity直接返回,其他基本类型也会直接返回
                        return value;
                    }
 
                    // 处理数组(使用Array.from提高效率)
                    if (Array.isArray(value)) {
                        return Array.from(value, item => this._deepCloneWithInfinity(item));
                    }
 
                    // 处理对象(使用Object.create保持原型,Object.keys避免原型链遍历)
                    const cloned = Object.create(Object.getPrototypeOf(value));
                    const keys = Object.keys(value);
 
                    for (let i = 0; i < keys.length; i++) {
                        const key = keys[i];
                        const val = value[key];
 
                        // 快速判断并处理Infinity,其他值递归克隆
                        cloned[key] = val === Infinity ? Infinity : this._deepCloneWithInfinity(val);
                    }
 
                    return cloned;
                },
 
                _calculateDevicesResult(currentStateArray) {
                    var time = new Date().getTime()
                    // 全局存储所有状态的数据
                    const allData = [];
 
                    // 遍历currentStateArray中的每个状态
                    currentStateArray.forEach(item => {
                        let currentState = item.state
                        // 遍历当前状态的所有装置位置(使用独立状态的网格尺寸,不依赖this.devicesGrid)
                        const gridRows = currentState.devicesGrid.length;
                        if (gridRows === 0) return;
                        const gridCols = currentState.devicesGrid[0].length;
                        // 遍历当前状态的所有装置位置
                        for (let i = 0; i < gridRows; i++) {
                            for (let j = 0; j < gridCols; j++) {
                                const device = currentState.devicesGrid[i][j];
                                // 跳过已耗尽的装置(无需预测点击)
                                if (device.remainingRotationTimes <= 0) continue;
                                // 预测点击后的结果
                                const predictedState = this._predictChainReaction(currentState, i, j);
                                const index = `${i}_${j}`;
 
                                // 汇总数据
                                allData.push({
                                    index: item.index ? `${item.index},${index}` : index,
                                    score: predictedState.score,
                                    zeroCount: predictedState.zeroRotationDevicesCount,
                                    state: predictedState,
                                    parentState: currentState // 保留父状态,便于迭代
                                });
                            }
                        }
                    });
                    return allData;
                },
 
                //  开启辅助,计算当前状态下的最优解
                startAssist() {
                    if (!this.assistEnabled || !this.isDeviceClickable) {
                        this.stopAssist();
                        return;
                    }
                    // 获取当前游戏状态
                    const currentState = {
                        devicesGrid: this.devicesGrid.map((row, r) =>
                            row.map((device, c) => {
                                const deviceRef = this._getDeviceRef(r, c);
                                return {
                                    maxRotationTimes: device.maxRotationTimes,
                                    initRotationAngle: device.initRotationAngle,
                                    currentRotationAngle: deviceRef ? deviceRef
                                        .currentRotationAngle : 0,
                                    remainingRotationTimes: deviceRef ? deviceRef
                                        .remainingRotationTimes : 0,
                                };
                            })
                        ),
                        actionPoints: this.actionPoints,
                        zeroRotationDevicesCount: this.zeroRotationDevicesCount,
                        score: this.operationLog.score
                    };
                    // [{index, score, zeroCount, state}]
                    let mergedAndUnique = this._calculateDevicesResult([{
                        state: currentState
                    }]);
                    if (this.selectedScore)
                        mergedAndUnique.sort((a, b) => b.score === a.score ? b.zeroCount - a.zeroCount : b
                            .score - a
                            .score)
                    else
                        mergedAndUnique.sort((a, b) => b.zeroCount === a.zeroCount ? b.score - a.score : b
                            .zeroCount - a.zeroCount)
                    this.assistPredictStyle = {}
                    if (this.assistPredictGlobal) {
                        // 全局预测
                        const length = mergedAndUnique.length;
                        // 1. 定义5份分级颜色(同色系渐变:蓝→青→黄→橙→红,视觉递进明显)
                        const hueGradeColors = [
                            [255, 107, 107], // 层级1:红色 (#FF6B6B)
                            [255, 209, 102], // 层级2:黄色 (#FFD166)
                            [6, 214, 160], // 层级3:绿色 (#06D6A0)
                            [17, 138, 178], // 层级4:蓝色 (#118AB2)
                            [188, 188, 188] // 层级5:紫色 (#9B5DE5)
                        ];
 
                        mergedAndUnique.forEach((item, index) => {
                            // 2. 计算当前索引的“占总长度比例”(0 ~ 1)
                            const ratio = index / length;
 
                            // 3. 按比例分5级:0~20%→0号色、20%~40%→1号色、…、80%~100%→4号色
                            // Math.min(..., 4) 限制最大等级为4,避免超出颜色数组索引(0~4)
                            const colorIndex = Math.min(Math.floor(ratio * 5), 4);
 
                            // 4. 获取当前分级对应的颜色(解构RGB值)
                            const [r, g, b] = hueGradeColors[colorIndex];
 
                            // 5. 背景色使用分级颜色,透明度可固定(如0.8,确保不完全遮挡下层)
                            this.assistPredictStyle[item.index] = {
                                position: 'absolute',
                                'width': '80%',
                                'height': '80%',
                                'border-radius': '50%',
                                'top': '50%',
                                'left': '50%',
                                'transform': 'translate(-50%, -50%)',
                                'z-index': '-1',
                                'filter': 'blur(0.1rem)',
                                'background': `radial-gradient(circle at center,
                                        rgb(${r}, ${g}, ${b}) 40%,
                                        rgba(${r}, ${g}, ${b}, 0.6) 50%,
                                        rgba(${r}, ${g}, ${b}, 0) 90%)`
                            };
                        });
                    } else {
                        // 非全局预测
                        let color = this.selectedScore ? '19, 206, 102' : '255, 73, 73';
                        mergedAndUnique = mergedAndUnique.slice(0, 20)
                        mergedAndUnique.forEach(item => {
                            this.assistPredictStyle[item.index] = {
                                position: 'absolute',
                                'width': '80%',
                                'height': '80%',
                                'border-radius': '50%',
                                'top': '50%',
                                'left': '50%',
                                'transform': 'translate(-50%, -50%)',
                                'z-index': '-1',
                                'filter': 'blur(0.1rem)',
                                'background': `radial-gradient(circle at center,
                                            rgb(${color}) 40%,
                                            rgba(${color}, 0.6) 50%,
                                            rgba(${color}, 0) 90%)`
                            }
                        })
                    }
                },
 
                stopAssist() {
                    this.assistPredictStyle = {};
                },
                // 9.预测与辅助计算 --end
                /**
                 * 根据星级获取对应分数范围(用于评级结果说明)
                 * @param {number} star - 当前星级
                 * @returns {string} 分数范围文本
                 */
                getStarScoreRange(star) {
                    switch (star) {
                        case 1:
                            return "≤50,000分";
                        case 2:
                            return "50,001 ~ 70,000分";
                        case 3:
                            return "70,001 ~ 100,000分";
                        case 4:
                            return "100,001 ~ 150,000分";
                        case 5:
                            return "150,001 ~ 200,000分";
                        case 10:
                            return ">200,000分(满分评级)";
                        default:
                            return "暂无数据";
                    }
                },
 
                /**
                 * 今日评级核心方法:基于今日种子生成独立网格,通过多轮预测计算最高评级
                 * 逻辑步骤:
                 * 1. 生成今日种子对应的独立二维数组(与现有devicesGrid完全隔离)
                 * 2. 第一轮预测:计算初始网格所有点击位置的结果,筛选前10高分+前10高乘数
                 * 3. 多轮迭代:对第一轮筛选结果中的每个位置,再次预测后续点击结果,累积最优解
                 * 4. 基于最终最优分数匹配评级规则,更新今日评级结果
                 */
                handlePredictStore() {
                    // 禁用重复点击(防止并发计算)
                    if (this.isCalculatingRating) return;
                    this.isCalculatingRating = true;
                    this.predictStoreStar = 0; // 重置评级结果(避免旧数据干扰)
 
                    this.predictProgress = {
                        currentStep: 0,
                        totalSteps: 10, // 总步骤=迭代轮次+初始步骤
                        isActive: true,
                        stepText: "初始化今日网格..."
                    };
 
                    try {
                        // -------------------------- 步骤1:生成今日种子的独立二维数组(与devicesGrid完全隔离) --------------------------
                        let todaySeed = this.getTodaySeed(); // 获取今日种子
                        // 1.1 生成独立的随机二维数组(复用现有随机生成逻辑,但不关联this.devicesGrid)
                        const independentGrid = this._generateRandom2DArray({
                            sizeMin: this.sizeMin,
                            sizeMax: this.sizeMax,
                            infinityProbability: this.infinityProbability,
                            numMin: this.numMin,
                            numMax: this.numMax,
                            seed: todaySeed
                        });
                        // 1.2 为独立网格补充「剩余旋转次数」属性(模拟初始状态,与组件实例隔离)
                        const initialIndependentState = {
                            devicesGrid: independentGrid.map(row =>
                                row.map(device => ({
                                    ...device,
                                    // 初始化剩余旋转次数:无限次为Infinity,有限次为maxRotationTimes
                                    remainingRotationTimes: device.maxRotationTimes ===
                                        Infinity ?
                                        Infinity : device.maxRotationTimes,
                                    // 初始旋转角度与配置一致
                                    currentRotationAngle: device.initRotationAngle
                                }))
                            ),
                            actionPoints: 10, // 初始行动点(与游戏默认一致)
                            zeroRotationDevicesCount: 0, // 初始耗尽装置数(0)
                            score: 0 // 初始分数(0)
                        };
 
                        this.predictProgress.totalSteps = initialIndependentState.actionPoints;
                        this.predictProgress.currentStep += 1;
                        this.predictProgress.stepText =
                            `预测中...(${this.predictProgress.currentStep}/${this.predictProgress.totalSteps})`;
 
                        // 需要截取的数组区间配置
                        // 格式:[start, end, maxCount]
                        // - start/end支持数字(索引)、百分比字符串(如'10%')
                        // - maxCount可选,限制当前区间最多截取的条数(默认无限制)
                        // 例如:[[0, 10], ['10%', '20%', 10]]
                        const numArray = [
                            [0, 5],
                            ['10%', '15%', 1],
                            ['15%', '20%', 1],
                            ['20%', '25%', 1],
                            ['25%', '30%', 1],
                            ['30%', '35%', 1],
                            ['35%', '40%', 1],
                            ['40%', '45%', 1],
                            ['45%', '50%', 1],
                            ['50%', '55%', 1],
                            ['55%', '60%', 1],
                        ];
 
                        // 按numArray区间截取数组的工具函数(支持百分比、负索引和数量限制)
                        const spliceNumArrayFunc = (numArray, array) => {
                            const len = array.length;
                            return numArray.flatMap(([start, end, maxCount]) => {
                                // 1. 转换start为索引(支持百分比和负索引)
                                let safeStart;
                                if (typeof start === 'string' && start.endsWith('%')) {
                                    // 百分比转换:'10%' -> 0.1 * 数组长度(向下取整)
                                    safeStart = Math.floor(len * (parseFloat(start) / 100));
                                } else {
                                    // 数字索引(支持负索引)
                                    safeStart = start < 0 ? len + start : start;
                                }
 
                                // 2. 转换end为索引(支持百分比和负索引)
                                let safeEnd;
                                if (typeof end === 'string' && end.endsWith('%')) {
                                    // 百分比转换:'20%' -> 0.2 * 数组长度(向下取整)
                                    safeEnd = Math.floor(len * (parseFloat(end) / 100));
                                } else {
                                    // 数字索引(负索引end需要+1,例如-1表示最后一个元素)
                                    safeEnd = end < 0 ? len + end + 1 : end;
                                }
 
                                // 3. 确保索引在有效范围内
                                const finalStart = Math.max(0, safeStart);
                                let finalEnd = Math.min(len, safeEnd);
 
                                // 4. 应用maxCount限制(如果设置了最大数量)
                                if (maxCount !== undefined) {
                                    const currentLength = finalEnd - finalStart;
                                    if (currentLength > maxCount) {
                                        finalEnd = finalStart + maxCount; // 超出时截断到maxCount
                                    }
                                }
 
                                // 5. 处理start >= end的情况(返回空数组)
                                if (finalStart >= finalEnd) return [];
 
                                return array.slice(finalStart, finalEnd);
                            });
                        };
                        setTimeout(() => {
                            // -------------------------- 步骤2:第一轮预测:筛选初始网格的指定区间高分+指定区间高乘数 --------------------------
                            // 2.1 计算初始网格所有点击位置的结果(调用_calculateDevicesResult,传入独立状态)
                            const firstRoundAllResults = this._calculateDevicesResult([{
                                    state: initialIndependentState,
                                    index: ''
                                } // index空字符串:标记初始状态
                            ]);
 
                            // 2.2 筛选规则1:按分数降序,取numArray指定区间的结果(高分优先)
                            const sortedByScore = [...firstRoundAllResults].sort((a, b) => b.score - a
                                .score);
                            const topNumByScore = spliceNumArrayFunc(numArray, sortedByScore);
 
                            const sortedByMultiplier = sortedByScore.sort((a, b) => b.zeroCount - a
                                .zeroCount);
                            const topNumByMultiplier = spliceNumArrayFunc(numArray, sortedByMultiplier);
 
                            // 2.4 第一轮筛选结果:合并指定区间高分+指定区间高乘数,去重(避免同一位置重复进入迭代)
                            const firstRoundFiltered = Array.from(
                                new Map([...topNumByScore, ...topNumByMultiplier].map(item => [item
                                    .index, item
                                ])).values()
                            );
 
                            // -------------------------- 步骤3:多轮迭代预测:基于第一轮结果,递归计算后续最优点击 --------------------------
                            // 3.1 定义迭代函数:接收当前状态数组,返回下一轮预测结果
                            const iteratePredict = (currentStateArray) => {
                                let nextRoundResults = [];
                                // 遍历当前状态数组中的每个状态
                                currentStateArray.forEach(stateItem => {
                                    // 计算当前状态下所有点击位置的结果
                                    const currentRoundResults = this
                                        ._calculateDevicesResult([stateItem]);
                                    // 筛选规则:指定区间高分 + 指定区间高乘数(与第一轮一致)
                                    const sortedByScore = [...currentRoundResults].sort((a,
                                        b) => b.score - a.score);
                                    const topNumScore = spliceNumArrayFunc(numArray,
                                        sortedByScore);
                                    const sortedByMulti = sortedByScore.sort((a, b) => b
                                        .zeroCount - a.zeroCount);
                                    const topNumMulti = spliceNumArrayFunc(numArray,
                                        sortedByMulti);
 
                                    // 合并当前状态的筛选结果,补充「父级索引」(便于追溯点击路径)
                                    const merged = [...topNumScore, ...topNumMulti].map(
                                        item => ({
                                            ...item
                                        }));
                                    nextRoundResults = [...nextRoundResults, ...merged];
                                });
                                // 去重:避免同一状态+同一位置的重复计算
                                const currentRoundResults = Array.from(
                                    new Map(nextRoundResults.map(item => [`${item.index}`,
                                        item
                                    ])).values()
                                );
                                // 再次筛选
                                const sortedByScore = [...currentRoundResults].sort((a, b) => b
                                    .score - a.score);
                                const topNumScore = spliceNumArrayFunc(numArray, sortedByScore);
                                const sortedByMulti = sortedByScore.sort((a, b) => b.zeroCount - a
                                    .zeroCount);
                                const topNumMulti = spliceNumArrayFunc(numArray, sortedByMulti);
 
                                // 合并当前状态的筛选结果,补充「父级索引」(便于追溯点击路径)
                                const merged = [...topNumScore, ...topNumMulti].map(item => ({
                                    ...item
                                }));
                                return merged;
                            };
 
                            // 3.2 执行多轮迭代
                            let currentIterationStates = firstRoundFiltered; // 初始迭代状态:第一轮筛选结果
                            let iterationRounds = initialIndependentState
                                .actionPoints; // 迭代轮次(建议3-5轮,平衡精准度与性能)
                            let currentRound = 1; // 当前迭代轮次(从1开始,与原逻辑一致)
 
                            // 异步迭代函数
                            const asyncIterate = () => {
                                if (currentRound >= iterationRounds) {
                                    // 迭代结束,执行步骤4(计算最终分数)
                                    calculateFinalScore();
                                    return;
                                }
 
                                // 1. 执行本轮迭代计算
                                currentIterationStates = iteratePredict(currentIterationStates);
 
                                // 2. 更新进度条(此时主线程空闲,Vue 能实时渲染)
                                this.predictProgress.currentStep += 1;
                                this.predictProgress.stepText =
                                    `预测中...(${this.predictProgress.currentStep}/${this.predictProgress.totalSteps})`;
 
                                // 3. 延迟 0ms 执行下一轮(让出主线程,允许浏览器重绘)
                                currentRound += 1;
                                setTimeout(asyncIterate, 0);
                            };
 
                            // 新增:计算最终分数的独立函数(迭代结束后执行)
                            const calculateFinalScore = () => {
                                const allResults = currentIterationStates;
                                allResults.sort((a, b) => b.score - a.score);
                                const maxScore = allResults[0] ? allResults[0].score : 0;
                                const maxScorePath = allResults[0] ? allResults[0].index : '';
 
                                // 匹配评级规则
                                if (maxScore > 200000) {
                                    this.predictStoreStar = 10; // 满分评级
                                } else if (maxScore > 150000) {
                                    this.predictStoreStar = 5;
                                } else if (maxScore > 100000) {
                                    this.predictStoreStar = 4;
                                } else if (maxScore > 70000) {
                                    this.predictStoreStar = 3;
                                } else if (maxScore > 50000) {
                                    this.predictStoreStar = 2;
                                } else if (maxScore > 0) {
                                    this.predictStoreStar = 1;
                                } else {
                                    this.predictStoreStar = 0; // 无有效分数(异常情况)
                                }
 
                                // 进度条更新为 100%
                                this.predictProgress.currentStep = this.predictProgress.totalSteps;
                                this.predictProgress.stepText =
                                    `计算完成(${this.predictProgress.totalSteps}/${this.predictProgress.totalSteps})`;
                            };
 
                            // 启动异步迭代
                            asyncIterate();
                        }, 0)
                    } catch (error) {
                        // 异常处理:避免计算失败导致界面卡死
                        alert('评级计算出错,请稍后重试');
                        this.predictStoreStar = 0;
                    } finally {
                        // 恢复点击状态(无论成功/失败,都允许再次点击)
                        this.isCalculatingRating = false;
                    }
                },
            }
        });
    </script>
</body>
 
</html>
除非特别注明,本页内容采用以下授权方式: Creative Commons Attribution-ShareAlike 3.0 License