我们一起学程序-五子棋

前言


  小时候很喜欢玩电视上自带的积木游戏,那时候电子产品也不少,小学就认识了low和high两个单词,因此攒了零花钱搞到了高级版的游戏--小霸王学习机,说错了,是“游戏机”,特别是一放暑假,插个小霸王游戏机卡就能开始撸几把魂斗罗,坦克大战,比夏天吃根冰棍可香多了,那时候没有空调,不惧严寒酷暑的我们在这些小游戏的陪伴下玩的不亦乐乎,陪我们度过一个又一个快乐冬夏,下图为证,有没有很熟悉的赶脚!

  看着这些画面,带着学习的心情的出发了,开始我们的五子棋大战;砍柴磨刀互相不耽误,先看看实现的网络版本效果吧,当然为了你看着舒服,体验的开心,博主花了些功夫大致在客户端(手机)做了适配,不至于你屏幕溢出,你爽我爽大家爽;简单说明下本人主攻后端Java,前端不深入,页面效果将就看看哈!

体验效果


  看看你想下盘棋,你需要做什么,首先你需要抢个位子啊【我媳妇说这个举手的小人太丑了,能换个动漫吗,我说我对漫画没啥审美,但是对另一半要求很高,所以我们在一起了,嘻,这个求生欲也特强了吧!】,然后你就到棋盘页面了,点击举手坐下,你就开始等,有人来了也举手了你们就可以开始了,就像你去棋牌室打牌一模一样,如果硬说有啥区别,咱们这是学习,他们那是赌博,好了,好了,扯远了,简单介绍下,五子棋的规则大家都懂,你五个棋子连成一条线就胜利了,一攻一防,胜率就看你的手段了,不知道你有没有发现,博主为了不让你有更多的束缚,连账户密码都默认为你输出了,同时为了让程序不是那么单调,下棋还能发声,还实现了查看复盘,和在线聊天,聊天IP内容已经存档,自动过滤色情信息;博主为你们担心的事情都精心考虑设计实现,是不是暖男你们说了算!下面两个动画分别是“准备过程”和“下棋过程”;

体验地址:棋子棋体验地址,有些功能可能有不完善的地方,功能也不特别太全,但基本功能应该是满足了,如果没有人陪你玩,你可以开两个客户端体验或call me,一毛钱一把,欢迎来战,如果有强迫症的或是有good idea,想要加入我们的修改的童鞋,欢迎留言加入我们,让我们共同成长。

游戏准备过程

下棋过程

关键技术简介


  其实在开发完这个小游戏后,回顾总了下,没有啥高精尖的技术,前端页面完全是html,css(样式),js+jquery(脚本语言),像“举手准备”,“画棋盘”等都是用到的这些前端技术,大家看到的淘宝页面基本都是基于这些技术来完成的;后端用到的技术是websocket,很多面试官会问到websocket和http的区别,博主简单介绍下,它是一个双向通信的协议,这个不难理解,如果你打我了,我也可以还手,不像http,它是单向的,比如你打我了,我就只能默默忍着,顶多就能回骂一句,绝不能还手,相信在这个人人平等的社会,你肯定喜欢websocket,他帮助我们实现了在线聊天,咿!我怎么突然想到了QQ,感觉我像腾讯的高级攻城狮一样牛掰;当然了,作为一个Java攻城狮,必须要理解的就是线程啦,我们里面的“查看复盘”的功能就用到了Java读写文件和多线程技术;是不是小小的程序还有大大的奥妙;好啦,就到这里吧,明不明白都不要紧,因为我们后面详细一点你就能明白了!

总结下:前端css+js实现画页面和交互,后台Java+websocket实现存储和通信相信有一点基础的你,肯定也能实现这个程序;在实际开发中,前后端是两个不同的岗位,前后端各司其职,当然有些小公司要求程序员都要会,所以有些时候在挑选公司时擦眼睛不是眼里进了沙子,是为了看的更清楚!

