html+css+JavaScript实现爱恩斯坦棋游戏

2023-12-04 02:40

本文主要是介绍html+css+JavaScript实现爱恩斯坦棋游戏,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!


title: “html+css+JavaScript实现爱恩斯坦棋游戏”
author: Sun-Wind
date: December 30, 2021

背景:本贴将基于前端的语言实现爱恩斯坦棋游戏的实现。
小声BB:查了一下,这应该是全网第一个基于前端语言实现爱恩斯坦棋的贴,应该是开端了。
#效果图
爱恩斯坦棋类
爱恩斯坦棋2
考虑到大家可能还不了解爱恩斯坦棋(其实点进来或多或少应该已经有了解过了吧)
理论上还是应该要介绍一下才对
规则如下:

  • 棋盘为5×5的方格形棋盘,方格为棋位,左上角为红方出发区;右下角为蓝方出发区;
  • 红蓝方各有6枚方块形棋子,分别标有数字1—6。开局时双方棋子在出发区的棋位可以随意摆放;
  • 双方轮流掷骰子,然后走动与骰子显示数字相对应的棋子。如果相对应的棋子已从棋盘上移出,便可走动大于或小于此数字的并与此数字最接近的棋子;
  • 红方棋子走动方向为向右、向下、向右下,每次走动一格;蓝方棋子走动方向为向左、向上、向左上,每次走动一格;
  • 如果在棋子走动的目标棋位上有棋子,则要将该棋子从棋盘上移出(吃掉)。有时吃掉本方棋子也是一种策略,因为可以增加其它棋子走动的机会与灵活性;
  • 率先到达对方出发区角点或将对方棋子全部吃掉的一方获胜;
  • 对弈结果只有胜负,没有和棋。
  • 每盘每方用时3分钟,超时判负;每轮双方对阵最多7盘,轮流先手(甲方一四五盘先手,乙方二三六七盘先手),两盘中间不休息,先胜4盘为胜方。

需要提前掌握的知识

  • css选择器
  • 绝对位置
  • css盒子模型
  • 动画效果
  • js基本语法
  • js中事件

css选择器

一般用于选择元素定义其样式
选择器表

绝对位置

position 的四个值:static、relative、absolute、fixed
由于只会用到绝对位置,所以我们主要介绍一下absolute属性
absolute:元素会脱离文档流,如果设置偏移量,会影响其他元素的位置定位
absolute定位原理剖析:
1.在父元素没有设置相对定位或绝对定位的情况下,元素相对于根元素定位(即html元素)(是父元素没有)。
2.父元素设置了相对定位或绝对定位,元素会相对于离自己最近的设置了相对或绝对定位的父元素进行定位(或者说离自己最近的不是static的父元素进行定位,因为元素默认是static)。
可以把整个屏幕看成一个坐标系,px是单位长度
比如下面这段代码

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"> 
<style>
h2
{position:absolute;left:100px;top:150px;
}
</style>
</head><body>
<h2>这是一个绝对定位了的标题</h2>
<p>用绝对定位,一个元素可以放在页面上的任何位置。标题下面放置距离左边的页面100 px和距离页面的顶部150 px的元素。.</p>
</body></html>

效果图如下所示
效果图

css盒子模型

所有HTML元素可以看作盒子,在CSS中,"box model"这一术语是用来设计和布局时使用。
CSS盒模型本质上是一个盒子,封装周围的HTML元素,它包括:边距,边框,填充,和实际内容。
盒模型允许我们在其它元素和周围元素边框之间的空间放置元素。
下面的图片说明了盒子模型(Box Model):
盒子模型

  • Margin(外边距) - 清除边框外的区域,外边距是透明的。
  • Border(边框) - 围绕在内边距和内容外的边框。
  • Padding(内边距) - 清除内容周围的区域,内边距是透明的。
  • Content(内容) - 盒子的内容,显示文本和图像。

总元素的宽度=宽度+左填充+右填充+左边框+右边框+左边距+右边距
总元素的高度=高度+顶部填充+底部填充+上边框+下边框+上边距+下边距
比如下面这个块

div {width: 300px;border: 25px solid green;padding: 25px;margin: 25px;
}

实际上300px (宽)+ 50px (左 + 右填充)+ 50px (左 + 右边框)+ 50px (左 + 右边距)= 450px

