国标麻将一抽胡

我将创建一个简单的国标麻将一抽胡游戏,玩家每次随机获得一个听牌牌型,然后从一组牌中抽取一张,看是否能胡牌。

思路分析

  1. 随机生成各种国标麻将听牌牌型(缺一张即可胡牌)

  2. 显示当前牌型,其中一张牌为"?"表示待抽牌

  3. 准备一组待抽牌,其中包含可以胡牌的牌和其他无关牌

  4. 玩家点击抽牌,显示抽牌结果和是否胡牌

下面是完整代码实现:

<!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>

* {

box-sizing: border-box;

margin: 0;

padding: 0;

font-family: 'Microsoft YaHei', sans-serif;

}

body {

background: linear-gradient(135deg, #1a5f23 0%, #0d3b1a 100%);

color: #fff;

min-height: 100vh;

padding: 20px;

display: flex;

flex-direction: column;

align-items: center;

}

.container {

max-width: 900px;

width: 100%;

background-color: rgba(0, 0, 0, 0.6);

border-radius: 20px;

padding: 30px;

box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);

margin-top: 20px;

}

header {

text-align: center;

margin-bottom: 30px;

width: 100%;

}

h1 {

font-size: 2.8rem;

color: #ffde59;

text-shadow: 3px 3px 0 #d35400;

margin-bottom: 10px;

letter-spacing: 2px;

}

.subtitle {

font-size: 1.2rem;

color: #b8e994;

margin-bottom: 20px;

}

.game-area {

display: flex;

flex-wrap: wrap;

justify-content: space-between;

gap: 30px;

}

.hand-section, .draw-section {

flex: 1;

min-width: 300px;

background-color: rgba(10, 60, 20, 0.7);

border-radius: 15px;

padding: 25px;

box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.5);

}

.section-title {

font-size: 1.8rem;

color: #ffde59;

margin-bottom: 20px;

text-align: center;

border-bottom: 2px solid #ffde59;

padding-bottom: 10px;

}

.current-hand {

display: flex;

flex-wrap: wrap;

gap: 12px;

justify-content: center;

margin-bottom: 25px;

min-height: 120px;

}

.tile {

width: 70px;

height: 100px;

background-color: #fff3cd;

border-radius: 8px;

display: flex;

flex-direction: column;

justify-content: center;

align-items: center;

font-size: 1.8rem;

font-weight: bold;

color: #222;

box-shadow: 0 5px 10px rgba(0, 0, 0, 0.3);

transition: all 0.3s;

cursor: default;

position: relative;

overflow: hidden;

}

.tile::before {

content: '';

position: absolute;

top: 5px;

left: 5px;

right: 5px;

bottom: 5px;

border: 1px solid rgba(0, 0, 0, 0.1);

border-radius: 5px;

}

.tile.character {

color: #c0392b;

}

.tile.bamboo {

color: #27ae60;

}

.tile.dot {

color: #2980b9;

}

.tile.wind {

color: #8e44ad;

}

.tile.dragon {

color: #d35400;

}

.tile.missing {

background-color: #ffcccc;

color: #c0392b;

font-size: 2.5rem;

}

.tile-value {

font-size: 1.4rem;

}

.tile-type {

font-size: 1rem;

margin-top: 5px;

}

.hand-info {

background-color: rgba(0, 0, 0, 0.3);

padding: 15px;

border-radius: 10px;

text-align: center;

margin-top: 20px;

}

.hand-info h3 {

color: #ffde59;

margin-bottom: 10px;

}

.draw-options {

display: flex;

flex-wrap: wrap;

gap: 15px;

justify-content: center;

margin-bottom: 30px;

}

.draw-tile {

width: 80px;

height: 110px;

background-color: #fff3cd;

border-radius: 8px;

display: flex;

flex-direction: column;

justify-content: center;

align-items: center;

font-size: 1.8rem;

font-weight: bold;

color: #222;

box-shadow: 0 5px 10px rgba(0, 0, 0, 0.3);

transition: all 0.3s;

cursor: pointer;

position: relative;

}

.draw-tile:hover {

transform: translateY(-10px);

box-shadow: 0 15px 20px rgba(0, 0, 0, 0.4);

}

.draw-tile:active {

transform: translateY(-5px);

}

.draw-tile.selected {

transform: translateY(-10px);

box-shadow: 0 0 20px #ffde59;

border: 3px solid #ffde59;

}

