五子棋应该是所有棋类游戏中规则最简单的一种了,对应着我们写代码,也是最简单,我们今天就来根据学过的知识,写一个五子棋玩一玩。
五子棋首先要画出界面,界面其实并不麻烦,但是在画出界面之前,肯定首先需要计算一下,不然脑子里面会完全是乱的.
首先,我们约定整个棋盘是 15 * 15 的大小
其次,棋盘格子和格子之间肯定是有距离的,我们约定,每个格子之间的距离是 35
当然为了让棋盘稍微美观一点,我们可以为棋盘加上一点背景色.为了让大家看到的更加直观,整个棋盘的布局,如下图:
1.整个Swing界面的大小
2.棋盘的大小
这里要稍微注意的一点是,这个棋盘是 15 * 15 的大小,但是棋盘的格子其实只有14个,所以有线框的部分实际只有 490 * 490 的大小
3.棋盘和Swing边框周围的计算
所以,根据上面的图像,先来编写代码
根据面向对象的思想,将代码划分了3个类去编写: BoardPanel类专门负责画出棋盘 Board类负责画出旗子以及判定胜负 GameFrame类画出主面板
首先来看画出棋盘的类BoardPanel.java,既然专门负责画出棋盘,所以让这个类直接去继承Panel类,然后paint出相应的图像就ok
BoardPanel.java
1 2345678910111213141516171819202122
package com.fivechess;import javax.swing.*;import java.awt.*;public class BoardPanel extends JPanel{ @Override public void paint(Graphics g) { g.setColor(new Color(165,185,75)); g.fillRect(35,35,525,525); g.setColor(Color.BLACK); //绘制棋盘 for (int i=0; i<15; i++){ g.drawLine(50, 50 + i*35, 540, 50 + i*35); g.drawLine(50 + i*35, 50, 50 + i*35, 540); } //绘制天元(中间的圆点) g.fillOval(290,290,10,10); }}
可以将这个放入到棋盘当如到Swing界面上,编写代码创建GameFrame.java
GameFrame.java
123456789101112131415161718192021
public class GameFrame extends JFrame{ private JPanel boardPanel; public GameFrame(){ this.setTitle("五子棋"); this.setSize(700, 600); this.setResizable(false); this.setLocationRelativeTo(null); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setLayout(null); boardPanel = new BoardPanel(); boardPanel.setBounds(0, 0, 600,600); this.add(boardPanel); } public static void main(String[] args) { GameFrame tf = new GameFrame(); tf.setVisible(true); }}
这样执行代码,一个棋盘就出来了,接下来实现点击出现棋子,而棋子我们需要单独的类来生成,编写Board代码,并将之前的代码稍微修改
Board.java
123456789101112131415161718192021222324252627282930313233343536373839
public class Board { private int [][] board = new int[15][15]; public void draw(Graphics g){ for (int i=0; i<board.length; i++){ for (int j=0; j<board[i].length; j++){ if(board[i][j] != 0){ //如果不是空格 if(board[i][j] == 1){ //如果是黑子 g.setColor(Color.BLACK); }else{ //白子 g.setColor(Color.white); } g.fillOval(35*(j+1),35*(i+1),30,30); //如果是白子,为了好看,给白子加上边框 if(board[i][j] == 2){ g.setColor(Color.BLACK); g.drawOval(35*(j+1),35*(i+1),30,30); } } } } } /** * 向棋盘中放置棋子 * @param row 行 * @param col 列 * @param isBlack 黑子还是白子 * @return 落子成功true,失败false(该位置已经有子) */ public boolean addPiece(int row, int col, boolean isBlack){ if(board[row][col] == 0){ //没有棋子的地方才能落子 board[row][col] = isBlack?1:2; return true; } return false; }}
修改BoardPanel.java文件,加入棋子的绘制
123456789101112131415161718192021222324252627282930
package com.fivechess;import javax.swing.*;import java.awt.*;public class BoardPanel extends JPanel{ private Board b = null; public BoardPanel(Board b) { this.b = b; } @Override public void paint(Graphics g) { g.setColor(new Color(165,185,75)); g.fillRect(35,35,525,525); g.setColor(Color.BLACK); //绘制棋盘 for (int i=0; i<15; i++){ g.drawLine(50, 50 + i*35, 540, 50 + i*35); g.drawLine(50 + i*35, 50, 50 + i*35, 540); } //绘制天元(中间的圆点) g.fillOval(290,290,10,10); //绘制棋子 b.draw(g); }}
修改GameFrame.java代码,加入鼠标点击事件和相应的判断
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
package com.fivechess; import javax.swing.*;import java.awt.event.MouseAdapter;import java.awt.event.MouseEvent;public class GameFrame extends JFrame{ private boolean isBlack = true; //是否黑子 true黑子 false白子 private JPanel boardPanel; private Board b = new Board(); public GameFrame(){ this.setTitle("五子棋"); this.setSize(700, 600); this.setResizable(false); this.setLocationRelativeTo(null); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setLayout(null); boardPanel = new BoardPanel(b); boardPanel.setBounds(0, 0, 600,600); //在boardPanel下棋需要执行点击事件 boardPanel.addMouseListener(new MouseHandle()); this.add(boardPanel); } private class MouseHandle extends MouseAdapter { @Override public void mousePressed(MouseEvent e) { int x = e.getX(); int y = e.getY(); //点击事件必须在棋盘内 if( x >= 50 && x<= 540 && y>=50 && y<=540) { //通过鼠标坐标计算出点击棋盘的行或者列 int row = Math.round((y - 50) / 35F); int col = Math.round((x - 50) / 35F); if (b.addPiece(row, col, isBlack)) { //刷新页面 repaint(); //黑白子轮流下棋,每次进行替换 isBlack = !isBlack; } } } } public static void main(String[] args) { GameFrame tf = new GameFrame(); tf.setVisible(true); }}
这样,我们就可以再棋盘上落子了,只是还不能判断输赢而已
所以接下来,我们在棋子类中加入判断输赢的代码
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
package com.fivechess;import java.awt.*;public class Board { private int [][] board = new int[15][15]; /** * 绘制棋盘 * @param g */ public void draw(Graphics g){ for (int i=0; i<board.length; i++){ for (int j=0; j<board[i].length; j++){ if(board[i][j] != 0){ //如果不是空格 if(board[i][j] == 1){ //如果是黑子 g.setColor(Color.BLACK); }else{ //白子 g.setColor(Color.white); } g.fillOval(35*(j+1),35*(i+1),30,30); //如果是白子,为了好看,给白子加上边框 if(board[i][j] == 2){ g.setColor(Color.BLACK); g.drawOval(35*(j+1),35*(i+1),30,30); } } } } } /** * 向棋盘中放置棋子 * @param row 行 * @param col 列 * @param isBlack 黑子还是白子 * @return 落子成功true,失败false(该位置已经有子) */ public boolean addPiece(int row, int col, boolean isBlack){ if(board[row][col] == 0){ //没有棋子的地方才能落子 board[row][col] = isBlack?1:2; return true; } return false; } public boolean isWin(int row, int col, boolean isBlack){ return checkH(row,col,isBlack) || checkV(row, col, isBlack) || checkX1(row, col, isBlack) || checkX2(row, col, isBlack); } /** * 从右斜线判断是否连成5颗 * @param row 行 * @param col 列 * @param isBlack 黑子还是白子 * @return 是否获胜 */ public boolean checkX2(int row, int col, boolean isBlack){ int count = 1; int currentRow = row; int currentCol = col; int v = isBlack ? 1 : 2; //从左下到右上判断 while(currentRow > 0 && currentCol < 14 && board[--currentRow][++currentCol] == v){ count ++; } currentRow = row; currentCol = col; //从右上到左下判断 while(currentRow < 14 && currentCol > 0 && board[++currentRow][--currentCol] == v){ count ++; } return count >= 5; } /** * 从左斜线判断是否连成5颗 * @param row 行 * @param col 列 * @param isBlack 黑子白子 * @return 是否获胜 */ public boolean checkX1(int row, int col, boolean isBlack){ int count = 1; int currentRow = row; int currentCol = col; int v = isBlack ? 1 : 2; //从右下到左上判断 while(currentRow > 0 && currentCol > 0 && board[--currentRow][--currentCol] == v){ count ++; } currentRow = row; currentCol = col; //从左上到右下判断 while(currentRow < 14 && currentCol < 14 && board[++currentRow][++currentCol] == v){ count ++; } return count >= 5; } /** * 竖线判断是否连成5颗 * @param row * @param col * @param isBlack * @return */ public boolean checkV(int row, int col, boolean isBlack){ int count = 1; int currentRow = row; int currentCol = col; int v = isBlack ? 1 : 2; //从上到下判断 while(currentRow < 14 && board[++currentRow][currentCol] == v){ count ++; } currentRow = row; currentCol = col; //从下到上判断 while(currentRow > 0 && board[--currentRow][currentCol] == v){ count ++; } return count >= 5; } /** * 横向判断是否连成5颗 * @param row * @param col * @param isBlack * @return */ public boolean checkH(int row, int col, boolean isBlack){ int count = 1; int currentRow = row; int currentCol = col; int v = isBlack ? 1 : 2; //从左到右判断 while(currentCol < 14 && board[currentRow][++currentCol] == v){ count ++; } currentRow = row; currentCol = col; //从右到左判断 while(currentCol > 0 && board[currentRow][--currentCol] == v){ count ++; } return count >= 5; } public void clearBoard(){ for (int i = 0; i < board.length; i++) { for (int j = 0; j < board[i].length; j++) { board[i][j] = 0; } } }}
这里修改Board.java代码其实主要就是加上了输赢判断,要判断输赢,就是判断横,输,左斜,右斜是否连续是一个颜色并且连成5个
最后在GameFrame.java中加入相应的代码和点击开始游戏的按钮
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
package com.fivechess;import javax.swing.*;import java.awt.event.ActionEvent;import java.awt.event.MouseAdapter;import java.awt.event.MouseEvent;public class GameFrame extends JFrame { private boolean isBlack = true; //是否黑子 private Board b = new Board(); //棋盘对象 private boolean isWin = false; //是否胜利 private boolean isStart = false; //是否开始 private class MouseHandle extends MouseAdapter{ @Override public void mousePressed(MouseEvent e) { if(isStart && !isWin){ int x = e.getX(); int y = e.getY(); //点击事件必须在棋盘内 if( x >= 50 && x<= 540 && y>=50 && y<=540){ //通过鼠标坐标计算出点击棋盘的行或者列 int row = Math.round((y - 50) / 35F); int col = Math.round((x - 50) / 35F); if(b.addPiece(row,col,isBlack)){ repaint(); isWin = b.isWin(row,col,isBlack); if(!isWin){ isBlack = !isBlack; }else{ JOptionPane.showMessageDialog(null, isBlack ? "黑子胜" : "白子胜"); btnStartGame.setEnabled(true); } } } } } } private JPanel boardPanel; private JButton btnStartGame; private JLabel lblStatus; public GameFrame() { this.setTitle("五子棋"); this.setSize(700, 600); this.setResizable(false); this.setLocationRelativeTo(null); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setLayout(null); //测试显示每次鼠标点击的坐标 lblStatus = new JLabel("~~~~"); lblStatus.setBounds(580, 200, 150,50); boardPanel = new BoardPanel(b); boardPanel.setBounds(0, 0, 600,600); //在boardPanel下棋需要执行点击事件 boardPanel.addMouseListener(new MouseHandle()); /**测试坐标位置*/ boardPanel.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e) { lblStatus.setText("坐标 x:" + e.getX() + ",y:"+e.getY()); } }); btnStartGame = new JButton("开始游戏"); btnStartGame.setBounds(580,100,100,35); //点击开始游戏,初始化变量 btnStartGame.addActionListener(new AbstractAction() { public void actionPerformed(ActionEvent e) { isStart = true; //开始游戏 isWin = false; //开始游戏之后还没有输赢 btnStartGame.setEnabled(false); //点击之后按钮不可用 b.clearBoard(); //清空界面,实际就是将数组所有值设置为0 repaint(); //刷新页面 } }); this.add(lblStatus); this.add(boardPanel); this.add(btnStartGame); } public static void main(String[] args) { GameFrame gf = new GameFrame(); gf.setVisible(true); }}