You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

斯诺克计分应用优化咨询:代码精简与规则限制实现

斯诺克计分应用优化与规则实现方案

Hey Josh, great start on your snooker scoring app! Let's break this down into two parts: cleaning up your repetitive code to make it smoother, and adding the rule-based restrictions you need (shot order limits and the 147 max score cap).

一、代码简洁化重构

Your original code has a lot of repeated DOM selection and event listener logic—we can fix that with a data-driven approach that centralizes all ball configurations. This makes the code shorter, easier to maintain, and simpler to extend later:

// 统一配置所有球的核心信息:选择器、分值、类型、初始状态
const ballConfigs = [
  { selector: '.red', points: 1, type: 'red', remaining: 15 },
  { selector: '.yellow', points: 2, type: 'colour', isPotted: false },
  { selector: '.green', points: 3, type: 'colour', isPotted: false },
  { selector: '.brown', points: 4, type: 'colour', isPotted: false },
  { selector: '.blue', points: 5, type: 'colour', isPotted: false },
  { selector: '.pink', points: 6, type: 'colour', isPotted: false },
  { selector: '.black', points: 7, type: 'colour', isPotted: false }
];

// 全局状态管理
const scoreElement = document.querySelector('.score');
let currentScore = 0;
let remainingReds = 15;
let canPotColour = false; // 标记:打完红球后是否可击打彩球
let gameOver = false;

// 通用分数更新函数
function updateScoreDisplay() {
  scoreElement.textContent = currentScore;
  // 检查是否达到满分147,触发游戏结束
  if (currentScore >= 147) {
    endGame();
  }
}

// 游戏结束:禁用所有球的点击
function endGame() {
  gameOver = true;
  ballConfigs.forEach(config => {
    const ball = document.querySelector(config.selector);
    ball.style.pointerEvents = 'none';
    ball.style.opacity = '0.5'; // 视觉上标记为不可用
  });
}

// 初始化所有球的事件监听
ballConfigs.forEach(config => {
  const ball = document.querySelector(config.selector);
  
  ball.addEventListener('click', () => {
    if (gameOver) return; // 游戏结束后不再响应点击

    // 处理红球击打逻辑
    if (config.type === 'red') {
      // 红球已打完,或当前处于需打彩球的阶段,无法点击红球
      if (remainingReds <= 0 || canPotColour) return;
      
      currentScore += config.points;
      remainingReds--;
      // 视觉上标记红球已击落
      ball.style.opacity = '0.5';
      ball.style.pointerEvents = 'none';
      canPotColour = true; // 打完红球后允许击打任意彩球
      updateScoreDisplay();
    } 
    // 处理彩球击打逻辑
    else {
      // 红球未打完且未先击打红球,无法直接打彩球
      if (remainingReds > 0 && !canPotColour) return;

      if (remainingReds > 0) {
        // 还有红球时,彩球击落会放回台面,只加分不标记为已击落
        currentScore += config.points;
        canPotColour = false; // 打完彩球后回到可击打红球的状态
      } else {
        // 红球已打完,需按分值从低到高击打彩球
        const availableColours = ballConfigs
          .filter(c => c.type === 'colour' && !c.isPotted)
          .sort((a, b) => a.points - b.points);
        
        // 不是当前允许击打的彩球(最低分值未击落彩球),直接返回
        if (availableColours[0].selector !== config.selector) return;

        // 击落彩球,标记状态并更新分数
        currentScore += config.points;
        config.isPotted = true;
        ball.style.opacity = '0.5';
        ball.style.pointerEvents = 'none';

        // 检查是否是最后一颗黑球,触发游戏结束
        if (config.points === 7 && availableColours.length === 1) {
          endGame();
        }
      }
      updateScoreDisplay();
    }
  });
});

// 初始化分数显示
updateScoreDisplay();

核心优化点:

  • 集中配置:所有球的属性存在ballConfigs数组里,避免重复的DOM选择和事件绑定
  • 通用函数:提取updateScoreDisplay和endGame函数,减少重复代码
  • 状态集中管理:把剩余红球数、击球阶段、游戏状态等变量统一管理,逻辑更清晰

二、规则限制实现

1. 击球顺序限制

  • 红球阶段:必须先击打红球,打完红球后才能选择任意彩球;彩球击打后会"放回"台面(代码中不标记为已击落,只是切换回可打红球状态)
  • 彩球清台阶段:红球全部打完后,必须按**黄(2分)→绿(3分)→棕(4分)→蓝(5分)→粉(6分)→黑(7分)**的顺序击打,无法跳级选择
  • 游戏终止:最后一颗黑球被击打后,所有球立即禁用点击

2. 147分最高分限制

在updateScoreDisplay函数中添加了满分判断:当分数达到147(15红15黑的120分 + 彩球总分27分)时,直接触发endGame函数,禁用所有球的操作,避免超分。

内容的提问来源于stack exchange,提问作者Josh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:04:17