.draw-button {

display: block;

margin: 30px auto;

padding: 15px 40px;

font-size: 1.5rem;

background: linear-gradient(to bottom, #ffde59, #f39c12);

color: #8b4513;

border: none;

border-radius: 50px;

cursor: pointer;

font-weight: bold;

box-shadow: 0 10px 20px rgba(0, 0, 0, 0.3);

transition: all 0.3s;

}

.draw-button:hover {

transform: scale(1.05);

box-shadow: 0 15px 25px rgba(0, 0, 0, 0.4);

}

.draw-button:active {

transform: scale(0.98);

}

.draw-button:disabled {

background: #cccccc;

color: #666666;

cursor: not-allowed;

transform: none;

box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);

}

.result-section {

margin-top: 40px;

background-color: rgba(0, 0, 0, 0.5);

border-radius: 15px;

padding: 25px;

text-align: center;

display: none;

}

.result-section.show {

display: block;

animation: fadeIn 0.8s;

}

@keyframes fadeIn {

from { opacity: 0; }

to { opacity: 1; }

}

.result-title {

font-size: 2.2rem;

margin-bottom: 15px;

}

.result-win {

color: #2ecc71;

}

.result-lose {

color: #e74c3c;

}

.result-details {

font-size: 1.3rem;

line-height: 1.8;

margin-bottom: 20px;

}

.winning-tile {

display: inline-block;

padding: 5px 15px;

background-color: #fff3cd;

color: #c0392b;

border-radius: 5px;

font-weight: bold;

font-size: 1.4rem;

margin: 0 5px;

}

.stats {

display: flex;

justify-content: space-around;

margin-top: 30px;

background-color: rgba(0, 0, 0, 0.3);

padding: 20px;

border-radius: 15px;

}

.stat-item {

text-align: center;

}

.stat-value {

font-size: 2.5rem;

font-weight: bold;

color: #ffde59;

}

.stat-label {

font-size: 1.1rem;

color: #b8e994;

}

.rules {

margin-top: 30px;

background-color: rgba(10, 60, 20, 0.7);

padding: 20px;

border-radius: 15px;

font-size: 1.1rem;

line-height: 1.6;

}

.rules h3 {

color: #ffde59;

margin-bottom: 10px;

}

.rules ul {

padding-left: 20px;

}

.rules li {

margin-bottom: 8px;

}

footer {

margin-top: 30px;

text-align: center;

color: #b8e994;

font-size: 0.9rem;

width: 100%;

padding-top: 20px;

border-top: 1px solid rgba(255, 255, 255, 0.1);

}

@media (max-width: 768px) {

.game-area {

flex-direction: column;

}

.hand-section, .draw-section {

width: 100%;

}

h1 {

font-size: 2rem;

}

.tile {

width: 55px;

height: 80px;

font-size: 1.5rem;

}

.draw-tile {

width: 65px;

height: 90px;

font-size: 1.5rem;

}

}

</style>

</head>

<body>

<header>

<h1>国标麻将一抽胡</h1>

<p class="subtitle">随机生成听牌牌型,只需一抽即可胡牌!</p>

</header>

<div class="container">

<div class="game-area">

<div class="hand-section">

<h2 class="section-title">当前牌型</h2>

<div class="current-hand" id="currentHand">

<!-- 牌型将通过JS动态生成 -->

</div>

<div class="hand-info">

<h3>听牌状态</h3>

<p id="handDescription">您当前有一个听牌牌型,只需要抽取正确的牌即可胡牌!</p>

</div>

</div>

<div class="draw-section">

<h2 class="section-title">抽取一张牌</h2>

<div class="draw-options" id="drawOptions">

<!-- 抽牌选项将通过JS动态生成 -->

</div>

<button class="draw-button" id="drawButton">抽取选中的牌</button>

</div>

</div>

<div class="result-section" id="resultSection">

<!-- 结果将通过JS动态生成 -->

</div>

<div class="stats">

<div class="stat-item">

<div class="stat-value" id="gamesPlayed">0</div>

<div class="stat-label">游戏次数</div>

</div>

<div class="stat-item">

<div class="stat-value" id="wins">0</div>

<div class="stat-label">胡牌次数</div>

</div>

<div class="stat-item">

<div class="stat-value" id="winRate">0%</div>

<div class="stat-label">胡牌率</div>

</div>

</div>

<div class="rules">

<h3>游戏规则</h3>

<ul>

<li>系统随机生成一个国标麻将听牌牌型(缺一张即可胡牌)</li>

<li>牌型中的"?"表示缺的那张牌</li>

<li>从右侧5张牌中选择一张抽取</li>

<li>如果抽到正确的牌,则胡牌!否则不胡</li>

<li>每次游戏都会随机生成新的牌型和待抽牌</li>