动画效果

要创建 CSS3 动画,你需要了解 @keyframes 规则。
@keyframes 规则是创建动画。
@keyframes 规则内指定一个 CSS 样式和动画将逐步从目前的样式更改为新的样式。

@keyframes myfirst
{from {background: red;}to {background: yellow;}
}

这个动画的意思显而易见是把背景色从红色变成黄色
现在可以给块加上动画了

div
{animation: myfirst 5s;
}

必须定义动画的名称和动画的持续时间。如果省略的持续时间,动画将无法运行,因为默认值是0。
用百分比来规定变化发生的时间,或用关键词 “from” 和 “to”,等同于 0% 和 100%。
0% 是动画的开始,100% 是动画的完成。
为了得到最佳的浏览器支持,我们应该始终定义 0% 和 100% 选择器。

js基本语法

这里只列举本帖子需要用到的一些语法
###JavaScript 显示数据
JavaScript 可以通过不同的方式来输出数据:

  • 使用 window.alert() 弹出警告框。
  • 使用 document.write() 方法将内容写到 HTML 文档中。
  • 使用 innerHTML 写入到 HTML 元素。
  • 使用 console.log() 写入到浏览器的控制台。

js变量

在 JavaScript 中创建变量通常称为"声明"变量。
我们使用 var 关键词来声明变量:
var carname;
变量声明之后,该变量是空的(它没有值)。
如果需要向变量赋值,可以使用等号,也可以在申明的时候给它赋值
JavaScript 拥有动态类型。这意味着相同的变量可用作不同的类型:

var x;               // x 为 undefined
var x = 5;           // 现在 x 为数字
var x = "John";      // 现在 x 为字符串

JavaScript 只有一种数字类型。数字可以带小数点,也可以不带:

var x1=34.00;      //使用小数点来写
var x2=34;         //不使用小数点来写

注意在js中的除法是按照小数除法,这一点和c++有区别
语句方面,c++和js几乎一样

js数组

数组下标是基于零的,所以第一个项目是 [0],第二个是 [1],以此类推。
创建数组

var cars=new Array();
cars[0]="Saab";
cars[1]="Volvo";
cars[2]="BMW";

js函数

函数就是包裹在花括号中的代码块,前面使用了关键词 function:

function functionname()
{// 执行代码
}

当调用该函数时,会执行函数内的代码。
可以在某事件发生时直接调用函数(比如当用户点击按钮时),并且可由 JavaScript 在任何位置进行调用。
可以发送任意多的参数,由逗号 (,) 分隔:

js事件

HTML 事件是发生在 HTML 元素上的事情。
当在 HTML 页面中使用 JavaScript 时, JavaScript 可以触发这些事件。
以下是 HTML 事件的实例:

  • HTML 页面完成加载
  • HTML input 字段改变时
  • HTML 按钮被点击


事件可以用于处理表单验证,用户输入,用户行为及浏览器动作:

  • 页面加载时触发事件
  • 页面关闭时触发事件
  • 用户点击按钮执行动作
  • 验证用户输入内容的合法性
    等等 …

设计思路

