拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

五子棋结构重构

五子棋结构重构

目录

  • 重构前
  • 重构后
    • 状态
    • 优势
    • 代码实现

当前的棋盘和棋子功能大部分挤压在监听器类中,为了便于之后的管理,我们将棋盘和棋子的用法都抽离出来,放在ChessUtils类中,其他类中只用调用ChessUtils对象的方法即可,大大增强了代码的可读性。

重构前

之前的GoListener类:

  • 鼠标事件监听:mouseClicked 里直接处理落子
  • 坐标换算:把鼠标坐标转成棋盘行列
  • 落子合法性判断:重复落子、越界检查
  • 棋盘数据维护:newArr、chessList
  • 绘制棋子:调用 g.fillOval
  • 胜负判断:调用 win.isWin
  • AI 调用:isAIMode 判断后调 aiplay()
  • 按钮事件:开始、结束、悔棋
  • MyFrame里也要反过来读取 gol.chessSize、gol.chessList,重绘逻辑和监听器的内部状态绑定在一起,眼花缭乱。

重构后

状态

  • ChessUtils类:监管棋盘状态 、 落子 、 悔棋 、胜负判断 、调用 AI 、绘制入口
  • GoListener和MyFrame:调用ChessUtils里的方法。管理设置。
  • GoBangUI:绘制UI界面,调用监听器的设置方法

优势

  1. 调用方便:调用者只用管传什么参数,不用关心方法怎么实现。
  2. 职责区分:监听器只负责监听,AI 只计算,窗体只绘制,工具类只管棋盘,后续要该也能第一时间根据职责区块知道去哪改。
  3. 整理结构的时候,自己打代码的逻辑也更加清晰也方便自己发现当前的漏洞。

代码实现

ChessUtils类