<li>国标麻将胡牌牌型包括:平胡、碰碰胡、混一色等</li>

</ul>

</div>

</div>

<footer>

<p>国标麻将一抽胡游戏 | 仅用于娱乐目的 | 使用HTML5、CSS3和JavaScript开发</p>

</footer>

<script>

// 麻将牌数据

const mahjongTiles = {

characters: '1万', '2万', '3万', '4万', '5万', '6万', '7万', '8万', '9万',

bamboos: '1条', '2条', '3条', '4条', '5条', '6条', '7条', '8条', '9条',

dots: '1筒', '2筒', '3筒', '4筒', '5筒', '6筒', '7筒', '8筒', '9筒',

winds: '东风', '南风', '西风', '北风',

dragons: '红中', '发财', '白板'

};

// 所有牌的数组

const allTiles = [

...mahjongTiles.characters,

...mahjongTiles.bamboos,

...mahjongTiles.dots,

...mahjongTiles.winds,

...mahjongTiles.dragons

];

// 预定义的听牌牌型(13张牌+1张听的牌)

const winningHands = [

{

name: "平胡",

tiles: "1万", "2万", "3万", "4筒", "5筒", "6筒", "7条", "8条", "9条", "东风", "东风", "东风", "5万", "7万",

winningTile: "6万",

description: "平胡:基本胡牌牌型,由四组顺子或刻子加一对将组成"

},

{

name: "碰碰胡",

tiles: "1万", "1万", "1万", "3条", "3条", "3条", "5筒", "5筒", "5筒", "北风", "北风", "北风", "红中",

winningTile: "红中",

description: "碰碰胡:由四组刻子(三张相同)加一对将组成"

},

{

name: "混一色",

tiles: "1万", "2万", "3万", "4万", "5万", "6万", "7万", "8万", "9万", "东风", "东风", "东风", "5万",

winningTile: "5万",

description: "混一色:由一种花色牌加上字牌组成的胡牌牌型"

},

{

name: "清一色",

tiles: "1条", "2条", "3条", "4条", "4条", "4条", "5条", "6条", "7条", "8条", "8条", "8条", "9条",

winningTile: "9条",

description: "清一色:全部由同一种花色的牌组成的胡牌牌型"

},

{

name: "全带幺",

tiles: "1万", "1万", "1万", "9万", "9万", "9万", "1筒", "2筒", "3筒", "7筒", "8筒", "9筒", "白板",

winningTile: "白板",

description: "全带幺:所有顺子、刻子、将牌都包含1或9"

},

{

name: "七对",

tiles: "1万", "1万", "3万", "3万", "5万", "5万", "7万", "7万", "9条", "9条", "东风", "东风", "发财",

winningTile: "发财",

description: "七对:由七个对子组成的特殊胡牌牌型"

},

{

name: "十三幺",

tiles: "1万", "9万", "1条", "9条", "1筒", "9筒", "东风", "南风", "西风", "北风", "红中", "发财", "白板",

winningTile: "白板",

description: "十三幺:由13种幺九牌各一张,再加上其中任意一张组成"

}

];

// 游戏状态

let gameState = {

currentHand: null,

winningTile: null,

drawOptions: \[\],

selectedTileIndex: null,

gamesPlayed: 0,

wins: 0

};

// DOM元素

const currentHandEl = document.getElementById('currentHand');

const drawOptionsEl = document.getElementById('drawOptions');

const drawButton = document.getElementById('drawButton');

const resultSection = document.getElementById('resultSection');

const handDescription = document.getElementById('handDescription');

const gamesPlayedEl = document.getElementById('gamesPlayed');

const winsEl = document.getElementById('wins');

const winRateEl = document.getElementById('winRate');

// 初始化游戏

function initGame() {

// 随机选择一个听牌牌型

const handIndex = Math.floor(Math.random() * winningHands.length);

const selectedHand = winningHandshandIndex;

// 复制牌型数组

const handTiles = ...selectedHand.tiles;

gameState.winningTile = selectedHand.winningTile;

// 随机选择一张牌作为缺失的牌(用"?"表示)

const missingTileIndex = Math.floor(Math.random() * handTiles.length);

gameState.currentHand = {

tiles: handTiles,

missingIndex: missingTileIndex,

name: selectedHand.name,

description: selectedHand.description

};

// 更新描述

handDescription.textContent = selectedHand.description;

// 生成待抽牌选项(包含正确的牌和4张随机牌)

gameState.drawOptions = generateDrawOptions(gameState.winningTile);

gameState.selectedTileIndex = null;

// 更新UI

renderCurrentHand();

renderDrawOptions();

// 隐藏结果

resultSection.classList.remove('show');

// 启用抽牌按钮

drawButton.disabled = true;

drawButton.textContent = "抽取选中的牌";

}

