8皇后问题 OSGI版本实现

本文介绍了一种使用OSGi方式整合8皇后问题的方法,包括棋盘、皇后、异常处理、打印接口等模块,提供了控制台和Swing两种显示方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

8皇后已经是一个很古老的问题了,今天我用OSGI方式整合一下8皇后。

工具:eclipse

 

第一步:分析需求,每个人的思想都不一样。对OSGI的理解也不一样,我理解为把8皇后问题分成8个模块

1、棋盘

2、皇后

3、自定义异常

4、打印接口

5、JAVA控制台方式打印

6、Swing方式打印

7、显示工厂(根据需求不同生成5或6方式对象)

8、启动

 

 

 

 

以下是我建立的项目

 

 

 

 

棋盘类:

package chessboard;

import java.util.HashSet;
import java.util.Set;


import chessman.Chessman;
import exception.ChessmanOutIndexException;


//棋盘
public class Chessboard {

	// 棋盘最大数量
	private final int gridMaxNum;

	// 棋子
	private Set<Chessman> chessmans;

	// 初始化
	public Chessboard(int gridMaxNum) {
		this.gridMaxNum = gridMaxNum;
		chessmans = new HashSet<Chessman>();
	}

	public int getGridMaxNum() {
		return gridMaxNum;
	}

	// 给棋盘添加棋子
	public void addChessman(Chessman chessman) {
		if (chessmans.size() >= this.getGridMaxNum()) {
			throw new ChessmanOutIndexException("棋子个数已经超出棋盘当前最大值:"
					+ chessmans.size() + "/" + this.getGridMaxNum());
		}
		chessmans.add(chessman);
	}

	// 移除棋盘中的棋子
	public void removeChessman(Chessman chessman) {
		if (chessmans.isEmpty()) {
			throw new ChessmanOutIndexException("期盘中已经没有棋子,不能在移除棋子:"
					+ chessmans.size() + "/" + this.getGridMaxNum());
		}
		chessmans.remove(chessman);
	}

	public boolean existEating() {
		for (Chessman chessman1 : chessmans) {
			for (Chessman chessman2 : chessmans) {
				if ((!chessman1.equals(chessman2))
						&& chessman1.isEating(chessman2)) {
					return true;
				}
			}
		}
		return false;
	}

	public static void main(String[] args) {
		HashSet<Chessman> set = new HashSet<Chessman>();
		Chessman empress = Chessman.createEmpress();
		empress.setRow(1);
		empress.setColumn(2);
		set.add(empress);
		empress.setColumn(3);
		set.remove(empress);
		System.out.println(set);
	}

}


 

棋盘引用:

 

 

 

皇后类:

 

package chessman;


public abstract class Chessman {
	/**
	 * 表示此棋子在棋盘中第几行 第几列
	 */
	//行
	private int row;
	//列
	private int column;
	
	public int getRow() {
		return row;
	}
	public void setRow(int row) {
		this.row = row;
	}
	public int getColumn() {
		return column;
	}
	public void setColumn(int column) {
		this.column = column;
	}
	
	@Override
	public String toString() {
		return "["+row+","+column+"]";
	}
	
	//检测是否可以放置棋子
	public abstract boolean isEating(Chessman chessman);
	
	//生成棋子
	public static Chessman createEmpress(){
		return new Empress();
	}
	
	//私有的内部类,并继承棋子类,实现是否可放棋子的抽象方法
	private static class Empress extends Chessman{
		@Override
		public boolean isEating(Chessman chessman) {
			if(chessman.getRow() == this.getRow()){//同行
				return true;
			}else if(chessman.getColumn() == this.getColumn()){//同列
				return true;
			}else if(chessman.getColumn() - chessman.getRow() == this.getColumn() - this.getRow()){//正斜线
				return true;
			}else if(chessman.getColumn() + chessman.getRow() == this.getColumn() + this.getRow()){//反斜线
				return true;
			}	
			return false;
		}
	}

}


皇后类无引用

 

 

显示接口:

package view;

import java.util.List;
//显示的接口
public interface IView {
	public int readGridNum();
	public void showResult(List<int[]> result);
}


接口无引用

 

 

控制台方式显示:

package consoleview;

import java.io.BufferedReader;
import java.io.Console;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.List;

import view.IView;

//打印
public class ConsoleView implements IView {

	private Console console = System.console();

	public String readLine(String msg) throws IOException {
		if (console != null) {
			return console.readLine(msg);
		} else {
			System.out.print(msg);
			InputStreamReader isr = new InputStreamReader(System.in);
			BufferedReader br = new BufferedReader(isr);
			return br.readLine();
		}
	}

	public void println(String msg) {
		System.out.println(msg);
	}

