HTML+JS谁是卧底游戏

先说一句:一段时间没发文章,好多僵尸粉关注我,这CSDN😠

主要功能

  1. 玩家设置:在游戏开始前,输入总人数、卧底人数和白板人数。系统会自动计算出剩下的平民人数,并随机分配身份。

  2. 身份查看:在游戏开始后,所有玩家的身份都会以卡片形式呈现。你可以点击卡片来查看自己的身份,内容会显示"你是白板"或者对应的词语。

  3. 判决系统:所有玩家看完自己的身份后,可以通过"判决"按钮来猜测谁是卧底或白板。你输入认为是卧底或白板的玩家编号,无论猜测正确与否,都会减少一次判决机会。

  4. 剩余机会提示:每次判决后,系统会自动计算并提示你剩余的判决机会

  5. 胜负判定:如果你在机会用完前成功找出了所有的卧底和白板,游戏会提示平民获胜。如果机会用尽而卧底或白板还没被全部找出,游戏会提示失败。

效果图


源代码

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>谁是卧底</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            height: 100vh;
            margin: 0;
            background-color: #1c1c2b;
            color: white;
        }
        .input-container {
            background-color: #2d2d44;
            padding: 20px;
            border-radius: 15px;
            box-shadow: 0 10px 25px rgba(0,0,0,0.3);
            margin-bottom: 20px;
            text-align: center;
        }
        h1 {
            margin-bottom: 15px;
            font-size: 24px;
            font-weight: bold;
        }
        label {
            display: block;
            margin-bottom: 10px;
            font-size: 18px;
        }
        input[type="number"] {
            width: 100px;
            padding: 8px;
            margin-bottom: 15px;
            border-radius: 10px;
            border: none;
            box-shadow: 0 5px 15px rgba(0,0,0,0.1);
            text-align: center;
        }
        button {
            padding: 10px 20px;
            border: none;
            border-radius: 15px;
            background-color: #007BFF;
            color: white;
            font-size: 16px;
            cursor: pointer;
            box-shadow: 0 5px 15px rgba(0,0,0,0.3);
        }
        .card-container {
            position: relative;
            width: 200px;
            height: 300px;
            perspective: 1000px;
        }
        .card {
            width: 100%;
            height: 100%;
            background-color: orange;
            border-radius: 15px;
            box-shadow: 0 5px 15px rgba(0,0,0,0.3);
            position: absolute;
            top: 0;
            left: 0;
            transition: transform 0.6s;
            transform-style: preserve-3d;
            cursor: pointer;
        }
        .card.flipped {
            transform: rotateY(180deg);
        }
        .card-content {
            position: absolute;
            width: 100%;
            height: 100%;
            backface-visibility: hidden;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 24px;
            color: white;
        }
        .card-content.back {
            transform: rotateY(180deg);
            background-color: #FFEB3B;
            border-radius: 15px;
        }
        .judge-button {
            display: none;
            padding: 20px 40px;
            border: none;
            border-radius: 25px;
            background-color: #FFD700;
            color: black;
            font-size: 20px;
            cursor: pointer;
            margin-top: 20px;
            box-shadow: 0 5px 15px rgba(0,0,0,0.3);
        }
    </style>
