package aima.gui.fx.applications.search; import aima.core.environment.nqueens.AttackingPairsHeuristic; import aima.core.environment.nqueens.NQueensBoard; import aima.core.environment.nqueens.NQueensBoard.Config; import aima.core.search.framework.Metrics; import aima.core.search.framework.qsearch.GraphSearch; import aima.core.search.framework.qsearch.TreeSearch; import aima.core.search.informed.AStarSearch; import aima.core.search.informed.GreedyBestFirstSearch; import aima.core.search.uninformed.BreadthFirstSearch; import aima.core.search.uninformed.DepthFirstSearch; import aima.core.search.uninformed.IterativeDeepeningSearch; import aima.gui.fx.framework.IntegrableApplication; import aima.gui.fx.framework.Parameter; import aima.gui.fx.framework.SimulationPaneBuilder; import aima.gui.fx.framework.SimulationPaneCtrl; import aima.gui.fx.views.NQueensViewCtrl; import javafx.application.Platform; import javafx.scene.layout.BorderPane; import javafx.scene.layout.Pane; import javafx.scene.layout.StackPane; import java.util.Arrays; import java.util.List; /** * Integrable application which demonstrates how different search strategies * solve the N-Queens problem. * * @author Ruediger Lunde * */ public class NQueensSearchApp extends IntegrableApplication { public static void main(String[] args) { launch(args); } private final static String PARAM_STRATEGY = "strategy"; private final static String PARAM_BOARD_SIZE = "boardSize"; private final static String PARAM_INIT_CONFIG = "initConfig"; private NQueensViewCtrl stateViewCtrl; private SimulationPaneCtrl simPaneCtrl; private NQueensSearchDemo experiment; public NQueensSearchApp() { experiment = new NQueensSearchDemo(); experiment.addProgressTracer(this::updateStateView); } @Override public String getTitle() { return "N-Queens Search App"; } /** * Defines state view, parameters, and call-back functions and calls the * simulation pane builder to create layout and controller objects. */ @Override public Pane createRootPane() { BorderPane root = new BorderPane(); StackPane stateView = new StackPane(); stateViewCtrl = new NQueensViewCtrl(stateView); List<Parameter> params = createParameters(); SimulationPaneBuilder builder = new SimulationPaneBuilder(); builder.defineParameters(params); builder.defineStateView(stateView); builder.defineInitMethod(this::initialize); builder.defineSimMethod(this::simulate); simPaneCtrl = builder.getResultFor(root); simPaneCtrl.setParam(SimulationPaneCtrl.PARAM_SIM_SPEED, 1); return root; } protected List<Parameter> createParameters() { Parameter p1 = new Parameter(PARAM_STRATEGY, "Depth-First Search (incremental)", "Breadth-First Search (incremental)", "Iterative Deepening Search", "Greedy Best-First Search (attacking pair heuristic)", "A* search (attacking pair heuristic)", "Hill Climbing", "Simulated Annealing", "Genetic Algorithm"); Parameter p2 = new Parameter(PARAM_BOARD_SIZE, 4, 8, 16, 32, 64); p2.setDefaultValueIndex(1); Parameter p3 = new Parameter(PARAM_INIT_CONFIG, "FirstRow", "Random"); p3.setDependency(PARAM_STRATEGY, "Iterative Deepening Search", "Greedy Best-First Search (attacking pair heuristic)", "A* search (attacking pair heuristic)", "Hill Climbing", "Simulated Annealing", "Genetic Algorithm"); return Arrays.asList(p1, p2, p3); } /** Displays the initialized board on the state view. */ @Override public void initialize() { experiment.setBoardSize(simPaneCtrl.getParamAsInt(PARAM_BOARD_SIZE)); Object strategy = simPaneCtrl.getParamValue(PARAM_STRATEGY); Config config; //noinspection SuspiciousMethodCalls if (Arrays.asList("Depth-First Search (incremental)", "Breadth-First Search (incremental)", "Genetic Algorithm") .contains(strategy)) config = Config.EMPTY; else if (simPaneCtrl.getParamValue(PARAM_INIT_CONFIG).equals("Random")) config = Config.QUEEN_IN_EVERY_COL; else config = Config.QUEENS_IN_FIRST_ROW; experiment.initExperiment(config); stateViewCtrl.update(experiment.getBoard()); } @Override public void cleanup() { simPaneCtrl.cancelSimulation(); } /** Starts the experiment. */ public void simulate() { Object strategy = simPaneCtrl.getParamValue(PARAM_STRATEGY); if (strategy.equals("Depth-First Search (incremental)")) experiment.startExperiment(new DepthFirstSearch(new TreeSearch())); else if (strategy.equals("Breadth-First Search (incremental)")) experiment.startExperiment(new BreadthFirstSearch(new TreeSearch())); else if (strategy.equals("Iterative Deepening Search")) experiment.startExperiment(new IterativeDeepeningSearch()); else if (strategy.equals("Greedy Best-First Search (attacking pair heuristic)")) experiment.startExperiment(new GreedyBestFirstSearch(new GraphSearch(), new AttackingPairsHeuristic())); else if (strategy.equals("A* search (attacking pair heuristic)")) experiment.startExperiment(new AStarSearch(new GraphSearch(), new AttackingPairsHeuristic())); else if (strategy.equals("Hill Climbing")) experiment.startHillClimbingExperiment(); else if (strategy.equals("Simulated Annealing")) experiment.startSimulatedAnnealingExperiment(); else if (strategy.equals("Genetic Algorithm")) experiment.startGenAlgoExperiment(simPaneCtrl.getParamValue(PARAM_INIT_CONFIG).equals("Random")); } /** * Caution: While the background thread should be slowed down, updates of * the GUI have to be done in the GUI thread! */ private void updateStateView(NQueensBoard board, Metrics metrics) { Platform.runLater(() -> updateStateViewLater(board, metrics)); simPaneCtrl.waitAfterStep(); } /** * Must be called by the GUI thread! */ private void updateStateViewLater(NQueensBoard board, Metrics metrics) { stateViewCtrl.update(board); simPaneCtrl.setStatus(metrics.toString()); } }