📄 blackwhite.java
字号:
package com;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.LineBorder;
public class BlackWhite extends JFrame
{
public BlackWhite()
{
setTitle ( "黑白棋" );
getContentPane().add ( new Chessboard() );
}
public static void main ( String[] args )
{
BlackWhite frame = new BlackWhite();
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.setSize (600,600);
//框架居中
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
int screenWidth = screenSize.width;
int screenHeight = screenSize.height;
int x = ( screenWidth - frame.getWidth() ) / 2;
int y = ( screenHeight - frame.getHeight() ) /2;
frame.setLocation ( x, y );
frame.setVisible ( true );
}
}
class Chessboard extends JPanel implements MouseListener
{
private int edge;
//chess[x][y]为O代表空,为B代表有黑子,为W代表有白子,为E代表有空子即当前可以在此处下子
private char[][] chess;
//mark记录电脑刚刚在哪里下了棋子
private int[] mark;
private Graphics g;
private char whoseTurn;
private int steps;
public Chessboard()
{
edge = 60;
chess = new char[8][8];
for ( int i = 0; i < 8; i++ )
for ( int j = 0; j < 8; j++ )
chess[i][j] = 'O';
mark = new int[2];
mark[0] = -1;
mark[1] = -1;
whoseTurn = 'B';
setBorder ( new LineBorder ( Color.black, 1 ) );
//在棋盘正中摆好四枚棋子,黑白各2枚,交叉放置
chess[3][3] = 'B';
chess[4][4] = 'B';
chess[3][4] = 'W';
chess[4][3] = 'W';
chess[3][5] = 'E';
chess[5][3] = 'E';
chess[4][2] = 'E';
chess[2][4] = 'E';
steps = 4;
addMouseListener ( this );
}
protected void paintComponent ( Graphics g )
{
super.paintComponent ( g );
g.setColor ( Color.cyan );
g.fillRect ( 0, 0, getWidth(), getHeight() );
//画出棋盘
g.setColor ( Color.black );
for ( int i = 1; i <= 8; i++ )
g.drawLine ( edge * i, 0, edge * i, edge * 8 );
for ( int j = 1; j <= 8; j++ )
g.drawLine ( 0, edge * j, edge * 8, edge * j );
//根据chess画出棋子以及空子
for ( int i = 0; i < 8; i++ )
for ( int j = 0; j < 8; j++ )
{
if ( chess[i][j] == 'B' )
{
g.setColor ( Color.black );
g.fillOval ( i*edge + 2, j*edge + 2, edge - 4, edge - 4 );
}
else if ( chess[i][j] == 'W' )
{
g.setColor ( Color.white );
g.fillOval ( i*edge + 2, j*edge + 2, edge - 4, edge - 4 );
}
else if ( chess[i][j] == 'E' )
{
g.setColor ( Color.red );
g.drawOval ( i*edge + 2, j*edge + 2, edge - 4, edge - 4 );
}
}
}
//在该格子处落子
public void drawTurn ( int x, int y )
{
g = getGraphics();
if ( whoseTurn == 'B' )
g.setColor ( Color.black );
else
g.setColor ( Color.white );
g.fillOval ( x*edge + 2, y*edge + 2, edge - 4, edge - 4 );
g.dispose();
chess[x][y] = whoseTurn;
}
//标记该格子刚刚落子,在棋子外画一个黄颜色圈
public void drawMark ( int x, int y )
{
g = getGraphics();
g.setColor ( Color.yellow );
g.drawOval ( x*edge + 1, y*edge + 1, edge - 2, edge - 2 );
g.dispose();
mark[0] = x;
mark[1] = y;
}
//清除该格子的标记
public void throwMark ()
{
int x = mark[0];
int y = mark[1];
g = getGraphics();
g.setColor ( Color.cyan );
g.drawOval ( x*edge + 1, y*edge + 1, edge - 2, edge - 2 );
g.dispose();
}
//恢复该格子为背景颜色
public void returnBackGround ( int x, int y )
{
g = getGraphics();
g.setColor ( Color.cyan );
g.fillRect ( x*edge + 1, y*edge + 1, edge - 2, edge - 2 );
g.dispose();
chess[x][y] = 'O';
}
//根据chess画出所有空子
public void drawAllEmpty ()
{
g = getGraphics ();
g.setColor ( Color.red );
for ( int i = 0; i < 8; i++ )
for ( int j = 0; j < 8; j++ )
if ( chess[i][j] == 'E' )
g.drawOval ( i*edge + 2, j*edge + 2, edge - 4, edge - 4 );
g.dispose ();
}
//查找当前可以下子的位置并记录,返回这种位置的个数
public int countAableToClick ()
{
int count = 0;
for ( int i = 0; i < 8; i++ )
for ( int j = 0; j < 8; j++ )
{
if ( chess[i][j] == 'O' ) //只有该格为空时才能继续判断是否ableToClick
if ( ableToClick ( i, j ) )
count++;
}
return count;
}
//判断该格子是否可以落子,如果可以就记录,已经判断过该格子一定为空
public boolean ableToClick ( int x, int y )
{
//eightDirection储存"上,右上,右,右下,下,左下,左,左上"八个方向
int[][] eightDirection = { {0, -1} , {1, -1} , {1, 0} , {1, 1} , {0, 1} , {-1, 1} , {-1, 0} , {-1, -1} };
for ( int i = 0; i < 8; i++ )
if ( ableThisDirection ( x, y, eightDirection[i] ) )
{
chess[x][y] = 'E';
return true;
}
return false;
}
//根据whoseTurn判断该格子在方向direction上是否可以吃子,已经判断过该格子一定为空
public boolean ableThisDirection ( int x, int y, int[] direction )
{
//nextX, nextY是x, y在方向direction上的下一个格子的坐标
int nextX = x + direction[0];
int nextY = y + direction[1];
//nextX, nextY超出棋盘
if ( nextX < 0 || nextX > 7 || nextY < 0 || nextY > 7 )
return false;
//坐标nextX, nextY的格子是对方棋子时才有可能为true,即落棋时要求必须放在与对方棋子相邻的空位上
else if ( chess[nextX][nextY] == whoseTurn || chess[nextX][nextY] == 'O' || chess[nextX][nextY] == 'E' )
return false;
//此时坐标nextX, nextY的格子是对方棋子,用enemy记录对方棋子
else
{
char enemy = (whoseTurn == 'B') ? 'W' : 'B';
while ( chess[nextX][nextY] == enemy )
{
nextX = nextX + direction[0];
nextY = nextY + direction[1];
//nextX, nextY超出棋盘
if ( nextX < 0 || nextX > 7 || nextY < 0 || nextY > 7 )
return false;
}
if ( chess[nextX][nextY] == whoseTurn )
return true;
else
return false;
}
}
//根据whoseTurn以及坐标重画棋盘,即完成“吃子”的功能
public void repaintChess ( int x, int y )
{
int[][] eightDirection = { {0, -1} , {1, -1} , {1, 0} , {1, 1} , {0, 1} , {-1, 1} , {-1, 0} , {-1, -1} };
for ( int i = 0; i < 8; i++ )
if ( ableThisDirection ( x, y, eightDirection[i] ) )
{
int nextX = x + eightDirection[i][0];
int nextY = y + eightDirection[i][1];
char enemy = (whoseTurn == 'B') ? 'W' : 'B';
while ( chess[nextX][nextY] == enemy )
{
drawTurn ( nextX, nextY );
nextX = nextX + eightDirection[i][0];
nextY = nextY + eightDirection[i][1];
}
}
}
//只在chess上吃子而不改变棋盘
public void eatAround ( int x, int y )
{
int[][] eightDirection = { {0, -1} , {1, -1} , {1, 0} , {1, 1} , {0, 1} , {-1, 1} , {-1, 0} , {-1, -1} };
for ( int i = 0; i < 8; i++ )
if ( ableThisDirection ( x, y, eightDirection[i] ) )
{
int nextX = x + eightDirection[i][0];
int nextY = y + eightDirection[i][1];
char enemy = (whoseTurn == 'B') ? 'W' : 'B';
while ( chess[nextX][nextY] == enemy )
{
chess[nextX][nextY] = whoseTurn;
nextX = nextX + eightDirection[i][0];
nextY = nextY + eightDirection[i][1];
}
}
}
//游戏结束,判断胜利者
public void gameOver()
{
//统计黑白棋数
int numberBlack = 0;
int numberWhite = 0;
for ( int i = 0; i < 8; i++ )
for ( int j = 0; j < 8; j++ )
{
if ( chess[i][j] == 'B' )
numberBlack++;
else if ( chess[i][j] == 'W' )
numberWhite++;
}
if ( numberBlack == numberWhite )
{
JOptionPane.showMessageDialog(null,"黑棋数:" + numberBlack + ", 白棋数:" + numberWhite + "\n平局",
"提示信息",JOptionPane.INFORMATION_MESSAGE);
}
else if ( numberBlack > numberWhite )
{
JOptionPane.showMessageDialog(null,"黑棋数:" + numberBlack + ", 白棋数:" + numberWhite + "\n黑棋胜",
"提示信息",JOptionPane.INFORMATION_MESSAGE);
}
else
{
JOptionPane.showMessageDialog(null,"黑棋数:" + numberBlack + ", 白棋数:" + numberWhite + "\n白棋胜",
"提示信息",JOptionPane.INFORMATION_MESSAGE);
}
JOptionPane.showMessageDialog(null,"玩的开心吗?是否再来一局吧!",
"提示信息",JOptionPane.INFORMATION_MESSAGE);
//清空棋盘,重新开局
for ( int i = 0; i < 8; i++ )
for ( int j = 0; j < 8; j++ )
chess[i][j] = 'O';
whoseTurn = 'B';
chess[3][3] = 'B';
chess[4][4] = 'B';
chess[3][4] = 'W';
chess[4][3] = 'W';
chess[3][5] = 'E';
chess[5][3] = 'E';
chess[4][2] = 'E';
chess[2][4] = 'E';
steps = 4;
repaint();
}
//电脑下一步棋(白字)
public void computerPlay ()
{
steps++;
int[] placeToClick = new int[2];
placeToClick = findClickPlace ();
//恢复所有空子为背景颜色
for ( int i = 0; i < 8; i++ )
for ( int j = 0; j < 8; j++ )
if ( chess[i][j] == 'E' )
returnBackGround ( i, j );
//在该位置落子
drawTurn ( placeToClick[0], placeToClick[1] );
//标记该位置
drawMark ( placeToClick[0], placeToClick[1] );
//吃子
repaintChess ( placeToClick[0], placeToClick[1] );
if ( steps == 64 )
{
JOptionPane.showMessageDialog(null,"棋盘已满,游戏结束",
"提示信息",JOptionPane.INFORMATION_MESSAGE);
gameOver();
}
else
{
//更改whoseTurn
whoseTurn = 'B';
//查找当前可以下子的位置
int numberAbleToClick = countAableToClick ();
//如果黑棋有可以下的位置,则画出可下的位置并等待mouseClick事件,如果黑棋无处可下,则电脑连续落子
if ( numberAbleToClick != 0 )
drawAllEmpty ();
else
{
JOptionPane.showMessageDialog(null,"黑棋无子可下,白棋可连续落子",
"提示信息",JOptionPane.INFORMATION_MESSAGE);
//更改whoseTurn
whoseTurn = 'W';
//查找当前可以下子的位置
numberAbleToClick = countAableToClick ();
//如果白棋有棋可下,则递归调用computerPlay
if ( numberAbleToClick != 0 )
computerPlay ();
else //白棋也无子可下
{
JOptionPane.showMessageDialog(null,"双方均无子可下,游戏结束",
"提示信息",JOptionPane.INFORMATION_MESSAGE);
gameOver();
}
}
}
}
//根据某种智能方法找到应该落子的位置,这里让敌人下一步可以走的棋的位置的数目尽量少
public int[] findClickPlace ()
{
//tempPlace用来存放找到的坐标
int[] tempPlace = new int[2];
//tempChess储存当前chess状态,便于随时恢复chess
char[][] tempChess = new char[8][8];
for ( int i = 0; i < 8; i++ )
for ( int j = 0; j < 8; j++ )
tempChess[i][j] = chess[i][j];
//leastNumberToClick记录下一步走tempPlace的话,留给对手下棋位置的最小数目
int leastNumberToClick = 100;
for ( int row = 0; row < 8; row++ )
for ( int col = 0; col < 8; col++ )
{
if ( chess[row][col] == 'E' )
{
//在该位置落子
chess[row][col] = 'W';
for ( int m = 0; m < 8; m++ )
for ( int n = 0; n < 8; n++ )
if ( chess[m][n] == 'E' )
chess[m][n] = 'O';
//吃子
eatAround ( row, col );
//更改whoseTurn
whoseTurn = 'B';
//查找敌人可以下子的位置的数目
int numberAbleToClick = countAableToClick ();
//更新leastNumberToClick
if ( leastNumberToClick > numberAbleToClick )
{
leastNumberToClick = numberAbleToClick;
tempPlace[0] = row;
tempPlace[1] = col;
}
//恢复whoseTurn
whoseTurn = 'W';
//恢复chess
for ( int m = 0; m < 8; m++ )
for ( int n = 0; n < 8; n++ )
chess[m][n] = tempChess[m][n];
}
}
return tempPlace;
}
//人下一步棋(黑子)
public void humanPlay ( int x, int y )
{
steps++;
//恢复所有空子为背景颜色
for ( int i = 0; i < 8; i++ )
for ( int j = 0; j < 8; j++ )
if ( chess[i][j] == 'E' )
returnBackGround ( i, j );
//清除之前的标记
throwMark ();
//在该位置落子
drawTurn ( x, y );
//吃子
repaintChess ( x, y );
if ( steps == 64 )
{
JOptionPane.showMessageDialog(null,"棋盘已满,游戏结束",
"提示信息",JOptionPane.INFORMATION_MESSAGE);
gameOver();
}
else
{
//更改whoseTurn
whoseTurn = 'W';
//查找当前可以下子的位置
int numberAbleToClick = countAableToClick ();
//如果电脑有可以下的位置,则让电脑下,如果电脑无处可下,则黑子连续落子
if ( numberAbleToClick == 0 )
{
JOptionPane.showMessageDialog(null,"白棋无子可下,黑棋可连续落子",
"提示信息",JOptionPane.INFORMATION_MESSAGE);
//更改whoseTurn
whoseTurn = 'B';
//查找当前可以下子的位置
numberAbleToClick = countAableToClick ();
//如果黑棋有棋可下,则画出可下的位置并等待下一个mouseClick事件
if ( numberAbleToClick != 0 )
drawAllEmpty ();
else //黑棋也无子可下
{
JOptionPane.showMessageDialog(null,"双方均无子可下,游戏结束",
"提示信息",JOptionPane.INFORMATION_MESSAGE);
gameOver();
}
}
}
}
public void mouseClicked ( MouseEvent e )
{
//获得鼠标位置
int xco = (int)e.getX() / edge;
int yco = (int)e.getY() / edge;
if ( chess[xco][yco] == 'E' ) //该位置可以落子
{
humanPlay ( xco, yco );
if ( whoseTurn == 'W' )
computerPlay ();
}
}
public void mousePressed ( MouseEvent e ) {}
public void mouseReleased ( MouseEvent e ) {}
public void mouseEntered ( MouseEvent e ) {}
public void mouseExited ( MouseEvent e ) {}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -