项目:双人五子棋对战-对战模块(6)

完整代码见: 邹锦辉个人所有代码: 测试仓库 - Gitee.com

当玩家进入到游戏房间后, 就要开始一局紧张而又刺激的五子棋对战了, 本文将就前端后端的落子与判断胜负的部分作详细讲解.

模块详细讲解

约定前后端交互的接口

首先是建立连接后, 服务器需要生成一些游戏的初始信息(可以看作初始化游戏地图这样式儿的), 并将这些信息告诉给客户端(响应).

建立连接: ws://127.0.0.1:8080/game 

{

        message: 'gameReady', //消息的类型是 游戏就绪

        ok: true,

        reason: '',

        roomId: '12345678', //玩家所处房间id

        thisUserId: 1, //玩家自己的id

        thatUserId: 2, //玩家对手的id

        whiteUser: 1 //哪个玩家是执白子

}

这些内容都是玩家匹配成功之后, 服务器生成的内容, 需要把这个请求返回给浏览器.

在初始化内容之后, 双方玩家就需要轮流进行落子了, 同时落子这个逻辑, 既要展示, 也要交给服务器处理, 看一下放哪了, 有没有分清胜负啊什么的. 要传递的内容有: 落子玩家id, 落子位置(row, col).

同理, 响应就是返回一下你比赛结果: 谁输谁赢, 还是继续?

请求: 

{

        message: 'putChess',

        userId: 1,

        row: 0,

        col: 0

}

响应: 

{

        message: 'putChess',

        userId: 1,

        row: 0,

        col: 0,

        winner: 0

}

如果winner为0, 还需要继续对战, 而如果winner非零, 就已经分出胜负了(winner的数字就表示胜利玩家的对战时玩家的id, 也就是1, 2) 

前端代码

这里我们使用game_room.html(这个就是匹配成功之后要跳转的页面), 这里我们就希望显示出棋盘和提示信息(该谁落子了). 

首先利用原先的方式创建WebSocket.

​
let websocketUrl = "ws://" + location.host + "/game";
let websocket = new WebSocket(websocketUrl);websocket.onopen = function () {console.log("连接游戏房间成功!");
}websocket.close = function () {console.log("和游戏服务器断开连接");
}websocket.onerror = function () {console.log("和服务器的连接出现异常!");
}//页面关闭前, 主动断开
window.onbeforeunload = function () {websocket.close();
}​

然后进行初始化的逻辑:

