Java五子棋最全教程
Java五子棋最全教程
Ps:首先当我们做一个项目时应该培养这样一种思维即这个项目怎么开展,分为哪几个功能,这每个功能又该分为哪几步去实现,只有确定了基本路线,才有利于我们设计程序的基本结构,也让我们的开发效率更高,所以我推荐大家在做项目的时候要刻意地去思考这些问题,思考多了,我们做起项目来就会得心应手。
第一步:
落到实处我们这个项目第一步即创建界面,并在界面上绘出棋盘。在Java中我们有一个专门创建界面的类JFrame,利用类里面的一些方法,我们可以设置一些基本功能。例如:
JFrame jf = new JFrame("五子棋");
jf.setSize(900,800);
jf.setLocationRelativeTo(null);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setVisible(true);
还有一些操作可根据自身需求自行设定。接下来就是绘制棋盘,首先确定棋盘线条数,格子大小,与界面边界距离,利用Graphics这个类获取画笔,接下来的步骤就很简单了……棋盘画好后。当我们运行时会发现一个问题—移动窗口时棋盘就会消失不见了,这当时确实令我也感到很疑惑,在经过资料查阅后我发现在Java中每个Component类(所有组件的父类)都有一个paint方法用于重绘,每次重画该Component时都自动调用paint方法,有了这个知识点我们很快想到,应该把画棋盘这步操作写在paint方法中,这里我们可以创建新类继承JFrame这个类,并重写paint方法。
第二步:
我们应该思考有了棋盘就应该画棋子了啊,可是怎样实现鼠标一点,电脑就会我们点击的地方画棋子呢,而且还要准确画在棋盘交界处?Java中给我们提供了一个监听器接口MouseListener(当然还有许多其他监听器种类,这里不一一介绍),这些接口通常是要我们自定义类,并实现接口里的方法。它的工作模式采用了著名的授权事件模型,由三部分组成:事件源,事件监听器,事件;当事件源产生一个事件后,事件记录发生的一切事件,并从事件源发送给事件监听器对象,事件监听器根据事件的类型确定调用的方法。
具体可参见
listener监听器的工作原理是什么
理解了这个技术点同时还要注意之前提到的重绘问题,但是继承监听器的类里无法实现重绘,这里我提供一种方法,即把棋盘看成二维数组,我们每下一个棋子,就相当于把二维数组的对应位置值置为1或-1(代表黑棋白棋),然后再把这个二维数组传到之前写的窗口类里,依据数组值,即可实现重绘。这里我提一个技术细节:我们如何准确地将棋子下在棋盘交界处呢,我的方法是建立自定义坐标模型,将棋盘看成另一个坐标系,左上角第一个点为(0,0)以此类推,当点击一个位置时,我们获取位置基于窗口的坐标,然后减掉边距,利用整除性质,将这个坐标换算成基于棋盘的坐标,如此,即使我们点击的位置没有落在棋盘交界处,电脑也会准确地将棋子画在交界处。
3.此时我们已经实现了棋盘和棋子的重绘,接下来应思考五子棋应具备那些功能,我们玩五子棋的时候,基本上都会看到这样几个功能,①人人对战 ②人机对战 ③悔棋 ④清空棋盘这样几个功能,并通过点击按钮来实现,接下来就应该思考如何给界面添加按钮。这里涉及到几个知识点。
一.界面的布局管理:更详细的讲解参考布局管理
JFrame默认使用边界布局
这种模式根据其首选大小和容器大小的约束 (constraints) 对组件进行布局。NORTH 和 SOUTH 组件可以在水平方向上拉伸;而 EAST 和 WEST 组件可以在垂直方向上拉伸;CENTER 组件可同时在水平和垂直方向上拉伸,从而填充所有剩余空间。 因此在一个方向上添加了按钮如果再添加按钮会覆盖原来的,而想到JPanel默认是流式布局,流布局一般用来安排面板中的按钮。它使得按钮呈水平放置,直到同一条线上再也没有适合的按钮。线的对齐方式由 align 属性确定。可能的值为:
故可以这样添加按钮:
JPanel jp = new JPanel();
jp.setLayout(new FlowLayout(FlowLayout.CENTER,0,30));//0为水平间距
JButton Btu1 = new JButton("mybutton");
jp.add(Btu1);
jp.setPreferredSize(new Dimension(120,0));//设置画布的宽度,因为画布会添加到采用边界布局的JFrame中,故不用设置高度
jf.add(jp,BoderLayout.EAST);
同时对于按钮可以这样设置
Btu1.setText(title);
Btu1.setFont(font);
Btu1.setPreferredSize(dimen);
Btu1.setMargin(Ins);
二.就是为添加的按钮重写功能,利用ActionListener,并重写里面的public void actionPerformed(ActionEvent e),原理与MouseListener类似
4.关于五子棋的人机对战我这里提供两种思路
4.1.权值算法
当进行五子棋对战时,我们每下一个棋子都要判断这个点的横竖斜情况,对不同的情况采取不同的应对措施,,而这种思考过程就是一种权值法,每下一步棋,我们通过权值找到最优解。
整个棋盘记为Location[15][15];初始全为0,即没有棋子,当棋子下在棋盘上时,这个位置值改变,黑棋为1,白棋2,整个棋局就被保存了;然后创建weight[15][15],来保存每个位置的权重,当遍历Location时首先判断是否为0,然后判断这个位置向左,向右,向上,向下等八个方向的棋局情况,并将各种情况权重加起来就是这个位置的权值,找最大值即可。
怎么将棋局与权值联系起来呢?
HashMap<String, Integer> map = new HashMap<String, Integer>();
设置权值的思路是什么呢?
上面的矩阵图只是一个思路,其中并没有涉及到具体的很多特殊情况和细节,其中眠和活分别指的是相连的同色棋的两端有没有敌方的棋堵住。我们可以根据这样的一个矩阵图思路清晰的写出自己对不同情况的认知,其中不仅仅需要考虑到单种情况的权值,还需要考虑到其中两个的权值和与其它的权值比较,例如当遍历到一个可下地方的时候发现对方存在两个活二,那么这个点就是十分危险的点了,必须要拦截,所以两个活三的和一定要比较大,才能让电脑发现这个情况的紧急。
4.2 AI算法
对整个棋局或其中的有效位置进行评价。往往会使用一个分表。而评分表却很难确定,也没有所谓最好的,有人根据经验和测试,总结了不错的评分表,我在程序中都是用的别人的评分表。评估当前棋局中,哪个位置的得分最高。五子棋要赢,必然要有五个棋子在一起成线,那么我们就可以计算棋盘中每一个五格相连的线,一下称之为五元组。一般情况(包括专业五子棋)下棋盘是15*15的。那么应该是572个五元组。同时,针对五元组中黑子和白子的数量(可以不考虑相对位置)的不同,给该五元组评不同的分。然后每一个位置的得分就是包含这个位置的所有五元组的得分之和。
这里我给出评分表和一个方向的评分计算:
for(int i=0;<15;i++){for(int j=0;j<15;j++){int k=j;while(k<j+5){if(Location[i][k]==1) humanNum++;if(Location[i][k]==-1) machineNum++;k++;}int tupleScoreTmp=tupleScore(humanNum,machineNum);for(int k=j;k<j+5;k++){Score[i][k]=tupleScore;}humanNum=0;machineNum=0;tupleScoreTmp=0;}}public int tupleScore(int humanChessmanNum, int machineChessmanNum){//1.既有人类落子,又有机器落子,判分为0if(humanChessmanNum > 0 && machineChessmanNum > 0){return 0;}//2.全部为空,没有落子,判分为7if(humanChessmanNum == 0 && machineChessmanNum == 0){return 7;}//3.机器落1子,判分为35if(machineChessmanNum == 1){return 35;}//4.机器落2子,判分为800if(machineChessmanNum == 2){return 800;}//5.机器落3子,判分为15000if(machineChessmanNum == 3){return 15000;}//6.机器落4子,判分为800000if(machineChessmanNum == 4){return 800000;}//7.人类落1子,判分为15if(humanChessmanNum == 1){return 15;}//8.人类落2子,判分为400if(humanChessmanNum == 2){return 400;}//9.人类落3子,判分为1800if(humanChessmanNum == 3){return 1800;}//10.人类落4子,判分为100000if(humanChessmanNum == 4){return 100000;}return -1;//若是其他结果肯定出错了。这行代码根本不可能执行}
具体代码我已上传github,有兴趣的小伙伴可以下载看看
https://github.com/wmdsg/gobang
Java五子棋最全教程相关推荐
- mysql ssl 连接配置与Java连接配置全教程
目录 开篇 开发环境 正文 安装OpenSSL 开启远程连接支持 查看是否支持SSL 创建SSL证书和私钥 创建存放证书和私钥的目录 生成证书和私钥 mysql的SSL开启与证书配置 本地ssl登陆 ...
- java开发五年多少钱,附超全教程文档
一.分布式架构学习路线图 据统计,人的阅读时间在20分钟以内是能够达到全身心投入的,顾文章单张篇幅以后会尽量缩短,但更新会尽量相应频繁一些. 二.计算机软件发展历史 首先我们了解下计算机软件的发展历史 ...
- 初学Java的安装和环境配置全教程
初学Java的安装和环境配置全教程 欢迎! 这是你第一次来安装和使用Java.你最应该下载哪个来安装,安装后Java环境变量的配置(配置问题会导致多种Java运行问题)等等.这篇博客将为初学者提供Ja ...
- 使用Reactor进行反应式编程最全教程
反应式编程(Reactive Programming)这种新的编程范式越来越受到开发人员的欢迎.在 Java 社区中比较流行的是 RxJava 和 RxJava 2.本文要介绍的是另外一个新的反应式编 ...
- Docker最全教程之使用 Visual Studio Code玩转Docker(二十一)
VS Code是一个年轻的编辑器,但是确实是非常犀利.通过本篇,老司机带你使用VS Code玩转Docker--相信阅读本篇之后,无论是初学者还是老手,都可以非常方便的玩转Docker了!所谓是&qu ...
- Docker最全教程之使用.NET Core推送钉钉消息(二十)
前言 上一篇我们通过实战分享了使用Go推送钉钉消息,由于技痒,笔者现在也编写了一个.NET Core的Demo,作为简单的对照和说明. 最后,由于精力有限,笔者希望有兴趣的朋友可以分享下使用CoreR ...
- Docker最全教程之使用TeamCity来完成内部CI、CD流程(十七)
本篇教程主要讲解基于容器服务搭建TeamCity服务,并且完成内部项目的CI流程配置.教程中也分享了一个简单的CI.CD流程,仅作探讨.不过由于篇幅有限,完整的DevOps,我们后续独立探讨. 为了降 ...
- Docker最全教程——从理论到实战(三)
容器是应用走向云端之后必然的发展趋势,因此笔者非常乐于和大家分享我们这段时间对容器的理解.心得和实践. 本篇教程持续编写了2个星期左右,只是为了大家更好地了解.理解和消化这个技术,能够搭上这波车. 你 ...
- 《Java程序设计与数据结构教程(第二版)》学习指导
<Java程序设计与数据结构教程(第二版)>学习指导 目录 图书简况 学习指导 第一章 绪论 第二章 数据和表达式 第三章 使用类和对象 第四章 条件和循环 第五章 编写类 第六章 图形用 ...
最新文章
- php 删除子字符串函数,PHP删除字符串中的任何字符函数
- 58个PPT下载丨2019 PostgreSQL中国技术大会资源放送
- oracle 调用main方法,main方法中调用spring注入bean
- new 操作符干了什么?
- 精通javascript笔记(智能社)——数字时钟
- python的re模块是自带的吗_python内置模块手册 python中的re模块是自带的吗
- java学习(一)多态
- mysql判断时间是否在某个区间_如何正确理解 RT 并监控 MySQL 的响应时间
- java中super和this_Java中this和super的用法总结
- 撰写项目的解决方案要点解析
- tftp协议服务器IP地址,TFTP服务器的搭建
- LQR,iLQR,DDP控制论经典算法(MBRL基础知识)
- 费马引理、罗尔定理、拉格朗日中值定理、柯西中值定理
- 真实渗透改编--综合渗透 sql注入写马+文件上传+udf提权 安鸾靶场SQL注入学习
- c++11 regex
- 1 初识Mybatis
- lol大区服务器维护,LOL官宣“扩容升级”服务器,排队时间将大大减少,电一玩家喜大普奔!...
- 集中式和分布式版本控制系统的区别
- 曾仕强《中国式管理-人际关系学》笔记中
- 任何播放器无法播放视频