	@Override
	public int readGridNum() {
		do {
			try {
				String line = this.readLine("请输入皇后个数(大于0,  输入EXIT退出):");
				if (line.trim().equalsIgnoreCase("exit")) {
					System.exit(0);
				} else {
					int num = Integer.parseInt(line);
					if (num <= 0) {
						throw new Exception();
					}
					return num;
				}
			} catch (IOException e) {
				this.println("系统出现IO异常");
				e.printStackTrace();
				System.exit(0);
			} catch (Exception e) {
				this.println("输入的值非法,必须是大于0的整数");
			}
		} while (true);

	}

	@Override
	public void showResult(List<int[]> results) {
		if (results == null || results.isEmpty()) {
			this.println("无解");
			return;
		}
		do {
			try {
				String line = this.readLine("共有[" + results.size()
						+ "]个解,请输入数字查看具体解的答案(1-" + results.size()
						+ ", 输入EXIT退出):");
				if (line.trim().equalsIgnoreCase("exit")) {
					System.exit(0);
					return;
				} else {
					int num = Integer.parseInt(line) - 1;
					if (num < 0 || num >= results.size()) {
						throw new Exception();
					}
					int[] result = results.get(num);
					this.println("第" + (num + 1) + "个解为"
							+ Arrays.toString(result) + ".下面是该解的图形");
					this.printMap(result);
				}
			} catch (IOException e) {
				this.println("系统出现IO异常");
				e.printStackTrace();
				System.exit(0);
			} catch (Exception e) {
				this.println("输入的值非法,必须是大于1-" + results.size() + "的整数");
			}
		} while (true);

	}

	// 打印的主函数
	public void printMap(int[] result) {
		this.printMapLine(result.length);
		for (int i = 0; i < result.length; i++) {
			this.printMapGrid(result.length, result[i]);
			this.printMapLine(result.length);
		}
	}

	// 打印棋子与棋盘
	private void printMapGrid(int length, int empressX) {
		StringBuffer sb = new StringBuffer();
		sb.append("|");
		for (int i = 0; i < length; i++) {
			sb.append(i == empressX ? "X|" : " |");
		}
		this.println(sb.toString());
	}

	// 打印棋盘边界及棋盘中间线
	private void printMapLine(int length) {
		StringBuffer sb = new StringBuffer();
		sb.append("+");
		for (int i = 0; i < length; i++) {
			sb.append("-+");
		}
		this.println(sb.toString());
	}

}


 

控制台方式显示引用

 

 

swing方式显示

类1:

package frameview;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;

import view.IView;


public class FrameView extends JPanel implements IView{

	private static final long serialVersionUID = -7997619554458231450L;

	private JFrame frame;		//主窗体	
	private JDialog dialog;		//输入对话框
	
	private JPanel inputPanel;	//输入对话框的布局面板
	private JNumberField field;	//自定义的数字输入框
	
	private JPanel outputPanel;	//输出布局面板
	private JComboBox result;	//所有解的下拉选择框
	private JPanel map;			//棋盘面板
	
	//初始化,构造器
	public FrameView(){
		//选择外观
		String lookandfeel="com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel";	
		try {
			UIManager.setLookAndFeel(lookandfeel);
		} catch (Exception e) {
			e.printStackTrace();
		}
		//创建主窗体,并设置相应属性
		frame = new JFrame();
		frame.setTitle("N皇后问题");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		createInputPanel();
		
		createOutputPanel();
		
	}
	
	/**
	 * 创建输出面板,就是画期盼的哪个
	 */
	private void createOutputPanel(){
		outputPanel = new JPanel();//创建面板
		outputPanel.setLayout(new BorderLayout()); //设置布局为边框布局
		
		JPanel toppanel = new JPanel();//创建顶部面板
		outputPanel.add(toppanel, BorderLayout.NORTH);//放在输出面板的顶部
		
		result = new JComboBox();//创建下拉框
		result.addItemListener(new ItemListener() {//注册下拉框监听器,当选项变化的时候调用			
			@Override
			public void itemStateChanged(ItemEvent e) {
				if(e.getStateChange() == ItemEvent.SELECTED){//如果选项的变化状态是选中的
					Result item = (Result)e.getItem();//获取选项内容
					int[] result = item.getResult();//获取坐标
					showMap(result);//输出棋盘
				}
			}
		});
		//设置下拉框不可编辑
		result.setEditable(false);
		toppanel.add(result); //将下拉框放入顶部面板
		
		map = new JPanel();//创建棋盘面板并放入中部位置
		outputPanel.add(map);
		
		frame.add(outputPanel);
	}
	