websocket.onmessage = function (event) {console.log("[handlerGameReady] " + event.data);let resp = JSON.parse(event.data);if (!resp.ok) {alert("连接游戏失败! reason: " + resp.reason);// 如果出现连接失败的情况, 回到游戏大厅location.assign("/game_hall.html");return;}if (resp.message == 'gameReady') {gameInfo.roomId = resp.roomId;gameInfo.thisUserId = resp.thisUserId;gameInfo.thatUserId = resp.thatUserId;gameInfo.isWhite = (resp.whiteUser == resp.thisUserId);//初始化棋盘initGame();//设置显示区域的内容setScreenText(gameInfo.isWhite);} else if (resp.message == 'repeatConnection') {alert("检测到游戏多开! 请使用其他账号登录!");location.assign("/login.html");}
}

这里主要是对于棋盘的初始化内容(这个初始化的函数(initGame)中其实也包含后面对于落子的处理即websocket.onmessage. 所以这个函数实际上是客户端的主体部分). 

对于initGame(), 它包含了一系列的对战处理逻辑: 

1.对于棋盘的绘制, 棋子的绘制(这里使用了canvas, 不做详细介绍)

2.对于落子时对应位置的坐标计算, 文本框状态的转换

3.对于相应位置的落子情况, 向服务器发送请求.

4.对于接收到的响应, 如果分出胜负, 则对其进行处理

后端代码

要注意的是, 不仅在前端要有一个用来展示的棋盘, 同时, 在服务器内部, 也需要维护一个"棋盘". 服务器就根据每次的落子请求, 在棋盘上进行更新. 还需要对胜负进行判定.

这里也还是用到了WebSocket的通信特性: 

这里需要注意, 客户端和服务器上的棋盘是有区别的:

1.客户端棋盘: 客户端只需要对于落子情况进行保存即可(这个位置有没有落子)

2.服务器棋盘: 服务器不仅需要得知是否落子, 还需得知是谁落的子, 这样才能进行输赢判断 

而这里为什么要这么设置呢? 因为一般是服务器进行的输赢逻辑判定.

接下来, 当每次落子之后, 就会进行输赢的判定, 判定规则就是: 落子所在行/列/主对角线/副对角线是否其它连续的5个子与其相同, 就判定胜利.即:

 这里仅列举一种即可, 代码很简单, 看看就可以:

       //1.检查所有的行//先遍历五种情况for(int c = col - 4; c <= col; c++) {// 针对其中一种情况, 来判定这五个子是不是连在一起了try {if(board[row][c] == chess&&board[row][c + 1] == chess&&board[row][c + 2] == chess&&board[row][c + 3] == chess&&board[row][c + 4] == chess) {//构成了五子连珠, 胜负已分return chess == 1 ? user1.getUserId() : user2.getUserId();}} catch (ArrayIndexOutOfBoundsException e) {//如果出现数组下标月结的情况, 直接忽略这个异常.continue;}}

 同时, 也可写一个方法用于打印棋盘, 这样可以观察执行情况.

 五子棋双人对战项目到此也就结项了, 下一期将对该项目进行测试, 敬请期待!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/347035.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java:FeignClient通过RequestInterceptor自动添加header

示例代码 【pom.xml】 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.3.12.RELEASE</version> </dependency> <dependency><groupId>o…

pytorch 自定义学习率更新 Poly

Poly 学习率调整策略需要继承_LRScheduler类&#xff0c;该类包含三个重要属性和两个重要方法 学习率与batch-size的关系 一般来说&#xff0c;batch-size的大小一般与学习率的大小成正比。batch-size越大一般意味着算法收敛方向的置信度越大&#xff0c;也可以选择较大的学…

【课程总结】Day6(下):机器学习项目实战–成人收入预测

机器学习项目实战&#xff1a;成人收入预测 项目目的 基于个人收入数据(包括教育程度、年龄、性别等)的数据集&#xff0c;通过机器学习算法&#xff0c;预测一个人的年收入是否超过5万美金。 数据集 地址&#xff1a;http://idatascience.cn/dataset-detail?table_id10036…

MEGALODON:突破传统,实现高效无限上下文长度的大规模语言模型预训练和推理

在人工智能领域&#xff0c;尤其是在自然语言处理&#xff08;NLP&#xff09;中&#xff0c;大模型&#xff08;LLMs&#xff09;的预训练和推理效率一直是研究的热点。最近&#xff0c;一项突破性的研究提出了一种新型神经网络架构——MEGALODON&#xff0c;旨在解决传统Tran…

2024/06/11--代码随想录算法1/17|理论基础、509. 斐波那契数、70. 爬楼梯、746. 使用最小花费爬楼梯

理论基础 动态规划&#xff1a;当前状态由前面的状态推导而来 贪心&#xff1a;局部选最优 动态规划5步曲 确定dp数组&#xff08;dp table&#xff09;以及下标的含义确定递推公式dp数组如何初始化确定遍历顺序举例推导dp数组 509. 斐波那契数 力扣链接 动态规划5步曲 确定d…

33.星号三角阵(二)

上海市计算机学会竞赛平台 | YACSYACS 是由上海市计算机学会于2019年发起的活动,旨在激发青少年对学习人工智能与算法设计的热情与兴趣,提升青少年科学素养,引导青少年投身创新发现和科研实践活动。https://www.iai.sh.cn/problem/742 题目描述 给定一个整数 𝑛,输出一个…

Linux用户,用户组,所有者权限分配,sftp用户权限分配

注意以下命令执行需要在root用户下执行 tenant命令切换至root命令 sudo -do root 删除用户信息 1.不删除用户主目录 userdel user_name 2.删除用户主目录 userdel -r user_name usermod命令修改用户账户权限 更改用户名 sudo usermod -l newusername oldusername 更…

QNX 7.0.0开发总结

1 QNX编译 1.1 基本概念 QNX可以直接使用Linux Makefile编译库和二进制&#xff0c;在Makefile文件中指定CCaarch64-unknown-nto-qnx7.0.0-g&#xff0c;或者CCx86_64-pc-nto-qnx7.0.0-g&#xff0c;保存退出后&#xff0c;运行source /qnx_sdk_path/qnxsdp-env.sh&#xff0c;…

React+TS前台项目实战(四)-- layout整体布局搭建

文章目录 前言一、Layout组件代码注释说明二、Content全局组件注释说明三、Header基础布局组件1. Header父级组件注释说明2. NavMenu导航子组件详细说明 四、效果展示总结 前言 本文主要讲Layout整体布局的构建以及全局内容盒子Content组件的使用。还包括了导航栏组件的基本封…

实现开源可商用的 ChatPDF RAG:密集向量检索(R)+上下文学习(AG)

实现 ChatPDF & RAG&#xff1a;密集向量检索&#xff08;R&#xff09;上下文学习&#xff08;AG&#xff09; RAG 是啥&#xff1f;实现 ChatPDF怎么优化 RAG&#xff1f; RAG 是啥&#xff1f; RAG 是检索增强生成的缩写&#xff0c;是一种结合了信息检索技术与语言生成…

python之点云数据读取与可视化

1、前言 将文件中点云数据进行读取进来&#xff0c;并进行数据处理&#xff0c;将处理后的点云数据进行可视化显示&#xff0c;是非常常见的操作。本博客介绍如何将文本形式的点云数据读取进来&#xff0c;并进行可视化展示。 2、点云可视化 点云可视化即将点云数据在三维空间…

亚马逊竞品分析之如何查找竞品

初选之后,要对产品进行竞品分析,查找竞品的方法: 1.Best Seller榜单查找 进入到该类目的BS榜单去找跟你选中的产品的竞品 看完BS榜单会找出一部分竞品 这个找相似也可以点击,是插件的一个以图搜图的功能,不过有的时候不太好使,某些同款产品可能搜不到。 Edge浏览器搭…

第7章 用户输入和 while 循环

第7章 用户输入和 while 循环 7.1 函数 input()的工作原理7.1.1 编写清晰的程序7.1.2 使用 int()来获取数值输入7.1.3 求模运算符 7.2 while 循环简介7.2.1 使用 while 循环7.2.2 让用户选择何时退出7.2.3 使用标志7.2.4 使用 break 退出循环7.2.5 在循环中使用 continue7.2.6 …

【Vue】Vuex概述

文章目录 一、使用场景二、优势三、注意 官网&#xff1a;https://vuex.vuejs.org/zh/ Vuex 是一个 Vue 的 状态管理工具&#xff0c;状态就是数据。 工具可以直接理解成插件 大白话&#xff1a;Vuex 是一个插件&#xff0c;可以帮我们管理 Vue 通用的数据 (多组件共享的数据)…

【Affine / Perspective Transformation】

文章目录 仿射变换介绍仿射变换 python 实现——cv2.warpAffine透视变换透视变换 python 实现——cv2.warpPerspective牛刀小试各类变换的区别与联系仿射变换和单应性矩阵透视变换和单应性矩阵 仿射变换介绍 仿射变换&#xff08;Affine Transformation&#xff09;&#xff0…

适配器模式和装饰器模式

文章目录 适配器模式1.引出适配器模式1.多功能转换插头2.基本介绍3.工作原理 2.类适配器1.基本介绍2.类图3.代码实现1.Voltage220V.java2.Voltage5V.java3.VoltageAdapter.java4.Phone.java5.Client.java6.结果 4.类适配器的注意事项 3.对象适配器1.基本介绍2.使用对象适配器改…

C51单片机 串口打印printf重定向

uart.c文件 #include "uart.h"void UartInit(void) //4800bps11.0592MHz {PCON | 0x80; //使能波特率倍速位SMODSCON 0x50; //8位数据,可变波特率。使能接收TMOD & 0x0F; //清除定时器1模式位TMOD | 0x20; //设定定时器1为8位自动重装方式TL1 0xF4; //设…

明天15点!如何打好重保预防针:迎战HVV经验分享

在当今数字化时代&#xff0c;网络攻击日益猖獗&#xff0c;各行各业面临的网络安全威胁不断升级。从钓鱼邮件到复杂的APT攻击&#xff0c;网络犯罪分子的手法层出不穷&#xff0c;给各行各业的信息安全带来了前所未有的挑战。 在这样的背景下&#xff0c;"HVV行动"应…

那些年我看过的技术书(持续更新,大佬的成长之路)

作为一个技术人啊&#xff0c;要学会多看书&#xff0c;发展自己。哦也&#xff01;你可以不关注&#xff0c;就把文章点个收藏吧&#xff0c;万一以后想看书了呢&#xff1f; 网络安全 CTF篇 入门篇 《极限黑客攻防&#xff1a;CTF赛题揭秘》 Web篇 Reserve篇 《IDApro…

ON DUPLICATE KEY UPDATE 子句

ON DUPLICATE KEY UPDATE 是 MySQL 中的一个 SQL 语句中的子句&#xff0c;主要用于在执行 INSERT 操作时处理可能出现的重复键值冲突。当尝试插入的记录导致唯一索引或主键约束冲突时&#xff08;即试图插入的记录的键值已经存在于表中&#xff09;&#xff0c;此子句会触发一…