// 生成待抽牌选项

function generateDrawOptions(winningTile) {

const options = winningTile;

// 添加4张随机牌(不能与正确牌重复)

while (options.length < 5) {

const randomTile = allTilesMath.floor(Math.random() \* allTiles.length);

if (!options.includes(randomTile) && randomTile !== winningTile) {

options.push(randomTile);

}

}

// 打乱数组

return shuffleArray(options);

}

// 打乱数组(Fisher-Yates洗牌算法)

function shuffleArray(array) {

const newArray = ...array;

for (let i = newArray.length - 1; i > 0; i--) {

const j = Math.floor(Math.random() * (i + 1));

newArray\[i, newArrayj] = newArray\[j, newArrayi];

}

return newArray;

}

// 渲染当前手牌

function renderCurrentHand() {

currentHandEl.innerHTML = '';

const hand = gameState.currentHand;

hand.tiles.forEach((tile, index) => {

const tileEl = document.createElement('div');

tileEl.className = 'tile';

if (index === hand.missingIndex) {

tileEl.classList.add('missing');

tileEl.innerHTML = '?';

} else {

// 根据牌的类型添加对应的CSS类

if (tile.includes('万')) tileEl.classList.add('character');

else if (tile.includes('条')) tileEl.classList.add('bamboo');

else if (tile.includes('筒')) tileEl.classList.add('dot');

else if (tile.includes('风')) tileEl.classList.add('wind');

else tileEl.classList.add('dragon');

const tileValue = tile.replace(/\^0-9/g, '') || tile.substring(0, 1);

const tileType = tile.replace(/0-9/g, '') || tile.substring(1);

tileEl.innerHTML = `

<div class="tile-value">${tileValue}</div>

<div class="tile-type">${tileType}</div>

`;

}

currentHandEl.appendChild(tileEl);

});

}

// 渲染抽牌选项

function renderDrawOptions() {

drawOptionsEl.innerHTML = '';

gameState.drawOptions.forEach((tile, index) => {

const tileEl = document.createElement('div');

tileEl.className = 'draw-tile';

// 根据牌的类型添加对应的CSS类

if (tile.includes('万')) tileEl.classList.add('character');

else if (tile.includes('条')) tileEl.classList.add('bamboo');

else if (tile.includes('筒')) tileEl.classList.add('dot');

else if (tile.includes('风')) tileEl.classList.add('wind');

else tileEl.classList.add('dragon');

const tileValue = tile.replace(/\^0-9/g, '') || tile.substring(0, 1);

const tileType = tile.replace(/0-9/g, '') || tile.substring(1);

tileEl.innerHTML = `

<div class="tile-value">${tileValue}</div>

<div class="tile-type">${tileType}</div>

`;

tileEl.addEventListener('click', () => selectDrawTile(index));

drawOptionsEl.appendChild(tileEl);

});

}

// 选择抽牌

function selectDrawTile(index) {

// 移除之前选中的样式

document.querySelectorAll('.draw-tile').forEach(tile => {

tile.classList.remove('selected');

});

// 添加当前选中的样式

document.querySelectorAll('.draw-tile')index.classList.add('selected');

// 更新选中的索引

gameState.selectedTileIndex = index;

// 启用抽牌按钮

drawButton.disabled = false;

}

// 抽取选中的牌

function drawSelectedTile() {

if (gameState.selectedTileIndex === null) return;

const selectedTile = gameState.drawOptionsgameState.selectedTileIndex;

const isWin = selectedTile === gameState.winningTile;

// 更新游戏统计

gameState.gamesPlayed++;

if (isWin) gameState.wins++;

// 更新统计显示

updateStats();

// 显示结果

showResult(isWin, selectedTile);

// 禁用抽牌按钮

drawButton.disabled = true;

drawButton.textContent = "重新开始游戏";

// 更改按钮功能为重新开始

drawButton.onclick = restartGame;

}

// 显示结果

