package aima.gui.fx.views; import aima.core.environment.nqueens.NQueensBoard; import aima.core.util.datastructure.XYLocation; import javafx.beans.binding.Bindings; import javafx.geometry.Pos; import javafx.scene.layout.Background; import javafx.scene.layout.BackgroundFill; import javafx.scene.layout.ColumnConstraints; import javafx.scene.layout.GridPane; import javafx.scene.layout.RowConstraints; import javafx.scene.layout.StackPane; import javafx.scene.paint.Color; import javafx.scene.shape.Polygon; /** * Controller class which provides functionality for using a stack pane as a * state view for the N-Queens problem. * * @author Ruediger Lunde */ public class NQueensViewCtrl { private GridPane gridPane = new GridPane(); private Polygon[] queens = new Polygon[0]; /** * Adds a grid pane to the provided pane and creates a controller class * instance which is responsible for queen symbol positioning on the grid. */ public NQueensViewCtrl(StackPane viewRoot) { viewRoot.getChildren().add(gridPane); viewRoot.setAlignment(Pos.BOTTOM_CENTER); gridPane.maxWidthProperty().bind(Bindings.min(viewRoot.widthProperty(), viewRoot.heightProperty()).subtract(20)); gridPane.maxHeightProperty().bind(Bindings.min(viewRoot.widthProperty(), viewRoot.heightProperty()).subtract(10)); } /** Updates the view. */ public void update(NQueensBoard board) { int size = board.getSize(); if (queens.length != size * size) { gridPane.getChildren().clear(); gridPane.getColumnConstraints().clear(); gridPane.getRowConstraints().clear(); queens = new Polygon[size * size]; RowConstraints c1 = new RowConstraints(); c1.setPercentHeight(100.0 / size); ColumnConstraints c2 = new ColumnConstraints(); c2.setPercentWidth(100.0 / size); for (int i = 0; i < board.getSize(); i++) { gridPane.getRowConstraints().add(c1); gridPane.getColumnConstraints().add(c2); } for (int i = 0; i < queens.length; i++) { StackPane field = new StackPane(); queens[i] = createQueen(); field.getChildren().add(queens[i]); int col = i % size; int row = i / size; field.setBackground(new Background( new BackgroundFill((col % 2 == row % 2) ? Color.WHITE : Color.LIGHTGRAY, null, null))); gridPane.add(field, col, row); } } double scale = 0.2 * gridPane.getWidth() / gridPane.getColumnConstraints().size(); for (int i = 0; i < queens.length; i++) { Polygon queen = queens[i]; queen.setScaleX(scale); queen.setScaleY(scale); XYLocation loc = new XYLocation(i % size, i / size); if (board.queenExistsAt(loc)) { queen.setVisible(true); queen.setFill(board.isSquareUnderAttack(loc) ? Color.RED : Color.BLACK); } else { queen.setVisible(false); } } } private Polygon createQueen() { return new Polygon(1, 0, 3, 0, 4, -2, 3, -1, 3, -2.2, 2.4, -1, 2, -2.3, 1.6, -1, 1, -2.2, 1, -1, 0, -2); } }