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);
}
}