从无到有思路


  这个程序博主一个人断断续续差不多花了两个礼拜完成的,当然你肯定怀疑我是否有一气呵成的能力,可以肯定的回答你,你的怀疑是对的,因为我也是人,我不能忘了吃饭和睡觉;最原始最原始的要追忆到两周前,下图是最初的版本,这是在idea控制台输出的,是的,你没有看错,五子棋程序实现了,“五子棋连线成功,恭喜你赢了”,说实话,打出这句话,连我这么没有追求的人都觉得他太枯燥了,生活它需要仪式感,你上面看到的页面都是我在仪式感基础上添加的;新事物,全新的页面,至少我感受到了程序至少还有那么一丝丝的美,是的,至少此刻我沦陷了,学程序我们要有意识的去追求一下她的美,不然他会教你从入门到放弃;

  慢慢的,“仪式感”让我走向一条不归路,首先需要解决的问题,就是棋盘的问题,现实中有木头刻制的棋盘,网络上可以用代码生成的棋盘,现实的中棋盘有她独特的美感,网络中这些棋盘他就更灵活了,每个方格,棋盘大小都是可调整的,成本微乎其微,有了棋盘那就需要把棋子落在棋盘上,这些可以用css+js画出来的,还不用浪费木材,落子了每次都需要判断这次走的这步棋是否连成了一个五子,如果连成五子就赢了,如果没有就换对手下棋,每一步过程组合在一起就组成了棋盘,电脑有超强计算和存储能力,人脑也有,但电脑没有人脑灵活,人工智能尚在起步,未来可期;

下完棋后想看下过程于是就有了“复盘回看”功能;下棋要沟通就有了网络聊天室;棋牌室永远不止一个座位,于是就需要支持多个座位,多人同时娱乐;当然你也可以说自己水平不够,需要人机对战,提升经验,或者有人说游戏赢了或输了要有对应的奖惩机制,没错,你能想到的,有兴趣的事情你都可以动手实现,兴趣或者学习目的都好,总比无聊消磨时光来的更有意义;这就是我从无到有一步步构建出来的程序。欢迎和我一起讨论学习!【公众号:叫练

代码实现过程


1.棋盘实现

  棋盘是用table表格画的,像你看到博主实现的这个表格,横轴是26,纵轴是23,每个格子的大小都是40像素,不信你话可以量量哈,前端循环放置在div中就可以了,格子像素是固定的,因为我们需要通过像素计算最终得到坐标,下棋过程就是通过点击格子,把白或黑的棋子(图片)放置上去,那怎么计算坐标呢?你需要计算相对于棋盘点击的坐标,也就是下图我们的红圈,我们知道棋盘表格(table)是整个页面(body)中的一部分,js中click事件可以获取到全局事件event变量,所以能够获取到相对于body的event.left,event.top,再减去table的top,left就可以得到表格具体的像素,table的top left可以通过getBoundingClientRect方法获取;table的像素再除40px就是具体坐标了;大家在实现的时候还需要注意一个有效点击,只有在这个范围内才算有效范围,像我们这个程序,是以坐标点15px都算有效点击;那么无效点击范围在16px-25px,也就是点击格子中间是无效的。举个例子吧,比如我们现在算出表格具体坐标是top:130px,left:70px,先计算这个坐标是否有效,130%40=10, 70%40=30,都不在无效范围内,说明是有效坐标,我们这里横纵坐标分别记为xy,那么具体坐标就y=130/40 =3,x=70/40=1,此时x坐标需要加上1,因为x坐标大于25,靠右,需要再除的基础上加上1,所以最终横纵坐标为(2,3),这个过程涉及到一点小算法,你对着下图再思考下这个计算过程看看是否有不明白的,万事开头难!下面的图方便大家理解!

