From 1b0e0488216567a0e5fa1f67e5748e1c4ae605de Mon Sep 17 00:00:00 2001
From: arnaudlabourel <arnaud.labourel@univ-amu.fr>
Date: Fri, 8 Oct 2021 15:10:46 +0200
Subject: [PATCH] =?UTF-8?q?Version=20d=C3=A9finitive?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/main/java/controller/GridController.java  | 76 ++++++++++++++---
 src/main/java/main/MainApp.java               | 16 +---
 src/main/java/model/ArrayGrid.java            | 82 ++++++++++++++++++
 src/main/java/model/ArraySquare.java          | 13 +++
 ...onstrainedRotatedTruchetTileGenerator.java | 25 +++---
 src/main/java/model/EmptyGrid.java            | 48 +++++++++++
 src/main/java/model/EmptyTileGenerator.java   | 10 +++
 src/main/java/model/Grid.java                 | 84 ++-----------------
 .../java/model/RandomTileSetGenerator.java    | 23 +++++
 .../java/model/RandomWangTileGenerator.java   |  1 +
 src/main/java/model/Square.java               |  1 +
 src/main/java/model/SquareIterator.java       |  4 +-
 src/main/java/model/UniformTileGenerator.java | 14 ++++
 src/main/java/view/GridTileCanvas.java        | 19 +++--
 src/main/resources/view/GridCanvas.fxml       | 38 +++++++--
 15 files changed, 329 insertions(+), 125 deletions(-)
 create mode 100644 src/main/java/model/ArrayGrid.java
 create mode 100644 src/main/java/model/EmptyGrid.java
 create mode 100644 src/main/java/model/EmptyTileGenerator.java
 create mode 100644 src/main/java/model/RandomTileSetGenerator.java
 create mode 100644 src/main/java/model/UniformTileGenerator.java

diff --git a/src/main/java/controller/GridController.java b/src/main/java/controller/GridController.java
index b4f9864..49f0021 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 941edde..be27ef6 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 0000000..312392b
--- /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 3298e58..b470781 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 0f69e7f..f41c280 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 0000000..98b69c1
--- /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 0000000..97f281a
--- /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 becc8e5..96eb89c 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 0000000..2044db7
--- /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 55927e9..7f0e877 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 2849e04..03b1798 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 c970bf2..10cef6e 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 0000000..6b3f137
--- /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 5eb1722..a1fdf23 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 162854f..009d4c0 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
-- 
GitLab