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

使用JS开发配对卡牌游戏时遭遇无限循环问题求助

配对卡牌游戏:实现卡牌内容随机分配(每个内容使用两次)

我正在开发一款基于JavaScript的配对卡牌游戏,需求为:将卡牌内容随机分配,每个内容被使用两次后从可用列表中移除。尝试用for或while循环实现该逻辑时,始终出现无限循环问题。查阅资料得知可创建包含0-4的对象并使用Object.keys方法,但作为JavaScript新手,希望获得相关技术协助。


原代码

CSS

*{
  box-sizing: border-box;
}

.clear {
  clear: both;
}

section {
  border: 1px solid black;
  height: 200px;
  width: 50%; 
  float: left; 
}

HTML

<!DOCTYPE html>
<html lang="en">
    <head>
    <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        
        <title>Card Game</title>

        <link rel="stylesheet" href="css/normalize.css">
        <link rel="stylesheet" href="css/style.css">
    </head>
    <body>
        <h1>Match-The-Cards</h1>
        <h2 id = "results"></h2>

    
            <section id="one" class="one"></section>
            <section id="two"  class="one"></section>
            <section id="three"class="one"></section>
            <section id="four" class="one"></section>
            <section id="five" class="one"></section>
            <section id="six"  class="one"></section>
            <section id="seven"class="one"></section>
            <section id="eight"class="one"></section>
            <section id="nine" class="one"></section>
            <section id="ten"  class="one"></section>
            
        <script type="text/javascript" src="js/main.js"></script>
    </body>
</html>

JavaScript

const theFlipSide = {
    cardOne: "🚕",
    cardTwo: "🗽",
    cardThree: "🌃",
    cardFour: "🍕",
    cardFive: "🍎"

}
console.log(theFlipSide);
const eachSection = Object.values(theFlipSide)
console.log(eachSection);
eachSectionReturn()

function eachSectionReturn() {
    let items


    let randomNumber = Math.floor(Math.random() * eachSection.length )
    let theIndex = [0,1,2,3,4]
    let randomEachSection = []
    console.log(randomNumber, 'Random number');
    console.log(theIndex, 'The index');
    console.log(randomEachSection, 'random each section');
    
        {
    
    
        if (theIndex.find((e) => e == randomNumber) != undefined){
            randomEachSection.push(eachSection[randomNumber] )
            theIndex = theIndex.filter((e) => e != randomNumber) 
console.log(theIndex,'filtered');
console.log(randomNumber, 'w/n if');
        
    
    


    //return eachSection[Math.floor(Math.random() * eachSection.length)]
    // allow that item to be outputted twice and then remove it from list 
    //_ => Math.random() - 0.5);
}
        }


document.querySelectorAll('.one').forEach(section => section.addEventListener('click', theGame))
function theGame(e) {
    

    let theSquares = eachSectionReturn()
    e.target.innerText = (theSquares)

}
}

问题分析

原代码存在几个核心问题:

  • eachSectionReturn函数每次调用都会重新初始化索引数组theIndex,无法持久跟踪哪些卡牌已经被使用了两次
  • 未实现「每个内容使用两次」的逻辑,仅做了单次索引过滤
  • 函数未正确返回卡牌内容,导致点击后显示undefined
  • 事件监听被嵌套在函数内部,会重复绑定触发逻辑

修改后的完整代码

CSS(优化交互样式)

* {
  box-sizing: border-box;
}

.clear {
  clear: both;
}

section {
  border: 1px solid black;
  height: 200px;
  width: 50%; 
  float: left;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 4rem;
  cursor: pointer;
  user-select: none;
}

HTML(结构不变)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Card Game</title>
    <link rel="stylesheet" href="css/normalize.css">
    <link rel="stylesheet" href="css/style.css">
</head>
<body>
    <h1>Match-The-Cards</h1>
    <h2 id="results"></h2>

    <section id="one" class="one"></section>
    <section id="two" class="one"></section>
    <section id="three" class="one"></section>
    <section id="four" class="one"></section>
    <section id="five" class="one"></section>
    <section id="six" class="one"></section>
    <section id="seven" class="one"></section>
    <section id="eight" class="one"></section>
    <section id="nine" class="one"></section>
    <section id="ten" class="one"></section>

    <script type="text/javascript" src="js/main.js"></script>
</body>
</html>

JavaScript(核心逻辑优化)

// 卡牌内容集合
const cardContents = {
    cardOne: "🚕",
    cardTwo: "🗽",
    cardThree: "🌃",
    cardFour: "🍕",
    cardFive: "🍎"
};

// 生成每个内容出现两次的数组,满足配对需求
let cardPool = [];
Object.values(cardContents).forEach(content => {
    cardPool.push(content, content);
});

// Fisher-Yates洗牌算法:保证随机分布均匀
function shuffleArray(arr) {
    for (let i = arr.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [arr[i], arr[j]] = [arr[j], arr[i]];
    }
    return arr;
}

// 初始化游戏
function initGame() {
    const shuffledCards = shuffleArray(cardPool);
    const sections = document.querySelectorAll('.one');
    
    sections.forEach((section, index) => {
        // 用dataset存储卡牌内容,点击前不显示
        section.dataset.cardContent = shuffledCards[index];
        section.addEventListener('click', handleCardClick);
    });
}

// 卡牌点击事件逻辑
function handleCardClick(e) {
    const section = e.target;
    // 点击后显示卡牌内容
    section.innerText = section.dataset.cardContent;
    // 可在此扩展配对逻辑:记录已点击卡牌、判断是否匹配、游戏胜利条件等
}

// 启动游戏
initGame();

关键逻辑说明

  1. 卡牌池生成:通过Object.values获取所有卡牌内容,循环将每个内容添加两次到数组,天然满足「每个内容使用两次」的需求
  2. 洗牌算法:使用Fisher-Yates算法打乱数组,相比简单的sort(() => Math.random() - 0.5)随机性更均匀,避免排序偏差
  3. 数据存储与事件绑定:初始化时给每个区块绑定点击事件,用dataset存储对应卡牌内容,点击时直接读取显示,无需反复随机取值
  4. 避免无限循环:预先生成包含所有重复内容的数组,洗牌后直接分配,从根源解决循环逻辑错误

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 11:15:16