2.计算棋子是否获胜

  在写这个之前先给大家爆料下,没思考听到这个问题前呼吸都是混乱的,说实话真的好难啊,什么?还要实现,我TM不想学习了!嘿,兄嘚,别怕,有我在呢!怕解决不了问题,我牵着你,我们在一起吧!

  兵马未动,图表先行,给大家先上个图吧,其实就四条线;一个"米"子,会写米字,问题就解决了,也就是说每次落子后需要逐一判断这4条线上是否有五个相同颜色的棋子,其实对应Java程序程序来说,他是用一个二维数组形式来存储的棋盘数据的,我们以红色为中心点,其实这个过程就是通过方式1(纵向):先向上找,找红色的棋子,找到一个计数器就+1,不是红色的棋子直接break退出,同理向下找,找红色的棋子,找到一个计数器就+1,不是红色的棋子直接break退出,最终如果满足5个相同颜色的棋就算成功,也不用再通过方式2,3,4找了,如果方式1不满足条件,方式1就结束了,接下来就按方式2(左斜)查找,也就是同样的套路,一直到方式4为止,哈哈,是不是有点感觉了!先以方式1查找举例子吧,对二维数组来说,以先上找后下找,上找:横坐标不变,纵坐标递减;下找:横坐标不变,纵坐标递增。再按方式三举例,先右上后左下查找,右上:横坐标+1,纵坐标-1,左下:横坐标-1,纵坐标+1;你看看原理还是很简单吧!isSuccess方法是按方式1查找的。

public boolean isSuccess(int x, int y,int color,int[][] oriData)  {
        boolean flag = false;
        int count = 0;
        //(2)上-下,左-右,左上-右下,右上-左下; 4种方式
        // 方式1 :上-下 x相同,y不同
        //上 纵坐标递减;
        for (int i = y-1; i>-1; i--) {
            //判断同一颜色的子;
            if (oriData[x][i] != color) break;
            count++;
        }
        //下 纵坐标递增;
        for (int i = y+1; i<GameManager.Y; i++) {
            //判断同一颜色的子;
            if (oriData[x][i] != color) break;
            count++;
        }
        //重置
        if(count >=4) return true;
        else count = 0;
        // 方式2
        // 方式3
        // 方式4
        return falg
    }

3.网络聊天室实现

不知道你有没有发现,你有时候浏览网页会弹出一些广告页,上面时长会自动弹出人工客服窗口,不需要登陆什么的,你们能在线对话,其实这个功能可能就是websocket实现的,我们说过,websocket是双向的,在实现上和http一样,都是基于TCP实现的应用层协议,除了http是单向,ws是双向的。在用法上http是以http://头请求的短连接,是一次请求,ws是以ws://请求头的长连接,我们在“五子棋游戏大厅”点击位置进入棋盘页面其实就是一个连接过程,前端通过ws://ip:port/xx形式连接后台暴露的地址,会触发后台onOpen函数,每个连接在后台都是以不同Session对象存在,通过Session可以获取每个每个网页的session的id,就可以调用sendText方法,通知对应的浏览器,这样一个过程就实现了浏览器和后台交互;比如我们的对话,每个桌子是保存两个用户(Session),当其中某一个用户发送了某段话,会通知对应的浏览器,另一个用户也会把这句话发给对应的浏览器,所以你看到的两个页面都出现了一样的文字,其实原理还是比较简单的。

我们画个图来理解下这个过程。

websocket通信过程

下面这两个段代码是websocket客户端和服务器交互的代码,只贴了部分源码,限于篇幅有限,如果需要完整代码,下方【环境部署部分】给了源码下载压缩包

webSocket = new WebSocket("ws://"+serverIp+"/game/game/"+table+"/" + nickname);
1 /**
 2  * websocket服务连接入口
 3  * update by jiaolian 2020 8 12
 4  * 公众号:叫练
 5  */
 6 @ServerEndpoint("/game/{table}/{nickname}")
 7 public class WebserviceSession {
 8     @OnOpen
 9     public void onOpen(@PathParam("table") String tableName,@PathParam("nickname") String nickname, Session session) throws IOException {}
10     @OnMessage
11     public void onMessage(@PathParam("table") String tableName,String message, @PathParam("nickname") String nickname) {}
12     @OnClose
13     public void onClose(Session session,@PathParam("nickname") String nickname,@PathParam("table") String roomName) {}
14 }

4.查看复盘实现

