"use strict"; const common_vendor = require("../../common/vendor.js"); const tongji_endlessGame_composables_useGameSfx = require("./composables/useGameSfx.js"); const tongji_endlessGame_composables_useGamePlatform = require("./composables/useGamePlatform.js"); const tongji_endlessGame_composables_useGameAuth = require("./composables/useGameAuth.js"); if (!Math) { TongjiIcon(); } const TongjiIcon = () => "../components/TongjiIcon.js"; const FOOD_IMAGE_BASE_URL = "https://gz-1349751149.cos.ap-guangzhou.myqcloud.com/games/food/"; const ROWS = 5; const COLS = 4; const GAME_DIFFICULTY = 5; const HIGH_CAP = 3; const MAX_CAMEL_COUNT = 5; const OVERFLOW_CAMEL_SCORE = 100; const MAX_CASCADE_WAVES = 3; const COMBO_TASK_WAVE = 2; const COMBO_TASK_TARGET = 2; const COMBO_PITY_TURNS = 6; const MEGA_COMBO_SCORE = 300; const _sfc_main = { __name: "index", setup(__props) { const DANGER_DROP_CHANCE = 0.05 + GAME_DIFFICULTY * 0.01; const COLUMN_GROUP_BIAS = 0.86 - GAME_DIFFICULTY * 0.028; const CHEER_MESSAGES = [ { source: "同行鼓励", text: "你需要加油哦!再向前一点,就能超过上一名。", tone: "warm" }, { source: "同行鼓励", text: "你太棒了!今天也在认真认识食物。", tone: "bright" }, { source: "开心鼓励", text: "你肯定是个大美女(大帅哥)!保持好心情。", tone: "bright" }, { source: "亲友留言示例", text: "游戏虽好,可不要贪吃哦!", tone: "family" }, { source: "亲友留言示例", text: "差不多行了,赶快洗洗睡吧!", tone: "family" }, { source: "亲友留言示例", text: "你太努力了,你是我的榜样!", tone: "warm" }, { source: "亲友留言示例", text: "好样的!", tone: "bright" }, { source: "亲友自定义留言示例", text: "我血糖已经正常了,你们玩吧。", tone: "family", userGenerated: true } ]; const FOODS = { corn: { name: "玉米", short: "玉米", emoji: "🌽", color: "yellow", level: "mid", levelLabel: "中糖" }, egg: { name: "鸡蛋", short: "鸡蛋", emoji: "🥚", color: "cream", level: "low", levelLabel: "低糖" }, tomato: { name: "番茄", short: "番茄", emoji: "🍅", color: "red", level: "low", levelLabel: "低糖" }, potato: { name: "红薯", short: "红薯", emoji: "🍠", color: "purple", level: "mid", levelLabel: "中糖" }, cucumber: { name: "黄瓜", short: "黄瓜", emoji: "🥒", color: "yellow", level: "low", levelLabel: "低糖" }, lettuce: { name: "生菜", short: "生菜", emoji: "🥬", color: "cream", level: "low", levelLabel: "低糖" }, grainMantou: { name: "杂粮馒头", short: "杂粮馒头", emoji: "🫓", color: "red", level: "mid", levelLabel: "中糖" }, wonton: { name: "馄饨", short: "馄饨", emoji: "🥟", color: "purple", level: "mid", levelLabel: "中糖" }, celery: { name: "芹菜", short: "芹菜", emoji: "🌿", color: "yellow", level: "low", levelLabel: "低糖" }, mushroom: { name: "香菇", short: "香菇", emoji: "🍄", color: "cream", level: "low", levelLabel: "低糖" }, chicken: { name: "鸡肉", short: "鸡肉", emoji: "🍗", color: "red", level: "mid", levelLabel: "中糖" }, taro: { name: "芋头", short: "芋头", emoji: "🥔", color: "purple", level: "mid", levelLabel: "中糖" }, broccoli: { name: "西兰花", short: "西兰花", emoji: "🥦", color: "yellow", level: "low", levelLabel: "低糖" }, milk: { name: "牛奶", short: "牛奶", emoji: "🥛", color: "cream", level: "low", levelLabel: "低糖" }, brownRice: { name: "糙米饭", short: "糙米饭", emoji: "🍙", color: "red", level: "mid", levelLabel: "中糖" }, apple: { name: "苹果", short: "苹果", emoji: "🍎", color: "yellow", level: "low", levelLabel: "低糖" }, strawberry: { name: "草莓", short: "草莓", emoji: "🍓", color: "cream", level: "low", levelLabel: "低糖" }, banana: { name: "香蕉", short: "香蕉", emoji: "🍌", color: "red", level: "mid", levelLabel: "中糖" }, mango: { name: "芒果", short: "芒果", emoji: "🥭", color: "purple", level: "mid", levelLabel: "中糖" }, tea: { name: "红茶", short: "红茶", emoji: "🍵", color: "yellow", level: "low", levelLabel: "低糖" }, blackCoffee: { name: "黑咖啡", short: "黑咖啡", emoji: "☕", color: "cream", level: "low", levelLabel: "低糖" }, coffee: { name: "咖啡", short: "咖啡", emoji: "☕", color: "red", level: "mid", levelLabel: "中糖" }, pineapple: { name: "菠萝", short: "菠萝", emoji: "🍍", color: "purple", level: "mid", levelLabel: "中糖" }, pepper: { name: "青椒", short: "青椒", emoji: "🫑", color: "yellow", level: "low", levelLabel: "低糖" }, greenBean: { name: "四季豆", short: "四季豆", emoji: "🫛", color: "cream", level: "low", levelLabel: "低糖" }, shrimp: { name: "虾仁", short: "虾仁", emoji: "🦐", color: "red", level: "mid", levelLabel: "中糖" }, udon: { name: "乌冬面", short: "乌冬面", emoji: "🍲", color: "purple", level: "mid", levelLabel: "中糖" }, onion: { name: "洋葱", short: "洋葱", emoji: "🧅", color: "yellow", level: "low", levelLabel: "低糖" }, congee: { name: "白米粥", short: "白粥", emoji: "🥣", color: "orange", level: "high", levelLabel: "高糖", high: true, replaceable: true, tip: "白米粥煮得软烂,消化吸收通常较快。糖尿病患者应结合食用量、搭配和个人血糖情况,在医生或营养师指导下合理选择。" }, eightCongee: { name: "八宝粥", short: "八宝粥", emoji: "🥣", color: "orange", level: "high", levelLabel: "高糖", high: true, replaceable: true, tip: "八宝粥常含糯米、豆类或添加糖,实际影响与配方和食用量有关,请留意营养成分。" }, centuryCongee: { name: "皮蛋瘦肉粥", short: "瘦肉粥", emoji: "🥣", color: "orange", level: "high", levelLabel: "高糖", high: true, replaceable: true, tip: "粥类煮得软烂后通常吸收较快,搭配和食用量需要结合个人情况。" }, milletCongee: { name: "小米粥", short: "小米粥", emoji: "🥣", color: "orange", level: "high", levelLabel: "高糖", high: true, replaceable: true, tip: "小米粥的升糖影响与浓稠度和食用量有关,游戏等级需由医生最终审核。" }, orangeJuice: { name: "柳橙汁", short: "橙汁", emoji: "🧃", color: "orange", level: "high", levelLabel: "高糖", high: true, replaceable: true, tip: "果汁缺少完整水果的部分膳食纤维,饮用量和是否添加糖都需要注意。" }, soda: { name: "含糖汽水", short: "汽水", emoji: "🥤", color: "orange", level: "high", levelLabel: "高糖", high: true, replaceable: true, tip: "含糖饮料中的糖吸收较快,日常应优先选择不加糖的饮品。" }, riceNoodleSoup: { name: "汤粉", short: "汤粉", emoji: "🍜", color: "orange", level: "high", levelLabel: "高糖", high: true, replaceable: true, tip: "汤粉以精制米粉为主,实际影响与分量和配菜有关,应注意搭配。" }, noodleSoup: { name: "汤面", short: "汤面", emoji: "🍜", color: "orange", level: "high", levelLabel: "高糖", high: true, replaceable: true, tip: "汤面以精细面食为主,汤汁和分量需要注意,具体建议以医生审核为准。" }, milkTea: { name: "含糖奶茶", short: "奶茶", emoji: "🧋", color: "orange", level: "high", levelLabel: "高糖", high: true, replaceable: true, tip: "含糖奶茶可能同时含有较多添加糖和能量,应关注配方与饮用量。" }, camel: { name: "驼乳", short: "驼乳", emoji: "🥛", color: "milk", level: "prop", levelLabel: "道具", product: true } }; Object.keys(FOODS).forEach((key) => { FOODS[key].img = `${FOOD_IMAGE_BASE_URL}${key}.jpg`; }); const FOOD_GROUPS = [ { title: "中式早餐", safe: ["egg", "cucumber", "corn", "grainMantou"], danger: "congee" }, { title: "家常粥餐", safe: ["celery", "mushroom", "chicken", "taro"], danger: "centuryCongee" }, { title: "粗粮早餐", safe: ["broccoli", "milk", "brownRice", "potato"], danger: "milletCongee" }, { title: "水果饮品", safe: ["apple", "strawberry", "banana", "mango"], danger: "orangeJuice" }, { title: "日常饮品", safe: ["milk", "tea", "blackCoffee", "coffee"], danger: "soda" }, { title: "南方汤粉", safe: ["pepper", "greenBean", "shrimp", "udon"], danger: "riceNoodleSoup" }, { title: "北方面食", safe: ["onion", "celery", "corn", "grainMantou"], danger: "noodleSoup" } ]; const { enabled: sfxEnabled, play: playSfx, playLayer: playSfxLayer, playDrop: playDropSfx, warmUp: warmUpSfx } = tongji_endlessGame_composables_useGameSfx.useGameSfx(); const { proxy } = common_vendor.getCurrentInstance(); const { ensureLoggedIn } = tongji_endlessGame_composables_useGameAuth.useGameAuth(proxy); const { connected: platformConnected, loading: platformLoading, syncStatus: platformSyncStatus, leaderboard: platformLeaderboard, confirmedSessionLearned, connect: connectPlatform, beginSession: beginPlatformSession, queueProgress: queuePlatformProgress, flushProgress: flushPlatformProgress, syncAndRefresh: syncAndRefreshPlatform, recordShare: recordPlatformShare, dispose: disposePlatform } = tongji_endlessGame_composables_useGamePlatform.useGamePlatform(proxy, ensureLoggedIn); const board = common_vendor.ref([]); const selected = common_vendor.ref(-1); const score = common_vendor.ref(0); const bestScore = common_vendor.ref(0); const learned = common_vendor.ref(0); const combo = common_vendor.ref(0); const feastMoves = common_vendor.ref(0); const camelCount = common_vendor.ref(3); const camelMode = common_vendor.ref(false); const busy = common_vendor.ref(false); const gameOver = common_vendor.ref(false); const themeIndex = common_vendor.ref(0); const endedFood = common_vendor.ref(FOODS.congee); const taskIndex = common_vendor.ref(0); const taskProgress = common_vendor.ref(0); const comboDryTurns = common_vendor.ref(0); const taskRewardVisible = common_vendor.ref(false); const taskRewardKey = common_vendor.ref(0); const statusText = common_vendor.ref("交换相邻食物,三个相同即可消除"); const navStyle = common_vendor.ref({ paddingTop: "20px" }); const touch = { x: 0, y: 0, index: -1 }; const dragIndex = common_vendor.ref(-1); const dragTarget = common_vendor.ref(-1); const dragX = common_vendor.ref(0); const dragY = common_vendor.ref(0); const clearingIndices = common_vendor.ref([]); const fireClearingIndices = common_vendor.ref([]); const impactText = common_vendor.ref(""); const impactLevel = common_vendor.ref(1); const camelJackpot = common_vendor.ref({ visible: false, count: 0, kicker: "", title: "", reward: "" }); const stageVisible = common_vendor.ref(false); const stageMeta = common_vendor.ref({ number: 1, title: "", foods: [] }); const reshuffleVisible = common_vendor.ref(false); const reshuffleDone = common_vendor.ref(false); const reshuffling = common_vendor.ref(false); const confettiVisible = common_vendor.ref(false); const weeklyRankVisible = common_vendor.ref(false); const cheerIndex = common_vendor.ref(0); const CONFETTI_COLORS = ["#ff3154", "#ffd928", "#28c76f", "#4d8dff", "#a855f7", "#ff7a1a"]; const confettiPieces = Array.from({ length: 34 }, (_, index) => ({ id: index, emoji: index % 8 === 0 ? "🎉" : index % 11 === 0 ? "★" : "", style: { left: `${(index * 37 + 7) % 100}%`, backgroundColor: index % 8 === 0 ? "transparent" : CONFETTI_COLORS[index % CONFETTI_COLORS.length], animationDelay: `${index % 9 * 0.065}s`, animationDuration: `${3.7 + index % 5 * 0.36}s`, width: `${12 + index % 3 * 5}rpx`, height: `${22 + index % 4 * 6}rpx` } })); let suppressTapUntil = 0; let tileId = 1; let hintTimer = null; let jackpotTimer = null; let confettiTimer = null; let stageTimer = null; let taskRewardTimer = null; let pendingThemeMatchCount = 0; let taskRewardStatusUntil = 0; let sfxGesturePrimed = false; let incomingInviteCode = ""; const currentTheme = common_vendor.computed(() => FOOD_GROUPS[themeIndex.value % FOOD_GROUPS.length]); const currentTask = common_vendor.computed(() => { const safe = currentTheme.value.safe; const templates = [ { key: safe[0], label: `消除 7 个${foodOf(safe[0]).short}`, target: 7, kind: "food" }, { key: "special", label: "制造 1 个惊喜棋子", target: 1, kind: "special" }, { key: "combo", label: "完成连消 ×2", target: COMBO_TASK_TARGET, kind: "combo" }, { key: safe[1], label: `消除 8 个${foodOf(safe[1]).short}`, target: 8, kind: "food" } ]; return templates[taskIndex.value % templates.length]; }); const taskPercent = common_vendor.computed(() => Math.min(100, taskProgress.value / currentTask.value.target * 100)); const highCount = common_vendor.computed(() => board.value.filter((tile) => tile && foodOf(tile.key).high).length); const boardRows = common_vendor.computed(() => Array.from({ length: ROWS }, (_, row) => board.value.slice(row * COLS, row * COLS + COLS).map((tile, col) => ({ ...tile, index: row * COLS + col })))); const pendingWeeklyLearned = common_vendor.computed(() => Math.max(0, learned.value - confirmedSessionLearned.value)); const weeklyMyCount = common_vendor.computed(() => { var _a; return Number(((_a = platformLeaderboard.value.me) == null ? void 0 : _a.count) || 0) + pendingWeeklyLearned.value; }); const weeklyRankRows = common_vendor.computed(() => { const remote = Array.isArray(platformLeaderboard.value.players) ? platformLeaderboard.value.players : []; const userData = common_vendor.index.getStorageSync("userData") || {}; const fallbackName = String(userData.nickname || "我"); const source = remote.length ? remote.map((player, index) => ({ ...player, isMe: !!(player.is_me || player.isMe), avatarUrl: player.avatar || "", avatar: String(player.name || "同行").slice(0, 1), tone: index % 7 + 1, count: player.is_me || player.isMe ? weeklyMyCount.value : Number(player.count || 0) })) : [{ id: "local-me", name: fallbackName, avatar: fallbackName.slice(0, 1) || "我", avatarUrl: userData.avatar || "", count: weeklyMyCount.value, tone: 1, isMe: true }]; return source.sort((a, b) => b.count - a.count || Number(b.best_score || 0) - Number(a.best_score || 0)).map((player, index) => ({ ...player, rank: index + 1 })); }); const weeklyMyRank = common_vendor.computed(() => { var _a; return ((_a = weeklyRankRows.value.find((player) => player.isMe)) == null ? void 0 : _a.rank) || 1; }); const weeklyRankRise = common_vendor.computed(() => 0); const weeklyIsFirst = common_vendor.computed(() => weeklyMyRank.value === 1); const weeklyDistance = common_vendor.computed(() => { const mineIndex = weeklyRankRows.value.findIndex((player) => player.isMe); if (mineIndex <= 0) return 0; return Math.max(1, weeklyRankRows.value[mineIndex - 1].count - weeklyMyCount.value + 1); }); const currentCheer = common_vendor.computed(() => CHEER_MESSAGES[cheerIndex.value % CHEER_MESSAGES.length]); const weeklyRangeLabel = common_vendor.computed(() => { const start = platformLeaderboard.value.week_start; const end = platformLeaderboard.value.week_end; if (!start || !end) return getWeekRangeLabel(/* @__PURE__ */ new Date()); return `${formatWeekDate(start)}—${formatWeekDate(end)}`; }); const weeklySexLabel = common_vendor.computed(() => platformLeaderboard.value.sex_label || "同行"); const weeklyMemberCount = common_vendor.computed(() => Math.max(1, Number(platformLeaderboard.value.member_count || weeklyRankRows.value.length))); const weeklyStatusLabel = common_vendor.computed(() => { if (platformLoading.value) return "连接中"; if (!platformConnected.value) return "离线记录中"; if (platformSyncStatus.value === "pending" || platformSyncStatus.value === "syncing") return "保存中"; return "真实周榜"; }); common_vendor.onShareAppMessage(() => { recordPlatformShare(); return { title: gameShareTitle(), path: gameSharePath() }; }); common_vendor.onShareTimeline(() => { recordPlatformShare(); const inviteCode = String(platformLeaderboard.value.invite_code || ""); return { title: gameShareTitle(), query: inviteCode ? `from=share&invite_code=${encodeURIComponent(inviteCode)}` : "from=share" }; }); function initNavLayout() { var _a; let paddingTop = 20; let paddingRight = common_vendor.index.upx2px(28); try { const info = common_vendor.index.getSystemInfoSync(); paddingTop = Number(((_a = info.safeAreaInsets) == null ? void 0 : _a.top) || info.statusBarHeight) || 20; const menu = typeof common_vendor.index.getMenuButtonBoundingClientRect === "function" ? common_vendor.index.getMenuButtonBoundingClientRect() : null; if (menu && menu.width > 0) { paddingTop = Math.max(paddingTop, Number(menu.top) || 0); paddingRight = Math.max( paddingRight, (Number(info.windowWidth) || 0) - Number(menu.left) + common_vendor.index.upx2px(8) ); } } catch (_) { } navStyle.value = { paddingTop: `${paddingTop}px`, paddingRight: `${paddingRight}px` }; } common_vendor.onLoad((options = {}) => { initNavLayout(); bestScore.value = Number(common_vendor.index.getStorageSync("tongji_endless_best") || 0); incomingInviteCode = String(options.invite_code || "").trim(); startGame(); weeklyRankVisible.value = true; connectPlatform(incomingInviteCode); }); common_vendor.onShow(() => { connectPlatform(incomingInviteCode).then((ok) => { if (ok) flushPlatformProgress(); }); }); common_vendor.onUnload(() => { if (learned.value > 0 || gameOver.value) { queuePlatformProgress(learned.value, score.value, gameOver.value); flushPlatformProgress(); } disposePlatform(); if (hintTimer) clearTimeout(hintTimer); if (jackpotTimer) clearTimeout(jackpotTimer); if (confettiTimer) clearTimeout(confettiTimer); if (stageTimer) clearTimeout(stageTimer); if (taskRewardTimer) clearTimeout(taskRewardTimer); }); function makeTile(key, special = "") { return { id: tileId++, key, special }; } function foodOf(key) { return FOODS[key] || FOODS.corn; } function getWeekRangeLabel(now) { const date = new Date(now); const day = date.getDay() || 7; const monday = new Date(date); monday.setDate(date.getDate() - day + 1); const sunday = new Date(monday); sunday.setDate(monday.getDate() + 6); const label = (value) => `${value.getMonth() + 1}月${value.getDate()}日`; return `${label(monday)}—${label(sunday)}`; } function formatWeekDate(value) { const parts = String(value).split("-").map(Number); if (parts.length !== 3) return String(value); return `${parts[1]}月${parts[2]}日`; } function gameShareTitle() { if (learned.value > 0) { return `我在识糖小课堂认识了${learned.value}份食物,一起来挑战吧`; } return "识糖小课堂:边玩边认识常见食物"; } function gameSharePath() { const inviteCode = String(platformLeaderboard.value.invite_code || ""); const query = inviteCode ? `?from=share&invite_code=${encodeURIComponent(inviteCode)}` : "?from=share"; return `/tongji/endless-game/index${query}`; } function openWeeklyRank() { primeSfxFromGesture(); if (gameOver.value) return; if (busy.value || reshuffling.value || stageVisible.value || camelJackpot.value.visible) { statusText.value = "本次消除完成后即可查看同行榜"; return; } weeklyRankVisible.value = true; syncAndRefreshPlatform(learned.value, score.value); playSfx("select", 0.72); } function closeWeeklyRank() { primeSfxFromGesture(); weeklyRankVisible.value = false; playSfx("select", 0.86); scheduleHint(); } function cycleCheer() { primeSfxFromGesture(); cheerIndex.value = (cheerIndex.value + 1) % CHEER_MESSAGES.length; playSfx("select", 0.68); } function startGame() { if (hintTimer) clearTimeout(hintTimer); beginPlatformSession(); themeIndex.value = 0; board.value = buildPlayableBoard(openingKeysForTheme(currentTheme.value)); selected.value = -1; score.value = 0; learned.value = 0; combo.value = 0; feastMoves.value = 0; camelCount.value = 3; camelMode.value = false; busy.value = false; gameOver.value = false; taskIndex.value = 0; taskProgress.value = 0; comboDryTurns.value = 0; taskRewardVisible.value = false; clearingIndices.value = []; fireClearingIndices.value = []; impactText.value = ""; camelJackpot.value.visible = false; stageVisible.value = false; reshuffleVisible.value = false; reshuffleDone.value = false; reshuffling.value = false; confettiVisible.value = false; pendingThemeMatchCount = 0; taskRewardStatusUntil = 0; resetDrag(); statusText.value = "交换相邻食物,三个相同即可消除"; scheduleHint(); } function goBack() { const pages = getCurrentPages(); if (pages.length > 1) { common_vendor.index.navigateBack({ delta: 1, fail: () => common_vendor.index.redirectTo({ url: "/tongji/pages/weekly" }) }); return; } common_vendor.index.redirectTo({ url: "/tongji/pages/weekly" }); } function showRules() { common_vendor.index.showModal({ title: "玩法说明", content: `当前难度:${GAME_DIFFICULTY}/10 交换相邻食物,三个相同即可消除。四连、直线五连会生成火焰惊喜棋子;横向三个与竖向三个相交的 L/T 形五消,会生成范围爆破棋子,再次消除可清除周围九格。连消×2会计入连消小目标,连续普通消除后会出现一次连消机会;连消×3可获得额外惊喜奖励。完成小目标直接获得 1 罐驼乳粉;驼乳粉可替换本组指定稀食或饮品,三个驼乳连消后进入下一组食品。主动三消“高糖”食物代表吃掉,会结束本局;火焰特效波及高糖食物代表将它移出餐盘,不算吃掉。没有可走步时会自动洗牌。`, showCancel: false, confirmText: "知道了" }); } function toggleSfx() { sfxEnabled.value = !sfxEnabled.value; try { common_vendor.index.setStorageSync("tongji_game_sfx_enabled", sfxEnabled.value ? "1" : "0"); } catch (_) { } if (sfxEnabled.value) { primeSfxFromGesture(); playSfx("select", 0.8); } common_vendor.index.showToast({ title: sfxEnabled.value ? "音效已开启" : "音效已关闭", icon: "none" }); } function primeSfxFromGesture() { if (sfxGesturePrimed || !sfxEnabled.value) return; sfxGesturePrimed = true; warmUpSfx(); } function cellClasses(tile) { const food = foodOf(tile.key); return [ `is-${food.color}`, `is-level-${food.level}`, { "is-selected": selected.value === tile.index, "is-high": food.high, "is-camel-target": camelMode.value && food.replaceable, "is-clearing": clearingIndices.value.includes(tile.index), "is-fire-clearing": fireClearingIndices.value.includes(tile.index), "is-dragging": dragIndex.value === tile.index || dragTarget.value === tile.index } ]; } function cellMotionStyle(index) { if (dragIndex.value === index) return { transform: `translate(${dragX.value}px, ${dragY.value}px) scale(1.05)`, zIndex: 6 }; if (dragTarget.value === index) return { transform: `translate(${-dragX.value * 0.72}px, ${-dragY.value * 0.72}px) scale(.96)`, zIndex: 4 }; return {}; } function touchStart(event, index) { var _a; primeSfxFromGesture(); const point = (_a = event.touches) == null ? void 0 : _a[0]; if (!point) return; touch.x = point.clientX; touch.y = point.clientY; touch.index = index; dragIndex.value = index; dragTarget.value = -1; dragX.value = 0; dragY.value = 0; } function touchMove(event, index) { var _a; const point = (_a = event.touches) == null ? void 0 : _a[0]; if (!point || touch.index !== index || busy.value) return; const rawX = point.clientX - touch.x; const rawY = point.clientY - touch.y; const horizontal = Math.abs(rawX) > Math.abs(rawY); dragX.value = horizontal ? Math.max(-82, Math.min(82, rawX)) : 0; dragY.value = horizontal ? 0 : Math.max(-82, Math.min(82, rawY)); let target = index; if (horizontal && Math.abs(rawX) > 10) target += rawX > 0 ? 1 : -1; if (!horizontal && Math.abs(rawY) > 10) target += rawY > 0 ? COLS : -COLS; dragTarget.value = target >= 0 && target < ROWS * COLS && isAdjacent(index, target) ? target : -1; } async function touchEnd(event, index) { var _a; const point = (_a = event.changedTouches) == null ? void 0 : _a[0]; if (!point || touch.index !== index) { resetDrag(); return; } const dx = point.clientX - touch.x; const dy = point.clientY - touch.y; if (Math.max(Math.abs(dx), Math.abs(dy)) < 32) { resetDrag(); return; } let target = index; if (Math.abs(dx) > Math.abs(dy)) target += dx > 0 ? 1 : -1; else target += dy > 0 ? COLS : -COLS; suppressTapUntil = Date.now() + 350; if (target >= 0 && target < ROWS * COLS && isAdjacent(index, target)) { const horizontal = Math.abs(dx) > Math.abs(dy); dragX.value = horizontal ? dx > 0 ? 78 : -78 : 0; dragY.value = horizontal ? 0 : dy > 0 ? 78 : -78; dragTarget.value = target; playSfx("swap", 0.85); await wait(85); resetDrag(); trySwap(index, target, true); } else { resetDrag(); playSfx("swapFail", 0.65); } } function resetDrag() { dragIndex.value = -1; dragTarget.value = -1; dragX.value = 0; dragY.value = 0; } async function tapTile(index) { primeSfxFromGesture(); if (Date.now() < suppressTapUntil) return; if (busy.value || gameOver.value) return; const tile = board.value[index]; if (camelMode.value) { if (!foodOf(tile.key).replaceable) { statusText.value = `本组驼乳粉用于替换${foodOf(currentTheme.value.danger).short}`; return; } board.value[index] = makeTile("camel"); board.value = [...board.value]; camelCount.value -= 1; camelMode.value = false; selected.value = -1; playSfxLayer("insulin", "sparkle", 55, 0.5); vibrate("light"); const groups = findMatches(board.value); if (groups.length) { busy.value = true; statusText.value = "驼乳棋子连起来了!"; await resolveMatches(groups, index); busy.value = false; finishTurn(); } else { statusText.value = `已将${foodOf(currentTheme.value.danger).short}移出餐盘,凑齐三个驼乳可换主题`; if (!checkBoardHealth()) scheduleHint(); } return; } if (selected.value < 0) { selected.value = index; playSfx("select", 0.75); statusText.value = "再选择一个相邻食物进行交换"; return; } if (selected.value === index) { selected.value = -1; playSfx("deselect", 0.65); return; } if (!isAdjacent(selected.value, index)) { selected.value = index; statusText.value = "只能交换上下左右相邻的食物"; return; } const from = selected.value; selected.value = -1; trySwap(from, index); } function toggleCamel() { primeSfxFromGesture(); if (busy.value || camelCount.value <= 0 || gameOver.value) return; camelMode.value = !camelMode.value; selected.value = -1; statusText.value = camelMode.value ? `请选择橙色边框的${foodOf(currentTheme.value.danger).short}进行替换` : "已取消使用驼乳粉"; } function isAdjacent(a, b) { const ar = Math.floor(a / COLS); const ac = a % COLS; const br = Math.floor(b / COLS); const bc = b % COLS; return Math.abs(ar - br) + Math.abs(ac - bc) === 1; } async function trySwap(a, b, soundPlayed = false) { if (busy.value || gameOver.value) return; busy.value = true; if (!soundPlayed) playSfx("swap", 0.85); swap(a, b); await wait(130); const groups = findMatches(board.value); if (!groups.length) { swap(a, b); playSfx("swapFail", 0.8); vibrate("light"); statusText.value = "这一步没有形成三连,再试一次"; busy.value = false; if (!checkBoardHealth()) scheduleHint(); return; } const directIndices = new Set(groups.flatMap((group) => group.indices)); const highTile = [...directIndices].map((i) => board.value[i]).find((tile) => foodOf(tile.key).high); if (highTile) { playSfx("lose", 0.9); vibrate("heavy"); endedFood.value = foodOf(highTile.key); saveBest(); gameOver.value = true; queuePlatformProgress(learned.value, score.value, true); busy.value = false; return; } await resolveMatches(groups, b); busy.value = false; if (!gameOver.value) finishTurn(); } function swap(a, b) { const next = [...board.value]; [next[a], next[b]] = [next[b], next[a]]; board.value = next; } async function resolveMatches(initialGroups, movedIndex) { const comboTaskAtStart = currentTask.value.kind === "combo"; let groups = initialGroups; let wave = 0; let turnConsumed = 0; let madeSpecial = 0; let firstWave = true; while (groups.length && wave < MAX_CASCADE_WAVES) { wave += 1; combo.value = wave; const remove = new Set(groups.flatMap((group) => group.indices)); let keeper = -1; let keeperSpecial = ""; const bentMatch = firstWave ? findBentFiveMatch(groups) : null; if (firstWave) { const large = groups.find((group) => group.indices.length >= 4); if (bentMatch) { keeper = bentMatch.intersection; keeperSpecial = "burst"; remove.delete(keeper); madeSpecial = 1; } else if (large) { keeper = large.indices.includes(movedIndex) ? movedIndex : large.indices[0]; keeperSpecial = large.indices.length >= 5 ? "all" : large.direction; remove.delete(keeper); madeSpecial = 1; } } fireClearingIndices.value = []; const specialEffects = expandSpecials(remove); const camelGroup = groups.filter((group) => group.indices.every((index) => { var _a; return ((_a = board.value[index]) == null ? void 0 : _a.key) === "camel"; })).sort((a, b) => b.indices.length - a.indices.length)[0]; const bentIndices = bentMatch ? [.../* @__PURE__ */ new Set([...bentMatch.row.indices, ...bentMatch.col.indices])] : []; const bentCamelCount = bentIndices.length === 5 && bentIndices.every((index) => { var _a; return ((_a = board.value[index]) == null ? void 0 : _a.key) === "camel"; }) ? 5 : 0; const camelMatchCount = Math.max(bentCamelCount, (camelGroup == null ? void 0 : camelGroup.indices.length) || 0); if (camelMatchCount >= 3) applyCamelJackpot(camelMatchCount, remove); const removedTiles = [...remove].map((i) => board.value[i]).filter(Boolean); const removedNormal = removedTiles.filter((tile) => { const food = foodOf(tile.key); return !food.high && !food.product; }); const fireRemovedHigh = fireClearingIndices.value.some((index) => { var _a; return foodOf((_a = board.value[index]) == null ? void 0 : _a.key).high; }); const largestMatch = Math.max( ...groups.map((group) => group.indices.length), keeperSpecial === "burst" || specialEffects.hasBurst ? 5 : 3 ); clearingIndices.value = [...remove]; const triggeredSpecial = fireRemovedHigh ? "fire-high" : specialEffects.hasBurst ? "burst-triggered" : specialEffects.hasFire ? "fire-triggered" : keeperSpecial; showImpact(largestMatch, wave, triggeredSpecial); playMatchImpact(largestMatch, wave); vibrate(largestMatch >= 5 || wave >= 3 ? "medium" : "light"); turnConsumed += removedNormal.length; learned.value += removedNormal.length; updateFoodTask(removedNormal); const multiplier = feastMoves.value > 0 ? 2 : 1; score.value += (removedNormal.length * 12 + Math.max(0, wave - 1) * 20 + madeSpecial * 35) * multiplier; queuePlatformProgress(learned.value, score.value, false); await wait(specialEffects.hasFire ? 330 : 210); const next = [...board.value]; remove.forEach((index) => { next[index] = null; }); if (keeper >= 0 && next[keeper]) next[keeper] = { ...next[keeper], special: keeperSpecial }; board.value = next; clearingIndices.value = []; fireClearingIndices.value = []; if (madeSpecial && currentTask.value.kind === "special") advanceTask(madeSpecial); await wait(70); const shouldGuaranteeCombo = firstWave && comboTaskAtStart && comboDryTurns.value >= COMBO_PITY_TURNS - 1; collapseAndFill(shouldGuaranteeCombo); playDropSfx(remove.size); await wait(190); groups = findMatches(board.value); const automaticHighMatch = groups.some((group) => group.indices.some((index) => { var _a; return foodOf((_a = board.value[index]) == null ? void 0 : _a.key).high; })); if (automaticHighMatch) { board.value = makeStablePlayableBoard(board.value); groups = []; statusText.value = "自动掉落避开了高糖连消,棋盘已整理"; } else if (wave >= MAX_CASCADE_WAVES && groups.length) { board.value = makeStablePlayableBoard(board.value); groups = []; statusText.value = "连消奖励已结算,棋盘已稳定"; } firstWave = false; madeSpecial = 0; } if (wave >= 3) rewardMegaCombo(wave); if (comboTaskAtStart) { if (wave >= COMBO_TASK_WAVE) { comboDryTurns.value = 0; advanceTask(1); } else { comboDryTurns.value += 1; } } if (turnConsumed > 0 && feastMoves.value > 0) feastMoves.value -= 1; if (pendingThemeMatchCount >= 3) { const matchedCount = pendingThemeMatchCount; pendingThemeMatchCount = 0; const celebrationDelay = matchedCount >= 5 ? 2300 : matchedCount === 4 ? 2e3 : 1250; await wait(celebrationDelay); advanceFoodTheme(); } } function playMatchImpact(matchSize, wave) { if (wave >= 3) playSfxLayer("comboMega", "blast", 70, 0.55); else if (wave === 2) playSfxLayer("combo3", "pop", 60, 0.5); else if (matchSize >= 5) playSfxLayer("match5", "blast", 65, 0.55); else if (matchSize >= 4) playSfxLayer("match4", "sparkle", 55, 0.5); else playSfxLayer("match3", "pop", 45, 0.45); } function planCamelReward(requested) { const available = Math.max(0, MAX_CAMEL_COUNT - camelCount.value); const granted = Math.min(requested, available); const overflow = requested - granted; return { granted, overflow, overflowScore: overflow * OVERFLOW_CAMEL_SCORE }; } function grantCamelReward(requested) { const reward = planCamelReward(requested); camelCount.value += reward.granted; score.value += reward.overflowScore; return reward; } function rewardMegaCombo(wave) { score.value += MEGA_COMBO_SCORE; const camelReward = grantCamelReward(1); const rewardText = camelRewardText(camelReward); statusText.value = `${wave} 连消惊喜:+${MEGA_COMBO_SCORE} 分${rewardText ? ` · ${rewardText}` : ""}`; taskRewardStatusUntil = Date.now() + 1800; if (camelReward.granted > 0) showTaskCamelReward(); startConfetti(); playSfxLayer("comboMega", "fanfare", 100, 0.82); vibrate("medium"); common_vendor.index.showToast({ title: `${wave} 连消惊喜:+${MEGA_COMBO_SCORE} 分${camelReward.granted > 0 ? "、驼乳粉 +1" : ""}`, icon: "none" }); } function camelRewardText(reward) { const parts = []; if (reward.granted > 0) parts.push(`驼乳粉 ×${reward.granted}`); if (reward.overflow > 0) parts.push(`满仓多余奖励换 ${reward.overflowScore} 分`); return parts.join(" · "); } function applyCamelJackpot(count, remove) { pendingThemeMatchCount = Math.max(pendingThemeMatchCount, count); if (count >= 5) { score.value += 1554; const camelReward = grantCamelReward(4); feastMoves.value = Math.max(feastMoves.value, 6); board.value.forEach((tile, index) => { if (foodOf(tile == null ? void 0 : tile.key).high) remove.add(index); }); showCamelJackpot(5, "驼乳五连双倍大奖", `+1554 分 · ${camelRewardText(camelReward)} · 双倍得分 ×6`); startConfetti(); playJackpotSequence(); return; } if (count === 4) { score.value += 288; const camelReward = grantCamelReward(1); const highIndex = board.value.findIndex((tile, index) => foodOf(tile == null ? void 0 : tile.key).high && !remove.has(index)); if (highIndex >= 0) remove.add(highIndex); showCamelJackpot(4, "驼乳超级四连", `+288 分 · ${camelRewardText(camelReward)} · 移出一份高糖食物`); playSfxLayer("match5", "fanfare", 90, 0.7); setTimeout(() => playSfx("tap", 1.16, 0.58), 260); vibrate("medium"); return; } score.value += 77; showCamelJackpot(3, "驼乳幸运三连", "+77 分 · 轻量连消奖励"); playSfxLayer("match3", "sparkle", 44, 0.38); vibrate("light"); } function advanceFoodTheme() { const previous = currentTheme.value; themeIndex.value = (themeIndex.value + 1) % FOOD_GROUPS.length; const nextTheme = currentTheme.value; const mapping = {}; previous.safe.forEach((key, index) => { mapping[key] = nextTheme.safe[index]; }); mapping[previous.danger] = nextTheme.danger; const mappedBoard = board.value.map((tile) => { if (!tile || !mapping[tile.key]) return tile; return { ...tile, key: mapping[tile.key] }; }); board.value = mappedBoard; if (findMatches(mappedBoard).length || !hasSafeMoveIn(mappedBoard)) { board.value = buildPlayableBoard(openingKeysForTheme(nextTheme)); } taskIndex.value = 0; taskProgress.value = 0; comboDryTurns.value = 0; selected.value = -1; camelMode.value = false; endedFood.value = foodOf(nextTheme.danger); stageMeta.value = { number: themeIndex.value + 1, title: nextTheme.title, foods: [...nextTheme.safe, nextTheme.danger].map((key) => ({ key, ...foodOf(key) })) }; stageVisible.value = true; statusText.value = `已进入${nextTheme.title},橙框${foodOf(nextTheme.danger).short}可替换`; playSfxLayer("fanfare", "sparkle", 100, 0.65); if (stageTimer) clearTimeout(stageTimer); stageTimer = setTimeout(() => { stageVisible.value = false; }, 1800); } function showCamelJackpot(count, title, reward) { if (jackpotTimer) clearTimeout(jackpotTimer); camelJackpot.value = { visible: true, count, kicker: count >= 5 ? "JACKPOT · 777" : count === 4 ? "ONE MORE · 再来一罐" : "LUCKY · 小惊喜", title, reward }; const duration = count >= 5 ? 2200 : count === 4 ? 1900 : 1150; jackpotTimer = setTimeout(() => { camelJackpot.value.visible = false; }, duration); } function startConfetti() { if (confettiTimer) clearTimeout(confettiTimer); confettiVisible.value = false; setTimeout(() => { confettiVisible.value = true; }, 20); confettiTimer = setTimeout(() => { confettiVisible.value = false; }, 6e3); } function playJackpotSequence() { playSfx("tap", 0.9, 0.82); setTimeout(() => playSfx("tap", 1, 1.05), 150); setTimeout(() => playSfx("tap", 1.08, 1.35), 300); setTimeout(() => playSfxLayer("comboMega", "fanfare", 100, 0.85), 430); setTimeout(() => playSfxLayer("blast", "sparkle", 90, 0.75), 690); vibrate("medium"); setTimeout(() => vibrate("medium"), 170); setTimeout(() => vibrate("heavy"), 430); } function showImpact(matchSize, wave, specialType = "") { impactLevel.value = Math.min(3, wave >= 3 ? 3 : matchSize >= 5 ? 3 : matchSize >= 4 ? 2 : 1); if (specialType === "fire-high") impactText.value = "火焰移出高糖!"; else if (wave >= 3) impactText.value = `${wave} 连消!`; else if (specialType === "fire-triggered") impactText.value = "火焰清除!"; else if (specialType === "burst-triggered") impactText.value = "范围爆破!"; else if (specialType === "burst") impactText.value = "L形惊喜!"; else if (matchSize >= 5) impactText.value = "五连惊喜!"; else if (matchSize >= 4) impactText.value = "四连!"; else impactText.value = "消除!"; setTimeout(() => { impactText.value = ""; }, 520); } function vibrate(type = "light") { try { common_vendor.index.vibrateShort({ type }); } catch (_) { } } function expandSpecials(remove) { const queue = [...remove]; const seen = /* @__PURE__ */ new Set(); const fire = /* @__PURE__ */ new Set(); let hasBurst = false; let hasFire = false; while (queue.length) { const index = queue.shift(); if (seen.has(index)) continue; seen.add(index); const tile = board.value[index]; if (!(tile == null ? void 0 : tile.special)) continue; hasFire = true; const extra = []; if (tile.special === "row") { const row = Math.floor(index / COLS); for (let col = 0; col < COLS; col += 1) extra.push(row * COLS + col); } else if (tile.special === "col") { const col = index % COLS; for (let row = 0; row < ROWS; row += 1) extra.push(row * COLS + col); } else if (tile.special === "burst") { hasBurst = true; const centerRow = Math.floor(index / COLS); const centerCol = index % COLS; for (let row = Math.max(0, centerRow - 1); row <= Math.min(ROWS - 1, centerRow + 1); row += 1) { for (let col = Math.max(0, centerCol - 1); col <= Math.min(COLS - 1, centerCol + 1); col += 1) { extra.push(row * COLS + col); } } } else { board.value.forEach((item, i) => { if ((item == null ? void 0 : item.key) === tile.key) extra.push(i); }); } extra.forEach((i) => fire.add(i)); extra.forEach((i) => { if (!remove.has(i)) { remove.add(i); queue.push(i); } }); } fireClearingIndices.value = [...fire]; return { hasBurst, hasFire }; } function collapseAndFill(forceSafeMatch = false) { const next = Array(ROWS * COLS).fill(null); for (let col = 0; col < COLS; col += 1) { const existing = []; for (let row = ROWS - 1; row >= 0; row -= 1) { const tile = board.value[row * COLS + col]; if (tile) existing.push(tile); } existing.forEach((tile, offset) => { next[(ROWS - 1 - offset) * COLS + col] = tile; }); } const forcedIndices = forceSafeMatch ? findForcedDropMatch(next) : []; const forcedSet = new Set(forcedIndices); const forcedKey = forcedIndices.length ? pickForcedDropKey(next, forcedIndices) : ""; for (let row = 0; row < ROWS; row += 1) { for (let col = 0; col < COLS; col += 1) { const index = row * COLS + col; if (!next[index]) { const key = forcedSet.has(index) ? forcedKey : pickDropFoodKey(next, index, col); next[index] = makeTile(key); } } } board.value = next; return forcedIndices.length === 3; } function findForcedDropMatch(snapshot) { const empty = new Set(snapshot.map((tile, index) => tile ? -1 : index).filter((index) => index >= 0)); for (let row = 0; row < ROWS; row += 1) { for (let col = 0; col <= COLS - 3; col += 1) { const indices = [0, 1, 2].map((offset) => row * COLS + col + offset); if (indices.every((index) => empty.has(index))) return indices; } } for (let col = 0; col < COLS; col += 1) { for (let row = 0; row <= ROWS - 3; row += 1) { const indices = [0, 1, 2].map((offset) => (row + offset) * COLS + col); if (indices.every((index) => empty.has(index))) return indices; } } return []; } function pickForcedDropKey(snapshot, indices) { var _a; return ((_a = currentTheme.value.safe.map((key) => ({ key, nearby: snapshot.reduce((count, tile, index) => (tile == null ? void 0 : tile.key) === key && indices.some((target) => isAdjacent(target, index)) ? count + 1 : count, 0) })).sort((a, b) => a.nearby - b.nearby)[0]) == null ? void 0 : _a.key) || currentTheme.value.safe[0]; } function pickDropFoodKey(snapshot, index, col) { for (let attempt = 0; attempt < 16; attempt += 1) { const key = randomFoodKey(snapshot, col); if (!wouldCreateMatchAt(snapshot, index, key)) return key; } const fallback = [...currentTheme.value.safe, currentTheme.value.danger].find((key) => !wouldCreateMatchAt(snapshot, index, key)); return fallback || currentTheme.value.safe[(index + col) % currentTheme.value.safe.length]; } function wouldCreateMatchAt(source, index, key) { const row = Math.floor(index / COLS); const col = index % COLS; const keyAt = (target) => { var _a; return target === index ? key : (_a = source[target]) == null ? void 0 : _a.key; }; let horizontal = 1; for (let c = col - 1; c >= 0 && keyAt(row * COLS + c) === key; c -= 1) horizontal += 1; for (let c = col + 1; c < COLS && keyAt(row * COLS + c) === key; c += 1) horizontal += 1; if (horizontal >= 3) return true; let vertical = 1; for (let r = row - 1; r >= 0 && keyAt(r * COLS + col) === key; r -= 1) vertical += 1; for (let r = row + 1; r < ROWS && keyAt(r * COLS + col) === key; r += 1) vertical += 1; return vertical >= 3; } function randomFoodKey(snapshot, col = -1) { const highs = snapshot.filter((tile) => tile && foodOf(tile.key).high).length; if (highs < HIGH_CAP && Math.random() < DANGER_DROP_CHANCE) return currentTheme.value.danger; const keys = currentTheme.value.safe; if (col >= 0 && Math.random() < COLUMN_GROUP_BIAS) return keys[col % keys.length]; return keys[Math.floor(Math.random() * keys.length)]; } function findBentFiveMatch(groups) { const rows = groups.filter((group) => group.direction === "row" && group.indices.length === 3); const cols = groups.filter((group) => group.direction === "col" && group.indices.length === 3); for (const row of rows) { for (const col of cols) { const intersection = row.indices.find((index) => col.indices.includes(index)); if (intersection !== void 0) return { intersection, row, col }; } } return null; } function findMatches(source) { var _a, _b, _c, _d; const groups = []; for (let row = 0; row < ROWS; row += 1) { let start = 0; while (start < COLS) { let end = start + 1; while (end < COLS && ((_a = source[row * COLS + end]) == null ? void 0 : _a.key) === ((_b = source[row * COLS + start]) == null ? void 0 : _b.key)) end += 1; if (source[row * COLS + start] && end - start >= 3) { groups.push({ direction: "row", indices: Array.from({ length: end - start }, (_, n) => row * COLS + start + n) }); } start = end; } } for (let col = 0; col < COLS; col += 1) { let start = 0; while (start < ROWS) { let end = start + 1; while (end < ROWS && ((_c = source[end * COLS + col]) == null ? void 0 : _c.key) === ((_d = source[start * COLS + col]) == null ? void 0 : _d.key)) end += 1; if (source[start * COLS + col] && end - start >= 3) { groups.push({ direction: "col", indices: Array.from({ length: end - start }, (_, n) => (start + n) * COLS + col) }); } start = end; } } return groups; } function updateFoodTask(tiles) { if (currentTask.value.kind !== "food") return; advanceTask(tiles.filter((tile) => tile.key === currentTask.value.key).length); } function advanceTask(amount) { if (!amount) return; taskProgress.value += amount; if (taskProgress.value < currentTask.value.target) return; score.value += 120; const camelReward = grantCamelReward(1); if (camelReward.granted > 0) { showTaskCamelReward(); statusText.value = "小目标完成,驼乳粉已放入道具栏"; } else { statusText.value = `驼乳粉已满,多余奖励换 ${camelReward.overflowScore} 分`; } common_vendor.index.showToast({ title: camelReward.granted > 0 ? "小目标完成:驼乳粉 +1" : `驼乳粉已满:奖励换 ${camelReward.overflowScore} 分`, icon: "none" }); taskIndex.value = (taskIndex.value + 1) % 4; taskProgress.value = 0; comboDryTurns.value = 0; } function showTaskCamelReward() { if (taskRewardTimer) clearTimeout(taskRewardTimer); taskRewardKey.value += 1; taskRewardVisible.value = true; taskRewardStatusUntil = Date.now() + 1600; playSfxLayer("boost", "sparkle", 75, 0.55); vibrate("light"); taskRewardTimer = setTimeout(() => { taskRewardVisible.value = false; }, 1150); } function finishTurn() { saveBest(); if (checkBoardHealth()) return; if (stageVisible.value) { scheduleHint(); return; } if (Date.now() < taskRewardStatusUntil) { scheduleHint(); return; } statusText.value = combo.value >= 2 ? `漂亮!完成 ${combo.value} 连消` : "食物已从上方补充,继续挑战"; scheduleHint(); } function checkBoardHealth() { if (hasSafeMove() || reshuffling.value) return false; performReshuffle(); return true; } function hasSafeMove() { return hasSafeMoveIn(board.value); } function hasSafeMoveIn(source) { return Boolean(findSafeMoveIn(source)); } function findSafeMoveIn(source) { for (let i = 0; i < source.length; i += 1) { const candidates = []; if (i % COLS < COLS - 1) candidates.push(i + 1); if (i + COLS < source.length) candidates.push(i + COLS); for (const j of candidates) { const copy = source.map((tile) => ({ ...tile })); [copy[i], copy[j]] = [copy[j], copy[i]]; const groups = findMatches(copy); if (groups.length && !groups.flatMap((group) => group.indices).some((index) => foodOf(copy[index].key).high)) { return { from: i, to: j }; } } } return null; } async function performReshuffle() { if (reshuffling.value || gameOver.value) return; reshuffling.value = true; busy.value = true; reshuffleDone.value = false; reshuffleVisible.value = true; selected.value = -1; camelMode.value = false; statusText.value = "没有可消除组合,正在重新洗牌"; playSfx("reshuffle", 0.9); vibrate("medium"); await wait(760); const source = board.value.map((tile) => ({ ...tile })); let candidate = null; for (let attempt = 0; attempt < 240; attempt += 1) { const shuffled = shuffleTiles(source); if (findMatches(shuffled).length) continue; if (!hasSafeMoveIn(shuffled)) continue; candidate = shuffled; break; } board.value = candidate || buildGuaranteedBoard(); reshuffleDone.value = true; statusText.value = "洗牌完成,新的消除机会已经出现"; playSfxLayer("drop", "sparkle", 70, 0.55); vibrate("light"); await wait(520); reshuffleVisible.value = false; reshuffling.value = false; busy.value = false; scheduleHint(); } function shuffleTiles(source) { const result = source.map((tile) => ({ ...tile })); for (let i = result.length - 1; i > 0; i -= 1) { const j = Math.floor(Math.random() * (i + 1)); [result[i], result[j]] = [result[j], result[i]]; } return result; } function buildGuaranteedBoard() { return buildPlayableBoard(openingKeysForTheme(currentTheme.value)); } function openingKeysForTheme(theme) { const [a, b, c, d] = theme.safe; const danger = theme.danger; return [ a, b, c, d, b, c, d, a, c, d, a, danger, d, a, danger, b, a, b, c, d ]; } function buildPlayableBoard(keys) { let candidate = keys.map((key) => makeTile(key)); for (let attempt = 0; attempt < 240; attempt += 1) { if (!findMatches(candidate).length && hasSafeMoveIn(candidate)) return candidate; candidate = shuffleTiles(candidate); } return forcedPlayableKeysForTheme(currentTheme.value).map((key) => makeTile(key)); } function forcedPlayableKeysForTheme(theme) { const [a, b, c, d] = theme.safe; const danger = theme.danger; return [ d, a, danger, c, d, c, b, danger, c, a, b, a, d, d, a, a, b, d, c, b ]; } function makeStablePlayableBoard(source) { const tiles = source.filter(Boolean).map((tile) => ({ ...tile })); if (tiles.length === ROWS * COLS) { for (let attempt = 0; attempt < 300; attempt += 1) { const candidate = shuffleTiles(tiles); if (!findMatches(candidate).length && hasSafeMoveIn(candidate)) return candidate; } } return buildGuaranteedBoard(); } function safeMoveHint(move) { var _a, _b; if (!move) return ""; const from = foodOf((_a = board.value[move.from]) == null ? void 0 : _a.key).short; const to = foodOf((_b = board.value[move.to]) == null ? void 0 : _b.key).short; const direction = move.to === move.from + 1 ? "向右" : "向下"; return `提示:把${from}${direction}与${to}交换`; } function scheduleHint() { if (hintTimer) clearTimeout(hintTimer); hintTimer = setTimeout(() => { if (busy.value || gameOver.value || stageVisible.value) return; const move = findSafeMoveIn(board.value); if (!move) { performReshuffle(); return; } statusText.value = safeMoveHint(move); }, 5e3); } function saveBest() { if (score.value <= bestScore.value) return; bestScore.value = score.value; common_vendor.index.setStorageSync("tongji_endless_best", bestScore.value); } function wait(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } return (_ctx, _cache) => { return common_vendor.e({ a: confettiVisible.value }, confettiVisible.value ? { b: common_vendor.f(common_vendor.unref(confettiPieces), (piece, k0, i0) => { return { a: common_vendor.t(piece.emoji), b: piece.id, c: piece.emoji ? 1 : "", d: common_vendor.s(piece.style) }; }) } : {}, { c: common_vendor.p({ name: "chevron-left", size: "md", color: "#155e4b" }), d: common_vendor.o(goBack, "cd"), e: common_vendor.t(themeIndex.value + 1), f: common_vendor.t(currentTheme.value.title), g: common_vendor.p({ name: "volume", size: "sm", color: common_vendor.unref(sfxEnabled) ? "#155e4b" : "#94a3b8" }), h: common_vendor.o(toggleSfx, "35"), i: common_vendor.p({ name: "info", size: "sm", color: "#155e4b" }), j: common_vendor.o(showRules, "e4"), k: common_vendor.s(navStyle.value), l: common_vendor.t(learned.value), m: common_vendor.t(score.value), n: common_vendor.t(weeklyMyRank.value), o: busy.value || reshuffling.value || stageVisible.value || camelJackpot.value.visible ? 1 : "", p: common_vendor.o(openWeeklyRank, "7c"), q: common_vendor.p({ name: "trophy", size: "sm", color: "#8a5a10" }), r: common_vendor.t(currentTask.value.label), s: common_vendor.t(Math.min(taskProgress.value, currentTask.value.target)), t: common_vendor.t(currentTask.value.target), v: taskPercent.value + "%", w: taskRewardVisible.value }, taskRewardVisible.value ? { x: foodOf("camel").img, y: taskRewardKey.value } : {}, { z: common_vendor.t(Math.max(combo.value, 1)), A: combo.value >= 3 ? 1 : "", B: feastMoves.value > 0 }, feastMoves.value > 0 ? { C: common_vendor.t(feastMoves.value) } : {}, { D: common_vendor.t(highCount.value), E: common_vendor.f(3, (n, k0, i0) => { return { a: n, b: n <= highCount.value ? 1 : "" }; }), F: common_vendor.f(boardRows.value, (row, rowIndex, i0) => { return { a: common_vendor.f(row, (tile, k1, i1) => { return common_vendor.e({ a: tile.special }, tile.special ? common_vendor.e({ b: tile.special === "row" || tile.special === "col" }, tile.special === "row" || tile.special === "col" ? {} : tile.special === "burst" ? {} : {}, { c: tile.special === "burst", d: common_vendor.n(`is-${tile.special}`) }) : {}, { e: fireClearingIndices.value.includes(tile.index) }, fireClearingIndices.value.includes(tile.index) ? {} : {}, { f: foodOf(tile.key).img, g: common_vendor.t(foodOf(tile.key).short), h: common_vendor.t(foodOf(tile.key).levelLabel || "低糖"), i: common_vendor.n(`is-${foodOf(tile.key).level || "low"}`), j: camelMode.value && foodOf(tile.key).replaceable }, camelMode.value && foodOf(tile.key).replaceable ? {} : {}, { k: tile.id, l: common_vendor.n(cellClasses(tile)), m: common_vendor.s(cellMotionStyle(tile.index)), n: common_vendor.o(($event) => tapTile(tile.index), tile.id), o: common_vendor.o(($event) => touchStart($event, tile.index), tile.id), p: common_vendor.o(($event) => touchMove($event, tile.index), tile.id), q: common_vendor.o(($event) => touchEnd($event, tile.index), tile.id) }); }), b: rowIndex }; }), G: busy.value ? 1 : "", H: impactText.value }, impactText.value ? { I: common_vendor.t(impactText.value), J: common_vendor.n(`is-level-${impactLevel.value}`) } : {}, { K: camelJackpot.value.visible }, camelJackpot.value.visible ? common_vendor.e({ L: common_vendor.t(camelJackpot.value.kicker), M: camelJackpot.value.count === 3 }, camelJackpot.value.count === 3 ? { N: common_vendor.f(3, (n, k0, i0) => { return { a: n }; }), O: foodOf("camel").img } : camelJackpot.value.count === 4 ? { Q: common_vendor.f(5, (n, k0, i0) => { return common_vendor.e({ a: n < 5 }, n < 5 ? { b: foodOf("camel").img } : {}, { c: n, d: n === 5 ? 1 : "" }); }) } : { R: common_vendor.f(5, (n, k0, i0) => { return { a: n }; }), S: foodOf("camel").img, T: common_vendor.f(3, (n, k0, i0) => { return { a: n }; }) }, { P: camelJackpot.value.count === 4, U: common_vendor.t(camelJackpot.value.title), V: camelJackpot.value.count >= 5 }, camelJackpot.value.count >= 5 ? {} : {}, { W: common_vendor.t(camelJackpot.value.reward), X: common_vendor.n(`is-match-${camelJackpot.value.count}`) }) : {}, { Y: common_vendor.p({ name: "bulb", size: "sm", color: "#9a6718" }), Z: common_vendor.t(statusText.value), aa: foodOf("camel").img, ab: common_vendor.p({ name: "refresh", size: "sm", color: "#ffffff" }), ac: common_vendor.t(foodOf(currentTheme.value.danger).short), ad: common_vendor.t(camelCount.value), ae: camelMode.value ? 1 : "", af: camelCount.value <= 0 || busy.value ? 1 : "", ag: common_vendor.o(toggleCamel, "1c"), ah: weeklyRankVisible.value }, weeklyRankVisible.value ? common_vendor.e({ ai: common_vendor.t(weeklyStatusLabel.value), aj: !common_vendor.unref(platformConnected) ? 1 : "", ak: common_vendor.t(weeklyRangeLabel.value), al: common_vendor.t(weeklySexLabel.value), am: common_vendor.t(weeklyMemberCount.value), an: common_vendor.t(weeklyMyRank.value), ao: common_vendor.t(weeklyMyCount.value), ap: weeklyRankRise.value > 0 }, weeklyRankRise.value > 0 ? { aq: common_vendor.t(weeklyMyRank.value), ar: common_vendor.t(weeklyRankRise.value) } : { as: common_vendor.t(weeklyMyRank.value) }, { at: weeklyIsFirst.value }, weeklyIsFirst.value ? {} : { av: common_vendor.t(weeklyDistance.value) }, { aw: common_vendor.f(weeklyRankRows.value, (player, k0, i0) => { return common_vendor.e({ a: common_vendor.t(player.rank), b: player.avatarUrl }, player.avatarUrl ? { c: player.avatarUrl } : { d: common_vendor.t(player.avatar) }, { e: common_vendor.n(`is-tone-${player.tone}`), f: common_vendor.t(player.name), g: player.isMe }, player.isMe ? {} : {}, { h: common_vendor.t(player.count), i: player.id, j: player.isMe ? 1 : "" }); }), ax: common_vendor.t(currentCheer.value.source), ay: common_vendor.o(cycleCheer, "02"), az: common_vendor.t(currentCheer.value.text), aA: currentCheer.value.userGenerated }, currentCheer.value.userGenerated ? {} : {}, { aB: common_vendor.n(`is-${currentCheer.value.tone}`), aC: common_vendor.o(closeWeeklyRank, "f2"), aD: common_vendor.o(() => { }, "9c") }) : {}, { aE: reshuffleVisible.value }, reshuffleVisible.value ? { aF: common_vendor.p({ name: "refresh", size: "lg", color: "#ffffff" }), aG: common_vendor.t(reshuffleDone.value ? "洗牌完成" : "没有可消除组合"), aH: common_vendor.t(reshuffleDone.value ? "新的消除机会已经出现" : "正在为您重新洗牌,请稍候"), aI: common_vendor.o(() => { }, "40") } : {}, { aJ: stageVisible.value }, stageVisible.value ? { aK: common_vendor.t(stageMeta.value.number), aL: common_vendor.t(stageMeta.value.title), aM: common_vendor.f(stageMeta.value.foods, (food, k0, i0) => { return { a: food.img, b: common_vendor.t(food.short), c: food.key, d: food.high ? 1 : "" }; }), aN: common_vendor.o(() => { }, "01") } : {}, { aO: gameOver.value }, gameOver.value ? { aP: common_vendor.t(endedFood.value.name), aQ: common_vendor.t(endedFood.value.tip), aR: common_vendor.t(score.value), aS: common_vendor.t(bestScore.value), aT: common_vendor.o(startGame, "33"), aU: common_vendor.o(goBack, "98"), aV: common_vendor.o(() => { }, "72") } : {}, { aW: common_vendor.o(primeSfxFromGesture, "77"), aX: common_vendor.o(primeSfxFromGesture, "a4") }); }; } }; const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["__scopeId", "data-v-ace1d107"]]); _sfc_main.__runtimeHooks = 6; wx.createPage(MiniProgramPage); //# sourceMappingURL=../../../.sourcemap/mp-weixin/tongji/endless-game/index.js.map