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

---
 build.gradle                                  |  6 +-
 src/main/java/controller/GridController.java  | 11 +++-
 src/main/java/model/ArraySquare.java          | 59 +++++++++++++++++++
 ...onstrainedRotatedTruchetTileGenerator.java | 23 ++++++++
 src/main/java/model/EmptySide.java            | 26 ++++++++
 src/main/java/model/Grid.java                 | 22 +++----
 src/main/java/model/InternalSide.java         | 35 +++++++++++
 .../RandomConstrainedWangTileGenerator.java   | 29 +++++++++
 .../RandomRotatedTruchetTileGenerator.java    | 22 +++++++
 .../model/RandomUniformTileGenerator.java     | 24 ++++++++
 .../RandomWangConstrainedTileGenerator.java   | 53 -----------------
 .../java/model/RandomWangTileGenerator.java   | 27 +++++++++
 src/main/java/model/RotatedTile.java          | 21 +++----
 src/main/java/model/Rotation.java             | 18 ++++++
 src/main/java/model/RotationType.java         |  5 --
 src/main/java/model/Side.java                 | 11 ++++
 src/main/java/model/Square.java               | 48 +++------------
 src/main/java/model/SquareIterator.java       | 20 +++----
 src/main/java/model/Tile.java                 |  7 +--
 src/main/java/model/TruchetTile.java          | 19 ++++++
 src/main/java/model/UniformTile.java          | 14 +++++
 src/main/java/model/WangTile.java             | 49 +++------------
 src/main/java/util/RandomUtil.java            | 16 +++++
 src/main/java/view/GridTileCanvas.java        | 10 +---
 src/test/java/model/TileTest.java             | 29 ---------
 src/test/java/model/WangTileTest.java         | 19 ++++++
 26 files changed, 398 insertions(+), 225 deletions(-)
 create mode 100644 src/main/java/model/ArraySquare.java
 create mode 100644 src/main/java/model/ConstrainedRotatedTruchetTileGenerator.java
 create mode 100644 src/main/java/model/EmptySide.java
 create mode 100644 src/main/java/model/InternalSide.java
 create mode 100644 src/main/java/model/RandomConstrainedWangTileGenerator.java
 create mode 100644 src/main/java/model/RandomRotatedTruchetTileGenerator.java
 create mode 100644 src/main/java/model/RandomUniformTileGenerator.java
 delete mode 100644 src/main/java/model/RandomWangConstrainedTileGenerator.java
 create mode 100644 src/main/java/model/RandomWangTileGenerator.java
 create mode 100644 src/main/java/model/Rotation.java
 delete mode 100644 src/main/java/model/RotationType.java
 create mode 100644 src/main/java/model/Side.java
 create mode 100644 src/main/java/model/TruchetTile.java
 create mode 100644 src/main/java/model/UniformTile.java
 create mode 100644 src/main/java/util/RandomUtil.java
 delete mode 100644 src/test/java/model/TileTest.java
 create mode 100644 src/test/java/model/WangTileTest.java