爱恩斯坦棋的界面设计相对比较简单,主要运用了JavaScript加入div块和规定绝对位置来进行实现,在初始化时对每个块加上id标记,指向这个块的绝对编号(即本身所具有的固有属性,不会随着后面玩家进行布局错乱棋子的位置影响。
同时也为后续进行编号和块号的映射进行了铺垫,在加入div块的同时对这个块设置它的样式(比如绝对位置等等),在外面格外设置一个ans全局变量,对块的编号进行计数。
由于玩家刚开始游戏的时候可以随意地布局,所以我们采用了用点击事件来对各个块编上玩家想要的号码。同样在最外层放置一个计数器cnt,在点击的同时进行计数,同时用querySelector选中这个块,对这个块的样式进行修改(如颜色等等)。
同理对玩家2也是同样的修改。
同样我们也需要让原来的加在每个块上的click事件移除,防止影响到对后续的棋子的移动。(这个移除操作封装到“开始游戏”按钮)。
设置随机数按钮,定义全局变量play,值为1时表示玩家1,值为2时表示玩家2。
分别对对应玩家1和玩家2。每次开始随机的时候,用Math库内置的函数产生一个随机数,然后加入一个div块,把随机数放到这个块上,更改块的样式,动画等。
用户开始游戏后,每次行棋前都要点击随机数,重新申明两个个Array数组player1和player2。
这个数组表示每个编号的棋子是否存活然后。
再利用一个Array数组,这个数组的效果是对应于每个编号所映射的块的绝对位置(块号)。
这样我们能知道所点击块的块号,利用点击来进行移动,对产生的随机数进行搜索,如果离它最近的棋子存活,可以通过mapp数组找到它映射的块号,进而对这个元素添加点击事件,同时搜素它的三种走法,如果这三种走法都是合法的,分别对对应的块添加点击事件。
方便用户的移动,同时可以改变play的值。
在第二次点击事件后,增加一个判断胜利的条件。如果对应块的位置是对面的颜色,或者player数组中没有棋子存活,那么把此作为胜利的条件。

行棋流程图

代码实现

<!DOCTYPE html>
<html lang='en'><head><meta charset="UTF-8"><title>爱恩斯坦棋</title><style>[class~=big] {position: absolute;left: 300px;top: 200px;border: 10px black solid;width: 600px;height: 600px;}[class~=an] {position: absolute;left: 1200px;top: 600px;width: 100px;height: 100px;border-radius: 50%;}[class~=bn]{position: absolute;left: 1200px;top: 800px;width: 200px;height: 50px;}[class~=tip]{position:absolute;left:350px;top:100px;width:500px;height:100px;border:1px black solid;box-shadow:0 9px 14px 0 rgb(240, 192, 35);text-align: center;font-size:50px;font-weight: normal;}[class~=tips]{position:absolute;border:1px black solid;left:1000px;top:0px;width:500px;height:600px;font-size: 20px;}[class~=saizi]{position:absolute;border:1px black solid;width: 100px;height:100px;left:1100px;top:600px;text-align: center;background:white;font-size:60px;border-radius: 20%;}@keyframes button1 {0%{background-color:rgb(117, 114, 106);box-shadow: 0 0 9px rgb(6, 34, 33);}100%{background-color: rgb(230, 167, 31);box-shadow: 0 0 9px rgb(6, 34, 33);}}@keyframes white_show{0%{background-color:gray;box-shadow: 0 0 9px rgb(6, 34, 33);}100%{background-color: white;box-shadow: 0 0 9px rgb(247, 198, 36);}} @keyframes blue_show {0%{background-color:gray;box-shadow: 0 0 9px rgb(6, 34, 33);}100%{background-color: skyblue;box-shadow: 0 0 9px rgb(235, 175, 48);}}/* @keyframes white_none {0%{background-color:white;}100%{background-color: gray;}}@keyframes blue_none {0%{background-color: skyblue;}100%{background-color: gray;}} */ </style>
</head><body bgcolor = "gray"><div class = "tips">爱恩斯坦棋:<p>1.棋盘为5×5的方格形棋盘,方格为棋位,左上角为白方出发区;右下角为蓝方出发区;</p><p>2.红蓝方各有6枚方块形棋子,分别标有数字1—6。开局时双方棋子在出发区的棋位可以随意摆放;</p><p>3.双方轮流掷骰子,然后走动与骰子显示数字相对应的棋子。如果相对应的棋子已从棋盘上移出,便可走动大于或小于此数字的并与此数字最接近的棋子;</p><p>4.白方方棋子走动方向为向右、向下、向右下,每次走动一格;蓝方棋子走动方向为向左、向上、向左上,每次走动一格;</p><p>5.如果在棋子走动的目标棋位上有棋子,则要将该棋子从棋盘上移出(吃掉)。</p><p>6.率先到达对方出发区角点或将对方棋子全部吃掉的一方获胜;</p></div><div class = "tip"></div><div class="big"></div><button class="an">随机数</button><div class = "saizi"></div><button class="bn">开始游戏</button><script>var cnt = 1;//计数器var ans = 1;//方格数量var click2 = 0;//表示第一个还没有放完var ram = 0;//储存随机数var val;//保存权值var play = 1;//表示该第几个玩家,var mapp1 = new Array(7);//由数字映射到编号var mapp2 = new Array(7);var player1 = new Array(7);//场上的棋子是否存活var player2 = new Array(7);var flag = 0;//标识是否随机完成var tc, tn; //保存上一个方块的颜色和数字var sel;//保存上一个次选中的元素var big = document.querySelector(".big");var an = document.querySelector(".an");var bn = document.querySelector(".bn");var tip = document.querySelector(".tip");var saizi = document.querySelector(".saizi");bn.addEventListener("click", clear);an.addEventListener("click", star);for (var i = 1; i <= 6; ++i) {player1[i] = 1;player2[i] = 1;}for (var i = 0; i < 5; ++i)for (var j = 0; j < 5; ++j) {div = document.createElement("div");div.setAttribute("class", "Block" + ans);div.setAttribute("id", ans);div.style.border = "2px black solid";div.style.width = "98px";div.style.height = "98px";div.style.position = "absolute";div.style.textAlign = "center";div.style.left = 50 + j * 100 + "px";div.style.top = 50 + i * 100 + "px";div.style.fontSize = "50px";big.appendChild(div);ans++;}for (ans = 1; ans <= 11; ++ans) {var temp = document.querySelector(".Block" + ans);temp.addEventListener("click", clickblock1);}for (cnt = 15; cnt <= 25; ++cnt) {var temp = document.querySelector(".Block" + cnt);// console.log(temp);temp.addEventListener("click", clickblock2);}ans = 1;cnt = 1;//重置方便后续的计数function clear(){for (var i = 1; i <= 11; ++i) {var temp = document.querySelector(".Block" + i);temp.removeEventListener("click", clickblock1);}for (var j = 15; j <= 25; ++j) {var temp = document.querySelector(".Block" + j);// console.log(temp);temp.removeEventListener("click", clickblock2);}}function clickblock1(e) {e.target.textContent = ans;mapp1[ans] = e.target.id;console.log(e.target.id);ans++;e.target.style.backgroundColor = "white";}function clickblock2(e) {e.target.textContent = cnt;mapp2[cnt] = e.target.id;cnt++;e.target.style.backgroundColor = "skyblue";}function star() {ram = Math.floor(Math.random() * 6 + 1);console.log(ram);// console.log(mapp1);// for(var i = 1; i <= 25; ++i){//     var id = document.getElementById(i);//     id.addEventListener("click", clickmove);// }saizi.textContent = ram;saizi.style.animation = "button1 2s infinite";var div = document.createElement("div");div.style.backgroundColor = "gray";div.style.width = "170px";div.style.height = "100px";div.style.borderRadius = "50px";div.style.textAlign = "center";div.textContent = "你只能移动和" + ram + "最接近的数";div.style.color = "red";div.style.position = "absolute";div.style.top = "100px";div.style.left = "-30px";an.appendChild(div);if(play == 1){tip.textContent = "轮到白方走棋";tip.style.animation = "white_show 5s infinite";}else{tip.textContent = "轮到蓝方走棋";tip.style.animation = "blue_show 5s infinite";}if (play == 1) {for (var i = 0; i < 6; ++i) {if (ram - i >= 1 && player1[ram - i] == 1) {var id = document.getElementById(mapp1[ram - i]);id.addEventListener("click", clickmove);var exp1 = mapp1[ram - i] - 1;var y = exp1 % 5;var x = (exp1 - y)/ 5;console.log("坐标" + x + "" + y);if (y + 1 < 5) {exp1 = x * 5 + y + 2;console.log(exp1);var temp = document.getElementById(exp1);temp.addEventListener("click", clickmove);}if (x + 1 < 5) {exp1 = (x + 1) * 5 + y + 1;console.log(exp1);var temp = document.getElementById(exp1);temp.addEventListener("click", clickmove);}if (y + 1 < 5 && x + 1 < 5) {exp1 = (x + 1) * 5 + y + 2;console.log(exp1);var temp = document.getElementById(exp1);temp.addEventListener("click", clickmove);}flag = 1;}if (ram + i <= 6 && player1[ram + i] == 1 && i != 0) {var id = document.getElementById(mapp1[ram + i]);id.addEventListener("click", clickmove);var exp1 = mapp1[ram + i] - 1;var y = exp1 % 5;var x = (exp1 - y)/ 5;console.log("坐标" + x + "" + y);if (y + 1 < 5) {exp1 = x * 5 + y + 2;console.log(exp1);var temp = document.getElementById(exp1);temp.addEventListener("click", clickmove);}if (x + 1 < 5) {exp1 = (x + 1) * 5 + y + 1;console.log(exp1);var temp = document.getElementById(exp1);temp.addEventListener("click", clickmove);}if (y + 1 < 5 && x + 1 < 5) {exp1 = (x + 1) * 5 + y + 2;console.log(exp1);var temp = document.getElementById(exp1);temp.addEventListener("click", clickmove);}flag = 1;}if (flag) {flag = 0;break;}}play = 2;}else {for (var i = 0; i < 6; ++i) {if (ram - i >= 1 && player2[ram - i] == 1) {var id = document.getElementById(mapp2[ram - i]);id.addEventListener("click", clickmove);var exp1 = mapp2[ram - i] - 1;var y = exp1 % 5;var x = (exp1 - y)/ 5;console.log("坐标" + x + "" + y);console.log(exp1);if (y - 1 >= 0) {exp1 = x * 5 + y;console.log(exp1);var temp = document.getElementById(exp1);temp.addEventListener("click", clickmove);}if (x - 1 >= 0) {exp1 = (x - 1) * 5 + y + 1;console.log(exp1);var temp = document.getElementById(exp1);temp.addEventListener("click", clickmove);}if (y - 1 >= 0 && x - 1 >= 0) {exp1 = (x - 1) * 5 + y;console.log(exp1);var temp = document.getElementById(exp1);temp.addEventListener("click", clickmove);}flag = 1;}if (ram + i <= 6 && player2[ram + i] == 1 && i != 0) {var id = document.getElementById(mapp2[ram + i]);id.addEventListener("click", clickmove);var exp1 = mapp2[ram + i] - 1;var y = exp1 % 5;var x = (exp1 - y)/ 5;console.log("坐标" + x + "" + y);if (y -1 >= 0) {exp1 = x * 5 + y;console.log(exp1);var temp = document.getElementById(exp1);temp.addEventListener("click", clickmove);}if (x -1 >= 0) {exp1 = (x - 1) * 5 + y + 1;console.log(exp1);var temp = document.getElementById(exp1);temp.addEventListener("click", clickmove);}if (y - 1 >= 0 && x - 1 >= 0) {exp1 = (x - 1) * 5 + y;console.log(exp1);var temp = document.getElementById(exp1);temp.addEventListener("click", clickmove);}flag = 1;}if (flag) {flag = 0;break;}}play = 1;}}function clickmove(e) {if (click2) {console.log("第二次点击");//不改变块的编号if (e.target.textContent != "") {if (e.target.style.backgroundColor == 'white') {player1[e.target.textContent]--;// mapp1[e.target.textContent] = e.target.id;}else {player2[e.target.textContent]--;// mapp2[e.target.textContent] = e.target.id;}}e.target.textContent = tn;e.target.style.backgroundColor = tc;if(tc == "white"){mapp1[tn] = e.target.id;}if(tc == "skyblue"){mapp2[tn] = e.target.id;}click2 = 0;console.log(mapp1);console.log(mapp2);console.log(player1);console.log(player2);//判断胜负var win1 = document.getElementById("1");var win2 = document.getElementById("25");if(win1.style.backgroundColor == "skyblue"){alert("蓝色方胜利");location.reload();}if(win2.style.backgroundColor == "white"){alert("白色方胜利");location.reload();}var rw = 1,bw = 1;for(var i = 1; i <= 6; ++i){if(player1[i]){bw = 0;break;}}for(var i = 1; i <= 6; ++i){if(player2[i]){rw = 0; break;}}if(rw) {alert("白色方胜利");location.reload();}if(bw){alert("蓝色方胜利");location.reload();}}else {console.log("第一次点击");sel = e.target;tc = e.target.style.backgroundColor;tn = e.target.textContent;e.target.style.backgroundColor = "gray";e.target.textContent = "";click2 = 1;}}</script>
</body></html>

这篇关于html+css+JavaScript实现爱恩斯坦棋游戏的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/451811

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

【 html+css 绚丽Loading 】000046 三才归元阵

前言:哈喽,大家好,今天给大家分享html+css 绚丽Loading!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 📚一、效果📚二、信息💡1.简介:💡2.外观描述:💡3.使用方式:💡4.战斗方式:💡5.提升:💡6.传说: 📚三、源代码,上代码,可以直接复制使用🎥效果🗂️目录✍️