【Golang语言社区】H5游戏开发--JavaScript学习:21点游戏
一、游戏规则
21点游戏的规则有很多种,我在写这个21点游戏的时候,选取了一种规则,描述如下:
1、游戏共有两名玩家,玩家1(庄家)和玩家2,在我编写的这个21点中,玩家1是电脑,玩家2是你,电脑坐庄。
2、一开始,给你和庄家各发两张牌,你可以看到你的两张牌,庄家的牌一张是明牌,一张是暗牌(暗牌是扣过来的牌,你不知道具体点数是多少)。
3、你和庄家的牌都是从一副牌里发出来的,共计52张(不要大小Joker)。
4、A可以当做1点和11点用,J、Q、K当做10点用,其他牌按面值计算点数。
5、发牌后,你可以选择要或不要牌,选择要牌后,如果你的点数大于21点,你就输了,否则你还可以选择要或不要牌,如果你选择不要牌,则轮到庄家要牌。
6、轮到庄家时,如果庄家的点数小于17点,则庄家必须要牌,当庄家点数大于或等于17时,庄家有权继续选择要或不要。如果庄家点数大于21点,则判定庄家输。
7、如果你和庄家都不要了,且双方都没有爆掉,则双方摊牌,计算双方点数,以点数大者胜,若双方点数一致则为平局。
二、目录结构
游戏的目录结构如下:
1、resource目录下,存储了游戏需要使用的图片。
2、bgm.ogg是游戏的背景音乐(我把QQ斗地主的背景音乐放进来了╮(╯▽╰)╭)
3、black_jack.html是一个网页,使用浏览器打开它就可以开始进行游戏了
4、black_jack.js存储了JavaScript代码
resource目录下的图片,包括纸牌图案、玩家头像等内容:
三、页面代码
black_jack.html页面代码如下:
<html>
<head>
<title>JS学习 - 21点 (black jack)</title>
<meta http-equiv="Content-Type" content="text/html;charset=gb2312"/>
</head>
<style type="text/css">
table th
{ text-align: center; text-decoration: none; font-weight: normal; padding: 3px 6px 3px 6px; width:200px;
} table td
{ vertical-align: center; text-align: center; padding: 3px 6px 3px 6px; margin: 0px;
} </style>
<body>
<table width="100%">
<tr>
<td>
<div align="left">
21点游戏 (Black Jack) </div>
</td>
<td>
<div align="right">
<audio width="300" height="10" controls autoplay="true" loop="true">
<source src="bgm.ogg" type="video/ogg"/>
</audio>
</div>
</td>
</tr>
</table>
<hr>
<table id="tableboard">
<tr>
<td id="player1"><img src="resourcecomputer.png" /></td>
<td/><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/>
</tr>
<tr>
<td id="player2"><img src="resourceplayer.jpg" /></td>
<td/><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/><td/>
</tr>
</table>
<hr>
<table>
<tr>
<td>
<div id="score"></div>
</td>
<td>
<div id="bulletin">请做出选择 (Please make a choice.)</div>
</td>
</tr>
</table>
<hr>
<input type="button" id="hit" value="加一张牌 (HIT)" onclick="hit();" />
<input type="button" id="stand" value="我不要了 (STAND)" onclick="stand();" />
<!--<input type="button" id="restart" value="再玩一局 (FIGHT AGAIN)" onclick="location.reload();" />-->
<input type="button" id="restart" value="再玩一局 (FIGHT AGAIN)" onclick="restart();" />
<script src="black_jack.js"></script>
</body></html>
black_jack.js页面代码如下:
//Firefox44.0,如果再来一局功能用location.reload()实现,则必须带上这两句话//document.getElementById("hit").disabled = false;//document.getElementById("stand").disabled = false;
var counter = 0; //发牌次数var winner = ""; //胜利者 player1 - 电脑/player2 - 玩家var hasStood = false; //标记玩家是否已经不要牌
//所有的牌var cards = ["club01", "club02", "club03", "club04", "club05", "club06", "club07", "club08", "club09", "club10", "club11", "club12", "club13", "diamond01", "diamond02", "diamond03", "diamond04", "diamond05", "diamond06", "diamond07","diamond08", "diamond09", "diamond10", "diamond11", "diamond12", "diamond13", "heart01", "heart02", "heart03", "heart04", "heart05", "heart06", "heart07", "heart08", "heart09", "heart10", "heart11", "heart12", "heart13", "spade01", "spade02", "spade03", "spade04", "spade05", "spade06", "spade07", "spade08", "spade09", "spade10", "spade11", "spade12", "spade13"];
//生成随机数var getRand = function (begin, end) { return Math.floor(Math.random() * (end - begin)) + begin;}
//洗牌var rand, tmp;for (var i = 0; i < 1000; i++) { rand = getRand(1, 52); tmp = cards[0]; cards[0] = cards[rand]; cards[rand] = tmp;}
//玩家手牌var cards1 = [getNewCard(), getNewCard()];var cards2 = [getNewCard(), getNewCard()];
var table = document.getElementById("tableboard");table.rows[0].cells[1].innerHTML = "<img src="resource\cardback.png" />";table.rows[0].cells[2].innerHTML = "<img src="resource\" + cards1[1] + ".jpg" />";table.rows[1].cells[1].innerHTML = "<img src="resource\" + cards2[0] + ".jpg" />";table.rows[1].cells[2].innerHTML = "<img src="resource\" + cards2[1] + ".jpg" />";showScore();
//玩家再要一张牌function hit() { getNewCard("player2"); if(checkIfBust("player2")) { document.getElementById("bulletin").innerHTML = "你爆了 (You BUST!)"; document.getElementById("hit").disabled = true; document.getElementById("stand").disabled = true; winner = "player1"; } showScore();}
//玩家选择不要了function stand() { hasStood = true; document.getElementById("hit").disabled = true; document.getElementById("stand").disabled = true; table.rows[0].cells[1].innerHTML = "<img src="resource\" + cards1[0] + ".jpg" />"; //电脑开始要牌 while (calcResult("player1") < 17) { getNewCard("player1"); if(checkIfBust("player1")) { document.getElementById("bulletin").innerHTML = "电脑爆了 (Computer BUST!)"; document.getElementById("hit").disabled = true; document.getElementById("stand").disabled = true; winner = "player2"; } } //如两名玩家都未爆掉,则以分数高者为胜 if (winner == "") { var result1 = calcResult("player1"); var result2 = calcResult("player2"); if (result1 == result2) { document.getElementById("bulletin").innerHTML = "平局 (PUSH!)"; } else if (result1 > result2) { document.getElementById("bulletin").innerHTML = "你输了 (You LOSE)"; } else if (result1 < result2) { document.getElementById("bulletin").innerHTML = "你赢了 (You WIN!)"; } } showScore();}
//获取一张新牌function getNewCard(player) { var card = cards[counter++]; if (player == "player1") { var len = cards1.length; cards1[len] = card; table.rows[0].cells[len + 1].innerHTML = "<img src="resource\" + cards1[len] + ".jpg" />"; } else if (player == "player2") { var len = cards2.length; cards2[len] = card; table.rows[1].cells[len + 1].innerHTML = "<img src="resource\" + cards2[len] + ".jpg" />"; } return card;}
//判断当前情况是否爆掉function checkIfBust(player) { var result = 0; if (player == "player1") { for (var i = 0; i < cards1.length; i++) { //parseInt一定要指定10进制,否则IE8下报错 var c = parseInt(cards1[i].substr(cards1[i].length - 2), "10"); if (c > 10) { c = 10; } result += c; } if (result > 21) { return true; } else { return false; } } else if (player == "player2") { for (var i = 0; i < cards2.length; i++) { var c = parseInt(cards2[i].substr(cards2[i].length - 2), "10"); if (c > 10) { c = 10; } result += c; } if (result > 21) { return true; } else { return false; } }}
//计算一名玩家的得分分数function calcResult(player) { var result = 0; var countOfA = 0; if (player == "player1") { for (var i = 0; i < cards1.length; i++) { var c = parseInt(cards1[i].substr(cards1[i].length - 2), "10"); if (c > 10) { c = 10; } else if (c == 1) { countOfA++; } result += c; } for (var i = 0; i < countOfA; i++) { if (result + 10 <= 21) { result += 10; } else { break; } } } else { for (var i = 0; i < cards2.length; i++) { var c = parseInt(cards2[i].substr(cards2[i].length - 2), "10"); if (c > 10) { c = 10; } else if (c == 1) { countOfA++; } result += c; } for (var i = 0; i < countOfA; i++) { if (result + 10 <= 21) { result += 10; } else { break; } } } return result;}
function showScore() { var result1 = calcResult("player1"); var result2 = calcResult("player2"); document.getElementById("score").innerHTML = "[Computer : You = " + (hasStood == true ? result1 : "?") + " : " + result2 + "]";}
function restart() { document.getElementById("hit").disabled = false; document.getElementById("stand").disabled = false; counter = 0; //发牌次数 winner = ""; //胜利者 player1 - 电脑/player2 - 玩家 hasStood = false; //标记玩家是否已经不要牌 cards = [ "club01", "club02", "club03", "club04", "club05", "club06", "club07", "club08", "club09", "club10", "club11", "club12", "club13", "diamond01", "diamond02", "diamond03", "diamond04", "diamond05", "diamond06", "diamond07", "diamond08", "diamond09", "diamond10", "diamond11", "diamond12", "diamond13", "heart01", "heart02", "heart03", "heart04", "heart05", "heart06", "heart07", "heart08", "heart09", "heart10", "heart11", "heart12", "heart13", "spade01", "spade02", "spade03", "spade04", "spade05", "spade06", "spade07", "spade08", "spade09", "spade10", "spade11", "spade12", "spade13"]; //洗牌 for (var i = 0; i < 1000; i++) { rand = getRand(1, 52); tmp = cards[0]; cards[0] = cards[rand]; cards[rand] = tmp; } //玩家手牌 cards1 = [getNewCard(), getNewCard()]; cards2 = [getNewCard(), getNewCard()]; table.rows[0].cells[1].innerHTML = "<img src="resource\cardback.png" />"; table.rows[0].cells[2].innerHTML = "<img src="resource\" + cards1[1] + ".jpg" />"; table.rows[1].cells[1].innerHTML = "<img src="resource\" + cards2[0] + ".jpg" />"; table.rows[1].cells[2].innerHTML = "<img src="resource\" + cards2[1] + ".jpg" />"; //清空牌桌 for (var i = 3; i < table.rows[0].cells.length; i++) { table.rows[0].cells[i].innerHTML = ""; table.rows[1].cells[i].innerHTML = ""; } showScore(); document.getElementById("bulletin").innerHTML = "请做出选择 (Please make a choice.)";}
/*
四、效果演示
使用Firefox浏览器(版本号44.0)打开black_jack.html后,效果如下图所示:
游戏代码可以从这个链接下载到:http://pan.baidu.com/s/1c1v2MQk
五、几点感受
1、我在IE8(版本8.0.7601.17514)、Chrome(版本46.0.2490.80 m)、Firefox(44.0)三个浏览器上测试了效果,除IE8中无法播放音乐外,其他功能都是正常的。
2、浏览器兼容性问题确实是个令人头疼的问题,就以parseInt函数来说,传入参数为"08"时,IE8返回0,Chrome和Firefox返回8。后来查了下才知道,原来IE8把字符串第一个字符为0的数字自动解析为八进制数了,需要在parseInt的第二个参数中强制指定使用十进制规则转换,才能让三个浏览器返回同样的结果。
3、说句题外话,这个游戏里,电脑赢的概率比你大,毕竟赌博游戏永远是庄家占便宜╭(╯^╰)╮。
END
- python爬取链家租房之获取北京所有区的网站分栏地址(第一次写,code太粗犷,欢迎提建议)
- Pandas-Series知识点总结
- Numpy基础知识点汇总
- P3388 【模板】割点(割顶)
- python爬取链家租房之获取房屋的链接和页面的详细信息
- 信用卡“坏账”客户分析(一)
- 一道简单的sql语句题
- python爬虫反爬取---设置User Agent自动变换header文件
- 一文读懂Python多线程
- 深入理解Python变量作用域与函数闭包
- TensorFlow从1到2 - 5 - 非专家莫入!TensorFlow实现CNN
- JetBrains Rider 破解 (ideaIU等等开发工具都通用)
- python中的小魔法(一)
- 由问题入手,步步爬出Python中赋值与拷贝的坑
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Jackson第一篇
- jackson第二篇
- 从源码分析常见集合的区别之List接口
- c++ 调用ffmpeg命令获取视频属性
- Kubernetes 1.19.0——网络策略
- TypeScript 参数简化实战(进阶知识点conditional types,中高级必会)
- 最简实现Promise,支持异步链式调用(20行)
- 40行代码把Vue3的响应式集成进React做状态管理
- 写给女朋友的中级前端面试秘籍(含详细答案,15k级别)
- 写给初中级前端的高级进阶指南
- 为什么 Vue 中不要用 index 作为 key?(diff 算法详解)
- Vue3 的响应式和以前有什么区别,Proxy 无敌?
- 腾讯云TKE-PV使用cos存储案例: 容器目录权限问题
- Vue3 究竟好在哪里?(和 React Hook 的详细对比)
- 前端「N皇后」递归回溯经典问题图解