这个功能是线程+文件实现的,既然需要查看复盘,那说明我们需要先写复盘,复盘其实就是写一个文件,查看复盘就是读文件,在一局棋中,每次落子就会写一行数据,每行数据会记录棋子的x,y坐标和棋子的颜色,按空格隔开,我们代码中Table【棋盘】对象保存color约定1为黑子,2为白子,当一局游戏结束后,查看复盘会生成对应一个线程,以每秒一行的速度读取保存在服务器的文件,文件名以“桌号+时间戳.wzq”命名,如:1_2020_09_01_15_45_15.wzq,每行数据读取出来后,会单独发给我们的User【Session】,浏览器收到通知后渲染页面就完事了;贴一段简单的代码;其中Table类是用来保存棋盘的;User类是用来保存用户信息的;finishReplayer()方法是读取文件,sendTextSingle()方法负责给浏览器发送信息;可以参考上面websocket通信过程;

/**
 * @author :jiaolian
 * @date :Created in 2020-08-14 13:30
 * @description:桌号
 * @modified By:
 * 公众号:叫练
 */
public class Table {

    //保存用户信息
    @JsonIgnore
    private List<User> userList = new CopyOnWriteArrayList<>();
    //桌号名
    private String name;
    //默认棋盘
    private int[][] oriData = new int[GameManager.X][GameManager.Y];
    //约定:1 黑子 2 白子  -1 无子(页面选棋子) 此时应该走动棋子颜色;
    //棋子颜色<默认黑子先走>
    private int color = CONST.CHEER_COLOR.BLACK;
    //对应的文件名<复盘> 最近一次
    private String fileName;
    //桌子状态; 已开始/未开始
    private int tableStatus;
    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
    private List<User> tempList;
}
/**
 * @author :jiaolian
 * @date :Created in 2020-08-14 13:56
 * @description:在线用户
 * @modified By:
 * 公众号:叫练
 */
public class User {

    //websocket sessoin;
    private Session session;
    private String nickname;
    //棋手是否已准备;
    private boolean isPrepared;

