ARTICLE DETAIL

资讯详情

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

五子棋结构重构

五子棋结构重构 目录重构前重构后状态优势代码实现当前的棋盘和棋子功能大部分挤压在监听器类中为了便于之后的管理我们将棋盘和棋子的用法都抽离出来放在ChessUtils类中其他类中只用调用ChessUtils对象的方法即可大大增强了代码的可读性。重构前之前的GoListener类鼠标事件监听mouseClicked 里直接处理落子坐标换算把鼠标坐标转成棋盘行列落子合法性判断重复落子、越界检查棋盘数据维护newArr、chessList绘制棋子调用 g.fillOval胜负判断调用 win.isWinAI 调用isAIMode 判断后调 aiplay()按钮事件开始、结束、悔棋MyFrame里也要反过来读取 gol.chessSize、gol.chessList重绘逻辑和监听器的内部状态绑定在一起眼花缭乱。重构后状态ChessUtils类监管棋盘状态 、 落子 、 悔棋 、胜负判断 、调用 AI 、绘制入口GoListener和MyFrame调用ChessUtils里的方法。管理设置。GoBangUI绘制UI界面调用监听器的设置方法优势调用方便调用者只用管传什么参数不用关心方法怎么实现。职责区分监听器只负责监听AI 只计算窗体只绘制工具类只管棋盘后续要该也能第一时间根据职责区块知道去哪改。整理结构的时候自己打代码的逻辑也更加清晰也方便自己发现当前的漏洞。代码实现ChessUtils类packageUI.Go.v20917;importjavax.swing.*;importjava.awt.*;publicclassChessUtils{//棋盘数据数组标记intX50,Y75,SIZE35,ROW15,COL15;intchessFlag;//棋子数组保存已经下过的棋子用于悔棋 重绘棋子Chess[]chessListnewChess[(ROW1)*(COL1)];intchessSize0;//棋盘下标变量用于保存已经下过的棋子下一颗棋子的位置//棋盘数组 二维数组用于判断输赢int[][]chessArrnewint[ROW1][COL1];Chesschess;intmode2;//切换人人对战 人机对战//开始对局publicvoidstart(Graphicsg){//数组清零chessListnewChess[(ROW1)*(COL1)];chessArrnewint[ROW1][COL1];chessSize0;chessFlag1;//重绘棋盘drawPad(g);}//结束对局publicvoidend(){//状态变量置为0chessFlag0;}publicbooleanwin(intr,intc){win winnewwin();if(win.isWin(chessArr,r,c)){Stringcolor;if(chessFlag1){color黑棋;}else{color白棋;}JOptionPane.showMessageDialog(null,color获胜了);returntrue;}returnfalse;}//绘制棋盘 单颗棋子 全部棋子publicvoiddrawPad(Graphicsg){//绘制填充底色的矩形g.setColor(Color.PINK);g.fillRect(X-SIZE/2,Y-SIZE/2,ROW*SIZESIZE,COL*SIZESIZE);//绘制棋盘格g.setColor(Color.BLACK);for(inti0;iROW;i){g.drawLine(X,Yi*SIZE,XROW*SIZE,Yi*SIZE);g.drawLine(Xi*SIZE,Y,Xi*SIZE,YCOL*SIZE);}}publicvoiddrawChess(Graphicsg,intr,intc){//黑白轮流if(chessFlag1){g.setColor(Color.black);chessFlag2;}elseif(chessFlag2){g.setColor(Color.white);chessFlag1;}//还原坐标intcxc*SIZEX-SIZE/2;intcyr*SIZEY-SIZE/2;g.fillOval(cx,cy,SIZE,SIZE);}publicvoiddrawAllChess(Graphicsg){//取出棋子数组中的数据还原坐标重绘for(inti0;ichessSize;i){intcxchess.c*SIZEX-SIZE/2;intcychess.r*SIZEY-SIZE/2;g.setColor(chessFlag1?Color.black:Color.white);g.fillOval(cx,cy,SIZE,SIZE);}}//落子 检查落子条件调用和绘制保存棋子数据publicbooleancheckPlay(intx,inty){//计算行列值intc(x-XSIZE/2)/SIZE;intr(y-YSIZE/2)/SIZE;//判断结束和开始游戏if(chessFlag0){JOptionPane.showMessageDialog(null,请先开始对局);returnfalse;}//判断重复落子//如果棋盘数组中已保存该位置的数据即重复落子/*for (int i 0; i chessSize; i) { if(chessList[i].ccchessList[i].rr){ JOptionPane.showMessageDialog(null,请勿重复落子); return false; } }*/if(chessArr[r][c]!0){JOptionPane.showMessageDialog(null,请勿重复落子);returnfalse;}//判断在有效范围内落子if(rROW||cCOL){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-XSIZE/2)/SIZE;intr(y-YSIZE/2)/SIZE;//保存数据saveData(r,c);//绘制棋子drawChess(g,r,c);//判断输赢if(win(r,c)){end();}//人机对局if(mode1){aiPlay(g);}}//权重一直叠加publicvoidaiPlay(Graphicsg){//ai选定落子地方AIainewAI();Chesschessai.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){chessFlagchessList[chessSize].flag;ChesschesschessList[chessSize];chessList[chessSize-1]null;chessSize--;chessArr[chess.r][chess.c]0;//刷新drawPad(g);drawAllChess(g);}else{JOptionPane.showMessageDialog(null,棋盘上没有棋子可悔);return;}}publicvoidsetMode(intmode){this.modemode;}}GoListenerpackageUI.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.chessUtilschessUtils;}publicvoidsetJRB(JRadioButtonjrb){this.jrbjrb;}publicvoidsetGraphics(Graphicsg){this.gg;}OverridepublicvoidactionPerformed(ActionEvente){Stringace.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){intxe.getX();intye.getY();chessUtils.playChess(g,x,y);}OverridepublicvoidmousePressed(MouseEvente){}OverridepublicvoidmouseReleased(MouseEvente){}OverridepublicvoidmouseEntered(MouseEvente){}OverridepublicvoidmouseExited(MouseEvente){}}MyFramepackageUI.Go.v20917;importjavax.swing.*;importjava.awt.*;publicclassMyFrameextendsJFrame{ChessUtilschessUtils;publicvoidsetChessUtils(ChessUtilschessUtils){this.chessUtilschessUtils;}// 窗体刷新时自动调用Override// 检查注解 检查这个方法是否是重写的publicvoidpaint(Graphicsg){super.paint(g);// 调用原本父类的刷新方法 绘制窗体本身 super 指代父类chessUtils.drawPad(g);chessUtils.drawAllChess(g);}}GoBangUIpackageUI.Go.v20917;importjavax.swing.*;importjava.awt.*;publicclassGoBangUI{ChessUtilschessUtilsnewChessUtils();GoListenergolnewGoListener();MyFramejfnewMyFrame();// 使用自己的窗体类 替换 JFramepublicvoidshowUI(){jf.setTitle(五子棋3.0);jf.setSize(800,700);jf.setLocation(400,200);jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.setLayout(null);String[]strs{开始对局,悔棋};FontfontnewFont(宋体,Font.BOLD,16);for(inti0;istrs.length;i){JButtonbtnnewJButton(strs[i]);btn.setBounds(660,150i*50,100,30);jf.add(btn);btn.setFont(font);btn.addActionListener(gol);btn.setBackground(Color.WHITE);}JRadioButtonjrbnewJRadioButton(人机对战);JRadioButtonjrb2newJRadioButton(人人对战);ButtonGroupbgnewButtonGroup();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);// 可视化 显示窗体// 获取窗体的图形渲染器Graphicsgjf.getGraphics();jf.addMouseListener(gol);gol.setJRB(jrb);gol.setGraphics(g);gol.setChessUtils(chessUtils);jf.setChessUtils(chessUtils);}}GameStartpackageUI.Go.v20917;publicclassGameStart{staticvoidmain(){GoBangUIgoBangUInewGoBangUI();goBangUI.showUI();}}
返回列表