packageUI.Go.v20917;importjavax.swing.*;importjava.awt.*;publicclassChessUtils{//棋盘数据,数组,标记intX=50,Y=75,SIZE=35,ROW=15,COL=15;intchessFlag;//棋子数组:保存已经下过的棋子,用于悔棋 重绘棋子Chess[]chessList=newChess[(ROW+1)*(COL+1)];intchessSize=0;//棋盘下标变量,用于保存已经下过的棋子,下一颗棋子的位置//棋盘数组: 二维数组,用于判断输赢int[][]chessArr=newint[ROW+1][COL+1];Chesschess;intmode=2;//切换人人对战 人机对战//开始对局publicvoidstart(Graphicsg){//数组清零chessList=newChess[(ROW+1)*(COL+1)];chessArr=newint[ROW+1][COL+1];chessSize=0;chessFlag=1;//重绘棋盘drawPad(g);}//结束对局publicvoidend(){//状态变量置为0chessFlag=0;}publicbooleanwin(intr,intc){win win=newwin();if(win.isWin(chessArr,r,c)){Stringcolor;if(chessFlag==1){color="黑棋";}else{color="白棋";}JOptionPane.showMessageDialog(null,color+"获胜了!");returntrue;}returnfalse;}//绘制:棋盘 单颗棋子 全部棋子publicvoiddrawPad(Graphicsg){//绘制填充底色的矩形g.setColor(Color.PINK);g.fillRect(X-SIZE/2,Y-SIZE/2,ROW*SIZE+SIZE,COL*SIZE+SIZE);//绘制棋盘格g.setColor(Color.BLACK);for(inti=0;i<=ROW;i++){g.drawLine(X,Y+i*SIZE,X+ROW*SIZE,Y+i*SIZE);g.drawLine(X+i*SIZE,Y,X+i*SIZE,Y+COL*SIZE);}}publicvoiddrawChess(Graphicsg,intr,intc){//黑白轮流if(chessFlag==1){g.setColor(Color.black);chessFlag=2;}elseif(chessFlag==2){g.setColor(Color.white);chessFlag=1;}//还原坐标intcx=c*SIZE+X-SIZE/2;intcy=r*SIZE+Y-SIZE/2;g.fillOval(cx,cy,SIZE,SIZE);}publicvoiddrawAllChess(Graphicsg){//取出棋子数组中的数据,还原坐标,重绘for(inti=0;i<chessSize;i++){intcx=chess.c*SIZE+X-SIZE/2;intcy=chess.r*SIZE+Y-SIZE/2;g.setColor(chessFlag==1?Color.black:Color.white);g.fillOval(cx,cy,SIZE,SIZE);}}//落子: 检查落子条件,调用和绘制,保存棋子数据publicbooleancheckPlay(intx,inty){//计算行列值intc=(x-X+SIZE/2)/SIZE;intr=(y-Y+SIZE/2)/SIZE;//判断结束和开始游戏if(chessFlag==0){JOptionPane.showMessageDialog(null,"请先开始对局");returnfalse;}//判断重复落子//如果棋盘数组中已保存该位置的数据,即重复落子/*for (int i = 0; i < chessSize; i++) { if(chessList[i].c==c&&chessList[i].r==r){ JOptionPane.showMessageDialog(null,"请勿重复落子"); return false; } }*/if(chessArr[r][c]!=0){JOptionPane.showMessageDialog(null,"请勿重复落子");returnfalse;}//判断在有效范围内落子if(r>ROW||c>COL){JOptionPane.showMessageDialog(null,"请在棋盘区域内落子");returnfalse;}returntrue;}publicvoidsaveData(intr,intc){chessList[chessSize]=newChess(r,c,chessFlag);chessSize++;chessArr[r][c]=chessFlag;}publicvoidplayChess(Graphicsg,intx,inty){//检查条件if(!checkPlay(x,y)){return;}intc=(x-X+SIZE/2)/SIZE;intr=(y-Y+SIZE/2)/SIZE;//保存数据saveData(r,c);//绘制棋子drawChess(g,r,c);//判断输赢if(win(r,c)){end();}//人机对局if(mode==1){aiPlay(g);}}//权重一直叠加publicvoidaiPlay(Graphicsg){//ai选定落子地方AIai=newAI();Chesschess=ai.AIplay(chessArr);//保存数据saveData(chess.r,chess.c);//绘制drawChess(g,chess.r,chess.c);//判断输赢if(win(chess.r,chess.c)){end();}}//悔棋:更换颜色,删除上一颗棋子数据,重绘publicvoidrebackChess(Graphicsg){if(chessSize!=0){chessFlag=chessList[chessSize].flag;Chesschess=chessList[chessSize];chessList[chessSize-1]=null;chessSize--;chessArr[chess.r][chess.c]=0;//刷新drawPad(g);drawAllChess(g);}else{JOptionPane.showMessageDialog(null,"棋盘上没有棋子可悔");return;}}publicvoidsetMode(intmode){this.mode=mode;}}

GoListener

packageUI.Go.v20917;importjavax.swing.*;importjava.awt.*;importjava.awt.event.ActionEvent;importjava.awt.event.ActionListener;importjava.awt.event.MouseEvent;importjava.awt.event.MouseListener;publicclassGoListenerimplementsActionListener,MouseListener{Graphicsg;JRadioButtonjrb;ChessUtilschessUtils;publicvoidsetChessUtils(ChessUtilschessUtils){this.chessUtils=chessUtils;}publicvoidsetJRB(JRadioButtonjrb){this.jrb=jrb;}publicvoidsetGraphics(Graphicsg){this.g=g;}@OverridepublicvoidactionPerformed(ActionEvente){Stringac=e.getActionCommand();JButtonbtn=(JButton)e.getSource();if(ac.equals("开始对局")){if(jrb.isSelected()){chessUtils.setMode(1);}else{chessUtils.setMode(2);}chessUtils.start(g);btn.setText("结束对局");btn.setBackground(Color.red);jrb.setEnabled(false);}elseif(ac.equals("结束对局")){chessUtils.end();jrb.setEnabled(true);btn.setText("开始对局");btn.setBackground(Color.green);}elseif(ac.equals("悔棋")){chessUtils.rebackChess(g);}}@OverridepublicvoidmouseClicked(MouseEvente){intx=e.getX();inty=e.getY();chessUtils.playChess(g,x,y);}@OverridepublicvoidmousePressed(MouseEvente){}@OverridepublicvoidmouseReleased(MouseEvente){}@OverridepublicvoidmouseEntered(MouseEvente){}@OverridepublicvoidmouseExited(MouseEvente){}}

MyFrame

packageUI.Go.v20917;importjavax.swing.*;importjava.awt.*;publicclassMyFrameextendsJFrame{ChessUtilschessUtils;publicvoidsetChessUtils(ChessUtilschessUtils){this.chessUtils=chessUtils;}// 窗体刷新时自动调用@Override// 检查注解 检查这个方法是否是重写的publicvoidpaint(Graphicsg){super.paint(g);// 调用原本父类的刷新方法 绘制窗体本身 super 指代父类chessUtils.drawPad(g);chessUtils.drawAllChess(g);}}

GoBangUI

packageUI.Go.v20917;importjavax.swing.*;importjava.awt.*;publicclassGoBangUI{ChessUtilschessUtils=newChessUtils();GoListenergol=newGoListener();MyFramejf=newMyFrame();// 使用自己的窗体类 替换 JFramepublicvoidshowUI(){jf.setTitle("五子棋3.0");jf.setSize(800,700);jf.setLocation(400,200);jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.setLayout(null);String[]strs={"开始对局","悔棋"};Fontfont=newFont("宋体",Font.BOLD,16);for(inti=0;i<strs.length;i++){JButtonbtn=newJButton(strs[i]);btn.setBounds(660,150+i*50,100,30);jf.add(btn);btn.setFont(font);btn.addActionListener(gol);btn.setBackground(Color.WHITE);}JRadioButtonjrb=newJRadioButton("人机对战");JRadioButtonjrb2=newJRadioButton("人人对战");ButtonGroupbg=newButtonGroup();bg.add(jrb);bg.add(jrb2);jrb.setBounds(660,260,100,20);jrb2.setBounds(660,300,100,20);jrb2.setSelected(true);jf.add(jrb);jf.add(jrb2);jf.setVisible(true);// 可视化 显示窗体// 获取窗体的图形渲染器Graphicsg=jf.getGraphics();jf.addMouseListener(gol);gol.setJRB(jrb);gol.setGraphics(g);gol.setChessUtils(chessUtils);jf.setChessUtils(chessUtils);}}

GameStart

packageUI.Go.v20917;publicclassGameStart{staticvoidmain(){GoBangUIgoBangUI=newGoBangUI();goBangUI.showUI();}}
返回列表