    //用户的复盘线程;key规则:桌号_用户名,为什么这么设计? 因为一个用户可能在多个桌子上同时游戏;
    //val值设计成Boolean,主要是查询对应桌数用户线程是否执行完毕; 如果有疑问,请咨询叫练;
    //设计这个目的主要实现:不能同时多次点击复盘;
    private ConcurrentHashMap<String,Boolean> reviewThreadMap = new ConcurrentHashMap();
}
public void finishReplayer(Table table,User user) {
        inputStream = new FileInputStream(table.getFileName());
        inputStreamReader = new InputStreamReader(inputStream);
        bufferedReader = new BufferedReader(inputStreamReader);
        while ((res = bufferedReader.readLine()) != null) {
            System.out.println(res);
            //谁点谁看
            GameManager.sendTextSingle(table,res,user);
            try {
                //休眠一秒
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

遇到问题


  • springMVC jackson返回实体对象通过不能修改后不能正常转化为json传递到前端?

在实现上述功能过程中,说没遇到问题是不可能的,很多都是业务的bug,就不详细介绍了 ,该五子棋程序没有写数据库,都是在内存处理的,其中渲染首页桌子页面的数据都是从后台一个大的List<User>获取的,如果List数据在修改后,再刷新首页,会出现栈溢出,不能写json的情况,目前处理的方式是用了@JsonIgnore忽略对象返回到前端,把这个List的User对象重新复制了一份到一个新的List<User>,查看了源码,暂时还没找到原因!找到原因的童鞋欢迎下方留言,一起探讨下!感谢了

Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind

源码下载地址及注意事项

  • JDK1.8及以上;有lamda表达式需要支持
  • maven;需要下载websocket包
  • 源码
(0)

相关推荐

  • 天睿:与大家分享昨天游玩的收获

    每日写一篇文章的第1年198天 天睿:帮你无虑的在天津买房 昨天是我的休息日. 我和我的小伙伴们去了一个游乐场,玩了差不多大半天. 上午我们大致都是在蹦床玩了一段时间,非常有趣. 然后又玩了一段时间的 ...

  • 黑白五子棋比赛

    黑白五子棋比赛 五子棋,棋子分为黑白两色,棋子放置于棋盘线交叉点上.两人对局,各执一色,轮流下一子,先将横.竖或 斜线的5个或5个以上同色棋子连成不间断的一排者为胜. 黑白五子棋比赛 类型:益智大小: ...

  • 棋牌游戏里都会有哪些玩法呢?

    要说在众多游戏中,哪个游戏是最常接触的,那应该就属于最受大众欢迎的棋牌游戏了.不管是在什么时刻,棋牌游戏都是可以放松身心和解压的小游戏.那这样一款休闲解压的小游戏,都有哪些玩法呢? 一.中国象棋,要想 ...

  • 五子棋教程:入门教学

    相信很多人都会下五子棋,但有多少人系统的学习过五子棋呢?本篇将系统讲解五子棋入门教程 1.下棋的器具:黑白两种颜色,黑113颗,白112颗.棋盘上有15条纵横相交的网格. 2.下棋方法:空盘开局,黑先 ...

  • 注意力训练小工具------五子棋

    五子棋,小时候没玩过,估计还是太高级了,没有普及开. 小时候,不是和尿泥,就是和小朋友玩过家家,要不就是爬树,掏鸟蛋,弹玻璃球,天天就是各种瞎玩. 后来辞职创业暑假办了个培训班,为了让孩子们不那么无聊 ...

  • 很多假新闻你都信了,那为什么还要学程序开发?

    先来看看一篇文章报道:<服务员学写程序,年薪暴增至320万> 根据纽约时报报导:美国男子保罗(Paul Minton)原本在餐厅端盘子,年薪2万美元(约人民币12万),但在学了3个月程序设 ...

  • 程序员之路——一个老程序员对刚上大学的学弟学妹的忠告

    始终认为,对一个初学者来说,IT界的技术风潮是不可追赶. 我时常看见自己的DDMM们把课本扔了,去买些价格不菲的诸如C#, VB.Net 这样的大部头,这让我感到非常痛心. 而许多搞不清指针是咋回事的 ...

  • 那些轻松拿高薪的程序员,在学完编程基础语法之后做了些什么?

    对于一个想要入行IT的新人,怎样选择一个前景好的编程语言十分很重要!让我们来看看那些拿高工资的程序员,到底是学的什么编程语言吧? 下面我介绍几个可以帮助你扎实地掌握编程基础知识,并且能够提升编程能力的 ...

  • 郭学谦 || 睡觉的程序

    选自<二女>第82篇. 今天是正月初四,我值班.其实这样的值班很奇怪,并不是要处理什么事务,等什么咨询,只是等着查岗,值班的目的只是为了防止查岗.所以你的样子就纷纷而来. 昨天晚上妈妈突发 ...

  • 学到了:goroutine 可能使程序变慢

    如何使用 goroutine 才能使你的 CPU 满负载运行呢 下面,我们将会展示一个关于 for 循环的代码,将输入分成几个序列添加到 Goroutines 里面!我敢打赌你之前可能有过几次这种情况 ...

  • 12岁女孩零编程经验开发系统千人用,80岁初代程序员300多天打卡学AI

    金磊 梦晨 发自 凹非寺 量子位 报道 | 公众号 QbitAI 纯小白,对AI感兴趣,想学习AI或是尝试做些有趣的小应用,有可能吗? 文科生一枚,自学了Python,但是对AI一无所知,能学深度学习 ...

  • 学PLC编程不得不了解的单按钮启停程序!(免费领42种起保停案例)

    42种起保停案例 那回复"42"免费领取 今天给大家介绍一些单按钮启停的控制程序(也叫一键启停程序),就是使用一个点动按钮,按一下启动一个灯泡点亮,再按一次,熄灭灯泡,再按一次,点 ...

  • Nature Biotechnology | 单细胞多组学分析揭示混合表型急性白血病调控程序 (1区 IF 31.864)

    编译:冬日暖阳,编辑:十九.江舜尧. 原创微文,欢迎转发转载. 美国斯坦福大学医学院William J.Greenleaf等人于2019年12月2日在国际顶级刊物NatureBiotechnology ...

  • 程序员学数学读哪本书?

    在互联网一直流传了一个这样的段子-- "一流程序员靠数学,二流靠算法,三流靠逻辑,四流靠SDK,五流靠Google和StackOverFlow,六流靠百度和CSDN.低端的看高端的就是黑魔法 ...