diff --git a/build.gradle b/build.gradle
index 8231943..b98a21c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -13,9 +13,9 @@ repositories {
 }
 
 dependencies {
-    testImplementation('org.junit.jupiter:junit-jupiter-api:5.8.0',
-            'org.assertj:assertj-core:3.20.2')
-    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.0'
+    testImplementation('org.junit.jupiter:junit-jupiter-api:5.8.1',
+            'org.assertj:assertj-core:3.21.0')
+    testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
 }
 
 test {
diff --git a/src/main/java/controller/GridController.java b/src/main/java/controller/GridController.java
index a0995b5..b4f9864 100644
--- a/src/main/java/controller/GridController.java
+++ b/src/main/java/controller/GridController.java
@@ -2,7 +2,10 @@ package controller;
 
 import javafx.fxml.FXML;
 import javafx.scene.paint.Color;
-import model.RandomWangConstrainedTileGenerator;
+import model.ConstrainedRotatedTruchetTileGenerator;
+import model.RandomConstrainedWangTileGenerator;
+import model.RandomRotatedTruchetTileGenerator;
+import model.RandomWangTileGenerator;
 import view.GridTileCanvas;
 
 import java.util.List;
@@ -13,8 +16,10 @@ public class GridController {
   public GridTileCanvas gridTileCanvas;
 
   public void initialize() {
-    gridTileCanvas.initializeGrid(new RandomWangConstrainedTileGenerator(List.of(Color.BLUE, Color.RED, Color.BLACK, Color.GREEN),
-            new Random(0)));
+    //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));
   }
   public void draw() {
     gridTileCanvas.drawGrid();
diff --git a/src/main/java/model/ArraySquare.java b/src/main/java/model/ArraySquare.java
new file mode 100644
index 0000000..3298e58
--- /dev/null
+++ b/src/main/java/model/ArraySquare.java
@@ -0,0 +1,59 @@
+package model;
+
+import java.util.List;
+
+public class ArraySquare implements Square {
+  private static final Tile EMPTY_TILE = new UniformTile(EmptySide.EMPTY_SIDE);
+  private static final Square EMPTY_SQUARE = new ArraySquare();
+
+  private Tile tile = EMPTY_TILE;
+
+  private final Square[] neighborhood = new Square[CardinalDirection.NUMBER_OF_DIRECTIONS];
+
+  public ArraySquare() {
+    setEmptyNeighborhood();
+  }
+
+  private void setEmptyNeighborhood(){
+    for(CardinalDirection direction : CardinalDirection.values())
+      setNeighbor(EMPTY_SQUARE, direction);
+  }
+
+  public Tile getTile(){
+    return tile;
+  }
+
+  public void put(Tile tile) {
+    this.tile = tile;
+  }
+
+  public void setNeighbor(Square neighbor, CardinalDirection direction) {
+    this.neighborhood[direction.ordinal()] = neighbor;
+  }
+
+  public Square getNeighbor(CardinalDirection direction) {
+    return this.neighborhood[direction.ordinal()];
+  }
+
+  @Override
+  public boolean accept(Tile tile) {
+    for(CardinalDirection direction : CardinalDirection.values()){
+      if(!accept(tile, direction))
+        return false;
+    }
+    return true;
+  }
+
+  public boolean accept(Tile tile, CardinalDirection direction) {
+    return getIncidentNeighboringSide(direction).accept(tile.side(direction));
+  }
+
+  private Side getIncidentNeighboringSide(CardinalDirection direction) {
+    return getNeighbor(direction).getTile().side(direction.oppositeDirection());
+  }
+
+  @Override
+  public List<Side> compatibleSides(List<Side> sides, CardinalDirection direction) {
+    return getIncidentNeighboringSide(direction).compatibleSides(sides);
+  }
+}
diff --git a/src/main/java/model/ConstrainedRotatedTruchetTileGenerator.java b/src/main/java/model/ConstrainedRotatedTruchetTileGenerator.java
new file mode 100644
index 0000000..0f69e7f
--- /dev/null
+++ b/src/main/java/model/ConstrainedRotatedTruchetTileGenerator.java
@@ -0,0 +1,23 @@
+package model;
+
+import javafx.scene.paint.Color;
+
+public class ConstrainedRotatedTruchetTileGenerator implements TileGenerator{
+  private final Tile truchetTile;
+
+  public ConstrainedRotatedTruchetTileGenerator(Color color1, Color color2) {
+    this.truchetTile = new TruchetTile(new InternalSide(color1), new InternalSide(color2));
+  }
+
+  @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);
+  }
+
+}
diff --git a/src/main/java/model/EmptySide.java b/src/main/java/model/EmptySide.java
new file mode 100644
index 0000000..ec97721
--- /dev/null
+++ b/src/main/java/model/EmptySide.java
@@ -0,0 +1,26 @@
+package model;
+
+import javafx.scene.paint.Color;
+
+import java.util.List;
+
+public class EmptySide implements Side {
+  public static final Side EMPTY_SIDE = new EmptySide();
+
+  private EmptySide(){}
+
+  @Override
+  public boolean accept(Side side) {
+    return true;
+  }
+
+  @Override
+  public List<Side> compatibleSides(List<Side> sides) {
+    return sides;
+  }
+
+  @Override
+  public Color color() {
+    return Color.WHITE;
+  }
+}
diff --git a/src/main/java/model/Grid.java b/src/main/java/model/Grid.java
index 91444e3..becc8e5 100644
--- a/src/main/java/model/Grid.java
+++ b/src/main/java/model/Grid.java
@@ -1,12 +1,11 @@
 package model;
 import java.util.Iterator;
-import java.util.Optional;
 
 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.
    *
@@ -22,7 +21,7 @@ public class Grid implements Iterable<Square> {
       throw new IllegalArgumentException("The number of columns must be positive and not equal to " + numberOfColumns);
     this.numberOfRows = numberOfRows;
     this.numberOfColumns = numberOfColumns;
-    squares = new Square[getNumberOfRows()][getNumberOfColumns()];
+    squares = new ArraySquare[getNumberOfRows()][getNumberOfColumns()];
     initializeGrid();
   }
 
@@ -34,7 +33,7 @@ public class Grid implements Iterable<Square> {
   private void initializeSquares() {
     for(int row = 0; row < getNumberOfRows(); row++)
       for(int column = 0; column < getNumberOfColumns(); column++)
-        squares[row][column] = new Square();
+        squares[row][column] = new ArraySquare();
   }
 
   private void initializeNeighborhood() {
@@ -43,8 +42,9 @@ public class Grid implements Iterable<Square> {
           for (CardinalDirection direction : CardinalDirection.values()){
             int rowNeighbor = row + direction.deltaRow;
             int columnNeighbor = column + direction.deltaColumn;
-            if(containsCoordinates(rowNeighbor, columnNeighbor))
-              squares[row][column].setNeighboringSquare(squares[rowNeighbor][columnNeighbor], direction);
+            Square neighboringSquare =
+                    containsCoordinates(rowNeighbor, columnNeighbor) ? getSquare(rowNeighbor, columnNeighbor) : outOfGridSquare;
+            getSquare(row, column).setNeighbor(neighboringSquare, direction);
           }
         }
   }
@@ -63,10 +63,6 @@ public class Grid implements Iterable<Square> {
     return new SquareIterator(this);
   }
 
-  public Optional<Tile> getTile(int rowIndex, int columnIndex) {
-    return getSquare(rowIndex, columnIndex).getSquareTile();
-  }
-
   public Square getSquare(int rowIndex, int columnIndex) {
     return squares[rowIndex][columnIndex];
   }
@@ -81,10 +77,6 @@ public class Grid implements Iterable<Square> {
 
   public void fill(TileGenerator tileGenerator){
     for(Square square : this)
-      square.add(tileGenerator.nextTile(square));
-  }
-
-  public boolean hasTile(int row, int column) {
-    return getSquare(row, column).hasTile();
+      square.put(tileGenerator.nextTile(square));
   }
 }
diff --git a/src/main/java/model/InternalSide.java b/src/main/java/model/InternalSide.java
new file mode 100644
index 0000000..11b1b7a
--- /dev/null
+++ b/src/main/java/model/InternalSide.java
@@ -0,0 +1,35 @@
+package model;
+
+import javafx.scene.paint.Color;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class InternalSide implements Side {
+  private final Color color;
+
+  public InternalSide(Color color) {
+    this.color = color;
+  }
+
+  @Override
+  public boolean accept(Side side) {
+    return color.equals(side.color());
+  }
+
+  @Override
+  public List<Side> compatibleSides(List<Side> sides) {
+    List<Side> filteredSides = new ArrayList<>();
+    for(Side side : sides){
+      if(this.accept(side)){
+        filteredSides.add(side);
+      }
+    }
+    return filteredSides;
+  }
+
+  @Override
+  public Color color() {
+    return color;
+  }
+}
diff --git a/src/main/java/model/RandomConstrainedWangTileGenerator.java b/src/main/java/model/RandomConstrainedWangTileGenerator.java
new file mode 100644
index 0000000..72dce8f
--- /dev/null
+++ b/src/main/java/model/RandomConstrainedWangTileGenerator.java
@@ -0,0 +1,29 @@
+package model;
+
+import javafx.scene.paint.Color;
+import util.RandomUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+public class RandomConstrainedWangTileGenerator implements TileGenerator {
+  private final List<Side> availableSides = new ArrayList<>();
+  private final Random randomGenerator;
+
+  public RandomConstrainedWangTileGenerator(List<Color> colors, Random randomGenerator) {
+    for(Color color : colors)
+      this.availableSides.add(new InternalSide(color));
+    this.randomGenerator = randomGenerator;
+  }
+
+  @Override
+  public Tile nextTile(Square square) {
+    Side[] sidesOfTile = new Side[CardinalDirection.NUMBER_OF_DIRECTIONS];
+    for(CardinalDirection direction : CardinalDirection.values()){
+      List<Side> compatibleSides = square.compatibleSides(availableSides, direction);
+      sidesOfTile[direction.ordinal()] = RandomUtil.randomElement(compatibleSides, randomGenerator);
+    }
+    return new WangTile(sidesOfTile);
+  }
+}
diff --git a/src/main/java/model/RandomRotatedTruchetTileGenerator.java b/src/main/java/model/RandomRotatedTruchetTileGenerator.java
new file mode 100644
index 0000000..69b8a53
--- /dev/null
+++ b/src/main/java/model/RandomRotatedTruchetTileGenerator.java
@@ -0,0 +1,22 @@
+package model;
+
+import javafx.scene.paint.Color;
+import util.RandomUtil;
+
+import java.util.Random;
+
+public class RandomRotatedTruchetTileGenerator implements TileGenerator{
+  private final Random randomGenerator;
+  private final Tile truchetTile;
+
+  public RandomRotatedTruchetTileGenerator(Color color1, Color color2, Random randomGenerator) {
+    this.randomGenerator = randomGenerator;
+    this.truchetTile = new TruchetTile(new InternalSide(color1), new InternalSide(color2));
+  }
+
+  @Override
+  public Tile nextTile(Square square) {
+    Rotation randomRotation = RandomUtil.randomElement(Rotation.values(), randomGenerator);
+    return new RotatedTile(truchetTile, randomRotation);
+  }
+}
diff --git a/src/main/java/model/RandomUniformTileGenerator.java b/src/main/java/model/RandomUniformTileGenerator.java
new file mode 100644
index 0000000..636116a
--- /dev/null
+++ b/src/main/java/model/RandomUniformTileGenerator.java
@@ -0,0 +1,24 @@
+package model;
+
+import javafx.scene.paint.Color;
+import util.RandomUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+public class RandomUniformTileGenerator implements TileGenerator{
+  private final List<Side> colors = new ArrayList<>();
+  private final Random randomGenerator;
+
+  public RandomUniformTileGenerator(List<Color> colors, Random randomGenerator) {
+    for(Color color : colors)
+      this.colors.add(new InternalSide(color));
+    this.randomGenerator = randomGenerator;
+  }
+
+  @Override
+  public Tile nextTile(Square square) {
+    return new UniformTile(RandomUtil.randomElement(colors, randomGenerator));
+  }
+}
diff --git a/src/main/java/model/RandomWangConstrainedTileGenerator.java b/src/main/java/model/RandomWangConstrainedTileGenerator.java
deleted file mode 100644
index d50ab02..0000000
--- a/src/main/java/model/RandomWangConstrainedTileGenerator.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package model;
-
-import javafx.scene.paint.Color;
-
-import java.util.List;
-import java.util.Optional;
-import java.util.Random;
-
-public class RandomWangConstrainedTileGenerator implements TileGenerator {
-
-  private final List<Color> colors;
-  private final Random randomGenerator;
-
-  public RandomWangConstrainedTileGenerator(List<Color> colors, Random randomGenerator) {
-    this.colors = colors;
-    this.randomGenerator = randomGenerator;
-  }
-
-  private Color randomColor(){
-    return colors.get(randomGenerator.nextInt(colors.size()));
-  }
-
-  public WangTile nextTile(){
-    Color[] colorsOfTile = new Color[4];
-    for(int index = 0; index < 4; index++)
-      colorsOfTile[index] = randomColor();
-    return new WangTile(colorsOfTile);
-  }
-
-  public WangTile nextUniformTile(){
-    Color[] colorsOfTile = new Color[4];
-    Color randomColor = randomColor();
-    for(int index = 0; index < 4; index++)
-      colorsOfTile[index] = randomColor;
-    return new WangTile(colorsOfTile);
-  }
-  @Override
-  public Tile nextTile(Square square) {
-    Color[] colorsOfTile = new Color[4];
-    for(CardinalDirection side : CardinalDirection.values()){
-      Optional<Tile> optionalSquareTile = square.getNeighboringSquare(side);
-      if(optionalSquareTile.isPresent()){
-        Tile neighboringTile = optionalSquareTile.get();
-        colorsOfTile[side.ordinal()] = neighboringTile.getSideColor(side.oppositeDirection());
-      }
-      else {
-        colorsOfTile[side.ordinal()] = randomColor();
-      }
-    }
-    return new WangTile(colorsOfTile);
-  }
-
-}
diff --git a/src/main/java/model/RandomWangTileGenerator.java b/src/main/java/model/RandomWangTileGenerator.java
new file mode 100644
index 0000000..55927e9
--- /dev/null
+++ b/src/main/java/model/RandomWangTileGenerator.java
@@ -0,0 +1,27 @@
+package model;
+
+import javafx.scene.paint.Color;
+import util.RandomUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+public class RandomWangTileGenerator implements TileGenerator{
+  private final List<Side> availableSides = new ArrayList<>();
+  private final Random randomGenerator;
+
+  public RandomWangTileGenerator(List<Color> colors, Random randomGenerator) {
+    for(Color color : colors)
+      this.availableSides.add(new InternalSide(color));
+    this.randomGenerator = randomGenerator;
+  }
+  @Override
+  public Tile nextTile(Square square) {
+    Side[] sidesOfTile = new Side[CardinalDirection.NUMBER_OF_DIRECTIONS];
+    for(CardinalDirection direction : CardinalDirection.values()){
+      sidesOfTile[direction.ordinal()] = RandomUtil.randomElement(availableSides, randomGenerator);
+    }
+    return new WangTile(sidesOfTile);
+  }
+}
diff --git a/src/main/java/model/RotatedTile.java b/src/main/java/model/RotatedTile.java
index 290dcaa..e00ee52 100644
--- a/src/main/java/model/RotatedTile.java
+++ b/src/main/java/model/RotatedTile.java
@@ -1,23 +1,16 @@
 package model;
 
-import javafx.scene.canvas.GraphicsContext;
-import javafx.scene.paint.Color;
-
 public class RotatedTile implements Tile {
+  private final Tile tile;
+  private final Rotation rotationType;
 
-
-  @Override
-  public boolean isCompatibleWith(Tile neighbor, CardinalDirection side) {
-    return false;
-  }
-
-  @Override
-  public Tile rotation(RotationType rotation) {
-    return null;
+  public RotatedTile(Tile tile, Rotation rotationType) {
+    this.tile = tile;
+    this.rotationType = rotationType;
   }
 
   @Override
-  public Color getSideColor(CardinalDirection side) {
-    return null;
+  public Side side(CardinalDirection direction) {
+    return tile.side(rotationType.rotatedDirection(direction));
   }
 }
diff --git a/src/main/java/model/Rotation.java b/src/main/java/model/Rotation.java
new file mode 100644
index 0000000..ffd3407
--- /dev/null
+++ b/src/main/java/model/Rotation.java
@@ -0,0 +1,18 @@
+package model;
+
+public enum Rotation {
+  NO_TURN(0),
+  QUARTER_TURN(1),
+  HALF_TURN(2),
+  THREE_QUARTER_TURN(3);
+
+  private final int NumberOfQuarterTurns;
+
+  Rotation(int numberOfQuarterTurns) {
+    NumberOfQuarterTurns = numberOfQuarterTurns;
+  }
+
+  public CardinalDirection rotatedDirection(CardinalDirection side) {
+    return CardinalDirection.values()[(side.ordinal() + this.NumberOfQuarterTurns) % CardinalDirection.NUMBER_OF_DIRECTIONS];
+  }
+}
diff --git a/src/main/java/model/RotationType.java b/src/main/java/model/RotationType.java
deleted file mode 100644
index bb49632..0000000
--- a/src/main/java/model/RotationType.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package model;
-
-public enum RotationType {
-  NO_TURN, QUARTER_TURN, HALF_TURN, THREE_QUARTER_TURN
-}
diff --git a/src/main/java/model/Side.java b/src/main/java/model/Side.java
new file mode 100644
index 0000000..4c66de4
--- /dev/null
+++ b/src/main/java/model/Side.java
@@ -0,0 +1,11 @@
+package model;
+
+import javafx.scene.paint.Color;
+
+import java.util.List;
+
+public interface Side {
+  List<Side> compatibleSides(List<Side> sides);
+  Color color();
+  boolean accept(Side side);
+}
diff --git a/src/main/java/model/Square.java b/src/main/java/model/Square.java
index 6675523..2849e04 100644
--- a/src/main/java/model/Square.java
+++ b/src/main/java/model/Square.java
@@ -1,42 +1,12 @@
 package model;
 
-import java.util.Optional;
-
-public class Square {
-
-  private Tile tile;
-  private Square[] neighboringSquares;
-
-  private Square(Tile tile, Square[] neighboringSquares) {
-    this.tile = tile;
-    this.neighboringSquares = neighboringSquares;
-  }
-
-  public Square(){
-    this(null, new Square[CardinalDirection.NUMBER_OF_DIRECTIONS]);
-  }
-
-  public Optional<Tile> getSquareTile(){
-    if(!hasTile())
-      return Optional.empty();
-    return Optional.of(tile);
-  }
-
-  public void add(Tile tile) {
-    this.tile = tile;
-  }
-
-  public boolean hasTile() {
-    return tile != null;
-  }
-
-  public Optional<Tile> getNeighboringSquare(CardinalDirection side) {
-    if (neighboringSquares[side.ordinal()] == null)
-      return Optional.empty();
-    return neighboringSquares[side.ordinal()].getSquareTile();
-  }
-
-  public void setNeighboringSquare(Square neighboringSquare, CardinalDirection direction) {
-    this.neighboringSquares[direction.ordinal()] = neighboringSquare;
-  }
+import java.util.List;
+
+public interface Square {
+  boolean accept(Tile tile);
+  void put(Tile tile);
+  Tile getTile();
+  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 52960a2..c970bf2 100644
--- a/src/main/java/model/SquareIterator.java
+++ b/src/main/java/model/SquareIterator.java
@@ -3,28 +3,28 @@ package model;
 import java.util.Iterator;
 
 public class SquareIterator implements Iterator<Square> {
-  private int rowIndex;
-  private int columnIndex;
+  private int rowNext;
+  private int columnNext;
   private final Grid grid;
 
   SquareIterator(Grid grid) {
-    this.rowIndex = 0;
-    this.columnIndex = 0;
+    this.rowNext = 0;
+    this.columnNext = 0;
     this.grid = grid;
   }
 
   @Override
   public boolean hasNext() {
-    return rowIndex < grid.getNumberOfRows();
+    return rowNext < grid.getNumberOfRows();
   }
 
   @Override
   public Square next() {
-    final Square result = grid.getSquare(rowIndex, columnIndex);
-    columnIndex = (columnIndex +1) % grid.getNumberOfColumns();
-    if(columnIndex == 0){
-      rowIndex++;
+    final Square next = grid.getSquare(rowNext, columnNext);
+    columnNext = (columnNext +1) % grid.getNumberOfColumns();
+    if(columnNext == 0){
+      rowNext++;
     }
-    return result;
+    return next;
   }
 }
diff --git a/src/main/java/model/Tile.java b/src/main/java/model/Tile.java
index c75dcb7..ef290d2 100644
--- a/src/main/java/model/Tile.java
+++ b/src/main/java/model/Tile.java
@@ -1,10 +1,5 @@
 package model;
 
-import javafx.scene.canvas.GraphicsContext;
-import javafx.scene.paint.Color;
-
 public interface Tile {
-  boolean isCompatibleWith(Tile neighbor, CardinalDirection side);
-  Tile rotation(RotationType rotation);
-  Color getSideColor(CardinalDirection side);
+  Side side(CardinalDirection direction);
 }
diff --git a/src/main/java/model/TruchetTile.java b/src/main/java/model/TruchetTile.java
new file mode 100644
index 0000000..46bfb2e
--- /dev/null
+++ b/src/main/java/model/TruchetTile.java
@@ -0,0 +1,19 @@
+package model;
+
+public class TruchetTile implements Tile{
+  private final Side northWestColor;
+  private final Side southEastColor;
+
+  public TruchetTile(Side northWestColor, Side southEastColor) {
+    this.northWestColor = northWestColor;
+    this.southEastColor = southEastColor;
+  }
+
+  @Override
+  public Side side(CardinalDirection direction) {
+    return switch (direction){
+      case SOUTH, EAST -> southEastColor;
+      case NORTH, WEST -> northWestColor;
+    };
+  }
+}
diff --git a/src/main/java/model/UniformTile.java b/src/main/java/model/UniformTile.java
new file mode 100644
index 0000000..89ea2db
--- /dev/null
+++ b/src/main/java/model/UniformTile.java
@@ -0,0 +1,14 @@
+package model;
+
+public class UniformTile implements Tile{
+  private final Side side;
+
+  public UniformTile(Side side) {
+    this.side = side;
+  }
+
+  @Override
+  public Side side(CardinalDirection direction) {
+    return side;
+  }
+}
diff --git a/src/main/java/model/WangTile.java b/src/main/java/model/WangTile.java
index ecfa87b..4d02bf7 100644
--- a/src/main/java/model/WangTile.java
+++ b/src/main/java/model/WangTile.java
@@ -1,50 +1,17 @@
 package model;
 
-import javafx.scene.canvas.GraphicsContext;
-import javafx.scene.paint.Color;
-
-import java.util.Arrays;
-import java.util.List;
-
 public class WangTile implements Tile {
-  private static final int NUMBER_OF_SIDES = 4;
-  private final Color[] colors = new Color[NUMBER_OF_SIDES];
 
-  public WangTile(Color[] colors) {
-    if(colors.length != NUMBER_OF_SIDES)
-      throw new IllegalArgumentException("A tile is defined by " + NUMBER_OF_SIDES
-                                            + "and not" + colors.length + "sides.");
-    System.arraycopy(colors, 0, this.colors, 0, NUMBER_OF_SIDES);
-  }
+  private final Side[] sides = new Side[CardinalDirection.NUMBER_OF_DIRECTIONS];
 
-  public Color getSideColor(CardinalDirection direction){
-    return colors[direction.ordinal()];
+  public WangTile(Side[] sides) {
+    if(sides.length != CardinalDirection.NUMBER_OF_DIRECTIONS)
+      throw new IllegalArgumentException("A tile is defined by " + CardinalDirection.NUMBER_OF_DIRECTIONS
+                                            + "and not" + sides.length + "sides.");
+    System.arraycopy(sides, 0, this.sides, 0, CardinalDirection.NUMBER_OF_DIRECTIONS);
   }
 
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) return true;
-    if (o == null || getClass() != o.getClass()) return false;
-    WangTile tile = (WangTile) o;
-    return Arrays.equals(colors, tile.colors);
+  public Side side(CardinalDirection direction){
+    return sides[direction.ordinal()];
   }
-
-  @Override
-  public int hashCode() {
-    return Arrays.hashCode(colors);
-  }
-
-
-
-  @Override
-  public boolean isCompatibleWith(Tile neighbor, CardinalDirection side) {
-    return false;
-  }
-
-  @Override
-  public Tile rotation(RotationType rotation) {
-    return null;
-  }
-
-
 }
diff --git a/src/main/java/util/RandomUtil.java b/src/main/java/util/RandomUtil.java
new file mode 100644
index 0000000..8ccb36f
--- /dev/null
+++ b/src/main/java/util/RandomUtil.java
@@ -0,0 +1,16 @@
+package util;
+
+import java.util.List;
+import java.util.Random;
+
+public final class RandomUtil {
+  private RandomUtil(){}
+
+  public static <T> T randomElement(List<T> elements, Random random){
+    return elements.get(random.nextInt(elements.size()));
+  }
+
+  public static <T> T randomElement(T[] elements, Random random){
+    return elements[random.nextInt(elements.length)];
+  }
+}
diff --git a/src/main/java/view/GridTileCanvas.java b/src/main/java/view/GridTileCanvas.java
index 5dede2f..5eb1722 100644
--- a/src/main/java/view/GridTileCanvas.java
+++ b/src/main/java/view/GridTileCanvas.java
@@ -4,9 +4,7 @@ import javafx.beans.NamedArg;
 import javafx.scene.canvas.Canvas;
 import javafx.scene.canvas.GraphicsContext;
 import model.*;
-
 import java.util.List;
-import java.util.Optional;
 
 public class GridTileCanvas extends Canvas {
 
@@ -44,12 +42,10 @@ public class GridTileCanvas extends Canvas {
   }
 
   public void drawGridTile(Grid tileGrid){
-    GraphicsContext graphicsContext = getGraphicsContext2D();
     for(int row = 0; row < numberOfRows; row++)
       for(int column = 0; column < numberOfColumns; column++){
-        Optional<Tile> tile = tileGrid.getTile(row, column);
-        if(tile.isPresent())
-          drawTile(tile.get(), column * tileWidth, row * tileHeight);
+        Tile tile = tileGrid.getSquare(row, column).getTile();
+        drawTile(tile, column * tileWidth, row * tileHeight);
       }
   }
 
@@ -67,7 +63,7 @@ public class GridTileCanvas extends Canvas {
       xPoints[index] =  x + (cornerTypes.get(index).getXPosition() * tileWidth);
       yPoints[index] =  y + (cornerTypes.get(index).getYPosition() * tileHeight);
     }
-    graphicsContext.setFill(tile.getSideColor(side));
+    graphicsContext.setFill(tile.side(side).color());
     graphicsContext.fillPolygon(xPoints, yPoints, 3);
   }
 }
diff --git a/src/test/java/model/TileTest.java b/src/test/java/model/TileTest.java
deleted file mode 100644
index 074d8ea..0000000
--- a/src/test/java/model/TileTest.java
+++ /dev/null
@@ -1,29 +0,0 @@
-package model;
-
-import javafx.scene.paint.Color;
-import org.junit.jupiter.api.Test;
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class TileTest {
-  @Test
-  void testGetColor(){
-    WangTile tile = new WangTile(new Color[]{Color.BLACK, Color.BLUE, Color.WHITE, Color.BLUE});
-    assertThat(tile.getSideColor(CardinalDirection.NORTH)).isEqualTo(Color.BLACK);
-    assertThat(tile.getSideColor(CardinalDirection.EAST)).isEqualTo(Color.BLUE);
-    assertThat(tile.getSideColor(CardinalDirection.SOUTH)).isEqualTo(Color.WHITE);
-    assertThat(tile.getSideColor(CardinalDirection.WEST)).isEqualTo(Color.BLUE);
-  }
-
-  @Test
-  void testEquals(){
-    Color[] colors1 = new Color[]{Color.BLACK, Color.BLUE, Color.WHITE, Color.BLUE};
-    Color[] colors2 = new Color[]{Color.BLACK, Color.BLUE, Color.WHITE, Color.WHITE};
-    WangTile tile1 = new WangTile(colors1);
-    WangTile tile2 = new WangTile(colors1);
-    WangTile tile3 = new WangTile(colors2);
-    assertThat(tile1)
-            .isEqualTo(tile1)
-            .isEqualTo(tile2)
-            .isNotEqualTo(tile3);
-  }
-}
diff --git a/src/test/java/model/WangTileTest.java b/src/test/java/model/WangTileTest.java
new file mode 100644
index 0000000..422b928
--- /dev/null
+++ b/src/test/java/model/WangTileTest.java
@@ -0,0 +1,19 @@
+package model;
+
+import javafx.scene.paint.Color;
+import org.junit.jupiter.api.Test;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class WangTileTest {
+
+  @Test
+  void testGetColor(){
+    WangTile tile = new WangTile(new Side[]{new InternalSide(Color.BLACK), new InternalSide(Color.BLUE),
+            new InternalSide(Color.WHITE), new InternalSide(Color.BLUE)});
+    assertThat(tile.side(CardinalDirection.NORTH).color()).isEqualTo(Color.BLACK);
+    assertThat(tile.side(CardinalDirection.EAST).color()).isEqualTo(Color.BLUE);
+    assertThat(tile.side(CardinalDirection.SOUTH).color()).isEqualTo(Color.WHITE);
+    assertThat(tile.side(CardinalDirection.WEST).color()).isEqualTo(Color.BLUE);
+  }
+
+}
-- 
GitLab