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 + -
显示快捷键?