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

JavaScript实现Simon游戏时数组长度异常翻倍问题求助

解决Simon游戏中roundList数组长度异常翻倍问题

问题根源

你的roundList数组长度翻倍的核心原因是nextRound函数的逻辑错误:

  • 用setInterval调用randomColor,次数等于当前roundList的长度,但randomColor每次执行都会向roundList中添加新元素,导致数组长度随着每次调用持续增加,最终执行次数超过预期,数组长度翻倍。
  • setTimeout(repeat, delay)是错误用法,setTimeout的第一个参数必须是函数,传入定时器ID会引发意外行为。
  • check函数仅验证用户输入是否等于最后一个元素,没有跟踪用户输入的步骤,不符合Simon游戏的规则(需要依次匹配整个序列)。

修复方案

  1. 拆分函数职责:将生成新颜色和播放颜色动画的逻辑分离,避免重放序列时误添加新元素。
  2. 修正nextRound逻辑:重放已有序列后,再添加一个新的随机颜色,而不是在重放过程中添加新元素。
  3. 修复check函数:跟踪用户当前输入的步骤索引,依次验证每个输入是否匹配序列中的对应位置。
  4. 移除错误的setTimeout调用:正确控制定时器的启动和停止。

完整修复后的代码

JavaScript

var audioContext = new AudioContext();

function playFrequency(frequency) {
  var sampleRate = audioContext.sampleRate;
  var duration = sampleRate / 2.5;
  var numChannels = 1;
  var buffer = audioContext.createBuffer(numChannels, duration, sampleRate);
  var channelData = buffer.getChannelData(0);
  for (var i = 0; i < duration; i++) {
    channelData[i] = Math.sin(2 * Math.PI * frequency * i / sampleRate);
  }

  var source = audioContext.createBufferSource();
  source.buffer = buffer;
  source.connect(audioContext.destination);
  source.start(0);
}

let A = document.getElementById('green');
let B = document.getElementById('red');
let C = document.getElementById('blue');
let D = document.getElementById('yellow');

function reset(color) {
  switch(color) {
    case 'green':
      A.style.backgroundColor = '#3f3';
      A.style.boxShadow = '0 0 0 0';
      break;
    case 'red':
      B.style.backgroundColor = "#f33";
      B.style.boxShadow = '0 0 0 0';
      break;
    case 'blue':
      C.style.backgroundColor = "#33f";
      C.style.boxShadow = "0 0 0 0";
      break;
    case 'yellow':
      D.style.backgroundColor = "#ff3";
      D.style.boxShadow = '0 0 0 0';
      break;
  }
}

// 播放单个颜色的动画和声音(不添加到序列)
function playColor(color) {
  switch(color) {
    case 'green':
      A.style.backgroundColor = '#8f8';
      A.style.boxShadow = '0 0 20px #8f8';
      playFrequency(440);
      setTimeout(() => reset('green'), 400);
      break;
    case 'red':
      B.style.backgroundColor = '#f88';
      B.style.boxShadow = '0 0 20px #f88';
      playFrequency(554.3653);
      setTimeout(() => reset('red'), 400);
      break;
    case 'blue':
      C.style.backgroundColor = '#88f';
      C.style.boxShadow = '0 0 20px #88f';
      playFrequency(659.2551);
      setTimeout(() => reset('blue'), 400);
      break;
    case 'yellow':
      D.style.backgroundColor = '#ff8';
      D.style.boxShadow = '0 0 20px #ff8';
      playFrequency(880);
      setTimeout(() => reset('yellow'), 400);
      break;
  }
}

let roundList = [];
const colors = ['green', 'red', 'blue', 'yellow'];
let currentStep = 0; // 跟踪用户当前输入的步骤
let score = 0;
let scoreText = document.getElementById('score');
scoreText.innerText = `Score: ${score}`;

// 生成新随机颜色并添加到序列
function generateNewColor() {
  const randomIndex = Math.floor(Math.random() * 4);
  const newColor = colors[randomIndex];
  roundList.push(newColor);
  return newColor;
}