</head>
<body>

    <div class="input-container">
        <h1>谁是卧底游戏</h1>
        <label for="totalPlayers">总人数 (2-10):</label>
        <input type="number" id="totalPlayers" min="2" max="10">
        
        <label for="undercoverCount">卧底人数:</label>
        <input type="number" id="undercoverCount" min="1">
        
        <label for="blankCount">白板人数:</label>
        <input type="number" id="blankCount" min="0">
        <p></p>
        <button onclick="startGame()">开始游戏</button>
    </div>

    <div class="card-container" id="cardContainer">
        <!-- 卡片将会在这里生成 -->
    </div>

    <button class="judge-button" id="judgeButton" onclick="judge()">判决</button>

    <script>
        const wordsPairs = [
            ['苹果', '香蕉'],
            ['水泥', '瓷砖'],
            ['博客园', 'CSDN']
        ];

        let totalPlayers, undercoverCount, blankCount, civilians, undercovers, blanks;
        let remainingChances;
        let cardsFlipped = 0;

        function startGame() {
            totalPlayers = parseInt(document.getElementById('totalPlayers').value);
            undercoverCount = parseInt(document.getElementById('undercoverCount').value);
            blankCount = parseInt(document.getElementById('blankCount').value);

            if (isNaN(totalPlayers) || isNaN(undercoverCount) || isNaN(blankCount) || 
                totalPlayers < 2 || totalPlayers > 10 || 
                undercoverCount > totalPlayers || blankCount > totalPlayers ||
                blankCount > undercoverCount || (undercoverCount + blankCount) > totalPlayers) {
                alert('请检查输入,确保所有数值合理!');
                return;
            }

            civilians = totalPlayers - undercoverCount - blankCount;
            
            // 设置判决机会 = 白板数 + 卧底数 + 1
            remainingChances = blankCount + undercoverCount + 1;

            const wordPair = wordsPairs[Math.floor(Math.random() * wordsPairs.length)];
            undercovers = Array(undercoverCount).fill(wordPair[1]);
            blanks = Array(blankCount).fill('白板');
            const civiliansArr = Array(civilians).fill(wordPair[0]);

            const words = [...undercovers, ...blanks, ...civiliansArr].sort(() => Math.random() - 0.5);

            document.querySelector('.input-container').style.display = 'none';

            generateCards(words);
        }

        function generateCards(words) {
            const cardContainer = document.getElementById('cardContainer');
            cardContainer.innerHTML = '';

            words.forEach((word, index) => {
                const card = document.createElement('div');
                card.className = 'card';
                card.setAttribute('data-word', word);
                card.onclick = () => flipCard(card, index);

                const front = document.createElement('div');
                front.className = 'card-content front';
                front.innerText = '点击查看';

                const back = document.createElement('div');
                back.className = 'card-content back';
                back.innerText = word === '白板' ? '你是白板' : word;

                card.appendChild(front);
                card.appendChild(back);
                cardContainer.appendChild(card);

                card.style.zIndex = words.length - index;
                card.style.top = `${index * 5}px`;
                card.style.left = `${index * 5}px`;
            });
        }

        function flipCard(card, index) {
            if (card.classList.contains('flipped')) return;

            card.classList.add('flipped');
            cardsFlipped++;

            setTimeout(() => {
                card.style.display = 'none';
                if (cardsFlipped === totalPlayers) {
                    document.getElementById('judgeButton').style.display = 'block';
                }
            }, 1500);
        }

        function judge() {
            const guess = prompt('请输入你认为的卧底或白板编号(1-' + totalPlayers + '):');
            const guessIndex = parseInt(guess) - 1;
            if (isNaN(guessIndex) || guessIndex < 0 || guessIndex >= totalPlayers) {
                alert('无效的编号,请重新输入!');
                return;
            }

            const word = document.querySelectorAll('.card')[guessIndex].getAttribute('data-word');

            if (word === '白板' || word === undercovers[0]) {
                alert(`你找到了${word === '白板' ? '白板' : '卧底'},他们被淘汰了!`);
                document.querySelectorAll('.card')[guessIndex].remove();
                if (word === '白板') {
                    blanks.pop();
                } else {
                    undercovers.pop();
                }
            } else {
                alert('你猜错了!');
            }
            
            remainingChances--;
            alert('剩余机会: ' + remainingChances);

            if (undercovers.length === 0 && blanks.length === 0) {
                alert('平民获胜!');
                resetGame();
            } else if (remainingChances === 0) {
                alert('游戏失败!');
                resetGame();
            }
        }

        function resetGame() {
            document.querySelector('.input-container').style.display = 'block';
            document.getElementById('cardContainer').innerHTML = '';
            document.getElementById('judgeButton').style.display = 'none';
            cardsFlipped = 0;
        }
    </script>

</body>
</html>

游戏规则

1. 角色分配

  • 平民:多数玩家会被分配到同一个词语,这些玩家就是平民。平民的目标是找出谁是卧底。
  • 卧底:少数玩家(通常只有一人)会被分配到一个与平民词语类似但不同的词语。卧底的目标是混淆视听,让自己不被平民发现。
  • 白板(可选):某些版本中还有"白板"角色,他们不会得到任何词语,只能靠别人的描述来猜测其他人的身份。

2. 游戏流程

  • 第一轮:描述词语 每个玩家依次用一句话描述自己的词语,注意不能太直白,也不能过于模糊。平民需要小心描述,确保卧底不会轻易发现他们的词语,但又要让其他平民认出自己是同伴。卧底则需要假装自己是平民,在描述时尽量不暴露自己的词语。
  • 讨论与投票 一轮描述结束后,玩家可以互相讨论,并试图找出谁的描述最可疑。然后,所有玩家进行投票,选出他们认为是卧底的玩家。得票最多的玩家会被淘汰,并揭示自己的身份。
  • 下一轮 剩下的玩家继续进行描述和投票,直到所有的卧底被找出(平民获胜)或平民人数与卧底人数相等(卧底获胜)。

3. 胜负判定

  • 平民获胜:如果所有的卧底被投票淘汰,平民获胜。
  • 卧底获胜:如果卧底成功存活到剩下人数与卧底人数相等,卧底获胜。

4. 游戏策略

  • 平民需要通过描述、观察和推理来识别卧底的微妙差异。
  • 卧底则需要运用策略来隐藏自己的身份,并尽量让平民之间互相怀疑。
相关推荐
沉默璇年16 分钟前
react中useMemo的使用场景
前端·react.js·前端框架
yqcoder22 分钟前
reactflow 中 useNodesState 模块作用
开发语言·前端·javascript
2401_8827275731 分钟前
BY组态-低代码web可视化组件
前端·后端·物联网·低代码·数学建模·前端框架
会发光的猪。1 小时前
css使用弹性盒,让每个子元素平均等分父元素的4/1大小
前端·javascript·vue.js
天下代码客1 小时前
【vue】vue中.sync修饰符如何使用--详细代码对比
前端·javascript·vue.js
猫爪笔记1 小时前
前端:HTML (学习笔记)【1】
前端·笔记·学习·html
前端李易安2 小时前
Webpack 热更新(HMR)详解:原理与实现
前端·webpack·node.js
红绿鲤鱼2 小时前
React-自定义Hook与逻辑共享
前端·react.js·前端框架
Domain-zhuo2 小时前
什么是JavaScript原型链?
开发语言·前端·javascript·jvm·ecmascript·原型模式
小丁爱养花2 小时前
前端三剑客(三):JavaScript
开发语言·前端·javascript