	/**
	 * 创建输入面板
	 */
	private void createInputPanel(){
		inputPanel = new JPanel();
		//标签
		JLabel label = new JLabel("皇后个数:");
		inputPanel.add(label);
		//数字输入框,设施数字至少是Integer类型
		field = new JNumberField(Integer.class);
		field.setMinValue(1);//允许输入的最小值
		field.setPreferredSize(new Dimension(100, 30));
		inputPanel.add(field);
		//按钮,设置监听动作,点击后关闭对话框
		JButton button = new JButton("确定");
		button.addActionListener(new ActionListener() {			
			@Override
			public void actionPerformed(ActionEvent e) {
				dialog.dispose();
				dialog = null;	
			}
		});
		inputPanel.add(button);
	}
	
	@Override
	public int readGridNum() {//返回输入的结果
		this.showInputDialog();//现实输入框,注意对话框是模式对话框,因此会阻塞在这里,直至该对话框关闭掉,在继续运行
		String text = field.getText();//获取数字框的值,并返回
		return Integer.parseInt(text);
	}

	@Override
	public void showResult(List<int[]> results) {//显示所有的结果
		for(int i=0;i<results.size();i++){//将结果放入下拉列表
			int[] result = results.get(i);
			Result rs = new Result(result, i);
			this.result.addItem(rs);
		}
		if(this.result.getItemCount() > 0){//如果有解默认选择第一个
			this.result.setSelectedIndex(0);
		}else{//如果无解,打印无解
			map.removeAll();
			map.setLayout(new BorderLayout());
			map.setAlignmentX(JPanel.CENTER_ALIGNMENT);
			map.setAlignmentY(JPanel.CENTER_ALIGNMENT);		
			
			JLabel nowap = new JLabel("无解");
			map.add(nowap);	
		}
		frame.pack();//窗体自适应面板布局大小
		frame.setLocationRelativeTo(null);//窗体现实在屏幕中央
		frame.setResizable(false);//不允许窗体大小可变
		frame.setVisible(true);//显示窗体
	}
	
	private void showInputDialog(){
		//创建对话框,病设置变体,模式,注册监听,放入面板
		dialog = new JDialog(frame, "N皇后问题", true);
		dialog.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		dialog.add(inputPanel);
		dialog.setResizable(false);//窗体大小不可变
		dialog.pack();//大小自适应面板大小
		dialog.setLocationRelativeTo(null);//位置居中
		dialog.setVisible(true);//显示,由于JDialog(frame, "N皇后问题", true); 模式参数为true,因此这句话一执行变阻塞到这里,直至窗体关闭继续运行
	}
	
	private void showMap(int[] data){
		//面板移除所有的东西
		map.removeAll();
		//设置布局管理器
		map.setLayout(new GridLayout(data.length, data.length));
		for(int i=0;i<data.length;i++){
			for(int j=0;j<data.length;j++){
				JLabel grid = new JLabel();//创建格子
				grid.setOpaque(true);//背景不透明
				if(data[i] == j){
					grid.setBackground(Color.RED);//红色
				}else{
					grid.setBackground(Color.BLUE);//蓝色
				}
				grid.setBorder(BorderFactory.createLineBorder(Color.BLACK));//格子边框
				grid.setPreferredSize(new Dimension(20,20));//各自默认大小
				map.add(grid);
			}
		}
		//重新绘制
		frame.repaint();
		frame.validate();
	}

	private class Result{
		private int[] result;
		private int index;
		
		public Result(int[] result, int index){
			this.result = result;
			this.index = index;
		}

		public int[] getResult() {
			return result;
		}
		
		@Override
		public String toString() {// 当该对象作为元素放入下拉列表后,下拉列表会调用对象toString方法,将其返回值打印在下拉面板上
			return "解" + (index + 1);
		}
		
	}
	
}


类2:

package frameview;

import java.awt.Toolkit;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import javax.swing.JTextField;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.PlainDocument;

public class JNumberField extends JTextField{

	private static final long serialVersionUID = 2711657283309257375L;

	private Class<? extends Number> type;
	
	private double minValue = Double.NEGATIVE_INFINITY;
	
	private double maxValue = Double.POSITIVE_INFINITY;
	
	public JNumberField(Class<? extends Number> type){
		this.type = type;
		this.setHorizontalAlignment(JTextField.RIGHT);
	}
	
	public double getMinValue() {
		return minValue;
	}

	public void setMinValue(double minValue) {
		this.minValue = minValue;
	}

	public double getMaxValue() {
		return maxValue;
	}

	public void setMaxValue(double maxValue) {
		this.maxValue = maxValue;
	}
	
