大家好,又见面了,我是你们的朋友全栈君。
五子棋基本思路
第一步:要分俩个类,一个是五子棋本身主类(包括黑白棋下棋方式),一个是棋子类(包括构建画布进行棋盘的设计,使其构成等距离的格子,正方形棋盘15*15格式)。
第二步:开始设计棋盘与棋子
1.利用圆形BUTTON实现棋子类,圆形棋子,利用Mathl类画出棋子,长宽都相等。
2.利用paintComponent()函数,进行在正方格交叉处点击出现黑棋与白棋落子,否则的话将不会出现下棋子的标志
- 限制棋子的落子,如果下到棋盘外,不会落子
4.侦查区域是落子标志,点击落子区域,从白子变黑子交替落下
第三步:设计五子棋下棋方式,获胜判定等
-
设计黑白棋子的落下,首先的黑子B会在棋盘上方显示“黑方下棋”
-
利用JPanel(面板容器类)在界面中用来分别添加棋盘界面和按钮界面。显示的“黑方下棋”使用宋体18号字来显示。
3.设计棋盘类,整体规划棋盘的横纵方向,以Button(按钮组件类)在界面作为按键,如“重新开始”按键。
4.每下一步都会用find()函数进行查找棋子的落子位置,并记录方便在判定是去判断棋子周围是否有同类型棋子,包括判定获胜五子相连的情况
- 利用for循环函数进行各个方向上的查找,并在每次落子之后用if()函数来判断是否这一排上有五颗同类型棋子,这个是竖直方向上的,接下来是左上和右下方向,坐下和右上方向,和水平方向,同理可得。
6.与画布棋盘时相似,使用paintComponent()函数进行棋子落子的判定,鼠标点在格子十字交叉点的周围进行分析
- 在MouseEvent(鼠标监听事件类)里面包含鼠标被点击等事件的处理方法。当界面被点击时就放下一个棋子。点击会落下棋子,“黑方下棋”与“白方下棋”交替出现。
以下利用距离格子十字交叉点30%以内判定棋子落在哪里的位置,在点击的位置上已经有棋子不可再放置。
7.实现接口ActionListener (状态监听处理类)
当点击重新开始会清除棋盘上所有的棋子,否则将无法去下下一步棋,保持棋盘在结束时的整体,包括画布的棋盘组件都不会动。
第四步:主类(测试类)将棋盘与落子方式进行整体输出。
源代码:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.*;
public class FiveChess extends JFrame{
private char whoseTurn='w';//黑方为B,白方为W
private JLabel jlblStatus=new JLabel("黑方下棋");
JPanel showWhoseTurn=new JPanel();
public FiveChess(){
ChessConvas ChessPanel=new ChessConvas();
add(ChessPanel,BorderLayout.CENTER);
//add(jlblStatus,BorderLayout.NORTH);
jlblStatus.setFont(new Font("宋体",Font.BOLD,18));
showWhoseTurn.add(jlblStatus,new GridLayout(1,3));
add(showWhoseTurn,BorderLayout.NORTH);
}
public static void main(String[] args){
JFrame fr=new FiveChess();
fr.setLocationRelativeTo(null);
fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
fr.setTitle("FiveChess");
fr.setVisible(true);
fr.setResizable(false);
fr.setSize(650,650);
}
//棋盘类
class ChessConvas extends JPanel{
//to move the ChessConvas by xMove and yMove
private int xMove=60;
private int yMove=60;
//to set the position chess
private int xPosition;
private int yPosition;
//private RoundButton1 []roundButtonArray=new RoundButton1[256];
private ArrayList rbList=new ArrayList();
private char chessSide=' ';//执棋的一方
private JPanel btPanel=new JPanel();
private JButton btReset=new JButton("重新开始");
//private JLabel jlblBackImage=new JLabel(new ImageIcon("chessFive.gif"));
public ChessConvas(){
addMouseListener(new MouseListener());
//jlblBackImage.setBounds(0,0,650,650);
//add(jlblBackImage);
//btPanel.setBounds(new Rectangle(0,0,650,100));
//btPanel.setLocation(0,5);
//btPanel.setBackground(Color.RED);
//btPanel.setLayout(new GridLayout(1,3,5,5));
//btPanel.add(btReset);
//btReset.setLocation(490,10);为什么这个不行呢?那它又有什么用呢?它与setBounds有什么不同呢?
btReset.setBounds(new Rectangle(440,40,100,30));
btReset.addActionListener(new ResetEvent());
add(btReset);
setLayout(null);//很关键,以在坐标上画组件,不然默认的是FlowLayout布局
}
public void setChessSide(char c){
chessSide=c;
repaint();
}
public char gerChessColor(){
return chessSide;
}
public void setXPosition(int xp){
xPosition=xp;
repaint();
}
public int getXPosition(){
return xPosition;
}
public void setYPosition(int yp){
yPosition=yp;
repaint();
}
public int getYPosition(){
return yPosition;
}
public boolean find(ArrayList rbList,int x,int y,Color bakColor){
for(int i=0;i<rbList.size();i++){
if((((RoundButton1)rbList.get(i)).getX()==x )&&(((RoundButton1)rbList.get(i)).getY()==y)&&(((RoundButton1)rbList.get(i)).getBackground()==bakColor)){
return true;
}
}
return false;
}
public boolean isWinner(ArrayList rbList,int x,int y,Color bakColor){
for(int i=0,k=0;i<6;i++){
//竖直方向
if(find(rbList,x+0*i,y+30*i,bakColor))k++;
if(find(rbList,x+0*i,y-30*i,bakColor)){
if(i!=0)k++;
}
System.out.println("竖直方向 k= "+k);
if(!find(rbList,x+0*i,y+30*i,bakColor)&&!find(rbList,x+0*i,y-30*i,bakColor))
break;//若竖直两个方向都走不通则跳出循环
if(k==5){
jlblStatus.setText((bakColor==Color.BLACK)?"黑方获胜!!!":"白方获胜!!!");
return true;
}
}
for(int i=0,k=0;i<6;i++){
//左上至右下方向
if(find(rbList,x-30*i,y-30*i,bakColor))k++;
if(find(rbList,x+30*i,y+30*i,bakColor)){
if(i!=0)k++;
}
System.out.println("左上至右下方向 k= "+k);
if(!find(rbList,x-30*i,y-30*i,bakColor)&&!find(rbList,x+30*i,y+30*i,bakColor))
break; //若左上与右下两个方向都走不通则跳出循环
if(k==5){
jlblStatus.setText((bakColor==Color.BLACK)?"黑方获胜!!!":"白方获胜!!!");
return true;
}
}
for(int i=0,k=0;i<6;i++){
//左下至右上方向
if(find(rbList,x-30*i,y+30*i,bakColor))k++;
if(find(rbList,x+30*i,y-30*i,bakColor)){
if(i!=0)k++;
}
System.out.println("左下至右上方向k= "+k);
if(!find(rbList,x-30*i,y+30*i,bakColor)&&!find(rbList,x+30*i,y-30*i,bakColor))
break;//若左下至右上两个方向都走不通则跳出循环
if(k==5){
jlblStatus.setText((bakColor==Color.BLACK)?"黑方获胜!!!":"白方获胜!!!");
return true;
}
}
for(int i=0,k=0;i<6;i++){
//水平方向
if(find(rbList,x-30*i,y+0*i,bakColor))k++;
if(find(rbList,x+30*i,y-0*i,bakColor)){
if(i!=0)k++;
}
System.out.println("水平方向 k= "+k);
if(!find(rbList,x-30*i,y+0*i,bakColor)&&!find(rbList,x+30*i,y-0*i,bakColor))
break; //若水平的两个方向都走不通则跳出循环
if(k==5){
jlblStatus.setText((bakColor==Color.BLACK)?"黑方获胜!!!":"白方获胜!!!");
return true;
}
}
return false;
}
protected void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
for(int i=1;i<=16;i++){
g2.draw(new Line2D.Double(30+xMove,30*i+yMove,16*30+xMove,30*i+yMove));
g2.draw(new Line2D.Double(30*i+xMove,30+yMove,30*i+xMove,16*30+yMove));
}
}
private class MouseListener extends MouseAdapter{
public void mouseClicked(MouseEvent e){
if(chessSide==' '&&whoseTurn!=' '){
setChessSide(whoseTurn);//set ChessSide in the chessCovas
}
xPosition=e.getX();
yPosition=e.getY();
if(xPosition > 30+xMove && xPosition < 16*30+xMove && yPosition>30+yMove && yPosition< 16*30+yMove) {
jlblStatus.setText((whoseTurn=='B')?"黑方下棋":"白方下棋");
whoseTurn=(whoseTurn=='B')?'W':'B';
int X = xPosition/30;
int Y = yPosition/30;
int centerX ;
int centerY ;
//棋子落点的判断
if(xPosition%30>30/2){
centerX=(X+1)*30;
if(yPosition%30>30/2)
centerY=(Y+1)*30;
else
centerY=Y*30;
}
else{
centerX=X*30;
if(yPosition%30>30/2)
centerY=(Y+1)*30;
else
centerY=Y*30;
}
RoundButton1 rb=new RoundButton1("");
//roundButtonArray[i]=rb;
//i++;
rbList.add(rb);
add(rb);
//棋子大小
rb.setBounds(new Rectangle(centerX-10,centerY-10,20,20));
if(whoseTurn=='B'){
rb.setBackground(Color.BLACK);
System.out.println("黑棋 x: "+rb.getX()+" y: "+rb.getY());
boolean flag=isWinner(rbList,rb.getX(),rb.getY(),Color.BLACK);
System.out.println(flag);
if(flag==true){
removeMouseListener(this);//当一方获胜后则不再响应鼠标事件
}
}
else{
rb.setBackground(Color.WHITE);
System.out.println("白棋 x: "+rb.getX()+" y: "+rb.getY());
boolean flag=isWinner(rbList,rb.getX(),rb.getY(),Color.WHITE);
System.out.println(flag);
if(flag==true){
removeMouseListener(this);//当一方获胜后则不再响应鼠标事件
}
}
repaint();
}
}
}
private class ResetEvent implements ActionListener{
public void actionPerformed(ActionEvent e){
for(int i=0;i<rbList.size();i++){
remove((RoundButton1)rbList.get(i));
}
rbList.clear();
repaint();//若不加repaint(),组件不会自动消失,等窗体稍有改动才会消失,为什么?
addMouseListener(new MouseListener());//以便重新开始后重新响应鼠标事件
}
}
}
}
//用圆形BUTTON实现棋子类
class RoundButton1 extends JButton {
public RoundButton1(){}
public RoundButton1(String label) {
super(label);
//下面的语句讲述这个按钮变为一个圆形而不是椭圆形
Dimension size = getPreferredSize();
size.width = size.height = Math.max(size.width, size.height);
setPreferredSize(size);
//不让JButton画背景而允许我们去画一个圆背景
setContentAreaFilled(false);
}
// 画出圆的背景和标签
protected void paintComponent(Graphics g) {
if (getModel().isArmed()) {
g.setColor(Color.lightGray);
} else {
g.setColor(getBackground());
}
g.fillOval(0, 0, getSize().width-1, getSize().height-1);
// 在焦点上画出一个标签
super.paintComponent(g);
}
// 画出一个边框
protected void paintBorder(Graphics g) {
g.setColor(getForeground());
g.drawOval(0, 0, getSize().width-1, getSize().height-1);
}
// 侦察单击区域
Shape shape;
public boolean contains(int x, int y) {
// 如果按钮改变了尺寸将重新创建一个Shape
if (shape == null || !shape.getBounds().equals(getBounds())) {
shape = new Ellipse2D.Float(0, 0, getWidth(), getHeight());
}
return shape.contains(x, y);
}
}
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/158180.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...