diff --git a/src/main/java/controller/GridController.java b/src/main/java/controller/GridController.java index b4f9864481e525762bf8bfb34974ec5afe6ad232..49f0021ccfed5b2755af9607acfc2cf280c3250d 100644 --- a/src/main/java/controller/GridController.java +++ b/src/main/java/controller/GridController.java @@ -1,27 +1,81 @@ package controller; - import javafx.fxml.FXML; import javafx.scene.paint.Color; -import model.ConstrainedRotatedTruchetTileGenerator; -import model.RandomConstrainedWangTileGenerator; -import model.RandomRotatedTruchetTileGenerator; -import model.RandomWangTileGenerator; +import model.*; import view.GridTileCanvas; import java.util.List; import java.util.Random; public class GridController { + Random random = new Random(); @FXML public GridTileCanvas gridTileCanvas; public void initialize() { - //gridTileCanvas.initializeGrid(new RandomConstrainedWangTileGenerator(List.of(Color.BLUE, Color.RED, Color.BLACK, Color.GREEN),new Random(0))); - //gridTileCanvas.initializeGrid(new RandomWangTileGenerator(List.of(Color.BLUE, Color.RED, Color.BLACK, Color.GREEN),new Random(0))); - //gridTileCanvas.initializeGrid(new RandomRotatedTruchetTileGenerator(Color.BLUE, Color.RED, new Random(0))); - gridTileCanvas.initializeGrid(new ConstrainedRotatedTruchetTileGenerator(Color.BLUE, Color.RED)); + clearGrid(); + } + + public void fillGrid(TileGenerator tileGenerator) { + gridTileCanvas.fillGrid(tileGenerator); + } + + public void drawGrid() { + gridTileCanvas.update(); + } + + public void clearGrid(){ + fillGrid(new EmptyTileGenerator()); + } + + public void updateGrid(TileGenerator tileGenerator){ + clearGrid(); + fillGrid(tileGenerator); + drawGrid(); + } + + @FXML + public void updateEmptyUniformTile(){ + updateGrid(new EmptyTileGenerator()); + } + + @FXML + public void updateRedUniformTile(){ + updateGrid(new UniformTileGenerator(new InternalSide(Color.RED))); + } + + @FXML + public void updateRandomColorUniformTile(){ + updateGrid(new RandomUniformTileGenerator(List.of(Color.RED, Color.BLUE, Color.BLACK), random)); + } + + @FXML + public void updateRandomTruchetTile(){ + updateGrid(new RandomRotatedTruchetTileGenerator(Color.RED, Color.BLUE, random)); } - public void draw() { - gridTileCanvas.drawGrid(); + + public void updateRandomWangTile() { + updateGrid(new RandomWangTileGenerator(List.of(Color.RED, Color.BLUE, Color.GREEN, Color.YELLOW), random)); + } + + public void updateRandomConstrainedWangTile() { + updateGrid(new RandomConstrainedWangTileGenerator(List.of(Color.RED, Color.BLUE, Color.GREEN, Color.YELLOW), random)); + } + + public void updateConstrainedTruchetTile() { + updateGrid(new ConstrainedRotatedTruchetTileGenerator(Color.RED, Color.BLUE, random)); + } + + public void updateRandomWangTileSet() { + updateGrid(new RandomTileSetGenerator(List.of( + new WangTile(new Side[]{new InternalSide(Color.RED), new InternalSide(Color.BLUE), new InternalSide(Color.RED), new InternalSide(Color.RED)}), + new WangTile(new Side[]{new InternalSide(Color.RED), new InternalSide(Color.RED), new InternalSide(Color.BLUE), new InternalSide(Color.BLUE)}), + new WangTile(new Side[]{new InternalSide(Color.RED), new InternalSide(Color.GREEN), new InternalSide(Color.GREEN), new InternalSide(Color.GREEN)}), + new WangTile(new Side[]{new InternalSide(Color.BLUE), new InternalSide(Color.GREEN), new InternalSide(Color.RED), new InternalSide(Color.BLUE)}), + new WangTile(new Side[]{new InternalSide(Color.BLUE), new InternalSide(Color.BLUE), new InternalSide(Color.BLUE), new InternalSide(Color.RED)}), + new WangTile(new Side[]{new InternalSide(Color.BLUE), new InternalSide(Color.RED), new InternalSide(Color.GREEN), new InternalSide(Color.GREEN)}), + new WangTile(new Side[]{new InternalSide(Color.GREEN), new InternalSide(Color.GREEN), new InternalSide(Color.BLUE), new InternalSide(Color.GREEN)}), + new WangTile(new Side[]{new InternalSide(Color.GREEN), new InternalSide(Color.RED), new InternalSide(Color.RED), new InternalSide(Color.RED)}), + new WangTile(new Side[]{new InternalSide(Color.GREEN), new InternalSide(Color.BLUE), new InternalSide(Color.GREEN), new InternalSide(Color.BLUE)})), random)); } } diff --git a/src/main/java/main/MainApp.java b/src/main/java/main/MainApp.java index 941edde50e0c32dc935bc8a4744f2dbbb631a075..be27ef614c4bf25820ec98c5861c8d0db53284d1 100644 --- a/src/main/java/main/MainApp.java +++ b/src/main/java/main/MainApp.java @@ -14,34 +14,26 @@ public class MainApp extends Application { private Stage primaryStage; private AnchorPane rootLayout; - - public MainApp() { - } - public void start(Stage primaryStage) { this.primaryStage = primaryStage; this.primaryStage.setTitle("Wang tiles"); initRootLayout(); } - /** - * Initializes the root layout and tries to load the last opened - * person file. - */ public void initRootLayout() { try { - // Load root layout from fxml file. + FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/GridCanvas.fxml")); rootLayout = loader.load(); - // Show the scene containing the root layout. + Scene scene = new Scene(rootLayout); primaryStage.setScene(scene); - // Give the controller access to the main app. + GridController controller = loader.getController(); controller.initialize(); - controller.draw(); + controller.drawGrid(); primaryStage.show(); } catch (IOException e) { e.printStackTrace(); diff --git a/src/main/java/model/ArrayGrid.java b/src/main/java/model/ArrayGrid.java new file mode 100644 index 0000000000000000000000000000000000000000..312392b61bc17bd2f2bf715221628f3e8e9a2981 --- /dev/null +++ b/src/main/java/model/ArrayGrid.java @@ -0,0 +1,82 @@ +package model; +import java.util.Iterator; + +public class ArrayGrid implements Grid { + private final int numberOfRows; + private final int numberOfColumns; + private final Square[][] squares; + private final Square outOfGridSquare = new ArraySquare(); + /** + * Creates a new {@code Grid} instance given the number of rows and columns. + * + * @param numberOfRows the number of rows + * @param numberOfColumns the number of columns + * @throws IllegalArgumentException if {@code numberOfRows} or {@code numberOfColumns} are + * less than or equal to 0 + */ + public ArrayGrid(int numberOfRows, int numberOfColumns) { + if(numberOfRows <= 0) + throw new IllegalArgumentException("The number of rows must be positive and not equal to " + numberOfRows); + if(numberOfColumns <= 0) + throw new IllegalArgumentException("The number of columns must be positive and not equal to " + numberOfColumns); + this.numberOfRows = numberOfRows; + this.numberOfColumns = numberOfColumns; + squares = new ArraySquare[getNumberOfRows()][getNumberOfColumns()]; + initializeGrid(); + } + + private void initializeGrid() { + initializeSquares(); + initializeNeighborhood(); + } + + private void initializeSquares() { + for(int row = 0; row < getNumberOfRows(); row++) + for(int column = 0; column < getNumberOfColumns(); column++) + squares[row][column] = new ArraySquare(); + } + + private void initializeNeighborhood() { + for(int row = 0; row < getNumberOfRows(); row++) + for(int column = 0; column < getNumberOfColumns(); column++) { + for (CardinalDirection direction : CardinalDirection.values()){ + int rowNeighbor = row + direction.deltaRow; + int columnNeighbor = column + direction.deltaColumn; + Square neighboringSquare = + containsCoordinates(rowNeighbor, columnNeighbor) ? getSquare(rowNeighbor, columnNeighbor) : outOfGridSquare; + getSquare(row, column).setNeighbor(neighboringSquare, direction); + } + } + } + + private boolean containsCoordinates(int row, int column){ + return 0 <= row && row < numberOfRows && 0 <= column && column < numberOfColumns; + } + + /** + * Returns an iterator over Squares. + * + * @return an Iterator. + */ + @Override + public Iterator<Square> iterator() { + return new SquareIterator(this); + } + + public Square getSquare(int rowIndex, int columnIndex) { + return squares[rowIndex][columnIndex]; + } + + public int getNumberOfRows() { + return numberOfRows; + } + + public int getNumberOfColumns() { + return numberOfColumns; + } + + public void fill(TileGenerator tileGenerator){ + for(Square square : this) + square.put(tileGenerator.nextTile(square)); + } +} diff --git a/src/main/java/model/ArraySquare.java b/src/main/java/model/ArraySquare.java index 3298e582bca2a6a4a4d6751f1bc488ac1f8c71ad..b470781e5f86f9ad9cdb0d4965f20393e301722b 100644 --- a/src/main/java/model/ArraySquare.java +++ b/src/main/java/model/ArraySquare.java @@ -1,5 +1,6 @@ package model; +import java.util.ArrayList; import java.util.List; public class ArraySquare implements Square { @@ -23,14 +24,26 @@ public class ArraySquare implements Square { return tile; } + @Override + public List<Tile> compatibleTiles(List<Tile> tiles) { + List<Tile> compatibleTiles = new ArrayList<>(); + for(Tile tile : tiles) + if(accept(tile)) + compatibleTiles.add(tile); + return compatibleTiles; + } + + @Override public void put(Tile tile) { this.tile = tile; } + @Override public void setNeighbor(Square neighbor, CardinalDirection direction) { this.neighborhood[direction.ordinal()] = neighbor; } + @Override public Square getNeighbor(CardinalDirection direction) { return this.neighborhood[direction.ordinal()]; } diff --git a/src/main/java/model/ConstrainedRotatedTruchetTileGenerator.java b/src/main/java/model/ConstrainedRotatedTruchetTileGenerator.java index 0f69e7fa071a5657b7bc8dd8cab43b53a956b215..f41c280b85d5c0c6c9b061dbc0c29cb320beb006 100644 --- a/src/main/java/model/ConstrainedRotatedTruchetTileGenerator.java +++ b/src/main/java/model/ConstrainedRotatedTruchetTileGenerator.java @@ -1,23 +1,26 @@ package model; import javafx.scene.paint.Color; +import util.RandomUtil; -public class ConstrainedRotatedTruchetTileGenerator implements TileGenerator{ - private final Tile truchetTile; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; - public ConstrainedRotatedTruchetTileGenerator(Color color1, Color color2) { - this.truchetTile = new TruchetTile(new InternalSide(color1), new InternalSide(color2)); +public class ConstrainedRotatedTruchetTileGenerator implements TileGenerator{ + private final List<Tile> rotatedTruchetTiles = new ArrayList<>(); + private final Random randomGenerator; + public ConstrainedRotatedTruchetTileGenerator(Color color1, Color color2, Random randomGenerator) { + Tile truchetTile = new TruchetTile(new InternalSide(color1), new InternalSide(color2)); + for(Rotation rotation : Rotation.values()){ + rotatedTruchetTiles.add(new RotatedTile(truchetTile, rotation)); + } + this.randomGenerator = randomGenerator; } @Override public Tile nextTile(Square square) { - for(Rotation rotation : Rotation.values()) { - Tile rotatedTile = new RotatedTile(truchetTile, rotation); - if(square.accept(rotatedTile)){ - return rotatedTile; - } - } - return new UniformTile(EmptySide.EMPTY_SIDE); + return RandomUtil.randomElement(square.compatibleTiles(rotatedTruchetTiles), randomGenerator); } } diff --git a/src/main/java/model/EmptyGrid.java b/src/main/java/model/EmptyGrid.java new file mode 100644 index 0000000000000000000000000000000000000000..98b69c11ce4907347f6ec7ad5c0e540e0286091d --- /dev/null +++ b/src/main/java/model/EmptyGrid.java @@ -0,0 +1,48 @@ +package model; + +import java.util.Iterator; + +public class EmptyGrid implements Grid{ + private final int numberOfRows; + private final int numberOfColumns; + private static final Square EMPTY_SQUARE = new ArraySquare(); + + public EmptyGrid(int numberOfRows, int numberOfColumns) { + this.numberOfRows = numberOfRows; + this.numberOfColumns = numberOfColumns; + } + + @Override + public Square getSquare(int rowIndex, int columnIndex) { + return EMPTY_SQUARE; + } + + @Override + public int getNumberOfRows() { + return numberOfRows; + } + + @Override + public int getNumberOfColumns() { + return numberOfColumns; + } + + @Override + public void fill(TileGenerator tileGenerator) { + } + + @Override + public Iterator<Square> iterator() { + return new Iterator<>() { + @Override + public boolean hasNext() { + return false; + } + + @Override + public Square next() { + return EMPTY_SQUARE; + } + }; + } +} diff --git a/src/main/java/model/EmptyTileGenerator.java b/src/main/java/model/EmptyTileGenerator.java new file mode 100644 index 0000000000000000000000000000000000000000..97f281a9500b2048bc87f1a7456c049507864374 --- /dev/null +++ b/src/main/java/model/EmptyTileGenerator.java @@ -0,0 +1,10 @@ +package model; + +public class EmptyTileGenerator implements TileGenerator{ + private Tile emptyTile = new UniformTile(EmptySide.EMPTY_SIDE); + + @Override + public Tile nextTile(Square square) { + return emptyTile; + } +} diff --git a/src/main/java/model/Grid.java b/src/main/java/model/Grid.java index becc8e57945d08e42f112fd1a88a0657948f5875..96eb89c91c63f30a87d48729c6445d1f542f314b 100644 --- a/src/main/java/model/Grid.java +++ b/src/main/java/model/Grid.java @@ -1,82 +1,8 @@ package model; -import java.util.Iterator; -public class Grid implements Iterable<Square> { - private final int numberOfRows; - private final int numberOfColumns; - private final Square[][] squares; - private final Square outOfGridSquare = new ArraySquare(); - /** - * Creates a new {@code Grid} instance given the number of rows and columns. - * - * @param numberOfRows the number of rows - * @param numberOfColumns the number of columns - * @throws IllegalArgumentException if {@code numberOfRows} or {@code numberOfColumns} are - * less than or equal to 0 - */ - public Grid(int numberOfRows, int numberOfColumns) { - if(numberOfRows <= 0) - throw new IllegalArgumentException("The number of rows must be positive and not equal to " + numberOfRows); - if(numberOfColumns <= 0) - throw new IllegalArgumentException("The number of columns must be positive and not equal to " + numberOfColumns); - this.numberOfRows = numberOfRows; - this.numberOfColumns = numberOfColumns; - squares = new ArraySquare[getNumberOfRows()][getNumberOfColumns()]; - initializeGrid(); - } - - private void initializeGrid() { - initializeSquares(); - initializeNeighborhood(); - } - - private void initializeSquares() { - for(int row = 0; row < getNumberOfRows(); row++) - for(int column = 0; column < getNumberOfColumns(); column++) - squares[row][column] = new ArraySquare(); - } - - private void initializeNeighborhood() { - for(int row = 0; row < getNumberOfRows(); row++) - for(int column = 0; column < getNumberOfColumns(); column++) { - for (CardinalDirection direction : CardinalDirection.values()){ - int rowNeighbor = row + direction.deltaRow; - int columnNeighbor = column + direction.deltaColumn; - Square neighboringSquare = - containsCoordinates(rowNeighbor, columnNeighbor) ? getSquare(rowNeighbor, columnNeighbor) : outOfGridSquare; - getSquare(row, column).setNeighbor(neighboringSquare, direction); - } - } - } - - private boolean containsCoordinates(int row, int column){ - return 0 <= row && row < numberOfRows && 0 <= column && column < numberOfColumns; - } - - /** - * Returns an iterator over Squares. - * - * @return an Iterator. - */ - @Override - public Iterator<Square> iterator() { - return new SquareIterator(this); - } - - public Square getSquare(int rowIndex, int columnIndex) { - return squares[rowIndex][columnIndex]; - } - - public int getNumberOfRows() { - return numberOfRows; - } - - public int getNumberOfColumns() { - return numberOfColumns; - } - - public void fill(TileGenerator tileGenerator){ - for(Square square : this) - square.put(tileGenerator.nextTile(square)); - } +public interface Grid extends Iterable<Square>{ + Square getSquare(int rowIndex, int columnIndex); + int getNumberOfRows(); + int getNumberOfColumns(); + void fill(TileGenerator tileGenerator); } diff --git a/src/main/java/model/RandomTileSetGenerator.java b/src/main/java/model/RandomTileSetGenerator.java new file mode 100644 index 0000000000000000000000000000000000000000..2044db70b3d0abc490f544496032f348c534e8a4 --- /dev/null +++ b/src/main/java/model/RandomTileSetGenerator.java @@ -0,0 +1,23 @@ +package model; + +import util.RandomUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class RandomTileSetGenerator implements TileGenerator{ + List<Tile> tiles = new ArrayList<>(); + Random randomGenerator; + + public RandomTileSetGenerator(Iterable<Tile> tiles, Random randomGenerator) { + for(Tile tile : tiles) + this.tiles.add(tile); + this.randomGenerator = randomGenerator; + } + + @Override + public Tile nextTile(Square square) { + return RandomUtil.randomElement(square.compatibleTiles(tiles), randomGenerator); + } +} diff --git a/src/main/java/model/RandomWangTileGenerator.java b/src/main/java/model/RandomWangTileGenerator.java index 55927e9d956992f610fefc447d0dd2d956757352..7f0e8772ae4249ccb65e87f0948826466ab7b7f4 100644 --- a/src/main/java/model/RandomWangTileGenerator.java +++ b/src/main/java/model/RandomWangTileGenerator.java @@ -16,6 +16,7 @@ public class RandomWangTileGenerator implements TileGenerator{ this.availableSides.add(new InternalSide(color)); this.randomGenerator = randomGenerator; } + @Override public Tile nextTile(Square square) { Side[] sidesOfTile = new Side[CardinalDirection.NUMBER_OF_DIRECTIONS]; diff --git a/src/main/java/model/Square.java b/src/main/java/model/Square.java index 2849e044ac7a3572784d5fb6512de1255735667b..03b1798081c86efd239b4476e7b719cbc664a8e1 100644 --- a/src/main/java/model/Square.java +++ b/src/main/java/model/Square.java @@ -6,6 +6,7 @@ public interface Square { boolean accept(Tile tile); void put(Tile tile); Tile getTile(); + List<Tile> compatibleTiles(List<Tile> tiles); List<Side> compatibleSides(List<Side> sides, CardinalDirection direction); Square getNeighbor(CardinalDirection direction); void setNeighbor(Square neighbor, CardinalDirection direction); diff --git a/src/main/java/model/SquareIterator.java b/src/main/java/model/SquareIterator.java index c970bf266e283f42a1a22c8bef8b85eb83d4e897..10cef6ee13ea7be58e2d5187d3bebcdb5e4133dd 100644 --- a/src/main/java/model/SquareIterator.java +++ b/src/main/java/model/SquareIterator.java @@ -5,9 +5,9 @@ import java.util.Iterator; public class SquareIterator implements Iterator<Square> { private int rowNext; private int columnNext; - private final Grid grid; + private final ArrayGrid grid; - SquareIterator(Grid grid) { + SquareIterator(ArrayGrid grid) { this.rowNext = 0; this.columnNext = 0; this.grid = grid; diff --git a/src/main/java/model/UniformTileGenerator.java b/src/main/java/model/UniformTileGenerator.java new file mode 100644 index 0000000000000000000000000000000000000000..6b3f13721707dc4fe0cb2961fd3eb5a46ef8651b --- /dev/null +++ b/src/main/java/model/UniformTileGenerator.java @@ -0,0 +1,14 @@ +package model; + +public class UniformTileGenerator implements TileGenerator{ + private final Tile tile; + + public UniformTileGenerator(Side side) { + tile = new UniformTile(side); + } + + @Override + public Tile nextTile(Square square) { + return tile; + } +} diff --git a/src/main/java/view/GridTileCanvas.java b/src/main/java/view/GridTileCanvas.java index 5eb17226e56c64dd070ec0b390e2922bfde506a9..a1fdf23f572e8c4dfef4925817674a6415d2d44f 100644 --- a/src/main/java/view/GridTileCanvas.java +++ b/src/main/java/view/GridTileCanvas.java @@ -3,6 +3,7 @@ package view; import javafx.beans.NamedArg; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; +import javafx.scene.paint.Color; import model.*; import java.util.List; @@ -25,19 +26,24 @@ public class GridTileCanvas extends Canvas { this.numberOfRows = numberOfRows; this.setWidth(tileWidth * numberOfColumns); this.setHeight(tileHeight * numberOfRows); - tileGrid = new Grid(numberOfRows, numberOfColumns); + tileGrid = new ArrayGrid(numberOfRows, numberOfColumns); graphicsContext = getGraphicsContext2D(); } - public void drawGrid(){ + public void update(){ + clear(); + drawGrid(); + } + + private void drawGrid(){ drawGridTile(tileGrid); } - public void clear(){ + private void clear(){ graphicsContext.clearRect(0, 0, getWidth(), getHeight()); } - public void initializeGrid(TileGenerator tileGenerator){ + public void fillGrid(TileGenerator tileGenerator){ tileGrid.fill(tileGenerator); } @@ -63,7 +69,10 @@ public class GridTileCanvas extends Canvas { xPoints[index] = x + (cornerTypes.get(index).getXPosition() * tileWidth); yPoints[index] = y + (cornerTypes.get(index).getYPosition() * tileHeight); } - graphicsContext.setFill(tile.side(side).color()); + + Color color = tile.side(side).color(); + graphicsContext.setFill(color); + graphicsContext.strokePolygon(xPoints, yPoints, 3); graphicsContext.fillPolygon(xPoints, yPoints, 3); } } diff --git a/src/main/resources/view/GridCanvas.fxml b/src/main/resources/view/GridCanvas.fxml index 162854f4a196ce3e5318e1abb5b32ebd8f6ac733..009d4c0ccc74ec5032a327383e6c7e4792c14ac9 100644 --- a/src/main/resources/view/GridCanvas.fxml +++ b/src/main/resources/view/GridCanvas.fxml @@ -6,24 +6,52 @@ <?import view.GridTileCanvas?> <?import java.lang.Double?> <?import java.lang.Integer?> +<?import javafx.scene.control.MenuBar?> +<?import javafx.scene.control.Menu?> +<?import javafx.scene.control.MenuItem?> <AnchorPane stylesheets="@DarkTheme.css" xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:controller="controller.GridController"> - <GridTileCanvas xmlns="http://javafx.com/javafx" + <MenuBar AnchorPane.topAnchor="0." AnchorPane.leftAnchor="0." AnchorPane.rightAnchor="0." minHeight="40."> + <Menu mnemonicParsing="false" text="Uniform Tiles"> + <MenuItem mnemonicParsing="false" onAction="#updateEmptyUniformTile" text="Empty"> + </MenuItem> + <MenuItem mnemonicParsing="false" onAction="#updateRedUniformTile" text="Red"> + </MenuItem> + <MenuItem mnemonicParsing="false" onAction="#updateRandomColorUniformTile" text="Random color"> + </MenuItem> + </Menu> + <Menu mnemonicParsing="false" text="Wang Tiles"> + <MenuItem mnemonicParsing="false" onAction="#updateRandomWangTile" text="Random"> + </MenuItem> + <MenuItem mnemonicParsing="false" onAction="#updateRandomConstrainedWangTile" text="Random constrained"> + </MenuItem> + <MenuItem mnemonicParsing="false" onAction="#updateRandomWangTileSet" text="Random tile set"> + </MenuItem> + </Menu> + <Menu mnemonicParsing="false" text="Truchet Tiles"> + <MenuItem mnemonicParsing="false" onAction="#updateRandomTruchetTile" text="Random"> + </MenuItem> + <MenuItem mnemonicParsing="false" onAction="#updateConstrainedTruchetTile" text="Constrained"> + </MenuItem> + </Menu> + </MenuBar> + <GridTileCanvas AnchorPane.topAnchor="40." + xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml" fx:id="gridTileCanvas"> <tileWidth> - <Double fx:value="10"/> + <Double fx:value="20"/> </tileWidth> <tileHeight> - <Double fx:value="10"/> + <Double fx:value="20"/> </tileHeight> <numberOfColumns> - <Integer fx:value="100"/> + <Integer fx:value="50"/> </numberOfColumns> <numberOfRows> - <Integer fx:value="100"/> + <Integer fx:value="50"/> </numberOfRows> </GridTileCanvas> </AnchorPane> \ No newline at end of file