单机版斗地主游戏源代码,纯JS编写的斗地主单机版小游戏源代码,下载游戏后,直接运行index.html即可。
完整代码下载地址:单机版斗地主游戏源代码
index.html
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>斗地主单机版-微信关注:Python代码大全</title><link rel="icon" href="img/favicon.ico" sizes="32x32"><link rel="stylesheet" href="css/reset.css"><link rel="stylesheet" href="css/style.min.css"><script src="js/alert.js"></script><script src="js/cards.js"></script></head><body><main><div class="wanduoda"><h3>底注: 100</h3></div><div class="wanduoda beishu"><h3>倍数: 1</h3></div><div class="box"><div class="box-left"><!-- 等待创建card --></div><div class="box-mid"><!-- 等待创建card --></div><div class="box-right"><!-- 等待创建card --></div></div><div class="my"><!-- 等待创建card --></div><div class="btnBox"><input type="button" value="抢地主"><input type="button" value="出牌"><input type="button" value="过" id="woGuo"></div><div class="whatPlayer"><div class="p1"><h3>玩家1正在出牌</h3></div><div class="p2"><h3>玩家2正在出牌</h3></div><div class="p3"><h3>我正在出牌</h3></div></div><div class="user"><div class="p1"><span>剩余牌数:17</span><img src="img/p1.jpg" alt=""><h4>余额:1509</h4><div><h6>报双</h6><img src="img/baodan.gif" alt=""></div></div><div class="p2"><span>剩余牌数:17</span><img src="img/p2.jpg" alt=""><h4>余额:8165</h4><div><h6>报双</h6><img src="img/baodan.gif" alt=""></div></div><div class="p3"><img src="img/p3.jpg" alt=""><h4>余额:896</h4></div></div><div class="iconShow"><img src="img/jiantou.png" alt=""><img src="img/jiantou.png" alt=""><img src="img/jiantou.png" alt=""></div></main><!-- bg --><audio src="" loop></audio> <!-- 其他音效 --><audio src=""></audio><!-- 出牌音效 --><audio src=""></audio><!-- 飞机火箭炸弹呜呜呜等音效 --><audio src=""></audio></body></html>
card.js
let all = [{huase: '🃏',pname: '大王',bijiao: 15},{huase: '🃏',pname: '小王',bijiao: 14},// ----------------------------{huase: '♠',pname: '2',bijiao: 13},{huase: '♥',pname: '2',bijiao: 13},{huase: '♣',pname: '2',bijiao: 13},{huase: '♦',pname: '2',bijiao: 13},// ----------------------------{huase: '♠',pname: 'A',bijiao: 12},{huase: '♥',pname: 'A',bijiao: 12},{huase: '♣',pname: 'A',bijiao: 12},{huase: '♦',pname: 'A',bijiao: 12},// ----------------------------{huase: '♠',pname: 'K',bijiao: 11},{huase: '♥',pname: 'K',bijiao: 11},{huase: '♣',pname: 'K',bijiao: 11},{huase: '♦',pname: 'K',bijiao: 11},// ----------------------------{huase: '♠',pname: 'Q',bijiao: 10},{huase: '♥',pname: 'Q',bijiao: 10},{huase: '♣',pname: 'Q',bijiao: 10},{huase: '♦',pname: 'Q',bijiao: 10},// ----------------------------{huase: '♠',pname: 'J',bijiao: 9},{huase: '♥',pname: 'J',bijiao: 9},{huase: '♣',pname: 'J',bijiao: 9},{huase: '♦',pname: 'J',bijiao: 9},// ----------------------------{huase: '♠',pname: '10',bijiao: 8},{huase: '♥',pname: '10',bijiao: 8},{huase: '♣',pname: '10',bijiao: 8},{huase: '♦',pname: '10',bijiao: 8},// ----------------------------{huase: '♠',pname: '9',bijiao: 7},{huase: '♥',pname: '9',bijiao: 7},{huase: '♣',pname: '9',bijiao: 7},{huase: '♦',pname: '9',bijiao: 7},// ----------------------------{huase: '♠',pname: '8',bijiao: 6},{huase: '♥',pname: '8',bijiao: 6},{huase: '♣',pname: '8',bijiao: 6},{huase: '♦',pname: '8',bijiao: 6},// ----------------------------{huase: '♠',pname: '7',bijiao: 5},{huase: '♥',pname: '7',bijiao: 5},{huase: '♣',pname: '7',bijiao: 5},{huase: '♦',pname: '7',bijiao: 5},// ----------------------------{huase: '♠',pname: '6',bijiao: 4},{huase: '♥',pname: '6',bijiao: 4},{huase: '♣',pname: '6',bijiao: 4},{huase: '♦',pname: '6',bijiao: 4},// ----------------------------{huase: '♠',pname: '5',bijiao: 3},{huase: '♥',pname: '5',bijiao: 3},{huase: '♣',pname: '5',bijiao: 3},{huase: '♦',pname: '5',bijiao: 3},// ----------------------------{huase: '♠',pname: '4',bijiao: 2},{huase: '♥',pname: '4',bijiao: 2},{huase: '♣',pname: '4',bijiao: 2},{huase: '♦',pname: '4',bijiao: 2},// ----------------------------{huase: '♠',pname: '3',bijiao: 1},{huase: '♥',pname: '3',bijiao: 1},{huase: '♣',pname: '3',bijiao: 1},{huase: '♦',pname: '3',bijiao: 1},];// 玩家余额let user1Money = 5509;let user2Money = 6165;let user3Money = 600;// 首次运行存浏览器缓存let moneyObj = {user1Money: 0,user2Money: 0,user3Money: 0};function setLocalStorageMoney() {moneyObj.user1Money = user1Money;moneyObj.user2Money = user2Money;moneyObj.user3Money = user3Money;localStorage.setItem('douDiZhuPMoney', JSON.stringify(moneyObj));}if (localStorage.getItem('douDiZhuPMoney')) {[user1Money, user2Money, user3Money] = [...Object.values(JSON.parse(localStorage.getItem('douDiZhuPMoney')))];}else {setLocalStorageMoney();}// 当前倍数let nowBeiShu = 1;// 当前底注let nowDizhu = 200;// 洗牌function xiPai(arr) {arr = [...arr];// 解决栈与堆问题,这样下面的操作不会改变原数组for (const key in arr) {let index = parseInt(Math.random() * arr.length);[arr[key], arr[index]] = [arr[index], arr[key]];}// arr.reverse();return arr;}let newAll = xiPai(all);// 发牌function faPai(arr) {let player1 = arr.slice(0,17);let player2 = arr.slice(17,34);let player3 = arr.slice(34,51);//34let diPai = arr.slice(51,54);return { player1, player2, player3, diPai };}let { player1, player2, player3, diPai } = faPai(newAll);// 排序function paiXu(arr){ // 这里会改变原数组(栈内引用地址复制),后面不用返回值// 排大小arr.sort((a, b) => b.bijiao - a.bijiao);// 排花色function setHuaseBijiao(huase) {switch (huase) {case '♠':return 4;case '♥':return 3;case '♣':return 2;case '♦':return 1;default:break;}}for (let i = 0; i < 4; i++) {for (const key in arr) {if (key != arr.length - 1) { // 不用遍历最后一次let huaseBijiao1 = setHuaseBijiao(arr[key].huase);let huaseBijiao2 = setHuaseBijiao(arr[+key + 1].huase);if (arr[key].pname == arr[+key + 1].pname && huaseBijiao1 < huaseBijiao2) {[arr[key], arr[+key + 1]] = [arr[+key + 1], arr[key]];}}}}}window.addEventListener('load', function(){const audioYinXiaoBox = document.querySelectorAll('audio');audioYinXiaoBox[0].src = 'audio/bg.mp3';// 音效状态function yinXiaoZhuangTaiChange(arg, sex = true) {let srcAudio = '';if (sex) {switch (arg[0]) {case '单牌':switch (arg[1]) {case 1:srcAudio = 'audio/斗地主音效/斗地主音效/A_K女声/3.ogg';break;case 2:srcAudio = 'audio/斗地主音效/斗地主音效/A_K女声/4.ogg';break;case 3:srcAudio = 'audio/斗地主音效/斗地主音效/A_K女声/5.ogg';break;case 4:srcAudio = 'audio/斗地主音效/斗地主音效/A_K女声/6.ogg';break;case 5:srcAudio = 'audio/斗地主音效/斗地主音效/A_K女声/7.ogg';break;case 6:srcAudio = 'audio/斗地主音效/斗地主音效/A_K女声/8.ogg';break;case 7:srcAudio = 'audio/斗地主音效/斗地主音效/A_K女声/9.ogg';break;case 8:srcAudio = 'audio/斗地主音效/斗地主音效/A_K女声/10.ogg';break;case 9:srcAudio = 'audio/斗地主音效/斗地主音效/A_K女声/J.ogg';break;case 10:srcAudio = 'audio/斗地主音效/斗地主音效/A_K女声/Q.ogg';break;case 11:srcAudio = 'audio/斗地主音效/斗地主音效/A_K女声/K.ogg';break;case 12:srcAudio = 'audio/斗地主音效/斗地主音效/A_K女声/A.ogg';break;case 13:srcAudio = 'audio/斗地主音效/斗地主音效/A_K女声/2.ogg';break;case 14:srcAudio = 'audio/斗地主音效/斗地主音效/A_K女声/小王.ogg';break;case 15:srcAudio = 'audio/斗地主音效/斗地主音效/A_K女声/大王.ogg';break;default:break;}break;case '对子':switch (arg[1]) {case 1:srcAudio = 'audio/斗地主音效/斗地主音效/对子/女声/对3.ogg';break;case 2:srcAudio = 'audio/斗地主音效/斗地主音效/对子/女声/对4.ogg';break;case 3:srcAudio = 'audio/斗地主音效/斗地主音效/对子/女声/对5.ogg';break;case 4:srcAudio = 'audio/斗地主音效/斗地主音效/对子/女声/对6.ogg';break;case 5:srcAudio = 'audio/斗地主音效/斗地主音效/对子/女声/对7.ogg';break;case 6:srcAudio = 'audio/斗地主音效/斗地主音效/对子/女声/对8.ogg';break;case 7:srcAudio = 'audio/斗地主音效/斗地主音效/对子/女声/对9.ogg';break;case 8:srcAudio = 'audio/斗地主音效/斗地主音效/对子/女声/对10.ogg';;break;case 9:srcAudio = 'audio/斗地主音效/斗地主音效/对子/女声/对J.ogg';break;case 10:srcAudio = 'audio/斗地主音效/斗地主音效/对子/女声/对Q.ogg';break;case 11:srcAudio = 'audio/斗地主音效/斗地主音效/对子/女声/对K.ogg';break;case 12:srcAudio = 'audio/斗地主音效/斗地主音效/对子/女声/对A.ogg';break;case 13:srcAudio = 'audio/斗地主音效/斗地主音效/对子/女声/对2.ogg';break;default:break;}break;case '三带一':srcAudio = 'audio/斗地主音效/斗地主音效/三带一/三带一-女.ogg';break;case '三带对子':srcAudio = 'audio/斗地主音效/斗地主音效/三带一对/三带一对-女.ogg';break;case '三不带':switch (arg[1]) {case 1:srcAudio = 'audio/斗地主音效/斗地主音效/三个/女声/三个3.ogg';break;case 2:srcAudio = 'audio/斗地主音效/斗地主音效/三个/女声/三个4.ogg';break;case 3:srcAudio = 'audio/斗地主音效/斗地主音效/三个/女声/三个5.ogg';break;case 4:srcAudio = 'audio/斗地主音效/斗地主音效/三个/女声/三个6.ogg';break;case 5:srcAudio = 'audio/斗地主音效/斗地主音效/三个/女声/三个7.ogg';break;case 6:srcAudio = 'audio/斗地主音效/斗地主音效/三个/女声/三个8.ogg';break;case 7:srcAudio = 'audio/斗地主音效/斗地主音效/三个/女声/三个9.ogg';break;case 8:srcAudio = 'audio/斗地主音效/斗地主音效/三个/女声/三个10.ogg';;;break;case 9:srcAudio = 'audio/斗地主音效/斗地主音效/三个/女声/三个J.ogg';break;case 10:srcAudio = 'audio/斗地主音效/斗地主音效/三个/女声/三个Q.ogg';break;case 11:srcAudio = 'audio/斗地主音效/斗地主音效/三个/女声/三个K.ogg';break;case 12:srcAudio = 'audio/斗地主音效/斗地主音效/三个/女声/三个A.ogg';break;case 13:srcAudio = 'audio/斗地主音效/斗地主音效/三个/女声/三个2.ogg';break;default:break;}break;case '四带二':srcAudio = 'audio/斗地主音效/斗地主音效/四带二/四带二-女.ogg';break;case '连子':srcAudio = 'audio/斗地主音效/斗地主音效/顺子/顺子-女.ogg';break;case '连对':srcAudio = 'audio/斗地主音效/斗地主音效/连对/连对-女.ogg';break;case '炸弹':srcAudio = 'audio/斗地主音效/斗地主音效/炸弹/炸弹-女.ogg';audioYinXiaoBox[3].src = 'audio/斗地主音效/斗地主音效/炸弹/炸弹-Duang~.ogg';audioYinXiaoBox[3].play();break;case '王炸':srcAudio = 'audio/斗地主音效/斗地主音效/王炸/王炸-女.ogg';audioYinXiaoBox[3].src = 'audio/斗地主音效/斗地主音效/王炸/honghong.mp3';audioYinXiaoBox[3].play();break;case '四带二大飞机':case '飞机0':case '飞机1':case '飞机2':srcAudio = 'audio/斗地主音效/斗地主音效/飞机/飞机-女.ogg';audioYinXiaoBox[3].src = 'audio/斗地主音效/斗地主音效/飞机/飞机-呜呜.ogg';audioYinXiaoBox[3].play();default:break;}}else {}audioYinXiaoBox[2].src = srcAudio;audioYinXiaoBox[2].play();}function otherYinXiao(arg) {let srcAudio = '';switch (arg) {case '过':let key = parseInt(Math.random() * 3);switch (key) {case 0:srcAudio = 'audio/斗地主音效/斗地主音效/要不起/要不起-女声.ogg';break;case 1:srcAudio = 'audio/斗地主音效/斗地主音效/过/过-女声.ogg';break;case 2:srcAudio = 'audio/斗地主音效/斗地主音效/不要/不要-女.ogg';break;default:break;}break;case '报双':srcAudio = 'audio/斗地主音效/斗地主音效/我就两张牌了/我就两张牌了-女声.ogg';break;case '报单':srcAudio = 'audio/斗地主音效/斗地主音效/我就一张牌了/我就一张牌了-女声.ogg';default:break;}audioYinXiaoBox[1].src = srcAudio;audioYinXiaoBox[1].play();}// 开始游戏function startGame() {tangZi = {};myShouPai = {};newAll = xiPai(all);let faPaiArr = faPai(newAll);[player1, player2, player3, diPai] = [faPaiArr.player1, faPaiArr.player2, faPaiArr.player3, faPaiArr.diPai];shuaXinShouPai();shuaXinTangZi();btnBox.children[0].style.display = 'inline-block';btnBox.children[1].style.display = 'none';btnBox.children[2].style.display = 'none';shuiChuDePaiJianTou[0].style.display = 'none';shuiChuDePaiJianTou[1].style.display = 'none';shuiChuDePaiJianTou[2].style.display = 'none';zhengZaiChuPaiTile[0].style.display = 'none';zhengZaiChuPaiTile[1].style.display = 'none';zhengZaiChuPaiTile[2].style.display = 'none';p1IsDizhu = p2IsDizhu = p3IsDizhu = false;isP1 = isP2 = isP3 = false;nowBeiShu = 1;wanduoda[1].children[0].innerHTML = `倍数: ${nowBeiShu}`;p1ChuPaiLeMaA = p2ChuPaiLeMaA = true;userBox[0].querySelector('div').style.display = 'none';userBox[1].querySelector('div').style.display = 'none';userBox[0].querySelector('span').innerHTML = `剩余牌数:17`;userBox[1].querySelector('span').innerHTML = `剩余牌数:17`;}// 胜利判断function canGameOver() {if (player1.length == 0 || player2.length == 0) {gameOverShuaXinPlayerShouPai();setTimeout(() => {user1Money += nowBeiShu * nowDizhu;user2Money += nowBeiShu * nowDizhu;user3Money -= nowBeiShu * nowDizhu * 2;alert2(`失败,您余额-${nowDizhu * nowBeiShu * 2}<br/>玩家1余额+${nowDizhu * nowBeiShu}<br/>玩家2余额+${nowDizhu * nowBeiShu}`, startGame);userBox[0].querySelector('h4').innerHTML = `余额:${user1Money}`;userBox[1].querySelector('h4').innerHTML = `余额:${user2Money}`;userBox[2].querySelector('h4').innerHTML = `余额:${user3Money}`;setLocalStorageMoney();},1000);return true;}else if (player3.length == 0) {gameOverShuaXinPlayerShouPai();setTimeout(() => {user1Money -= nowBeiShu * nowDizhu;user2Money -= nowBeiShu * nowDizhu;user3Money += nowBeiShu * nowDizhu * 2;alert2(`胜利,您余额+${nowDizhu * nowBeiShu * 2}<br/>玩家1余额-${nowDizhu * nowBeiShu}<br/>玩家2余额-${nowDizhu * nowBeiShu}`, startGame);userBox[0].querySelector('h4').innerHTML = `余额:${user1Money}`;userBox[1].querySelector('h4').innerHTML = `余额:${user2Money}`;userBox[2].querySelector('h4').innerHTML = `余额:${user3Money}`;setLocalStorageMoney();},1000);return true;}return false;}const zhengZaiChuPaiTile = document.querySelector('.whatPlayer').children;const shuiChuDePaiJianTou = document.querySelector('.iconShow').children;const player1Box = document.querySelector('.box > .box-left');const player2Box = document.querySelector('.box > .box-right');const player3Box = document.querySelector('.my');const diPaiBox = document.querySelector('.box > .box-mid');const userBox = document.querySelector('.user').children;const wanduoda = document.querySelectorAll('.wanduoda');userBox[0].querySelector('h4').innerHTML = `余额:${user1Money}`;userBox[1].querySelector('h4').innerHTML = `余额:${user2Money}`;userBox[2].querySelector('h4').innerHTML = `余额:${user3Money}`;wanduoda[0].children[0].innerHTML = `底注: ${nowDizhu}`;wanduoda[1].children[0].innerHTML = `倍数: ${nowBeiShu}`;// 出牌箭头显示function chuPaiLeJianTouShow(key) {shuiChuDePaiJianTou[2].style.display = 'none';shuiChuDePaiJianTou[1].style.display = 'none';shuiChuDePaiJianTou[0].style.display = 'none';switch (key) {case 2:setTimeout(() => {shuiChuDePaiJianTou[1].style.display = 'block';},40);break;case 1:setTimeout(() => {shuiChuDePaiJianTou[0].style.display = 'block';},40);break;case 3:setTimeout(() => {shuiChuDePaiJianTou[2].style.display = 'block';},40);break;default:break;}}// 出牌桥接对象let tangZi = {};// 我的手牌let myShouPai = {};// 刷新点击function shuaXinShouPaiDianJi() {for (const iterator of player3Box.children) {iterator.onclick = e => {if (iterator.getAttribute('data-index') == '1') {iterator.style.transform = 'translateY(-20px)';iterator.setAttribute('data-index','0');myShouPai[iterator.getAttribute('data-key')] = player3[iterator.getAttribute('data-key')];}else if(iterator.getAttribute('data-index') == '0') {iterator.style.transform = 'translateY(0)';iterator.setAttribute('data-index','1');delete myShouPai[iterator.getAttribute('data-key')];}};}}// 刷新人机1手牌function shuaXinPlayer1ShouPai() {player1Box.innerHTML = '';paiXu(player1);for (let i = 0; i < player1.length; i++) {const card1 = document.createElement('div');if (player1[i].huase == '♥' || player1[i].huase == '♦' || player1[i].pname == '大王') {card1.style.color = 'red';}card1.className = 'card';card1.setAttribute('data-key', i);// card1.innerHTML = `//<div class="card-leftTitle absBox">// <h3>${player1[i].pname}</h3>// <h3>${player1[i].huase}</h3>//</div>//<div class="card-rightTitle absBox">// <h3>${player1[i].pname}</h3>// <h3>${player1[i].huase}</h3>//</div>//<div class="card-content">// <h1>${player1[i].huase}</h1>//</div>// `;player1Box.appendChild(card1);}}// 游戏结束刷新人机手牌function gameOverShuaXinPlayerShouPai() {player1Box.innerHTML = '';paiXu(player1);for (let i = 0; i < player1.length; i++) {const card1 = document.createElement('div');if (player1[i].huase == '♥' || player1[i].huase == '♦' || player1[i].pname == '大王') {card1.style.color = 'red';}card1.className = 'card';card1.setAttribute('data-key', i);card1.style.backgroundImage = 'none';card1.innerHTML = `<div class="card-leftTitle absBox"><h3>${player1[i].pname}</h3><h3>${player1[i].huase}</h3></div><div class="card-rightTitle absBox"><h3>${player1[i].pname}</h3><h3>${player1[i].huase}</h3></div><div class="card-content"><h1>${player1[i].huase}</h1></div>`;player1Box.appendChild(card1);}player2Box.innerHTML = '';paiXu(player2);for (let i = 0; i < player2.length; i++) {const card2 = document.createElement('div');if (player2[i].huase == '♥' || player2[i].huase == '♦' || player2[i].pname == '大王') {card2.style.color = 'red';}card2.className = 'card';card2.setAttribute('data-key', i);card2.style.backgroundImage = 'none';card2.innerHTML = `<div class="card-leftTitle absBox"><h3>${player2[i].pname}</h3><h3>${player2[i].huase}</h3></div><div class="card-rightTitle absBox"><h3>${player2[i].pname}</h3><h3>${player2[i].huase}</h3></div><div class="card-content"><h1>${player2[i].huase}</h1></div>`;player2Box.appendChild(card2);}}// 刷新人机2手牌function shuaXinPlayer2ShouPai() {player2Box.innerHTML = '';paiXu(player2);for (let i = 0; i < player2.length; i++) {const card2 = document.createElement('div');if (player2[i].huase == '♥' || player2[i].huase == '♦' || player2[i].pname == '大王') {card2.style.color = 'red';}card2.className = 'card';card2.setAttribute('data-key', i);// card2.innerHTML = `//<div class="card-leftTitle absBox">// <h3>${player2[i].pname}</h3>// <h3>${player2[i].huase}</h3>//</div>//<div class="card-rightTitle absBox">// <h3>${player2[i].pname}</h3>// <h3>${player2[i].huase}</h3>//</div>//<div class="card-content">// <h1>${player2[i].huase}</h1>//</div>// `;player2Box.appendChild(card2);}}// 刷新手牌function shuaXinShouPai() {shuaXinPlayer1ShouPai();shuaXinPlayer2ShouPai();player3Box.innerHTML = '';paiXu(player3);for (let i = 0; i < player3.length; i++) {const card3 = document.createElement('div');if (player3[i].huase == '♥' || player3[i].huase == '♦' || player3[i].pname == '大王') {card3.style.color = 'red';}card3.className = 'card';card3.setAttribute('data-index','1');card3.setAttribute('data-key', i);card3.innerHTML = `<div class="card-leftTitle absBox"><h3>${player3[i].pname}</h3><h3>${player3[i].huase}</h3></div><div class="card-rightTitle absBox"><h3>${player3[i].pname}</h3><h3>${player3[i].huase}</h3></div><div class="card-content"><h1>${player3[i].huase}</h1></div>`;player3Box.appendChild(card3);}shuaXinShouPaiDianJi();}shuaXinShouPai();// 刷新堂子function shuaXinTangZi() {diPaiBox.innerHTML = '';for (let i = 0; i < diPai.length; i++) {const card = document.createElement('div');card.className = 'card';if (diPai[i].huase == '♥' || diPai[i].huase == '♦' || diPai[i].pname == '大王') {card.style.color = 'red';}card.innerHTML = `<div class="card-leftTitle absBox"><h3>${diPai[i].pname}</h3><h3>${diPai[i].huase}</h3></div><div class="card-rightTitle absBox"><h3>${diPai[i].pname}</h3><h3>${diPai[i].huase}</h3></div><div class="card-content"><h1>${diPai[i].huase}</h1></div>`;diPaiBox.appendChild(card);}}// 刷新底牌function shuaXinDiPai() {diPaiBox.innerHTML = '';for (let i = 0; i < diPai.length; i++) {const card = document.createElement('div');card.className = 'card';card.style.backgroundImage = "url('img/pai.jpg')";card.style.backgroundSize = '100% 100%';if (diPai[i].huase == '♥' || diPai[i].huase == '♦' || diPai[i].pname == '大王') {card.style.color = 'red';}diPaiBox.appendChild(card);}}shuaXinDiPai();// 谁是地主let p1IsDizhu = false, p2IsDizhu = false, p3IsDizhu = false;const btnBox = document.querySelector('main > div.btnBox');// 要不起(过)(用于人机判定,不能误伤队友)// 淘汰,不再使用let p1YaoBuQi = false, p2YaoBuQi = false, p3YaoBuQi = false; // 淘汰// 现在是谁出的牌let isP1 = false, isP2 = false, isP3 = false;// 用于报单人机智商问题let p1ChuPaiLeMaA = true, p2ChuPaiLeMaA = true;// 人机出牌流程function renJiLiuCheng(flag) { // true人机无敌随意出牌 false正常流程// ---------------人机2出牌-----------------btnBox.children[1].style.display = 'none';btnBox.children[2].style.display = 'none';setTimeout(() => {if (p3IsDizhu || !isP3) { // p3是地主或p3要不起p1就出牌if (flag) {if (player1.length == 1 && p1ChuPaiLeMaA) {// 如果p1报单,p2放单牌,如果下轮p1没出牌,p2放弃p1p2YaoBuQi = renJiPlay(player2, 'p2', false, true, '单牌');p1ChuPaiLeMaA = false;}else {p2YaoBuQi = renJiPlay(player2, 'p2', false, true);}}else {p2YaoBuQi = renJiPlay(player2, 'p2');}shuaXinPlayer2ShouPai();if (canGameOver()) {return;}}else {renJiPlay(player2, 'p2', true);}zhengZaiChuPaiTile[1].style.display = 'none';zhengZaiChuPaiTile[0].style.display = 'block';zhengZaiChuPaiTile[2].style.display = 'none';// ---------------人机1出牌-----------------setTimeout(() => {if (p2IsDizhu || !isP2 || true) { // p2是地主或p2要不起p1就出牌 ----------暂时开启见人就轰模式,关闭删除true-------------------------// 优化人机算法,防止误伤队友-----------------------------------let flag = true;let num = 0;let tangZiCardType = getTangZiPaiType();if (tangZiCardType[0] == '炸弹') {flag = false;}else {if (tangZiCardType[0] == '单牌' || tangZiCardType[0] == '对子' || tangZiCardType[0] == '三不带') {for (const iterator of Object.values(tangZi)) {if (iterator.bijiao > 10) { // p2出大于Q的p1就放flag = false;}}}else if(tangZiCardType[0] == '三带一' || tangZiCardType[0] == '三带对子') {for (const iterator of Object.values(tangZi)) {if (iterator.bijiao > 6) { // P2出大于8的三带*p1就放num++;if (num > 2) {flag = false;}}}}}// -----------如果地主出的牌,直接干--------------------if (isP3 && p3IsDizhu) {flag = true;}// -------------------------------if (flag) {p1YaoBuQi = renJiPlay(player1, 'p1');}else {p1YaoBuQi = renJiPlay(player1, 'p1', true);}// -------------------------------------------------------------shuaXinPlayer1ShouPai();if (canGameOver()) {return;}}else {renJiPlay(player1, 'p1', true);}// tangZi = {};btnBox.children[1].style.display = 'inline-block';if (!isP3) {btnBox.children[2].style.display = 'inline-block';}zhengZaiChuPaiTile[0].style.display = 'none';zhengZaiChuPaiTile[1].style.display = 'none';zhengZaiChuPaiTile[2].style.display = 'block';p1YaoBuQi = p2YaoBuQi = p3YaoBuQi = false;},2000);},2000);// --------------------------------}function renJiLiuCheng1(flag) { // true人机无敌随意出牌 false正常流程btnBox.children[1].style.display = 'none';btnBox.children[2].style.display = 'none';// ---------------人机1出牌-----------------setTimeout(() => {renJiPlay(player2, 'p2', true);zhengZaiChuPaiTile[1].style.display = 'none';zhengZaiChuPaiTile[0].style.display = 'block';zhengZaiChuPaiTile[2].style.display = 'none';setTimeout(() => {if (p2IsDizhu || !isP2) { // p2是地主或p2要不起p1就出牌---------------这里不开启见人就轰模式,让下家(p1)走提高人机胜率----------if (flag) {if (player2.length == 1 && p2ChuPaiLeMaA) {// 如果p2报单,p1放单牌,如果下轮p2没出牌,p1放弃p2p1YaoBuQi = renJiPlay(player1, 'p1', false, true, '单牌');p2ChuPaiLeMaA = false;}else {p1YaoBuQi = renJiPlay(player1, 'p1', false, true);}}else {p1YaoBuQi = renJiPlay(player1, 'p1');}shuaXinPlayer1ShouPai();if (canGameOver()) {return;}}else {renJiPlay(player1, 'p1', true);}// tangZi = {};btnBox.children[1].style.display = 'inline-block';if (!isP3) {btnBox.children[2].style.display = 'inline-block';}zhengZaiChuPaiTile[0].style.display = 'none';zhengZaiChuPaiTile[1].style.display = 'none';zhengZaiChuPaiTile[2].style.display = 'block';p1YaoBuQi = p2YaoBuQi = p3YaoBuQi = false;},2000);},2000);// --------------------------------}// 检索我是否能出牌压住上家function canIPlayCard(myShouPai) {console.log('上家堂子',tangZi);let tangZiCardType = getTangZiPaiType();let myCardType = getTangZiPaiType(myShouPai);console.log(tangZiCardType,'tangZiCardType');console.log(myCardType,'myCardType');if (tangZiCardType == 0) {return true;}if (!isP3) {if (tangZiCardType[0] != myCardType[0]) {if (tangZiCardType[0] != '炸弹' && tangZiCardType[0] != '王炸' && myCardType[0] == '炸弹') {return true;}if ((myCardType[0] == '炸弹' && myCardType[1] > tangZiCardType[1]) || myCardType[0] == '王炸') {return true;}return false;}else {if (myCardType[1] > tangZiCardType[1]) {return true;}return false;}}return true;}btnBox.addEventListener('click',e => {// 抢地主if (e.target.value == '抢地主') {audioYinXiaoBox[0].play();isP3 = true;zhengZaiChuPaiTile[2].style.display = 'block';p3IsDizhu = true;tangZi = {};myShouPai = {};e.target.style.display = 'none';btnBox.children[1].style.display = 'inline-block';// btnBox.children[2].style.display = 'inline-block';diPaiBox.innerHTML = '';for (const iterator of diPai) {player3.push(iterator);}shuaXinShouPai();}// 出牌if (e.target.value == '出牌') {// e.target.style.display = 'none';let shangJiaTangZi = canIPlayCard(myShouPai);if (shangJiaTangZi) {tangZi = myShouPai;}console.log('我当前出牌类型:',getTangZiPaiType());let cardType = getTangZiPaiType();if (cardType && shangJiaTangZi) {for (const key in tangZi) {player3[key] = '0';}for (let i = 0; i < player3.length; ) {if (player3[i] == '0') {player3.splice(i, 1);}else {i++;}}if (player3.length == 2) {otherYinXiao('报双');}else if (player3.length == 1) {otherYinXiao('报单');}diPai = Object.values(tangZi);shuaXinTangZi();zhengZaiChuPaiTile[2].style.display = 'none';zhengZaiChuPaiTile[0].style.display = 'none';zhengZaiChuPaiTile[1].style.display = 'block';shuaXinShouPai();chuPaiLeJianTouShow(3);isP3 = true;isP1 = isP2 = false;let srcAudio = getTangZiPaiType();yinXiaoZhuangTaiChange(srcAudio);if (cardType[0] == '王炸' || cardType[0] == '炸弹') {nowBeiShu *= 2;wanduoda[1].children[0].innerHTML = `倍数: ${nowBeiShu}`;}if (canGameOver()) {return;}renJiLiuCheng();}else {alert('当前出牌不正确,请重新出牌');setTimeout(function() {document.body.removeChild(document.body.childNodes[document.body.childNodes.length - 1]);}, 1000);return;}myShouPai = {};}// 过if (e.target.value == '过') {otherYinXiao('过');zhengZaiChuPaiTile[2].style.display = 'none';zhengZaiChuPaiTile[0].style.display = 'none';zhengZaiChuPaiTile[1].style.display = 'block';alert1('过', 300, 60, 'left');p3YaoBuQi = true;if (isP2) {renJiLiuCheng(true);}else if(isP1) {renJiLiuCheng1(true);}}});// 重复数量检查,返回出牌的牌名和对应数量function getChongFu(arr) {arr = [...arr];let newArr = [];for (let i = 0; i < arr.length; i++) {let pname = arr[i].pname;let bijiao = arr[i].bijiao;let ciShu = 1;newArr[i] = { pname, ciShu, bijiao };for (let j = i+1; j <arr.length; ) {if (arr[i].pname == arr[j].pname) {newArr[i].ciShu++;arr.splice(j, 1);}else {j++;}}}return newArr;}// 出牌类型判断function getTangZiPaiType(arg = false) {let typeArr = [];let tangZiValues;if (arg) {tangZiValues = Object.values(arg);}else {tangZiValues = Object.values(tangZi);}const regE = /\W/;const chongFuWrapArr = getChongFu(tangZiValues);// ------------------------单牌-------------------------if (tangZiValues.length == 1) {typeArr[0] = '单牌';typeArr[1] = tangZiValues[0].bijiao;return typeArr;}// ------------------------对子-------------------------if (tangZiValues.length == 2 && tangZiValues[0].pname == tangZiValues[1].pname) {typeArr[0] = '对子';typeArr[1] = tangZiValues[0].bijiao;return typeArr;}// ------------------------王炸-------------------------if (tangZiValues.length == 2 && regE.test(tangZiValues[0].pname) && regE.test(tangZiValues[1].pname)) {typeArr[0] = '王炸';return typeArr;}// ------------------------三不带-------------------------if (tangZiValues.length == 3 && tangZiValues[0].pname == tangZiValues[1].pname && tangZiValues[1].pname == tangZiValues[2].pname) {typeArr[0] = '三不带';typeArr[1] = tangZiValues[0].bijiao;return typeArr;}// ------------------------三带一或炸弹(4张牌)-------------------if (tangZiValues.length == 4) {for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 3) {typeArr[0] = '三带一';typeArr[1] = iterator.bijiao;return typeArr;}if (iterator.ciShu == 4) {typeArr[0] = '炸弹';typeArr[1] = iterator.bijiao;return typeArr;}}}// ------------------------三带对子-------------------------if (tangZiValues.length == 5) {if (chongFuWrapArr.length == 2) {for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 3) {typeArr[0] = '三带对子';typeArr[1] = iterator.bijiao;return typeArr;}}}}// ------------------------连子-------------------------if (tangZiValues.length >= 5 && chongFuWrapArr.length == tangZiValues.length) {let flag = true;tangZiValues.sort((a, b) => a.bijiao - b.bijiao);for (let i = 0; i < tangZiValues.length; i++) {if (tangZiValues[i].bijiao == '13' || tangZiValues[i].bijiao == '14' || tangZiValues[i].bijiao == '15') {//剔除出大小王和2flag = false;}if (tangZiValues.length - 1 != i && tangZiValues[i].bijiao + 1 != tangZiValues[i + 1].bijiao) {// 判断是否连号flag = false;}}if (flag) {typeArr[0] = '连子';typeArr[1] = tangZiValues[0].bijiao;typeArr[2] = tangZiValues.length;return typeArr;}}// ------------------------飞机0(三不带飞机)-------------------------if (tangZiValues.length % 3 == 0 && tangZiValues.length != 0) {let flag = true;// 三不带飞机判断let fly3 = 0;// 保存3张牌的出现判断是否连子const fly3Arr = [];// 初始化准备for (const iterator of chongFuWrapArr) {if (iterator.pname == '2') {flag = false;}if (iterator.ciShu == 3) {fly3++;fly3Arr.push(iterator.bijiao);}}if (tangZiValues.length - fly3 * 3 == 0) {fly3Arr.sort((a, b) => a - b);for (let i = 0; i < fly3Arr.length - 1; i++) {if (fly3Arr[i] + 1 != fly3Arr[i + 1]) {flag = false;}}if (flag) {typeArr[0] = '飞机0';typeArr[1] = fly3Arr[0];typeArr[2] = fly3Arr.length;return typeArr;}}}// ------------------------飞机1(三带一飞机)或滚炸-------------------------if (tangZiValues.length % 4 == 0 && tangZiValues.length != 0) {let flag = true;let flagBoom = true;// 滚炸判断开关let gunZha = true;// 三带1飞机判断let fly3 = 0;// 保存3张牌的出现判断是否连子const fly3Arr = [];// 炸弹出现判断连号const boomArr = [];// 初始化准备for (const iterator of chongFuWrapArr) {if (iterator.pname == '2') {flag = false;gunZha = false;}if (iterator.ciShu != 4) {gunZha = false;}if (iterator.ciShu == 3) {fly3++;fly3Arr.push(iterator.bijiao);}if (iterator.ciShu == 4) {boomArr.push(iterator.bijiao);}}// 开始滚炸判断// if (gunZha) {//boomArr.sort((a, b) => a - b);//for (let i = 0; i < boomArr.length - 1; i++) {// if (boomArr[i] + 1 != boomArr[i + 1]) {// flagBoom = false;// }//}//if (flagBoom) {// typeArr[0] = '滚炸';// typeArr[1] = boomArr[0];// typeArr[2] = boomArr.length;// return typeArr;//}// }// 开始三带一飞机判断if (tangZiValues.length - fly3 * 3 == fly3 || (tangZiValues.length - (fly3 - 1) * 3 == fly3 - 1 && (fly3 == 4 || fly3 == 5 || fly3 == 6))) {fly3Arr.sort((a, b) => a - b);if (fly3 < 4) {typeArr[2] = fly3Arr.length;typeArr[1] = fly3Arr[0];for (let i = 0; i < fly3Arr.length - 1; i++) {if (fly3Arr[i] + 1 != fly3Arr[i + 1]) {flag = false;}}}if (fly3 >= 4) {typeArr[2] = fly3Arr.length - 1;let flag1 = false, flag2 = false;for (let i = 0; i < fly3Arr.length - 2; i++) {if (fly3Arr[i] + 1 != fly3Arr[i + 1]) {flag1 = true;typeArr[1] = fly3Arr[1];}}for (let i = 1; i < fly3Arr.length - 1; i++) {if (fly3Arr[i] + 1 != fly3Arr[i + 1]) {flag2 = true;typeArr[1] = fly3Arr[0];}}if (flag1 && flag2) {// 只要首尾有能连上的就不会进入这个条件 例如333/444/555/888也是三带一飞机flag = false;}}if (flag) {typeArr[0] = '飞机1';return typeArr;}}}// ------------------------飞机2(三带对子飞机)-------------------------if (tangZiValues.length % 5 == 0 && tangZiValues.length != 0) {let flag = true;// 三带2飞机判断let fly3 = 0;// 保存3张牌的出现判断是否连子const fly3Arr = [];// 带的牌是对子出现的次数let fly2 = 0;// 初始化准备for (const iterator of chongFuWrapArr) {if (iterator.pname == '2') {flag = false;}if (iterator.ciShu == 3) {fly3++;fly3Arr.push(iterator.bijiao);}if (iterator.ciShu == 2) {fly2++;}}if (tangZiValues.length - fly3 * 3 == fly2 * 2) {fly3Arr.sort((a, b) => a - b);for (let i = 0; i < fly3Arr.length - 1; i++) {if (fly3Arr[i] + 1 != fly3Arr[i + 1]) {flag = false;}}if (flag) {typeArr[0] = '飞机2';typeArr[1] = fly3Arr[0];typeArr[2] = fly3Arr.length;return typeArr;}}}// ------------------------连对-------------------------if (tangZiValues.length % 2 == 0 && tangZiValues.length > 5) {let flag = true;// 保存对子的出现const douBle2Arr = [];// 初始化准备for (const iterator of chongFuWrapArr) {if (iterator.pname == '2') {flag = false;}if (iterator.ciShu == 2) {douBle2Arr.push(iterator.bijiao);}}if (tangZiValues.length - douBle2Arr.length * 2 == 0) {douBle2Arr.sort((a, b) => a - b);for (let i = 0; i < douBle2Arr.length - 1; i++) {if (douBle2Arr[i] + 1 != douBle2Arr[i + 1]) {flag = false;}}if (flag) {typeArr[0] = '连对';typeArr[1] = douBle2Arr[0];typeArr[2] = douBle2Arr.length;return typeArr;}}}// ------------------------四带二-------------------------if (tangZiValues.length == 6) {for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 4) {typeArr[0] = '四带二';typeArr[1] = iterator.bijiao;return typeArr;}}}// ------------------------四带二大飞机-------------------------if (tangZiValues.length % 6 == 0 && tangZiValues.length > 5) {let flag = true;let flagBoom = true;// 炸弹出现判断连号const boomArr = [];// 初始化准备for (const iterator of chongFuWrapArr) {if (iterator.pname == '2') {flag = false;}if (iterator.ciShu == 4) {boomArr.push(iterator.bijiao);}}if (flag && ((tangZiValues.length - (boomArr.length - 1) * 4 == (boomArr.length - 1) * 2 && tangZiValues.length > 11) || tangZiValues.length - boomArr.length * 4 == boomArr.length * 2)) {boomArr.sort((a, b) => a - b);let flag1 = false, flag2 = false;if (boomArr.length < 3) {typeArr[1] = boomArr[0];typeArr[2] = boomArr.length;for (let i = 0; i < boomArr.length - 1; i++) {if (boomArr[i] + 1 != boomArr[i + 1]) {flagBoom = false;}}}if (boomArr.length >= 3) {typeArr[2] = boomArr.length - 1;for (let i = 0; i < boomArr.length - 2; i++) {if (boomArr[i] + 1 != boomArr[i + 1]) {typeArr[1] = boomArr[1];flag1 = true;}}for (let i = 1; i < boomArr.length - 1; i++) {if (boomArr[i] + 1 != boomArr[i + 1]) {typeArr[1] = boomArr[0];flag2 = true;}}if (flag1 && flag2) {// 同理三带一飞机flagBoom = false;}}if (flagBoom) {typeArr[0] = '四带二大飞机';return typeArr;}}}return 0;}// 手牌查询(获取可出牌区桥接数组)// 手牌 牌型 最小牌值 连号量(可选)function shouPaiChaXun(arr, type, bijiao = 0, more) {// 手牌重复检索const chongFuWrapArr = getChongFu(arr);chongFuWrapArr.reverse();// 可出牌区桥接数组const canIPlay = [];// 有无双王判断let jokerFlag = false;let bigJoker = false, smallJoker = false;for (const iterator of chongFuWrapArr) {if (iterator.bijiao == 14) {smallJoker = true;}if (iterator.bijiao == 15) {bigJoker = true;}}if (bigJoker && smallJoker) {jokerFlag = true;}// 王炸查询function haveJoker() {if (jokerFlag) {let pname = '王';let bijiao = 20;let ciShu = 1;canIPlay.push({ pname, ciShu, bijiao });}}// ---------------------------------------------------// 单牌查询 用于三带一function getOneCard() {for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 1 && iterator.bijiao < 14) {for (let i = 0; i < arr.length; i++) {if (iterator.pname == arr[i].pname) {return 1;}}}}for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 2) {for (let i = 0; i < arr.length; i++) {if (iterator.pname == arr[i].pname) {return 1;}}}}return 0;}// 单牌、对子查询 用于四带二function getDoubleCard() {let num = 0;for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 1 && iterator.bijiao < 14) {for (let i = 0; i < arr.length; i++) {if (iterator.pname == arr[i].pname) {num++;if (num == 2) {return 1;}}}}}for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 2) {for (let i = 0; i < arr.length; i++) {if (iterator.pname == arr[i].pname) {return 1;}}}}return 0;}function getDuiZiCard() {for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 2) {for (let i = 0; i < arr.length; i++) {if (iterator.pname == arr[i].pname) {return 1;}}}}return 0;}switch (type) {case '单牌':for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 1 && iterator.bijiao > bijiao) {if (jokerFlag) { // 有双王的话就不要拆单if (iterator.bijiao < 14) {canIPlay.push(iterator);}}else {canIPlay.push(iterator);}}}for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 2 && iterator.bijiao > bijiao) {canIPlay.push(iterator);}}for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 3 && iterator.bijiao > bijiao) {canIPlay.push(iterator);}}for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 4) {canIPlay.push(iterator);}}haveJoker();break;case '对子':for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 2 && iterator.bijiao > bijiao) {canIPlay.push(iterator);}}for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 3 && iterator.bijiao > bijiao) {canIPlay.push(iterator);}}for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 4) {canIPlay.push(iterator);}}haveJoker();break;case '三不带':for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 3 && iterator.bijiao > bijiao) {canIPlay.push(iterator);}}for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 4) {canIPlay.push(iterator);}}haveJoker();break;case '三带一':for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 3 && iterator.bijiao > bijiao) {if (getOneCard()) {canIPlay.push(iterator);}}}for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 4) {canIPlay.push(iterator);}}haveJoker();break;case '炸弹':for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 4 && iterator.bijiao > bijiao) {canIPlay.push(iterator);}}haveJoker();break;case '四带二':for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 4 && iterator.bijiao > bijiao) {if (getDoubleCard()) {iterator.can4 = '可压';canIPlay.push(iterator);}}}for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 4) {canIPlay.push(iterator);}}haveJoker();break;case '三带对子':for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 3 && iterator.bijiao > bijiao) {if (getDuiZiCard()) {canIPlay.push(iterator);}}}for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 4) {canIPlay.push(iterator);}}haveJoker();break;case '连对':let tempArr = [];let flagt1 = true, flagt2 = true, flagt3 = false;for (const iterator of chongFuWrapArr) {if (iterator.ciShu >= 2 && iterator.bijiao > bijiao && iterator.ciShu < 4 && iterator.bijiao < 13) {tempArr.push(iterator);}}if (tempArr.length >= more) {for (let i = 0; i < more - 1; i++) {if (tempArr[i].bijiao + 1 != tempArr[i + 1].bijiao) {flagt1 = false;}}for (let i = tempArr.length - more; i < tempArr.length - 1; i++) {if (tempArr[i].bijiao + 1 != tempArr[i + 1].bijiao) {flagt2 = false;}}if (tempArr.length - more == 2 && tempArr.length > 4) {flagt3 = true;for (let i = 1; i < more; i++) {if (tempArr[i].bijiao + 1 != tempArr[i + 1].bijiao) {flagt3 = false;}}}if (flagt1) {let tarr = tempArr.slice(0, more);tarr.unshift(true);canIPlay.push(tarr);}else if (flagt2) {let tarr = tempArr.slice(tempArr.length - more, tempArr.length);tarr.unshift(true);canIPlay.push(tarr);}else if (flagt3) {let tarr = tempArr.slice(1, tempArr.length - 1);tarr.unshift(true);canIPlay.push(tarr);}}for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 4) {canIPlay.push(iterator);}}haveJoker();break;case '连子':{let tempArr = [];let flagt1 = true, flagt2 = true, flagt3 = false;for (const iterator of chongFuWrapArr) {if (iterator.ciShu >= 1 && iterator.bijiao > bijiao && iterator.ciShu < 4 && iterator.bijiao < 13) {tempArr.push(iterator);}}if (tempArr.length >= more) {for (let i = 0; i < more - 1; i++) {if (tempArr[i].bijiao + 1 != tempArr[i + 1].bijiao) {flagt1 = false;}}for (let i = tempArr.length - more; i < tempArr.length - 1; i++) {if (tempArr[i].bijiao + 1 != tempArr[i + 1].bijiao) {flagt2 = false;}}if (tempArr.length - more == 2 && tempArr.length > 6) {flagt3 = true;for (let i = 1; i < more; i++) {if (tempArr[i].bijiao + 1 != tempArr[i + 1].bijiao) {flagt3 = false;}}}if (flagt1) {let tarr = tempArr.slice(0, more);tarr.unshift(true);canIPlay.push(tarr);}else if (flagt2) {let tarr = tempArr.slice(tempArr.length - more, tempArr.length);tarr.unshift(true);canIPlay.push(tarr);}else if (flagt3) {let tarr = tempArr.slice(1, tempArr.length - 1);tarr.unshift(true);canIPlay.push(tarr);}}for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 4) {canIPlay.push(iterator);}}haveJoker();}break;case '王炸':break;default:break;}return canIPlay;}// 获取待出牌arr:shouPaiChaXun的返回值,player:玩家手牌,index:shouPaiChaXun的返回值数组的下标(往下可依次提示),type:牌型function getTempCardArr(arr, player, index, type) {let cardObj = {};// 获取单牌,供三带一function getOneCard() {const chongFuWrapArr = getChongFu(player);chongFuWrapArr.reverse();for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 1 && iterator.bijiao < 14) {for (let i = 0; i < player.length; i++) {if (iterator.pname == player[i].pname) {let tempObj = {};tempObj[i] = player[i];return tempObj;}}}}for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 2) {for (let i = 0; i < player.length; i++) {if (iterator.pname == player[i].pname) {let tempObj = {};tempObj[i] = player[i];return tempObj;}}}}return 0;}// 获取2张单牌或对子,供四带二function getDoubleCard() {const chongFuWrapArr = getChongFu(player);chongFuWrapArr.reverse();let num = 0;let tempObj = {};for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 1 && iterator.bijiao < 14) {for (let i = 0; i < player.length; i++) {if (iterator.pname == player[i].pname) {num++;tempObj[i] = player[i];if (num == 2) {return tempObj;}}}}}for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 2) {for (let i = 0; i < player.length; i++) {if (iterator.pname == player[i].pname) {num++;tempObj[i] = player[i];if (num == 2) {return tempObj;}}}}}return 0;}// 获取对子,供三带对子function getDuiZiCard() {const chongFuWrapArr = getChongFu(player);chongFuWrapArr.reverse();let num = 0;let tempObj = {};for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 2) {for (let i = 0; i < player.length; i++) {if (iterator.pname == player[i].pname) {num++;tempObj[i] = player[i];if (num == 2) {return tempObj;}}}}}return 0;}switch (type) {case '单牌':for (let i = 0; i < player.length; i++) {if (arr[index].pname == player[i].pname) {if (arr[index].ciShu != 4) {cardObj[i] = player[i];return cardObj;}else if (arr[index].ciShu == 4) {cardObj[i] = player[i];}}else if(arr[index].pname == '王' && player[i].bijiao >= 14) {cardObj[i] = player[i];}}return cardObj;case '对子':for (let i = 0; i < player.length; i++) {if (arr[index].pname == player[i].pname) {if (arr[index].ciShu != 4) {cardObj[i] = player[i];if (Object.keys(cardObj).length == 2) {return cardObj;}}else if (arr[index].ciShu == 4) {cardObj[i] = player[i];}}else if(arr[index].pname == '王' && player[i].bijiao >= 14) {cardObj[i] = player[i];}}return cardObj;case '三不带':for (let i = 0; i < player.length; i++) {if (arr[index].pname == player[i].pname) {if (arr[index].ciShu != 4) {cardObj[i] = player[i];if (Object.keys(cardObj).length == 3) {return cardObj;}}else if (arr[index].ciShu == 4) {cardObj[i] = player[i];}}else if(arr[index].pname == '王' && player[i].bijiao >= 14) {cardObj[i] = player[i];}}return cardObj;case '三带一':for (let i = 0; i < player.length; i++) {if (arr[index].pname == player[i].pname) {if (arr[index].ciShu != 4) {cardObj[i] = player[i];if (Object.keys(cardObj).length == 3) {let oneCard = getOneCard();cardObj[Object.keys(oneCard)[0]] = Object.values(oneCard)[0];return cardObj;}}else if (arr[index].ciShu == 4) {cardObj[i] = player[i];}}else if(arr[index].pname == '王' && player[i].bijiao >= 14) {cardObj[i] = player[i];}}return cardObj;case '炸弹':for (let i = 0; i < player.length; i++) {if (arr[index].pname == player[i].pname) {cardObj[i] = player[i];}else if(arr[index].pname == '王' && player[i].bijiao >= 14) {cardObj[i] = player[i];}}return cardObj;case '四带二':for (let i = 0; i < player.length; i++) {if (arr[index].pname == player[i].pname) {if (arr[index].can4 == '可压') {cardObj[i] = player[i];if (Object.keys(cardObj).length == 4) {let doubleCard = getDoubleCard();cardObj[Object.keys(doubleCard)[0]] = Object.values(doubleCard)[0];cardObj[Object.keys(doubleCard)[1]] = Object.values(doubleCard)[1];return cardObj;}}else if (arr[index].ciShu == 4) {cardObj[i] = player[i];}}else if(arr[index].pname == '王' && player[i].bijiao >= 14) {cardObj[i] = player[i];}}return cardObj;case '三带对子':for (let i = 0; i < player.length; i++) {if (arr[index].pname == player[i].pname) {if (arr[index].ciShu != 4) {cardObj[i] = player[i];if (Object.keys(cardObj).length == 3) {let duiZiObj = getDuiZiCard();cardObj[Object.keys(duiZiObj)[0]] = Object.values(duiZiObj)[0];cardObj[Object.keys(duiZiObj)[1]] = Object.values(duiZiObj)[1];return cardObj;}}else if (arr[index].ciShu == 4) {cardObj[i] = player[i];}}else if(arr[index].pname == '王' && player[i].bijiao >= 14) {cardObj[i] = player[i];}}return cardObj;case '连对':let num = 0;let j = 1;if (arr[index][0]) {arr[index].reverse();arr[index].unshift(arr[index][arr[index].length - 1]);arr[index].pop();}for (let i = 0; i < player.length; i++) {if (arr[index].pname == player[i].pname || arr[index][0]) {if (arr[index][0]) {if (arr[index][j].pname == player[i].pname) {cardObj[i] = player[i];if (++num == 2) {num = 0;j++;}if (Object.keys(cardObj).length == (arr[index].length - 1) * 2) {return cardObj;}}}else if (arr[index].ciShu == 4) {cardObj[i] = player[i];}}else if(arr[index].pname == '王' && player[i].bijiao >= 14) {cardObj[i] = player[i];}}return cardObj;case '连子':{let j = 1;if (arr[index][0]) {arr[index].reverse();arr[index].unshift(arr[index][arr[index].length - 1]);arr[index].pop();}for (let i = 0; i < player.length; i++) {if (arr[index].pname == player[i].pname || arr[index][0]) {if (arr[index][0]) {if (arr[index][j].pname == player[i].pname) {cardObj[i] = player[i];j++;if (Object.keys(cardObj).length == arr[index].length - 1) {return cardObj;}}}else if (arr[index].ciShu == 4) {cardObj[i] = player[i];}}else if(arr[index].pname == '王' && player[i].bijiao >= 14) {cardObj[i] = player[i];}}}return cardObj;default:break;}}console.log(shouPaiChaXun(player3, '单牌'));console.log(getTempCardArr(shouPaiChaXun(player3, '单牌'), player3, 0, '单牌'));// 随机获取牌型(用于人机无敌后自动出牌型)function getChuShenMePaiNe(whatPlayer, suijima = false) {let key = 100;if (suijima) {// 优化算法,规定算法也无法选牌则进行switch随机选牌key = parseInt(Math.random() * 7);}else {const chongFuWrapArr = getChongFu(whatPlayer);chongFuWrapArr.reverse();let oneArr = [];let twoArr = [];let threeArr = [];for (const iterator of chongFuWrapArr) {if (iterator.ciShu == 1) {oneArr.push(iterator);}else if (iterator.ciShu == 2) {twoArr.push(iterator);}else if (iterator.ciShu == 3) {threeArr.push(iterator);}}// -----------------这里人机作弊,监视偷看我报单或报双的牌,注释掉即可关闭作弊-------------if (player3.length == 2 && whatPlayer.length > 2) {let typeCard = [];let renjikey;if (player3[0].bijiao == player3[1].bijiao) {renjikey = parseInt(Math.random() * 6);typeCard = renjizuobi(renjikey);let canTemp = shouPaiChaXun(whatPlayer, typeCard[0], typeCard[1], typeCard[2]);let num = 0;while (true) {if (canTemp.length > 0 || ++num == 30) {break;}else {renjikey = parseInt(Math.random() * 6);typeCard = renjizuobi(renjikey);canTemp = shouPaiChaXun(whatPlayer, typeCard[0], typeCard[1], typeCard[2]);}}return typeCard;}function renjizuobi(key) {switch (key) {case 0:return ['单牌', 0];case 1:return ['三带一', 0];case 2:return ['三带对子', 0];case 3:return ['连对', 0, 3];case 4:return ['连子', 0, 5];case 5:return ['对子', player3[0].bijiao - 1];default:break}}}else if (player3.length == 1 && whatPlayer.length > 1) {let typeCard = [];let renjikey;renjikey = parseInt(Math.random() * 6);typeCard = renjizuobi(renjikey);let canTemp = shouPaiChaXun(whatPlayer, typeCard[0], typeCard[1], typeCard[2]);let num = 0;while (true) {if (canTemp.length > 0 || ++num == 30) {break;}else {renjikey = parseInt(Math.random() * 6);typeCard = renjizuobi(renjikey);canTemp = shouPaiChaXun(whatPlayer, typeCard[0], typeCard[1], typeCard[2]);}}return typeCard;function renjizuobi(key) {switch (key) {case 0:return ['单牌', player3[0].bijiao - 1];case 1:return ['三带一', 0];case 2:return ['三带对子', 0];case 3:return ['连对', 0, 3];case 4:return ['连子', 0, 5];case 5:return ['对子', 0];default:break}}}// ------------------------------------------------------------------------------if (oneArr.length > 4) {let flagL = true;for (let i = 0; i < 4; i++) {if (oneArr[i].bijiao + 1 != oneArr[i + 1].bijiao) {flagL = false;}}if (flagL) {return ['连子', 0, 5];}}if (twoArr.length > 2) {let flagL = true;for (let i = 0; i < 2; i++) {if (twoArr[i].bijiao + 1 != twoArr[i + 1].bijiao) {flagL = false;}}if (flagL) {return ['连对', 0, 3];}if (twoArr.length > 3) {let flagL = true;for (let i = 1; i < 3; i++) {if (twoArr[i].bijiao + 1 != twoArr[i + 1].bijiao) {flagL = false;}}if (flagL) {return ['连对', 0, 3];}}}if (threeArr.length > 0 && whatPlayer.length > 6 && threeArr[0].bijiao < 9) { // 手里有三张的,手牌大于6张,三张的小于Jif (oneArr.length < twoArr.length) {return ['三带对子', 0];}else {return ['三带一', 0];}}if (threeArr.length > 0 && whatPlayer.length <= 6) {return ['三带一', 0];}if (twoArr.length >= oneArr.length) {return ['对子', 0];}if (twoArr.length < oneArr.length) {return ['单牌', 0];}}switch (key) {case 0:return ['单牌', 0];case 1:return ['对子', 0];case 2:return ['三不带', 0];case 3:return ['三带一', 0];case 4:return ['三带对子', 0];case 5:return ['连对', 0, 3];case 6:return ['连子', 0, 5];case 7:case 8:case 9:case 10:case 11:case 12:case 13:case 14:case 15:case 16:case 17:case 18:case 19:case 20:case 21:default:break;}return ['王炸', 20];}// 人机1出牌function renJiPlay(whatPlayer, p, guo, isWuDi, danpai) { // p:true人机1, guo:true人机过,用于不误伤队友,isWuDi:true人机无敌进入随机出牌let typeCard; // 可出牌区桥接数组if (isWuDi) {typeCard = getChuShenMePaiNe(whatPlayer);while (true) {if (shouPaiChaXun(whatPlayer, typeCard[0], typeCard[1], typeCard[2]).length > 0) {break;}else {typeCard = getChuShenMePaiNe(whatPlayer, true);}}if (danpai == '单牌') {typeCard = ['单牌', 0];}console.log('当前随机获取牌--------------------------------',typeCard);}else {typeCard = getTangZiPaiType(); // 牌型}let canTemp = shouPaiChaXun(whatPlayer, typeCard[0], typeCard[1], typeCard[2]);console.log('可出牌区桥接数组',canTemp);if (canTemp.length == 0 || guo) {if (p == 'p1') {alert1('过', 300, 10, 'left');}else if (p == 'p2') {alert1('过', 300, 10, 'right');}otherYinXiao('过');return true;}let cardObj = getTempCardArr(canTemp, whatPlayer, 0, typeCard[0]); // 根据可出牌区桥接数组获取待出牌for (const key in cardObj) {whatPlayer[key] = '0';}for (let i = 0; i < whatPlayer.length; ) {if (whatPlayer[i] == '0') {whatPlayer.splice(i, 1);}else {i++;}}diPai = Object.values(cardObj);if (diPai.length == 4) {let isZhaDan = true;for (let i = 0; i < diPai.length - 1; i++) {if (diPai[i].pname != diPai[i + 1].pname) {isZhaDan = false;}}if (isZhaDan) {nowBeiShu *= 2;wanduoda[1].children[0].innerHTML = `倍数: ${nowBeiShu}`;}}else if (diPai.length == 2) {let isZhaDan = true;for (let i = 0; i < diPai.length; i++) {if (diPai[i].bijiao < 14) {isZhaDan = false;}}if (isZhaDan) {nowBeiShu *= 2;wanduoda[1].children[0].innerHTML = `倍数: ${nowBeiShu}`;}}tangZi = diPai;console.log(tangZi);let srcAudio = getTangZiPaiType();yinXiaoZhuangTaiChange(srcAudio);shuaXinTangZi();if (p == 'p1') {userBox[0].querySelector('span').innerHTML = `剩余牌数:${whatPlayer.length}`;if (whatPlayer.length < 3) {userBox[0].querySelector('div').style.display = 'block';if (whatPlayer.length == 2) {userBox[0].querySelector('div > h6').innerHTML = '报双';otherYinXiao('报双');}else if (whatPlayer.length == 1) {userBox[0].querySelector('div > h6').innerHTML = '报单';otherYinXiao('报单');}}chuPaiLeJianTouShow(1);isP1 = true;isP3 = isP2 = false;}else if (p == 'p2') {if (whatPlayer.length < 3) {userBox[1].querySelector('div').style.display = 'block';if (whatPlayer.length == 2) {userBox[1].querySelector('div > h6').innerHTML = '报双';otherYinXiao('报双');}else if (whatPlayer.length == 1) {userBox[1].querySelector('div > h6').innerHTML = '报单';otherYinXiao('报单');}}userBox[1].querySelector('span').innerHTML = `剩余牌数:${whatPlayer.length}`;chuPaiLeJianTouShow(2);isP2 = true;isP1 = isP3 = false;}return false;}});
完整代码下载地址:单机版斗地主游戏源代码,
如果觉得《单机版斗地主游戏源代码 纯JS编写的斗地主单机版小游戏源代码》对你有帮助,请点赞、收藏,并留下你的观点哦!