board.java
来自「这是一个八皇后问题的扩展」· Java 代码 · 共 464 行
JAVA
464 行
//棋盘
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.JOptionPane;
import java.lang.NumberFormatException;
import java.awt.event.*;
import javax.swing.event.*;
class Board extends JPanel
{
public Board()
{
IsQueue=new int[N];//存储每行中放置皇后的列数
AllSolution=new int[1000][N];//存储所以解中皇后的放置位置
for(int i=0;i<N;i++)
IsQueue[i]=-1;//初始化,所有位置都不放置皇后
BoardPanel=new JPanel();
BoardPanel.setLayout(new GridLayout(N, N, 0, 0));//显示棋盘部分的布局方式:N行N列,各按钮紧凑排列
buttons=new QueuesButton[N*N];//创建N*N个按钮
//把按钮添加到棋盘上
for (int i = 0; i < N; i++) {
for (int j = 0; j< N; j++) {
int pos = toPosition(i, j);
buttons[pos] = new QueuesButton();
buttons[pos].setPiece(1);
BoardPanel.add(buttons[pos]);
}
}
setLayout(new BorderLayout());
ControlPanel controlPane=new ControlPanel();
add(controlPane,BorderLayout.EAST);//添加控制面板到主界面的东方,即右边
add(BoardPanel,BorderLayout.CENTER);//添加棋盘到主界面的中心。
getSolution();//求N后问题的所有解
}
public void changeBoard()//改变N的大小后重绘棋盘
{
this.remove(BoardPanel);//删除原先的棋盘
BoardPanel=new JPanel();//创建一个新的棋盘
BoardPanel.setLayout(new GridLayout(N, N, 0, 0));
buttons=new QueuesButton[N*N];//创建新按钮
//添加按钮
for (int i = 0; i < N; i++) {
for (int j = 0; j< N; j++) {
int pos = toPosition(i, j);
buttons[pos] = new QueuesButton();
buttons[pos].setPiece(1);
BoardPanel.add(buttons[pos]);
}
}
this.add(BoardPanel,BorderLayout.CENTER);//添加棋盘到主界面上
this.updateUI();//更新界面
//BoardPanel.repaint();
this.repaint();//重绘界面
IsQueue=new int[N];//重新为IsQueue分配空间
AllSolution=new int[1000][N];//重新为AllSolution分配空间
Pos=0;//定义当前解为第0个解
end=0;//共有0个解
getSolution();//求所有解
}
public int getN()
{
return this.N;//获得N的大小
}
public void setN(int _N)
{
this.N=_N;//设置N的大小
}
public int toPosition(int row,int col) {
return row * N + col;//确定按钮的位置
}
public void DynamicShow()//动态演示第一个解的求解过程
{
int i,j;
//初始化界面,把界面上所有的皇后都清空
for(i=0;i<N;i++)
for(j=0;j<N;j++)
{
int pos=toPosition(i,j);
buttons[pos].setPiece(1);
}
//动态显示部分
try{
int k=0;//第0行
IsQueue[k]=-1;//没有放置皇后
while(k>-1)
{
IsQueue[k]=IsQueue[k]+1;
while(IsQueue[k]<N&&(!place(IsQueue,k)))//不能放置皇后,并且同行中所有位置还没有试完
IsQueue[k]=IsQueue[k]+1;//试下一个位置
if(IsQueue[k]<N){//第k行可以放置皇后
if(k==N-1)//求得第一个解
{
int pos=toPosition(k, IsQueue[k]);//得到最后一个皇后的放置位置
buttons[pos].setPiece(0);//把按钮设为皇后的图标
this.updateUI();//更新
this.paint(this.getGraphics()); //重绘
break;
}
else{//不是最后一个皇后
int pos=toPosition(k, IsQueue[k]);
buttons[pos].setPiece(0);
this.updateUI();
this.paint(this.getGraphics());
Thread.sleep(1000);
k=k+1;//继续下一行的测试
IsQueue[k]=-1;
}
}
else{//不能求得解,回溯,在前一行重新寻找放置皇后的位置
IsQueue[k]=-1;k=k-1;//当前行置为没有皇后
int pos=toPosition(k, IsQueue[k]);
buttons[pos].setPiece(1);//把前一行有皇后的位置置为没有皇后
this.updateUI();
this.paint(this.getGraphics());
Thread.sleep(1000);//延时
}
}
}catch(InterruptedException e){}
}
//测试当前位置是否可以放置皇后
public boolean place(int x[],int k)
{
int i;
for(i=0;i<k;i++)
{
if(x[i]==x[k]||Math.abs(x[i]-x[k])==Math.abs(i-k))//测试条件
return false;
}
return true;
}
public void getSolution()//求得所有解
{
int count=0;//记录解的个数
int i=0,k=0;
IsQueue[k]=-1;
//求解过程和动态演示类似,只是在求得第一个解时没有跳出循环。
while(k>-1)
{
IsQueue[k]=IsQueue[k]+1;
while(IsQueue[k]<N&&(!place(IsQueue,k)))
IsQueue[k]=IsQueue[k]+1;
if(IsQueue[k]<N){
if(k==N-1)
{
for(int j=0;j<N;j++)
{
AllSolution[count][j]=IsQueue[j];//把第count+1个解放置到AllSolution中
}
count++;//解的个数加1
if(count==1000)//只求前1000个解,当超过1000时,跳出循环
break;
IsQueue[k]=-1;k=k-1;//回溯,继续测试求下一个解
}
else{
k=k+1;//不是最后一个皇后,继续在下一行找可以放置的位置
IsQueue[k]=-1;
}
}
else{
IsQueue[k]=-1;k=k-1;//不能求得解,回溯
}
}
if(count==0)
Pos=-1;
end=count-1;//最后一个解的下标
}
public void N_Queues(int k)//把第k+1个解显示到棋盘上
{
int i,j;
//清空棋盘上所有的皇后
for(i=0;i<N;i++)
for(j=0;j<N;j++)
{
int pos=toPosition(i,j);
buttons[pos].setPiece(1);
}
//在第k+1个解的放置皇后的位置上放置皇后图标
for(i=0;i<N;i++)
{int pos=toPosition(i,AllSolution[k][i]);
buttons[pos].setPiece(0);
}
this.updateUI();//更新界面
this.paint(this.getGraphics());
}
public void Begin()//显示第一个解
{
Pos=0;
N_Queues(Pos);
}
public void End()//显示最后一个解
{
Pos=end;
N_Queues(Pos);
}
public void Prior()//显示前一个解
{
if(Pos==0)//当为第一个解时
JOptionPane.showMessageDialog(null,"已经是第一个解!");
else
{
Pos--;//当前位置减1
N_Queues(Pos);
}
}
public void Next()//显示下一个解
{
if(Pos==end)//当为最后一个解或第1000个解时
{
String S;
if(Pos==999)
S="第一千个";
else
S="最后一个";
JOptionPane.showMessageDialog(null,"已经是"+S+"解!");
}
else
{
Pos++;//当前位置加1
N_Queues(Pos);
}
}
public int getPos()
{
return Pos;
}
//私有类,控制面板部分
private class ControlPanel extends JPanel
implements DocumentListener , ActionListener
{
public ControlPanel()
{
setLayout(new BorderLayout());
ControlPane=new JPanel();
setSize(80,400);//设置大小
ControlPane.setLayout(new GridLayout(13,1,0,10));//13行1列
//定义标签,提示输入N的值
JLabel InputN=new JLabel("输入N值:");
ControlPane.add(InputN,"Center");
//文本框用于输入N的值
N= new JTextField("8", 4);
ControlPane.add(N,"Center");
N.getDocument().addDocumentListener(this);
//确定按钮
comfirmButton = new JButton("确定");
ControlPane.add(comfirmButton);
comfirmButton.addActionListener(this);
//动态演示选择区
JLabel DynamicShow=new JLabel("动态演示:");
ControlPane.add(DynamicShow);
//动态演示按钮
DynamicButton = new JButton("显示");
ControlPane.add(DynamicButton);
DynamicButton.addActionListener(this);
//取消动态演示
DynamicCancel=new JButton("停止");
ControlPane.add(DynamicCancel);
DynamicCancel.addActionListener(this);
//静态演示选择区
JLabel StaticShow=new JLabel("静态演示:");
ControlPane.add(StaticShow);
Anum=new JLabel("共__个解");
ControlPane.add(Anum);
Solution=new JLabel("第__个解");
ControlPane.add(Solution);
//第一个解
Begin=new JButton("Begin");
ControlPane.add(Begin);
Begin.addActionListener(this);
//前一个解
Prior=new JButton("<<Prior");
ControlPane.add(Prior);
Prior.addActionListener(this);
//后一个解
Next=new JButton("Next>>");
ControlPane.add(Next);
Next.addActionListener(this);
//最后一个解
End=new JButton("End");
ControlPane.add(End);
End.addActionListener(this);
add(ControlPane,BorderLayout.EAST);
}
public void insertUpdate(DocumentEvent e)
{
}
public void removeUpdate(DocumentEvent e)
{
}
public void changedUpdate(DocumentEvent e)
{
}
//获得用户输入的N值
public int getN()
{
int aN;
try{
aN= Integer.parseInt(N.getText().trim());
}catch(NumberFormatException e) //捕捉数字异常
{
JOptionPane.showMessageDialog(null,"请输入数字!");
return -1;
}
if(aN<1||aN>20)
{
JOptionPane.showMessageDialog(null,"请输入1到20之间的整数!");
return -1;
}
return aN;
}
public void actionPerformed(ActionEvent evt)
{
Object source = evt.getSource();
if (source == comfirmButton)//按下确定按钮时
{
int aN=getN();
if(aN!=-1)
{
Board.this.setN(aN);
Board.this.changeBoard();
}
Anum.setText("共__个解");
Solution.setText("第__个解");
repaint();
}
if(source==DynamicButton)//按下动态演示按钮
{
Board.this.DynamicShow();
}
if(source==Begin)//Begin按钮
{
if(Board.this.end==-1)
JOptionPane.showMessageDialog(null,"无解!");
else
Board.this.Begin();
changePane();
}
if(source==End)//End 按钮
{
if(Board.this.end==-1)
JOptionPane.showMessageDialog(null,"无解!");
else
Board.this.End();
changePane();
}
if(source==Prior) //Prior按钮
{
if(Board.this.end==-1)
JOptionPane.showMessageDialog(null,"无解!");
else
Board.this.Prior();
changePane();
}
if(source==Next) //Next按钮
{
if(Board.this.end==-1)
JOptionPane.showMessageDialog(null,"无解!");
else
Board.this.Next();
changePane();
}
}
public void changePane()
{
// int p=Board.this.getPos()
position=Integer.toString((Board.this.getPos()+1));
// Solution=new JLabel("第"+(Pos+1)+"个解");
System.out.print(position+"\t");
System.out.print(Board.this.end);
Anum.setText("共"+(Board.this.end+1)+"个解");
Solution.setText("第"+position+"个解");
// updateUI();//更新界面
//paint(this.getGraphics());
repaint();
}
private JTextField N;
private JButton comfirmButton;
private JButton DynamicButton;
private JButton DynamicCancel;
private JPanel ControlPane;
private JButton Begin;
private JButton End;
private JButton Next;
private JButton Prior;
private JLabel Solution;
private JLabel Anum;
private String position="0";
}
private QueuesButton buttons[];
private int N=8;
private JPanel BoardPanel;
private int IsQueue[];
private int AllSolution[][];
private int Pos=0;
private int end=0;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?