function showResult(isWin, selectedTile) {

resultSection.innerHTML = '';

const resultTitle = document.createElement('h2');

resultTitle.className = `result-title ${isWin ? 'result-win' : 'result-lose'}`;

resultTitle.textContent = isWin ? '恭喜胡牌!' : '很遗憾,没有胡牌';

const resultDetails = document.createElement('div');

resultDetails.className = 'result-details';

const winningTileSpan = document.createElement('span');

winningTileSpan.className = 'winning-tile';

winningTileSpan.textContent = gameState.winningTile;

const selectedTileSpan = document.createElement('span');

selectedTileSpan.className = 'winning-tile';

selectedTileSpan.textContent = selectedTile;

if (isWin) {

resultDetails.innerHTML = `

您抽中了<span class="winning-tile">${selectedTile}</span>,成功胡牌!

<br>胡牌牌型:<strong>${gameState.currentHand.name}</strong>

<br>${gameState.currentHand.description}

`;

} else {

resultDetails.innerHTML = `

您抽中了<span class="winning-tile">${selectedTile}</span>,但这不是胡牌所需要的牌。

<br>胡牌需要的牌是:<span class="winning-tile">${gameState.winningTile}</span>

<br>胡牌牌型:<strong>${gameState.currentHand.name}</strong>

`;

}

const restartButton = document.createElement('button');

restartButton.className = 'draw-button';

restartButton.textContent = '再来一局';

restartButton.onclick = restartGame;

resultSection.appendChild(resultTitle);

resultSection.appendChild(resultDetails);

resultSection.appendChild(restartButton);

resultSection.classList.add('show');

}

// 重新开始游戏

function restartGame() {

initGame();

drawButton.onclick = drawSelectedTile;

}

// 更新统计

function updateStats() {

gamesPlayedEl.textContent = gameState.gamesPlayed;

winsEl.textContent = gameState.wins;

const winRate = gameState.gamesPlayed > 0

? Math.round((gameState.wins / gameState.gamesPlayed) * 100)

: 0;

winRateEl.textContent = `${winRate}%`;

}

// 初始化事件监听器

drawButton.addEventListener('click', drawSelectedTile);

// 初始化游戏

initGame();

// 添加键盘事件支持

document.addEventListener('keydown', (e) => {

if (e.key >= '1' && e.key <= '5') {

const index = parseInt(e.key) - 1;

if (index < gameState.drawOptions.length) {

selectDrawTile(index);

}

} else if (e.key === 'Enter' || e.key === ' ') {

if (!drawButton.disabled) {

drawSelectedTile();

} else if (resultSection.classList.contains('show')) {

restartGame();

}

} else if (e.key === 'r' || e.key === 'R') {

restartGame();

}

});

</script>

</body>

</html>

游戏功能说明

  1. 牌型生成:游戏随机生成7种不同的国标麻将听牌牌型,包括平胡、碰碰胡、混一色、清一色、全带幺、七对和十三幺。

  2. 游戏流程:

· 系统显示一个听牌牌型,其中一张牌用"?"表示缺失

· 右侧显示5张待抽牌,其中一张是正确的胡牌

· 玩家选择一张牌抽取

· 显示结果,告诉玩家是否胡牌

  1. 游戏特性:

· 每次游戏都会随机生成新的牌型和待抽牌

· 记录游戏统计:游戏次数、胡牌次数和胡牌率

· 支持键盘操作(按1-5选择牌,按Enter或空格键抽取)

· 响应式设计,适配各种屏幕尺寸

  1. 视觉效果:

· 采用麻将主题的绿色和金色配色

· 牌面设计区分不同的花色(万、条、筒、风牌、箭牌)

· 动画效果提升游戏体验

您可以直接复制上面的代码到HTML文件中,然后在浏览器中打开即可开始游戏!

相关推荐
lfwh4 分钟前
探针程序技术解析:基于 Spring Boot 非 Web 模式的云服务监控告警系统
前端·spring boot·后端
Ajie'Blog8 分钟前
AI 周报 | Claude Opus 4.8、Copilot Agent 和 Codex 工作流加速
前端·人工智能·gpt·ai·copilot·ai编程
sugar__salt16 分钟前
深入吃透前端线性数据结构:数组、栈、队列、链表核心原理与实战
前端·数据结构·链表
ikoala20 分钟前
Codex 不得不装的 12 个插件,都在这了
前端·javascript·后端
skywalk816326 分钟前
记录段言的开发过程
开发语言·学习·编程
知识分享小能手26 分钟前
Hadoop学习教程,从入门到精通, MapReduce分布式计算框架 — 完整知识点与代码案例(4)
hadoop·学习·mapreduce
道友可好1 小时前
用 Linter 驾驭 AI:机械化执行的艺术
前端·人工智能·后端
流浪码农~1 小时前
Element Plus DatePicker 动态设置每周起始日
前端·vue.js·elementui
jason_yang1 小时前
刚发版就背锅?前端版本控制就靠他version-rocket
前端
YM52e1 小时前
鸿蒙HarmonyOS ArkTS 实战:教师座椅出入记录 APP 从零到一
学习·华为·harmonyos·鸿蒙系统