JAVA小项目之五子棋
五子棋V1.0
功能:
- 人人对战,人机对战(初级)
- 记录双方分数;
主要知识点:
二维坐标系中,各方向坐标的关系及规律。
效果图:

- 主框架类:
package com.gxlee.wzq;
/**
*五子棋 Java版 V1.0
*@author http://www.cnblogs.com/HFLY
*时间2005-8-20
*功能:人机对战 人人对战
*/
import java.awt.Color;
import java.awt.Container;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
@SuppressWarnings("serial")
public class MainFrame extends JFrame {
private JButton btStart = new JButton("开始");
private JComboBox model = new JComboBox(new Object[] { "人机对战", "人人对战" });
private JRadioButton jr1 = new JRadioButton("电脑先下");
private JRadioButton jr2 = new JRadioButton("自己先下");
private JRadioButton level1 = new JRadioButton("难");
private JRadioButton level2 = new JRadioButton("中");
private JRadioButton level3 = new JRadioButton("易");
private boolean myOrder = true;// false 对方,true 自己
private boolean gameOver = true;// false 游戏结束
private boolean win = false;
private int advCouner;// 对方赢的次数
private int myCouter;// 自己赢的次数
private List<Chess> myChess = new ArrayList<Chess>();// 自己的棋
private List<Chess> advChess = new ArrayList<Chess>();// 对方的棋
private List<Chess> allChess = new ArrayList<Chess>();// 所有的棋
private int gameModel = 0;// 0 人机模式,1人人模式
public MainFrame() {
// 构造函数
this.setTitle("五子棋 v1.0");
this.setSize(Utils.WIDTH, Utils.HEIGHT);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setResizable(false);
Mypanel zb = new Mypanel();
zb.setLayout(null);
// 添加难易 人机模式时才可选
level1.setBackground(new Color(224, 192, 0));
level2.setBackground(new Color(224, 192, 0));
level3.setBackground(new Color(224, 192, 0));
level1.setBounds(Utils.IMAGE_WIDTH + (Utils.WIDTH - Utils.IMAGE_WIDTH)
/ 2 - 53, Utils.HEIGHT - 290, 100, 30);
level2.setBounds(Utils.IMAGE_WIDTH + (Utils.WIDTH - Utils.IMAGE_WIDTH)
/ 2 - 53, Utils.HEIGHT - 260, 100, 30);
level3.setBounds(Utils.IMAGE_WIDTH + (Utils.WIDTH - Utils.IMAGE_WIDTH)
/ 2 - 53, Utils.HEIGHT - 230, 100, 30);
level3.setSelected(true);
zb.add(level1);
zb.add(level2);
zb.add(level3);
ButtonGroup group1 = new ButtonGroup();
group1.add(level1);
group1.add(level2);
group1.add(level3);
// 添加模式
model.setBounds(Utils.IMAGE_WIDTH + (Utils.WIDTH - Utils.IMAGE_WIDTH)
/ 2 - 53, Utils.HEIGHT - 180, 100, 30);
model.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// String(model.getSelectedItem());
switch (model.getSelectedIndex()) {
case 0:
gameModel = 0;
jr1.setText("电脑先下");
break;
case 1:
gameModel = 1;
jr1.setText("对方先下");
break;
default:
break;
}
}
});
zb.add(model);
// 添加谁先下:
jr1.setBounds(Utils.IMAGE_WIDTH + (Utils.WIDTH - Utils.IMAGE_WIDTH) / 2
- 53, Utils.HEIGHT - 150, 80, 30);
jr1.setBackground(new Color(224, 192, 0));
jr1.setForeground(Color.WHITE);
jr1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
myOrder = false;// 轮到对方出棋
}
});
zb.add(jr1);
jr2.setBounds(Utils.IMAGE_WIDTH + (Utils.WIDTH - Utils.IMAGE_WIDTH) / 2
- 53, Utils.HEIGHT - 120, 80, 30);
jr2.setBackground(new Color(224, 192, 0));
jr2.setForeground(Color.WHITE);
jr2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
myOrder = true;// 自己先下;
}
});
jr2.setSelected(true);// 默认自己先下
zb.add(jr2);
ButtonGroup group2 = new ButtonGroup();
group2.add(jr1);
group2.add(jr2);
// 添加开始按钮
btStart.setBounds(Utils.IMAGE_WIDTH + (Utils.WIDTH - Utils.IMAGE_WIDTH)
/ 2 - 53, Utils.HEIGHT - 90, 100, 30);
btStart.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 复位
gameOver = false;
win = false;
myChess.clear();
advChess.clear();
allChess.clear();
// 其他复位的地方
btStart.setText("再来一局");
// 谁出?
myOrder = jr1.isSelected() ? false : true;
if (!myOrder) {
computerGetNextChess();
myOrder = true;
}
repaint();
}
});
zb.add(btStart);
zb.addMouseListener(new MouseClick());
Container c = this.getContentPane();
c.add(zb);
this.setVisible(true);
}
private class MouseClick extends MouseAdapter {
@Override
public void mouseClicked(MouseEvent e) {
// 如果是游戏结束状态
if (gameOver) {
return;
}
// 若是人机模式,并且当前是对方出的时候
if (gameModel == 0 && !myOrder) {
return;
}
if (e.getX() > 430) // 坐标越界
return;
int x = e.getX();
int y = e.getY() > 420 ? 420 : e.getY();
int xIndex = (x - 18) / 25 + ((x - 18) % 25 > 25 / 2 ? 1 : 0);
int yIndex = (y - 18) / 25 + ((y - 18) % 25 > 25 / 2 ? 1 : 0);
boolean result = addChess(new Chess(xIndex, yIndex), myOrder);
if (result) {
// 先绘画
repaint();
// 检查是否有输赢
if (gameOver = checkResult(xIndex, yIndex)) {
win = true;
return;
} else {
// 交换顺序
myOrder = !myOrder;
// 如果没有赢的时候,人机模式需要调用电脑出棋
if (gameModel == 0) {
if (gameOver = computerGetNextChess()) {
win = true;
return;
}
myOrder = true;
}
}
}
}
}
/**
* 电脑自动下棋的方法
*
* @return
*/
public boolean computerGetNextChess() {
// 电脑出 最大索引为 16;
int xIndex = Utils.r.nextInt(17);
int yIndex = Utils.r.nextInt(17);
// 如果没有棋 并且是电脑模式自己先出
if (myChess.size() == 0 && advChess.size() == 0) {// 这是表示是电脑先出
addChess(new Chess(xIndex, yIndex), advChess);
return false;
} else if (myChess.size() == 1 && advChess.size() == 0) {// 玩家先出
// 这个完全是多余的 纯粹增加花样
// 可以在玩的周边出一个
// 得到个随机数,在他的的哪个方向即偏移地址
Chess myCh = myChess.get(0);
int offset = 1;// Utils.r.nextInt(15)+1;//偏移距离
int rndX = Utils.r.nextInt(2);
int rndY = Utils.r.nextInt(2);
int rX = rndX == 0 ? -1 : 1;
int rY = rndY == 0 ? -1 : 1;
while (!addChess(new Chess(myCh.getxIndex() + rX * offset, myCh
.getyIndex()
+ rY * offset), advChess)) {
rndX = Utils.r.nextInt(2);
rndY = Utils.r.nextInt(2);
rX = rndX == 0 ? -1 : 1;
rY = rndY == 0 ? -1 : 1;
}
return false;
}
// 这时,如果自己要赢了就开始赢
Chess c = getBestChess(advChess, true);
if (checkResult(c.getxIndex(), c.getyIndex(), advChess)) {
return addChess(c, advChess);
}
// 电脑防御模式,如果玩家有只要放入一个棋可以达到4分,就要进行防御
Chess advC = getBestChess(myChess, false);
if (advC == null) {
advC = c;
}
addChess(advC, advChess);
return false;// checkResult(c.getxIndex(),c.getyIndex());//是否胜
}
/**
* 得到玩家可能要赢了的点 玩家4分的点也要控制 得到一个可以最大分数的点 最佳的点
*
* @param playerChess
* @param flag
* 标示电脑的棋还是玩家的棋 玩家的话 如果分数小于4则不要
* @return
*/
public Chess getBestChess(List<Chess> playerChess, boolean flag) {
int maxScore = -1;
int score = -1;
int maxScoreX = -1;
int maxScoreY = -1;
int xIndex = -1, yIndex = -1;
geted: for (Chess c : playerChess) {
xIndex = c.getxIndex();
yIndex = c.getyIndex();
// 左边 {-1,0},右边{1,0},左上角的{-1,-1}....
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
// 不能同时为零0
if (i == j && i == 0)
continue;
score = Utils.getBestPointScore(xIndex + i, yIndex + j,
allChess, playerChess);
if (score >= maxScore) {
maxScore = score;
maxScoreX = xIndex + i;
maxScoreY = yIndex + j;
if (maxScore >= 5)
break geted;
}
}
}
}
// 如果此时再判断玩家的棋
if (!flag) {
if (maxScore < 4)
return null;
}
return new Chess(maxScoreX, maxScoreY, true);
}
public boolean checkResult(int x, int y, List<Chess> playerChess) {
int scorePre = 0; // 这个点的左,左上,上 ,左下能得分
int socreNext = 0;// 这个点的 右,右下,下,右上
int score = 0;
int maxScore = 0;
int offsetX, offsetY;
/**
* 前半段 后半段 X Y X Y 横 向 -1 0 1 0 竖 向 0 -1 0 1 下上斜 -1 1 1 -1 上下斜 -1 -1 1 1
*/
for (int i = -1; i <= 0; i++) {
for (int j = -1; j <= 1; j++) {
if (i == j && i == 0)
continue;
if (0 == 0 && y == 1)
continue;// 不判断也可以
// 前半段
offsetX = i;
offsetY = j;
scorePre = Utils.getPointScore(x, y, offsetX, offsetY,
playerChess);
// 后半段
offsetX = -i;
offsetY = -j;
socreNext = Utils.getPointScore(x, y, offsetX, offsetY,
playerChess);
score = scorePre + socreNext + 1;
maxScore = score >= maxScore ? score : maxScore;
if (maxScore >= 5)
return true;
}
}
return false;
}
/**
* 重载,检查是否赢了
*
* @param x
* @param y
* @return
*/
public boolean checkResult(int x, int y) {
List<Chess> playerChess = myOrder ? myChess : advChess;
return checkResult(x, y, playerChess);
}
/**
* 添加棋的方法
*
* @param chess
* @param playerChess
* @return
*/
public boolean addChess(Chess chess, List<Chess> playerChess) {
// 判断是否越界
if (chess.getxIndex() < 0)
return false;
if (chess.getxIndex() > 16)
return false;
if (chess.getyIndex() < 0)
return false;
if (chess.getyIndex() > 16)
return false;
// 重载
if (allChess.contains(chess)) {
return false;
}
Chess c = new Chess(chess);
// 没有被占用的话
allChess.add(c);
return playerChess.add(c);
}
//
/**
* 重载 添加棋的方法
*
* @param chess
* @param myOrder
* @return
*/
public boolean addChess(Chess chess, boolean myOrder) {
List<Chess> playerChess = myOrder ? myChess : advChess;
return addChess(chess, playerChess);
}
/**
* 画图容器
*
* @author
*
*/
public class Mypanel extends JPanel {
@Override
protected void paintComponent(Graphics g) {
// 画背景
g.drawImage(Utils.images.get("Board.gif"), 0, 0, this);
g.setColor(new Color(224, 192, 0));
g.fillRect(Utils.IMAGE_WIDTH, 0, Utils.WIDTH - Utils.IMAGE_WIDTH,
Utils.HEIGHT);
g.setColor(Color.WHITE);
g.setFont(new Font("隶书", Font.PLAIN, 20));
// 画图标
g.drawString("当前:", Utils.IMAGE_WIDTH + 10, 52);// 让电脑延时几秒再出其
BufferedImage img = Utils.images.get("white.gif");
if (!myOrder) {
img = Utils.images.get("black.gif");
}
g.drawImage(img, Utils.IMAGE_WIDTH + 70, 35, this);
// 画框
g.drawRect(Utils.IMAGE_WIDTH, 20, Utils.WIDTH - Utils.IMAGE_WIDTH
- 10, Utils.HEIGHT - 68);
// 画自己的棋
img = Utils.images.get("white.gif");
for (Chess c : myChess) {
g.drawImage(img, c.getX(), c.getY(), this);
}
// 画对方的棋
img = Utils.images.get("black.gif");
for (Chess c : advChess) {
g.drawImage(img, c.getX(), c.getY(), this);
}
// 画赢了
if (gameOver && win) {
// 谁赢了?
String name = "";
if (myOrder) {
myCouter++;
name = (gameModel == 1) ? "白方" : "我";
} else {
advCouner++;
name = (gameModel == 0) ? "电脑" : "黑方";// 电脑模式
}
g.setFont(new Font("隶书", Font.BOLD, 65));
g.setColor(Color.WHITE);
g.drawString(name + "赢了!", 100, 200);
g.setFont(new Font("隶书", Font.BOLD, 65));
g.setColor(Color.RED);
g.drawString(name + "赢了!", 100, 202);
}
// 画战绩:
g.setFont(new Font("楷体", Font.PLAIN, 15));
g.setColor(Color.WHITE);
g.drawString(((gameModel == 1) ? "黑方(赢):" : "电脑(赢):") + advCouner,
Utils.IMAGE_WIDTH + 10, 100);
g.drawString(((gameModel == 1) ? "白方(赢):" : " 我(赢):") + myCouter,
Utils.IMAGE_WIDTH + 10, 120);
}
}
public static void main(String[] args) {
new MainFrame();
}
}
- 棋子类:
package com.gxlee.wzq;
/**
* 棋
* @author http://www.cnblogs.com/HFLY
*
*/
public class Chess {
private int x;// x坐标
private int y;// y 坐标
private int xIndex;
private int yIndex;
// 构造函数
public Chess(int xIndex, int yIndex) {
super();
this.xIndex = xIndex;
this.yIndex = yIndex;
this.x = xIndex * 25 + 18 - 12;// 通过格子求出十字架的位置 12 是棋子的一半
this.y = yIndex * 25 + 20 - 12;
}
public Chess(Chess c) {
this.xIndex = c.getxIndex();
this.yIndex = c.getyIndex();
this.x = xIndex * 25 + 18 - 12;//
this.y = yIndex * 25 + 20 - 12;
}
public Chess(int xIndex, int yIndex, boolean checkFlag) {
super();
this.xIndex = xIndex;
this.yIndex = yIndex;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Chess) {
Chess c = (Chess) obj;
if (c.xIndex == this.xIndex && c.yIndex == this.yIndex) {
return true;
}
}
return false;
}
public int getxIndex() {
return xIndex;
}
public void setxIndex(int xIndex) {
this.xIndex = xIndex;
}
public int getyIndex() {
return yIndex;
}
public void setyIndex(int yIndex) {
this.yIndex = yIndex;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
- 工具类:
package com.gxlee.wzq;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import javax.imageio.ImageIO;
/**
* 工具类
* @author http://www.cnblogs.com/HFLY
*
*/
public class Utils {
public static Random r = new Random();
public static Map<String,BufferedImage> images = new HashMap<String,BufferedImage>();
public static final int WIDTH = 560;//游戏界面的宽
public static final int IMAGE_WIDTH = 437;
public static final int HEIGHT = 465;//游戏界面的高
static{
File dir = new File("src/img");
File[] files = dir.listFiles();
for (File file : files) {
BufferedImage img;
try {
img = ImageIO.read(file);
images.put(file.getName(), img);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**电脑出棋时判断双方最佳点的方法
* @param x
* @param y
* @param allChess
* @param playerChess 传入哪方就得出哪方最佳点
* @return
*/
public static int getBestPointScore(int x,int y,List<Chess> allChess,List<Chess> playerChess){
//坐标越界
if(x<0) return -1;
if(x>16) return -1;
if(y<0) return -1;
if(y>16) return -1;
//如果这个点被电脑占用了 则不能使用
if(allChess.contains(new Chess(x,y))) return -1;
// 向前延伸得分加上向后加当前1分为总得分
int scorePre=0; //这个点的左,左上,上 ,左下能得分
int socreNext=0;//这个点的 右,右下,下,右上
int score = 0 ;
int maxScore = 0;
int offsetX,offsetY;
/**
* 前半段 后半段
X Y X Y
横 向 -1 0 1 0
竖 向 0 -1 0 1
下上斜 -1 1 1 -1
上下斜 -1 -1 1 1
*/
geted:for (int i = -1; i <=0; i++) {
for(int j = -1;j<=1;j++){
if(i==j && i==0) continue;
//前半段
offsetX = i;offsetY = j;
scorePre = getPointScore(x,y,offsetX,offsetY,playerChess);
//后半段
offsetX = i*(-1);offsetY = j*(-1);
socreNext = getPointScore(x,y,offsetX,offsetY,playerChess);
score = scorePre+socreNext+1;
maxScore = score>=maxScore?score:maxScore;
if (maxScore>=5) break geted;
}
}
return maxScore;
}
/**每一点的得分
* @param x
* @param y
* @param offsetX
* @param offsetY
* @param playerChess
* @return
*/
public static int getPointScore(int x,int y,int offsetX,int offsetY,List<Chess> playerChess){
int score = 0;
int xAdd = offsetX;
int yAdd = offsetY;
while (playerChess.contains(new Chess(x+offsetX,y+offsetY))) {
score ++;
offsetX += xAdd;
offsetY += yAdd;
}
return score;
}
}
- 素材
- 棋盘

- 棋子


JAVA小项目之五子棋的更多相关文章
- Java小项目之:五子棋,你下棋下得过电脑吗?
Java小项目之:五子棋,你下棋下得过电脑吗? Java五子棋功能要求: 1.创建窗口和设计一个棋盘界面 2.实现鼠标点击,棋子出现,黑白棋轮流下 3.能够判断五子相连输赢 4.添加重新开始,悔棋,退 ...
- Java小项目--坦克大战(version1.0)
Java小项目--坦克大战<TankWar1.0> 这个小项目主要是练习j2se的基础内容和面向对象的思想.项目实现了基本的简单功能,我方一辆坦克,用上下左右键控制移动方向,按F键为发射炮 ...
- Java学习笔记三十:Java小项目之租车系统
Java小项目之租车系统 一:项目背景介绍: 根据所学知识,编写一个控制台版的“呱呱租车系统” 功能: 1.展示所有可租车辆: 2.选择车型.租车量: 3.展示租车清单,包含:总金额.总载货量以及其车 ...
- java小项目之:植物大战僵尸,这个僵尸有点冷!内附素材源码
Java小项目之:植物大战僵尸! <植物大战僵尸>是由PopCap Games开发的一款益智策略类单机游戏,于2009年5月5日发售,这款游戏可谓是无人不知无人不晓. 在我身边,上到40岁 ...
- Java小项目之:教你做个聊天系统!
Java小项目之:聊天系统 今天给大家带来的java练手小项目是一个简单的聊天室,界面简单,操作不难. 分为注册系统,登录系统和聊天系统三部分,很适合java小白练手. 完整的源码和素材请关注并私信我 ...
- java小项目之:扫雷,这游戏没有你想的那么简单!
扫雷 我之前分享的小项目和小游戏,电影购票.坦克大战.捕鱼达人.贪吃蛇等,虽然已经是耳熟能详人尽皆知的项目和游戏,但是保不齐真的有人没接触过. 今天分享的这个项目,我不相信没人接触过(仅限80后-00 ...
- Python小项目之五子棋
1.项目简介 在刚刚学习完python套接字的时候做的一个五子棋小游戏,可以在局域网内双人对战,也可以和电脑对战 2.实现思路 局域网对战 对于局域网功能来说,首先建立连接(tcp),然后每次下棋时将 ...
- java小项目之:象棋,羡慕你们有对象的!
象棋,是我国传统棋类益智游戏,在中国有着悠久的历史,属于二人对抗性游戏的一种,由于用具简单,趣味性强,成为流行极为广泛的棋艺活动.中国象棋是中国棋文化也是中华民族的文化瑰宝. 象棋还有很多口诀,这是最 ...
- java小项目——抽奖系统
来了来了!这不又到考试周了吗!愁人,又得复习,复习,复习!这段时间每天都在复习线代和高数!(说是复习,说实话其实是在预习,啊哈哈哈哈哈),得有一段时间都没有学到新的知识了,代码感觉都生疏了,惆怅.博客 ...
随机推荐
- [jQuery] $.grep使用
1.$.grep的功能是查找过滤功能的数组,原数组不受影响. 2.参数定义 jQuery.grep( array, function(elementOfArray, indexInArray), [ ...
- linux命令——Grep 命令 用法大全
1. 参数: -I :忽略大小写 -c :打印匹配的行数 -l :从多个文件中查找包含匹配项 -v :查找不包含匹配项的行 -n:打印包含匹配项的行和行标 2.RE(正则表达式) \ 忽略正则表达式中 ...
- js-ajax实现获取xmlHttp对象
//获取xmlHttp对象 function createXMLHttp() { var xmlhttp; //对于大多数浏览器适用 if (window.XMLHttpRequest) { xmlh ...
- mysql的mvcc(多版本并发控制)
mysql的mvcc(多版本并发控制) 我们知道,mysql的innodb采用的是行锁,而且采用了多版本并发控制来提高读操作的性能. 什么是多版本并发控制呢 ?其实就是在每一行记录的后面增加两个隐藏列 ...
- get set
关于C# get set的文章很多,但是笔者的这篇文章有它的特别之处,笔者用简单的语言把c# get set讲述的十分明了. C# get set释一:属性的访问器包含与获取(读取或计算)或设置(写) ...
- Java中匿名类的两种实现方式(转)
使用匿名内部类课使代码更加简洁.紧凑,模块化程度更高.内部类能够访问外部内的一切成员变量和方法,包括私有的,而实现接口或继承类做不到.然而这个不是我说的重点,我说的很简单,就是匿名内部类的两种实现方式 ...
- BZOJ 1008 [HNOI2008]越狱
1008: [HNOI2008]越狱 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 5166 Solved: 2242[Submit][Status] ...
- BZOJ1782: [Usaco2010 Feb]slowdown 慢慢游
1782: [Usaco2010 Feb]slowdown 慢慢游 Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 541 Solved: 326[Sub ...
- (2015年郑州轻工业学院ACM校赛题) E 汇编原理
此题属于比较麻烦的模拟题,比赛的时候是队友写的, 比赛结束之后自己也写了一遍,感觉对复杂模拟的掌控还是不行! 解析: 我感觉 ADD操作 和 MOV操作比较类似 所以就写在了一块,MUL操作单独写就行 ...
- 【转】 Linux中的工作队列
原文网址:http://blog.chinaunix.net/uid-20583479-id-1920134.html 工作队列一般用来做滞后的工作,比如在中断里面要做很多事,但是比较耗时,这时就可以 ...