	@Override
	protected Document createDefaultModel() {
		return new PlainDocument(){
			private static final long serialVersionUID = -4589029521250625953L;

			@Override
			public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
				if(str == null) return;
				int length = getLength();
				String value = getText(0, length);
				value = value.substring(0, offs) + str + value.substring(offs, length);
				try{
					Number number = parser(value);
					if(number.doubleValue() < minValue || number.doubleValue() > maxValue){
						throw new Exception();
					}					
				}catch(Exception e){
					Toolkit.getDefaultToolkit().beep();
					return;
				}				
				super.insertString(offs, str, a);
			}
		};
	}
	
	private Number parser(String value) throws SecurityException, NoSuchMethodException, IllegalArgumentException,
			IllegalAccessException, InvocationTargetException {
		String name = type.getSimpleName();
		if (type == Integer.class) {
			name = "Int";
		}
		Method method = type.getMethod("parse" + name, String.class);
		Object result = method.invoke(null, value);
		return type.cast(result);
	}

}


实现接口:

 

 

 

显示工厂:

package viewfactory;

import view.IView;
import consoleview.ConsoleView;
import exception.NullViewTypeException;
import frameview.FrameView;


public class ViewFactory  {

	public static enum ViewType{
		FRAME("窗体View"),
		CONSOLE("控制台View");
		
		private String value;
		
		private ViewType(String value){
			this.value = value;
		}
		
		@Override
		public String toString() {
			return this.value;
		}
	}
	
	public static IView createView(ViewType type){
		switch(type){
		case FRAME:
			return new FrameView();
		case CONSOLE:
			return new ConsoleView();
		default:
			throw new NullViewTypeException("无法识别类型:" + type.toString());
		}
	}
	
}


显示工厂引用:

 

 

自定义异常类:

类1:

package exception;

//声明异常类
public class ChessmanOutIndexException extends RuntimeException{

	private static final long serialVersionUID = 1668411926899207995L;

	public ChessmanOutIndexException(){
		super();
	}
	
	public ChessmanOutIndexException(String msg){
		super(msg);
	}
	
	public ChessmanOutIndexException(String msg, Throwable t){
		super(msg, t);
	}
	
}


类2:

package exception;

public class NullViewTypeException extends RuntimeException{

	private static final long serialVersionUID = 8231353296327423242L;

	public NullViewTypeException(){
		super();
	}
	
	public NullViewTypeException(String msg){
		super(msg);
	}
	
	public NullViewTypeException(String msg, Throwable t){
		super(msg, t);
	}
	
}


自定义异常类无引用

 

 

启动类:

package start;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import view.IView;
import viewfactory.ViewFactory;
import viewfactory.ViewFactory.ViewType;
import chessboard.Chessboard;
import chessman.Chessman;

public class NEmpressQuestion {

	private Chessman[] chessmans;	
	private Chessboard chessboard;
	
	private Set<int[]> answers;
	
	public NEmpressQuestion(int empressCount){
		chessmans = new Chessman[empressCount];
		for(int i=0;i<chessmans.length;i++){
			chessmans[i] = Chessman.createEmpress();
			chessmans[i].setRow(i);
		}
		chessboard = new Chessboard(empressCount);
		answers = new HashSet<int[]>();
	}
	
	public void running(){
		this.nextRow(0);
	}
	
	private void nextRow(int row){
		chessboard.addChessman(chessmans[row]);
		for(int col=0;col<chessboard.getGridMaxNum();col++){
			chessmans[row].setColumn(col);
			if(!chessboard.existEating()){
				if(row<chessboard.getGridMaxNum() - 1){
					nextRow(row + 1);
				}else{
					recordAnswer();
				}				
			}
		}
		chessboard.removeChessman(chessmans[row]);
	}
	
	public void recordAnswer(){
		int[] answer = new int[chessmans.length];
		for(int i=0;i<chessmans.length;i++){
			answer[i] = chessmans[i].getColumn();
		}
		answers.add(answer);
	}
	
	public Set<int[]> getAnswers(){
		return answers;
	}
	
	//程序的主函数入口
	public static void main(String[] args) {
		
		ViewType type=ViewType.CONSOLE;
		if(args != null && args.length > 0 && args[0].trim().equalsIgnoreCase("frame")){
			type = ViewType.FRAME;
		}		
		IView view = ViewFactory.createView(type);
		int gridNum = view.readGridNum();
		NEmpressQuestion nempress = new NEmpressQuestion(gridNum);
		nempress.running();
		
		Set<int[]> answers = nempress.getAnswers();		

		List<int[]> results = new ArrayList<int[]>(answers.size());
		results.addAll(answers);
		view.showResult(results);
	}
	
}


启动类引用:

 

 

 

注意启动类的

ViewType type=ViewType.CONSOLE;  这一行,这一行就是具体需要哪个显示方式了,这里是控制台方式

 

源码下载地址:http://download.youkuaiyun.com/source/3520092

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值