回想起從前初學代碼的五子棋簡直寫的不像樣子。今天閒來無事就寫了個五子棋的小程序。前端
一來呢回憶一下好久之前寫代碼時的感受。java
二來呢順便幫下諸位有需求的學生,順利的Ctrl+C。git
五子棋的運行效果以下。算法
這個小程序是基於Java實現的。所以呢須要提早安裝JDK環境。(老油條忽略此條信息)數據庫
開發環境jdk1.8 + eclipse小程序
eclipse 目錄結構以下所示api
不管你作數據庫開發仍是作一些小程序,第一時間考慮的必須是需求+建模。把核心設計出來。數組
這次咱們用一個二維數組做爲棋盤,每條線交叉的地方設爲二維數組的值,並約定:數據結構
0=空eclipse
1=白棋
2=黑棋
而後對應的把下棋,悔棋,判斷輸贏(橫豎斜)和清盤的算法都實現出來。
具體展示以下:
悔棋時候咱們須要用一個棧來保存咱們以前下棋的信息:
/** * 在該位置下棋 1:white 2:black * @param x 橫座標 * @param y 縱座標 * @param var 棋子種類 * @return 1:white 贏 2:black贏 */ public int ChessIt(int x,int y,int var) { if(__CanInput(x,y)) { core[x][y] =var; Chess chess = new Chess(x,y); stack.push(chess); return checkVictory(x, y, var); } else return -1; } //悔棋 public boolean RetChess() { if(stack.isEmpty()) return false; Chess chess = stack.pop(); core[chess.x][chess.y]= 0; return true; }
判斷輸贏:
private int checkVictory(int x,int y,int var) { //橫向判斷 int trans = 0; for(int i=x-4;i<x+5;i++) { if(i<0||i>=this.x) continue; if(core[i][y]==var) { trans++; } else { trans=0; } if(trans==5) return var; } //縱向判斷 int longitudinal = 0; for(int i=y-4;i<y+5;i++) { if(i<0||i>=this.y) continue; if(core[x][i]==var) { longitudinal++; } else { longitudinal=0; } if(longitudinal==5) return var; } //從左上到右下 int leftUPToDown = 0; for(int i=x-4,j=y+4;i<x+5&&j>y-5;i++,j--) { if(i<0||i>=this.x||j<0||j>=this.y) continue; if(core[i][j]==var) { leftUPToDown++; }else { leftUPToDown=0; } if(leftUPToDown==5) return var; } //從左下到右上 int leftDownToUP = 0; for(int i=x+4,j=y+4;i>x-5&&j>y-5;i--,j--) { if(i<0||i>=this.x||j<0||j>=this.y) continue; if(core[i][j]==var) { leftDownToUP++; }else { leftDownToUP=0; } if(leftDownToUP==5) return var; } return 0; }
整體:Core.java 的代碼以下·:
package main; import java.util.Stack; /** * @author GodofOrange * 棋盤數據結構 */ public class Core { //棋盤大小 private int[][] core; private int x; private int y; //記錄下棋的類 class Chess{ int x; int y; public Chess(int x,int y) { this.x=x; this.y=y; } } //棧 Stack<Chess> stack; //構造方法 public Core(int x,int y) { stack = new Stack<>(); core = new int[x][y]; this.x=x; this.y=y; } //檢查該地是否有空位置 private boolean __CanInput(int x,int y) { if(core[x][y]==0) return true; else return false; } //判斷輸贏 private int checkVictory(int x,int y,int var) { //橫向判斷 int trans = 0; for(int i=x-4;i<x+5;i++) { if(i<0||i>=this.x) continue; if(core[i][y]==var) { trans++; } else { trans=0; } if(trans==5) return var; } //縱向判斷 int longitudinal = 0; for(int i=y-4;i<y+5;i++) { if(i<0||i>=this.y) continue; if(core[x][i]==var) { longitudinal++; } else { longitudinal=0; } if(longitudinal==5) return var; } //從左上到右下 int leftUPToDown = 0; for(int i=x-4,j=y+4;i<x+5&&j>y-5;i++,j--) { if(i<0||i>=this.x||j<0||j>=this.y) continue; if(core[i][j]==var) { leftUPToDown++; }else { leftUPToDown=0; } if(leftUPToDown==5) return var; } //從左下到右上 int leftDownToUP = 0; for(int i=x+4,j=y+4;i>x-5&&j>y-5;i--,j--) { if(i<0||i>=this.x||j<0||j>=this.y) continue; if(core[i][j]==var) { leftDownToUP++; }else { leftDownToUP=0; } if(leftDownToUP==5) return var; } return 0; } /** * 在該位置下棋 1:white 2:black * @param x 橫座標 * @param y 縱座標 * @param var 棋子種類 * @return 1:white 贏 2:black贏 */ public int ChessIt(int x,int y,int var) { if(__CanInput(x,y)) { core[x][y] =var; Chess chess = new Chess(x,y); stack.push(chess); return checkVictory(x, y, var); } else return -1; } //悔棋 public boolean RetChess() { if(stack.isEmpty()) return false; Chess chess = stack.pop(); core[chess.x][chess.y]= 0; return true; } //得到棋盤狀態 public int[][] getCore(){ return this.core; } //從新開始 public void Restart() { for(int i=0;i<this.x;i++) { for(int j=0;j<this.y;j++) { this.core[i][j]=0; } } this.stack.clear(); } }
在上一步咱們把一個五子棋的數據結構實現了以後,咱們下一步就須要用JavaSwing的知識來畫前端。
首先咱們定義一個類來繼承JFrame,從而包含JFrame的全部功能。
如下是JFrame經常使用的方法。
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//關閉JFrame時運行System.exit(0) jFrame.setLocationRelativeTo(null);//屏幕中央顯示 jFrame.setVisible(true);//可見
其次咱們須要單擊屏幕進行下棋,因此咱們須要符合鼠標單擊事件的接口。所以咱們去接上MouseListener的接口。
關於MouseListener接口的介紹以下:
鼠標監聽器MouseListener 監聽鼠標事件MouseEvent。 相應事件和處理方法 鼠標事件 處理方法 MOUSE_CLICKED MouseClicked (MouseEvent) 鼠標點擊(單或雙) MOUSE_PRESSED MousePressed (MouseEvent) 鼠標按下 MOUSE_RELEASED MouseReleased(MouseEvent) 鼠標鬆開 MOUSE_ENTERED MouseEntered (MouseEvent) 鼠標進入(某組件區域) MOUSE_EXITED MouseExited (MouseEvent) 鼠標離開(某組件區域) 鼠標事件MouseEvent經常使用方法 int getClickCount() 獲得點擊次數1 OR 2; int getX(), int getY() 獲得鼠標的(象素)位置。 鼠標監聽器MouseMotionListener 對於鼠標的移動和拖放,另外用鼠標運動監聽器MouseMotionListener。 由於許多程序不須要監聽鼠標運動,把二者分開可簡化程序。 相應事件和處理方法 鼠標事件 處理方法 MOUSE_MOVED MouseMoved (MouseEvent) 鼠標在移動 MOUSE_DRAGGED MouseDragged(MouseEvent) 鼠標被拖動
再而後咱們重寫JFrame裏的paint方法來畫畫。
具體體現:以下
其中橫線和豎線都是調用的Graphics中的drawLine方法。
畫圈圈用的是drawOval和fillOval分別是畫空心圓和畫實心圓。
@Override public void paint(Graphics g) { // TODO Auto-generated method stub super.paint(g); // 橫 for (int i = 0; i < 19; i++) g.drawLine(30, 30 + i * 30, 570, 30 + i * 30); // 豎線 for (int i = 0; i < 19; i++) g.drawLine(30 + i * 30, 60, 30 + i * 30, 570); int[][] board = core.getCore(); for (int i = 0; i < 19; i++) { for (int j = 0; j < 19; j++) { if (board[i][j] == 1) g.drawOval(20 + i * 30, 50 + j * 30, 20, 20); if(board[i][j]==2) g.fillOval(20+i*30, 50+j*30, 20, 20); } } g.drawRect(690,60, 50, 30); g.drawString("悔棋",700,80); g.drawRect(690,120,50, 30); g.drawString("開始",700,140); g.drawRect(690,180,50, 30); g.drawString("設置",700,200); g.drawString("Code by 禿桔子 QQ:1243137612", 600,260); }
再而後咱們須要肯定每次鼠標單擊的事件和信息。
具體實現以下:
@Override public void mousePressed(MouseEvent e) { // TODO Auto-generated method stub if (e.getX() < 570 && e.getY() < 570) { int a = core.ChessIt(_CgetX(e.getX()), (_CgetY(e.getY())), var); this.repaint(); if (a == 1) { JOptionPane.showMessageDialog(null,"白的贏了", "恭喜", JOptionPane.DEFAULT_OPTION);; } if(a==2) { JOptionPane.showMessageDialog(null,"黑的贏了", "恭喜", JOptionPane.DEFAULT_OPTION);; } if(a!=-1) { if(var==1) var=2; else if(var==2) var=1; } } else if(e.getX()>690&&e.getX()<760&&e.getY()>60&&e.getY()<90) { core.RetChess(); if(var==1) var=2; else if(var==2) var=1; this.repaint(); } if(e.getX()>690&&e.getX()<760&&e.getY()>120&&e.getY()<150) { core.Restart(); this.repaint(); } if(e.getX()>690&&e.getX()<760&&e.getY()>180&&e.getY()<210) { Object[] options = {"白先","黑先"}; int n = JOptionPane.showOptionDialog(null,"紅先仍是黑先?","遊戲設置",JOptionPane.YES_NO_OPTION,JOptionPane.QUESTION_MESSAGE, null,options,options[0]); if(n==0) this.var=1; if(n==1) this.var=2; this.core.Restart(); this.repaint(); } }
這裏面我調用了一個JOptionPane的組件。該組件的使用的方法通常以下
JOptionPane.showMessageDialog(null, "消息"); JOptionPane.showMessageDialog(null, "消息", "標題",JOptionPane.WARNING_MESSAGE); JOptionPane.showMessageDialog(null, "消息.", "標題",JOptionPane.ERROR_MESSAGE); JOptionPane.showMessageDialog(null, "消息.", "標題",JOptionPane.PLAIN_MESSAGE);
再而後每次單擊的時候進行repaint重繪將代碼重寫出來。
這些東西我也不記得,看api就行了。
下面是整體源碼:
package main; import java.awt.Graphics; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.JFrame; import javax.swing.JOptionPane; /** * * @author GodofOrange * @see 圖形界面 */ public class Windows extends JFrame implements MouseListener { public Core core; private static final long serialVersionUID = 1L; private int var = 1; public Windows(String title) { super(title); core = new Core(19, 19); this.setSize(800, 600); this.setLocation(800, 300); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); this.setResizable(false); this.addMouseListener(this); } @Override public void paint(Graphics g) { // TODO Auto-generated method stub super.paint(g); // 橫 for (int i = 0; i < 19; i++) g.drawLine(30, 30 + i * 30, 570, 30 + i * 30); // 豎線 for (int i = 0; i < 19; i++) g.drawLine(30 + i * 30, 60, 30 + i * 30, 570); int[][] board = core.getCore(); for (int i = 0; i < 19; i++) { for (int j = 0; j < 19; j++) { if (board[i][j] == 1) g.drawOval(20 + i * 30, 50 + j * 30, 20, 20); if(board[i][j]==2) g.fillOval(20+i*30, 50+j*30, 20, 20); } } g.drawRect(690,60, 50, 30); g.drawString("悔棋",700,80); g.drawRect(690,120,50, 30); g.drawString("開始",700,140); g.drawRect(690,180,50, 30); g.drawString("設置",700,200); g.drawString("Code by 禿桔子 QQ:1243137612", 600,260); } @Override public void mouseClicked(MouseEvent arg0) { } @Override public void mouseEntered(MouseEvent e) { // TODO Auto-generated method stub } @Override public void mouseExited(MouseEvent e) { // TODO Auto-generated method stub } @Override public void mousePressed(MouseEvent e) { // TODO Auto-generated method stub if (e.getX() < 570 && e.getY() < 570) { int a = core.ChessIt(_CgetX(e.getX()), (_CgetY(e.getY())), var); this.repaint(); if (a == 1) { JOptionPane.showMessageDialog(null,"白的贏了", "恭喜", JOptionPane.DEFAULT_OPTION);; } if(a==2) { JOptionPane.showMessageDialog(null,"黑的贏了", "恭喜", JOptionPane.DEFAULT_OPTION);; } if(a!=-1) { if(var==1) var=2; else if(var==2) var=1; } } else if(e.getX()>690&&e.getX()<760&&e.getY()>60&&e.getY()<90) { core.RetChess(); if(var==1) var=2; else if(var==2) var=1; this.repaint(); } if(e.getX()>690&&e.getX()<760&&e.getY()>120&&e.getY()<150) { core.Restart(); this.repaint(); } if(e.getX()>690&&e.getX()<760&&e.getY()>180&&e.getY()<210) { Object[] options = {"白先","黑先"}; int n = JOptionPane.showOptionDialog(null,"紅先仍是黑先?","遊戲設置",JOptionPane.YES_NO_OPTION,JOptionPane.QUESTION_MESSAGE, null,options,options[0]); if(n==0) this.var=1; if(n==1) this.var=2; this.core.Restart(); this.repaint(); } } @Override public void mouseReleased(MouseEvent e) { // TODO Auto-generated method stub } private int _CgetX(int x) { x -= 30; if (x % 15 <= 7) return x / 30; else return x / 30 + 1; } private int _CgetY(int y) { y -= 60; if (y % 15 <= 7) return y / 30; else return y / 30 + 1; } }
而後就是啓動函數了
這個函數放哪都行-.-。。。。。一看就懂吧?
package main; public class Main { /** 啓動函數 * @param args */ public static void main(String[] args) { new Windows("五子棋"); } }
其實五子棋的小程序對於初學者來講並不簡單。不適合作練手項目,不過當代碼量積累到必定程度,寫這個小程序簡直不要過輕鬆。完成起來分分鐘鍾。必定要打好數據結構的基礎並加大代碼量。