// 重放整个序列
function replaySequence() {
  currentStep = 0;
  roundList.forEach((color, index) => {
    setTimeout(() => playColor(color), 600 * index);
  });
  // 重放结束后等待用户输入
  setTimeout(() => enableInput(), 600 * roundList.length);
}

function startGame() {
  roundList = [];
  score = 0;
  scoreText.innerText = `Score: ${score}`;
  disableInput();
  const firstColor = generateNewColor();
  setTimeout(() => playColor(firstColor), 500);
  setTimeout(() => enableInput(), 1000);
}

function check(input) {
  disableInput();
  playColor(input); // 播放用户点击的动画
  if (input === roundList[currentStep]) {
    currentStep++;
    if (currentStep === roundList.length) {
      // 用户完成当前序列,进入下一轮
      score++;
      scoreText.innerText = `Score: ${score}`;
      setTimeout(() => nextRound(), 1000);
    } else {
      enableInput();
    }
  } else {
    scoreText.innerText = "you lose";
  }
}

function nextRound() {
  disableInput();
  generateNewColor();
  replaySequence();
}

// 禁用/启用用户输入,避免重复点击
function disableInput() {
  document.querySelectorAll('.input-btn').forEach(btn => btn.disabled = true);
}

function enableInput() {
  document.querySelectorAll('.input-btn').forEach(btn => btn.disabled = false);
}

CSS

* {
  max-width: 1920px;
  max-height: 1080px;
  overflow-x: hidden;
  overflow-y: hidden;
}

#row1 {
  height: 400px;
}

.square {
  width: 100px;
  height: 100px;
}

#green {
  background-color: #33ff33;
}

#red {
  background-color: #ff3333;
}

#blue {
  background-color: #3333ff;
}

#yellow {
  background-color: #ffff33;
}

.buttonbox {
  width: 100%;
}

.input-btn {
  margin: 0;
  height: 100%;
  width: 100%;
  cursor: pointer;
}

#greenbtn {
  background-color: inherit;
  border: none;
}

#redbtn {
  background-color: inherit;
  border: none;
}

#bluebtn {
  background-color: inherit;
  border: none;
}

#yellowbtn {
  background-color: inherit;
  border: none;
}

#start,
#score {
  width: 100px;
  display: block;
}

HTML

<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">

<div class="simon">
  <div class="row" id="row1"></div>
  <div class="row">
    <div class="col col-xxl-4"></div>
    <div class="col col-xxl-1">
      <div class="square mx-auto" id="green">
        <button class="input-btn" id="greenbtn" onclick="check('green')"></button>
      </div>
    </div>
    <div class="col col-xxl-1">
      <div class="square mx-auto" id="red">
        <button class="input-btn" id="redbtn" onclick="check('red')"></button>
      </div>
    </div>
    <div class="col col-xxl-1">
      <div class="square mx-auto" id="blue">
        <button class="input-btn" id="bluebtn" onclick="check('blue')"></button>
      </div>
    </div>
    <div class="col col-xxl-1">
      <div class="square mx-auto" id="yellow">
        <button class="input-btn" id="yellowbtn" onclick="check('yellow')"></button>
      </div>
    </div>
    <div class="col col-xxl-4"></div>
  </div>
  <br>
  <div class="row">
    <div class="col col-xxl-4"></div>
    <div class="col col-xxl-4">
      <button id="start" onclick="startGame()" class="mx-auto">Start Game</button>
    </div>
    <div class="col col-xxl-4"></div>
  </div>
  <br>
  <div class="row">
    <div class="col col-xxl-4"></div>
    <div class="col col-xxl-4">
      <p id="score" class="mx-auto text-center"></p>
    </div>
    <div class="col col-xxl-4"></div>
  </div>
</div>

关键修复点说明

  • 拆分出playColor负责播放动画,generateNewColor负责生成新元素,重放序列时不再向roundList添加元素。
  • 添加currentStep跟踪用户输入进度,确保用户依次匹配序列中的每个元素。
  • 加入enableInput/disableInput函数,避免用户在序列播放期间重复点击。
  • nextRound现在先添加新元素,再重放整个序列,符合Simon游戏的规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 03:57:02