diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..1ca2791ac9f020514c76d0f18cf6359445967815
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,34 @@
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# Idea
+.idea/
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
+
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..09a6c289f945ec428a53dbc8f3aab2adec420fd4
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,40 @@
+image: openjdk:17-alpine
+
+variables:
+  GRADLE_OPTS: "-Dorg.gradle.daemon=false"
+
+before_script:
+  - export GRADLE_USER_HOME=`pwd`/.gradle
+
+cache:
+  paths:
+    - .gradle/wrapper
+    - .gradle/caches
+
+stages:
+  - build
+  - test
+
+build:
+  stage: build
+  script: ./gradlew --build-cache assemble
+  cache:
+    key: "$CI_COMMIT_REF_NAME"
+    policy: push
+    paths:
+      - build
+      - .gradle
+
+java:
+  stage: test
+  script: ./gradlew test
+  artifacts:
+    when: always
+    reports:
+      junit: build/test-results/test/**/TEST-*.xml
+  cache:
+    key: "$CI_COMMIT_REF_NAME"
+    policy: pull
+    paths:
+      - build
+      - .gradle
\ No newline at end of file
diff --git a/.gradle/7.4/checksums/checksums.lock b/.gradle/7.4/checksums/checksums.lock
deleted file mode 100644
index df54c1e0932a6aad9b35fe2f5781753d92dd27c2..0000000000000000000000000000000000000000
Binary files a/.gradle/7.4/checksums/checksums.lock and /dev/null differ
diff --git a/.gradle/7.4/checksums/md5-checksums.bin b/.gradle/7.4/checksums/md5-checksums.bin
deleted file mode 100644
index 38740cef473d59e77cc7580e7c7e168c289010c2..0000000000000000000000000000000000000000
Binary files a/.gradle/7.4/checksums/md5-checksums.bin and /dev/null differ
diff --git a/.gradle/7.4/checksums/sha1-checksums.bin b/.gradle/7.4/checksums/sha1-checksums.bin
deleted file mode 100644
index 37d18a5f1d3ac5802ec2e11e6e2ee389d38eabe7..0000000000000000000000000000000000000000
Binary files a/.gradle/7.4/checksums/sha1-checksums.bin and /dev/null differ
diff --git a/.gradle/7.4/dependencies-accessors/dependencies-accessors.lock b/.gradle/7.4/dependencies-accessors/dependencies-accessors.lock
deleted file mode 100644
index 9ea5ddcee208651ce5fe944ac8385c34443ae9f3..0000000000000000000000000000000000000000
Binary files a/.gradle/7.4/dependencies-accessors/dependencies-accessors.lock and /dev/null differ
diff --git a/.gradle/7.4/dependencies-accessors/gc.properties b/.gradle/7.4/dependencies-accessors/gc.properties
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/.gradle/7.4/executionHistory/executionHistory.bin b/.gradle/7.4/executionHistory/executionHistory.bin
deleted file mode 100644
index 8044f8db540d8ca16951815ac998f6158a86ba9c..0000000000000000000000000000000000000000
Binary files a/.gradle/7.4/executionHistory/executionHistory.bin and /dev/null differ
diff --git a/.gradle/7.4/executionHistory/executionHistory.lock b/.gradle/7.4/executionHistory/executionHistory.lock
deleted file mode 100644
index e57456dc4f9a187338a1af68d935fbf5cffe29da..0000000000000000000000000000000000000000
Binary files a/.gradle/7.4/executionHistory/executionHistory.lock and /dev/null differ
diff --git a/.gradle/7.4/fileChanges/last-build.bin b/.gradle/7.4/fileChanges/last-build.bin
deleted file mode 100644
index f76dd238ade08917e6712764a16a22005a50573d..0000000000000000000000000000000000000000
Binary files a/.gradle/7.4/fileChanges/last-build.bin and /dev/null differ
diff --git a/.gradle/7.4/fileHashes/fileHashes.bin b/.gradle/7.4/fileHashes/fileHashes.bin
deleted file mode 100644
index ac4d206fd6144671088bac4e8af72f9d24c99d8f..0000000000000000000000000000000000000000
Binary files a/.gradle/7.4/fileHashes/fileHashes.bin and /dev/null differ
diff --git a/.gradle/7.4/fileHashes/fileHashes.lock b/.gradle/7.4/fileHashes/fileHashes.lock
deleted file mode 100644
index f382ced7e8f10e14ccd723be3c74dae1c97aa72b..0000000000000000000000000000000000000000
Binary files a/.gradle/7.4/fileHashes/fileHashes.lock and /dev/null differ
diff --git a/.gradle/7.4/gc.properties b/.gradle/7.4/gc.properties
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock
deleted file mode 100644
index f7492f18c6ecf67db5af3279f7c8498953313f0a..0000000000000000000000000000000000000000
Binary files a/.gradle/buildOutputCleanup/buildOutputCleanup.lock and /dev/null differ
diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties
deleted file mode 100644
index 44aa1b1b004c00c3ca26d0558f1cac2374def7cc..0000000000000000000000000000000000000000
--- a/.gradle/buildOutputCleanup/cache.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-#Thu Nov 03 08:22:32 CET 2022
-gradle.version=7.4
diff --git a/.gradle/buildOutputCleanup/outputFiles.bin b/.gradle/buildOutputCleanup/outputFiles.bin
deleted file mode 100644
index 22247e075c97d900294472751d70aa6810330c43..0000000000000000000000000000000000000000
Binary files a/.gradle/buildOutputCleanup/outputFiles.bin and /dev/null differ
diff --git a/.gradle/vcs-1/gc.properties b/.gradle/vcs-1/gc.properties
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/.idea/.gitignore b/.idea/.gitignore
deleted file mode 100644
index 13566b81b018ad684f3a35fee301741b2734c8f4..0000000000000000000000000000000000000000
--- a/.idea/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Editor-based HTTP Client requests
-/httpRequests/
-# Datasource local storage ignored files
-/dataSources/
-/dataSources.local.xml
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
deleted file mode 100644
index 659bf43190d1afbfe1907e2e5e2bd75ad761dfb3..0000000000000000000000000000000000000000
--- a/.idea/compiler.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="CompilerConfiguration">
-    <bytecodeTargetLevel target="16" />
-  </component>
-</project>
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
deleted file mode 100644
index ba1ec5c7e20c12eb5b893684698eab151c4a8803..0000000000000000000000000000000000000000
--- a/.idea/gradle.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="GradleSettings">
-    <option name="linkedExternalProjectsSettings">
-      <GradleProjectSettings>
-        <option name="distributionType" value="DEFAULT_WRAPPED" />
-        <option name="externalProjectPath" value="$PROJECT_DIR$" />
-        <option name="modules">
-          <set>
-            <option value="$PROJECT_DIR$" />
-          </set>
-        </option>
-      </GradleProjectSettings>
-    </option>
-  </component>
-</project>
\ No newline at end of file
diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml
deleted file mode 100644
index fdc392fe877c32ab51d532fa67f65ff2e75e9061..0000000000000000000000000000000000000000
--- a/.idea/jarRepositories.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="RemoteRepositoriesConfiguration">
-    <remote-repository>
-      <option name="id" value="central" />
-      <option name="name" value="Maven Central repository" />
-      <option name="url" value="https://repo1.maven.org/maven2" />
-    </remote-repository>
-    <remote-repository>
-      <option name="id" value="jboss.community" />
-      <option name="name" value="JBoss Community repository" />
-      <option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
-    </remote-repository>
-    <remote-repository>
-      <option name="id" value="MavenRepo" />
-      <option name="name" value="MavenRepo" />
-      <option name="url" value="https://repo.maven.apache.org/maven2/" />
-    </remote-repository>
-  </component>
-</project>
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
deleted file mode 100644
index 3db7abf849bb2eb6f6e84f40abd01c1aba9033b5..0000000000000000000000000000000000000000
--- a/.idea/misc.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="ExternalStorageConfigurationManager" enabled="true" />
-  <component name="FrameworkDetectionExcludesConfiguration">
-    <file type="web" url="file://$PROJECT_DIR$" />
-  </component>
-  <component name="ProjectRootManager" version="2" languageLevel="JDK_16" default="true" project-jdk-name="corretto-16" project-jdk-type="JavaSDK">
-    <output url="file://$PROJECT_DIR$/out" />
-  </component>
-</project>
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
deleted file mode 100644
index 94a25f7f4cb416c083d265558da75d457237d671..0000000000000000000000000000000000000000
--- a/.idea/vcs.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="VcsDirectoryMappings">
-    <mapping directory="$PROJECT_DIR$" vcs="Git" />
-  </component>
-</project>
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 10ee756a7c605e5a18cf5342e0a07c5c64e02b83..f51eff276a6ecca48a4999b7ecb22f85c5c22429 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,26 +1,34 @@
 
 plugins {
+    id("com.github.johnrengelman.shadow") version "8.1.1"
     id 'application'
-    id "org.openjfx.javafxplugin" version "0.0.10"
+    id 'java'
+    id "org.openjfx.javafxplugin" version "0.1.0"
 }
 
 javafx {
-    version = "17"
-    modules = [ 'javafx.controls', 'javafx.fxml' ]
+    version = "21"
+    modules = [ 'javafx.controls', 'javafx.fxml', 'javafx.graphics']
 }
 
 
 repositories {
     mavenCentral()
 }
+
 dependencies {
-    testImplementation group: 'junit', name: 'junit', version: '4.12'
-    testImplementation 'org.hamcrest:hamcrest-library:1.3'
+    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
+    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
+    testImplementation("org.assertj:assertj-core:3.24.2")
+    testImplementation("org.junit.jupiter:junit-jupiter:5.10.0")
 }
 
-mainClassName = "App"
-
-
 test {
     useJUnitPlatform()
 }
+
+application {
+    mainClass.set("app.SimulatorMain")
+}
+
+
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 41dfb87909a877d96c3af4adccce4c7a301b55a2..1e2fbf0d45879712d4e3ca644375f6109ad81740 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,5 @@
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
diff --git a/settings.gradle b/settings.gradle
index 634fa3e8dee539db93732d9ac0b186c7290dee54..5d3f861d10877d6653e10fdd716089a5ceffa7d4 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,2 +1,4 @@
-rootProject.name = 'ff'
+rootProject.name = 'firefighter'
+include 'src:main:aapp'
+findProject(':src:main:aapp')?.name = 'aapp'
 
diff --git a/src/main/java/App.java b/src/main/java/App.java
deleted file mode 100644
index 10dda1d5b5dac2118958e64a64772f18e7258f18..0000000000000000000000000000000000000000
--- a/src/main/java/App.java
+++ /dev/null
@@ -1,51 +0,0 @@
-import javafx.application.Application;
-import javafx.scene.Group;
-import javafx.scene.Scene;
-import javafx.scene.control.Button;
-import javafx.scene.layout.HBox;
-import javafx.scene.layout.VBox;
-import javafx.stage.Stage;
-
-import static java.lang.Thread.sleep;
-
-
-public class App extends Application {
-
-    public static void main(String[] args) {
-        launch(args);
-    }
-
-    @Override
-    public void start(Stage primaryStage) throws InterruptedException {
-        Group root = new Group();
-        Button restart = new Button("Restart");
-        VBox buttons = new VBox();
-        HBox total = new HBox();
-        Grid grid = new Grid(1000,1000,20,20);
-
-        root.getChildren().add(total);
-        total.getChildren().add(buttons);
-        total.getChildren().add(grid);
-        buttons.getChildren().add(restart);
-        restart.setOnMouseClicked(grid::restart);
-        primaryStage.setScene(new Scene(root));
-        primaryStage.show();
-        grid.repaint();
-        new Thread(new Runnable() {
-            @Override
-            public void run() {
-                while(true){
-                    try {
-                        sleep(50);
-                        grid.model.activation();
-                        grid.repaint();
-                    } catch (InterruptedException e) {
-                        e.printStackTrace();
-                    }
-                }
-
-            }
-        }).start();
-    }
-}
-
diff --git a/src/main/java/Grid.java b/src/main/java/Grid.java
deleted file mode 100644
index 23fb50d23d9ba0dd308def943a81d8fe898d40a9..0000000000000000000000000000000000000000
--- a/src/main/java/Grid.java
+++ /dev/null
@@ -1,60 +0,0 @@
-import javafx.scene.canvas.Canvas;
-import javafx.scene.canvas.GraphicsContext;
-import javafx.scene.input.MouseEvent;
-import javafx.scene.paint.Color;
-
-public class Grid extends Canvas{
-    int width, height, colCount, rowCount;
-    Model model;
-
-
-    public Grid(int width, int height, int colCount, int rowCount) {
-        super(width,height);
-        this.width = width;
-        this.height = height;
-        this.colCount = colCount;
-        this.rowCount = rowCount;
-        setFocusTraversable(true);
-        setOnMousePressed(this::mousePressed);
-        model = new Model(this);
-        model.initialisation(3,8);
-    }
-
-    public void restart(MouseEvent mouseEvent){
-        model = new Model(this);
-        model.initialisation(3,6);
-        getGraphicsContext2D().clearRect(0,0,width,height);
-        repaint();
-    }
-    private void mousePressed(MouseEvent mouseEvent) {
-        model.activation();
-        repaint();
-            /*double x = mouseEvent.getX();
-            double y = mouseEvent.getY();
-            model.click((int)x*rowCount/height,(int)y*colCount/width);*/
-    }
-
-    void repaint(){
-        for(int col=0; col<colCount; col++)
-            getGraphicsContext2D().strokeLine(0, col*width/colCount,height, col*width/colCount);
-        for(int row=0; row<rowCount;row++)
-            getGraphicsContext2D().strokeLine(row*height/rowCount,0,row*height/rowCount,width);
-
-    }
-
-    void paint(int row, int col){
-        getGraphicsContext2D().setFill(Color.WHITE);
-        getGraphicsContext2D().fillRect(row*height/rowCount,col*width/colCount,height/rowCount,width/colCount);
-    }
-
-    public void paintFF(int row, int col) {
-        getGraphicsContext2D().setFill(Color.BLUE);
-        getGraphicsContext2D().fillRect(row*height/rowCount,col*width/colCount,height/rowCount,width/colCount);
-    }
-
-    public void paintFire(int row, int col) {
-        getGraphicsContext2D().setFill(Color.RED);
-        getGraphicsContext2D().fillRect(row*height/rowCount,col*width/colCount,height/rowCount,width/colCount);
-    }
-
-}
\ No newline at end of file
diff --git a/src/main/java/Model.java b/src/main/java/Model.java
deleted file mode 100644
index f23d0d13c6a3e847962201dc7c72fd5dedc0a249..0000000000000000000000000000000000000000
--- a/src/main/java/Model.java
+++ /dev/null
@@ -1,105 +0,0 @@
-import java.util.*;
-
-
-public class Model {
-    Grid grid;
-    int colCount, rowCount;
-    List<Position> firefighters = new ArrayList<>();
-    Set<Position> fires = new HashSet<>();
-    List<Position> ffNewPositions;
-    int step = 0;
-
-    public Model(Grid grid) {
-        this.grid = grid;
-        colCount = grid.colCount;
-        rowCount = grid.rowCount;
-    }
-
-
-    public void initialisation(int fireNumber, int fireFighterNumber){
-        for(int index=0; index<fireNumber;index++)
-            fires.add(randomPosition());
-        for(int index=0; index<fireFighterNumber;index++)
-            firefighters.add(randomPosition());
-    }
-
-    private Position randomPosition() {
-        return new Position((int) (Math.random()*rowCount), (int) (Math.random()*colCount));
-    }
-
-
-    public void activation(){
-        ffNewPositions = new ArrayList<>();
-        for(Position ff : firefighters){
-            Position newPosition = activateFirefighter(ff);
-            grid.paint(ff.row,ff.col);
-            grid.paintFF(newPosition.row, newPosition.col);
-            ffNewPositions.add(newPosition);
-        }
-        firefighters = ffNewPositions;
-        if(step%2==0){
-            List<Position> newFires = new ArrayList<>();
-            for(Position fire : fires){
-                newFires.addAll(activateFire(fire));
-            }
-            for(Position newFire : newFires)
-                grid.paintFire(newFire.row, newFire.col);
-
-            fires.addAll(newFires);}
-        step++;
-
-    }
-
-    private List<Position> activateFire(Position position) {
-        return next(position);
-    }
-
-
-
-    private Position activateFirefighter(Position position) {
-        Position randomPosition = aStepTowardFire(position);
-                //next(position).get((int) (Math.random()*next(position).size()));
-        List<Position> nextFires = next(randomPosition).stream().filter(fires::contains).toList();
-        extinguish(randomPosition);
-            for (Position fire : nextFires)
-                extinguish(fire);
-            return randomPosition;
-        }
-
-        private void extinguish(Position position) {
-        fires.remove(position);
-        grid.paint(position.row, position.col);
-    }
-
-    private List<Position> next(Position position){
-        List<Position> list = new ArrayList<>();
-        if(position.row>0) list.add(new Position(position.row-1, position.col));
-        if(position.col>0) list.add(new Position(position.row, position.col-1));
-        if(position.row<rowCount-1) list.add(new Position(position.row+1, position.col));
-        if(position.col<colCount-1) list.add(new Position(position.row, position.col+1));
-        return list;
-    }
-
-    private Position aStepTowardFire(Position position){
-        Queue<Position> toVisit = new LinkedList<>();
-        Set<Position> seen = new HashSet<>();
-        HashMap<Position,Position> firstMove = new HashMap<>();
-        toVisit.addAll(next(position));
-        for(Position initialMove : toVisit)
-            firstMove.put(initialMove,initialMove);
-        while(!toVisit.isEmpty()){
-            Position current = toVisit.poll();
-            if(fires.contains(current))
-                return firstMove.get(current);
-            for(Position adjacent : next(current)){
-                if(seen.contains(adjacent)) continue;
-                toVisit.add(adjacent);
-                seen.add(adjacent);
-                firstMove.put(adjacent, firstMove.get(current));
-            }
-        }
-        return position;
-    }
-
-    public record Position(int row, int col){}
-}
\ No newline at end of file
diff --git a/src/main/java/app/SimulatorApplication.java b/src/main/java/app/SimulatorApplication.java
new file mode 100644
index 0000000000000000000000000000000000000000..e88b0e9856086cc6f53f2782175393dca6365eb6
--- /dev/null
+++ b/src/main/java/app/SimulatorApplication.java
@@ -0,0 +1,59 @@
+package app;
+
+import controller.Controller;
+import javafx.application.Platform;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Parent;
+import javafx.scene.Scene;
+import javafx.stage.Stage;
+
+import java.io.IOException;
+import java.net.URL;
+
+public class SimulatorApplication extends javafx.application.Application {
+  private static final String VIEW_RESOURCE_PATH = "/view/view.fxml";
+  private static final String APP_NAME = "Firefighter simulator";
+  private static final int ROW_COUNT = 20;
+  private static final int COLUMN_COUNT = 20;
+  private static final int BOX_WIDTH = 50;
+  private static final int BOX_HEIGHT = 50;
+  public static final int INITIAL_FIRE_COUNT = 3;
+  public static final int INITIAL_FIREFIGHTER_COUNT = 6;
+
+  private Stage primaryStage;
+  private Parent view;
+  private void initializePrimaryStage(Stage primaryStage) {
+    this.primaryStage = primaryStage;
+    this.primaryStage.setTitle(APP_NAME);
+    this.primaryStage.setOnCloseRequest(event -> Platform.exit());
+    this.primaryStage.setResizable(true);
+    this.primaryStage.sizeToScene();
+  }
+
+  @Override
+  public void start(Stage primaryStage) throws IOException {
+    initializePrimaryStage(primaryStage);
+    initializeView();
+    showScene();
+  }
+
+  private void initializeView() throws IOException {
+    FXMLLoader loader = new FXMLLoader();
+    URL location = SimulatorApplication.class.getResource(VIEW_RESOURCE_PATH);
+    loader.setLocation(location);
+    view = loader.load();
+    Controller controller = loader.getController();
+    controller.initialize(BOX_WIDTH, BOX_HEIGHT, COLUMN_COUNT, ROW_COUNT,
+            INITIAL_FIRE_COUNT, INITIAL_FIREFIGHTER_COUNT);
+  }
+
+  private void showScene() {
+    Scene scene = new Scene(view);
+    primaryStage.setScene(scene);
+    primaryStage.show();
+  }
+
+  public static void main(String[] args) {
+    launch(args);
+  }
+}
diff --git a/src/main/java/app/SimulatorMain.java b/src/main/java/app/SimulatorMain.java
new file mode 100644
index 0000000000000000000000000000000000000000..f2e49f262ebec4136cf57d3b50fea3987b3b69fc
--- /dev/null
+++ b/src/main/java/app/SimulatorMain.java
@@ -0,0 +1,7 @@
+package app;
+
+public class SimulatorMain {
+  public static void main(String[] args){
+    SimulatorApplication.main(args);
+  }
+}
diff --git a/src/main/java/controller/Controller.java b/src/main/java/controller/Controller.java
new file mode 100644
index 0000000000000000000000000000000000000000..2a60897c6eb8ba847cb8589840c16a0f175ce0a3
--- /dev/null
+++ b/src/main/java/controller/Controller.java
@@ -0,0 +1,141 @@
+package controller;
+
+import javafx.animation.Animation;
+import javafx.animation.KeyFrame;
+import javafx.animation.Timeline;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
+import javafx.fxml.FXML;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.control.ToggleButton;
+import javafx.scene.control.ToggleGroup;
+import javafx.util.Duration;
+import javafx.util.Pair;
+import model.Board;
+import model.ModelElement;
+import model.FirefighterBoard;
+import util.Position;
+import view.Grid;
+import view.ViewElement;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static java.util.Objects.requireNonNull;
+
+public class Controller {
+
+  public static final int PERIOD_IN_MILLISECONDS = 50;
+  @FXML
+  public Button restartButton;
+  @FXML
+  public Button oneStepButton;
+  @FXML
+  public Label generationNumberLabel;
+  @FXML
+  private ToggleButton pauseToggleButton;
+  @FXML
+  private ToggleButton playToggleButton;
+  @FXML
+  private Grid<ViewElement> grid;
+  private Timeline timeline;
+  private Board<List<ModelElement>> board;
+
+  @FXML
+  private void initialize() {
+    initializePlayAndPauseToggleButtons();
+    initializeTimeline();
+  }
+
+  private void initializePlayAndPauseToggleButtons() {
+    ToggleGroup toggleGroup = new PersistentToggleGroup();
+    toggleGroup.getToggles().addAll(playToggleButton, pauseToggleButton);
+    pauseToggleButton.setSelected(true);
+  }
+
+  private void setModel(FirefighterBoard firefighterBoard) {
+    this.board = requireNonNull(firefighterBoard, "firefighter.model is null");
+  }
+
+  private void updateBoard(){
+    List<Position> updatedPositions = board.updateToNextGeneration();
+    List<Pair<Position, ViewElement>> updatedSquares = new ArrayList<>();
+    for(Position updatedPosition : updatedPositions){
+      List<ModelElement> squareState = board.getState(updatedPosition);
+      ViewElement viewElement = getViewElement(squareState);
+      updatedSquares.add(new Pair<>(updatedPosition, viewElement));
+    }
+    grid.repaint(updatedSquares);
+    updateGenerationLabel(board.stepNumber());
+  }
+
+  private void repaintGrid(){
+    int columnCount = board.columnCount();
+    int rowCount = board.rowCount();
+    ViewElement[][] viewElements = new ViewElement[rowCount][columnCount];
+    for(int column = 0; column < columnCount; column++)
+      for(int row = 0; row < rowCount; row++)
+        viewElements[row][column] = getViewElement(board.getState(new Position(row, column)));
+    grid.repaint(viewElements);
+    updateGenerationLabel(board.stepNumber());
+  }
+
+  private ViewElement getViewElement(List<ModelElement> squareState) {
+    if(squareState.contains(ModelElement.FIREFIGHTER)){
+      return ViewElement.FIREFIGHTER;
+    }
+    if (squareState.contains(ModelElement.FIRE)){
+      return ViewElement.FIRE;
+    }
+    return ViewElement.EMPTY;
+  }
+
+  private void initializeTimeline() {
+    Duration duration = new Duration(Controller.PERIOD_IN_MILLISECONDS);
+    EventHandler<ActionEvent> eventHandler =
+            event -> updateBoard();
+    KeyFrame keyFrame = new KeyFrame(duration, eventHandler);
+    timeline = new Timeline(keyFrame);
+    timeline.setCycleCount(Animation.INDEFINITE);
+  }
+
+  public void play() {
+    timeline.play();
+  }
+
+  public void pause() {
+    timeline.pause();
+  }
+
+  public void pauseToggleButtonAction() {
+    this.pause();
+  }
+
+  public void playToggleButtonAction() {
+    this.play();
+  }
+
+  public void restartButtonAction() {
+    this.pause();
+    board.reset();
+    pauseToggleButton.setSelected(true);
+    repaintGrid();
+  }
+
+  public void initialize(int squareWidth, int squareHeight, int columnCount,
+                                int rowCount, int initialFireCount, int initialFirefighterCount) {
+    grid.setDimensions(columnCount, rowCount, squareWidth, squareHeight);
+    this.setModel(new FirefighterBoard(columnCount, rowCount, initialFireCount, initialFirefighterCount));
+    repaintGrid();
+  }
+
+  public void oneStepButtonAction() {
+    this.pause();
+    updateBoard();
+  }
+
+  private void updateGenerationLabel(int value){
+    generationNumberLabel.setText(Integer.toString(value));
+  }
+}
\ No newline at end of file
diff --git a/src/main/java/controller/PersistentToggleGroup.java b/src/main/java/controller/PersistentToggleGroup.java
new file mode 100644
index 0000000000000000000000000000000000000000..7c2c4b5c79d6ff65e0bfbe53c2fb7e9fd5944a1b
--- /dev/null
+++ b/src/main/java/controller/PersistentToggleGroup.java
@@ -0,0 +1,34 @@
+package controller;
+
+import javafx.collections.ListChangeListener.Change;
+import javafx.scene.control.Toggle;
+import javafx.scene.control.ToggleButton;
+import javafx.scene.control.ToggleGroup;
+import javafx.scene.input.MouseEvent;
+
+/**
+ * An extension of {@link ToggleGroup} that ensures that a {@link Toggle} in a group must always be
+ * selected.
+ *
+ */
+class PersistentToggleGroup extends ToggleGroup {
+
+  /**
+   * Creates a new {@code PersistentToggleGroup}.
+   */
+  PersistentToggleGroup() {
+    getToggles().addListener((Change<? extends Toggle> change) -> {
+      while (change.next()) {
+        for (Toggle toggle : change.getAddedSubList()) {
+          ToggleButton toggleButton = (ToggleButton) toggle;
+          toggleButton.addEventFilter(MouseEvent.MOUSE_RELEASED, mouseEvent -> {
+            if (toggleButton.equals(getSelectedToggle())) {
+              mouseEvent.consume();
+            }
+          });
+        }
+      }
+    });
+  }
+
+}
diff --git a/src/main/java/model/Board.java b/src/main/java/model/Board.java
new file mode 100644
index 0000000000000000000000000000000000000000..bb089a41406d57b0b2fe3d43b3c040cbd640b6b9
--- /dev/null
+++ b/src/main/java/model/Board.java
@@ -0,0 +1,65 @@
+package model;
+
+import util.Position;
+
+import java.util.List;
+
+/**
+ * This interface represents a generic board for modeling various state-based systems.
+ *
+ * @param <S> The type of state represented on the board.
+ */
+public interface Board<S> {
+
+  /**
+   * Get the state of the board at a specific position.
+   *
+   * @param position The position on the board for which to retrieve the state.
+   * @return The state at the specified position.
+   */
+  S getState(Position position);
+
+  /**
+   * Set the state of a specific position on the board to the specified state.
+   *
+   * @param state The state to set for the given position.
+   * @param position The position on the board for which to set the state.
+   */
+  void setState(S state, Position position);
+
+  /**
+   * Get the number of rows in the board.
+   *
+   * @return The number of rows in the board.
+   */
+  int rowCount();
+
+  /**
+   * Get the number of columns in the board.
+   *
+   * @return The number of columns in the board.
+   */
+  int columnCount();
+
+  /**
+   * Update the board to its next generation or state. This method may modify the
+   * internal state of the board and return a list of positions that have changed
+   * during the update.
+   *
+   * @return A list of positions that have changed during the update.
+   */
+  List<Position> updateToNextGeneration();
+
+  /**
+   * Reset the board to its initial state.
+   */
+  void reset();
+
+  /**
+   * Get the current step number or generation of the board.
+   *
+   * @return The current step number or generation.
+   */
+  int stepNumber();
+}
+
diff --git a/src/main/java/model/FirefighterBoard.java b/src/main/java/model/FirefighterBoard.java
new file mode 100644
index 0000000000000000000000000000000000000000..c0bd67cc4f444a33c41551779b11f3d619412bef
--- /dev/null
+++ b/src/main/java/model/FirefighterBoard.java
@@ -0,0 +1,147 @@
+package model;
+
+import util.Position;
+
+import java.util.*;
+
+
+public class FirefighterBoard implements Board<List<ModelElement>> {
+  private final int columnCount;
+  private final int rowCount;
+  private final int initialFireCount;
+  private final int initialFirefighterCount;
+  private final TargetStrategy targetStrategy = new TargetStrategy();
+  private List<Position> firefighterPositions;
+  private Set<Position> firePositions;
+  private Map<Position, List<Position>> neighbors = new HashMap();
+  private final Position[][] positions;
+  private int step = 0;
+  private final Random randomGenerator = new Random();
+
+  public FirefighterBoard(int columnCount, int rowCount, int initialFireCount, int initialFirefighterCount) {
+    this.columnCount = columnCount;
+    this.rowCount = rowCount;
+    this.positions = new Position[rowCount][columnCount];
+    for (int column = 0; column < columnCount; column++)
+      for (int row = 0; row < rowCount; row++)
+        positions[row][column] = new Position(row, column);
+    for (int column = 0; column < columnCount; column++)
+      for (int row = 0; row < rowCount; row++) {
+        List<Position> list = new ArrayList<>();
+        if (row > 0) list.add(positions[row - 1][column]);
+        if (column > 0) list.add(positions[row][column - 1]);
+        if (row < rowCount - 1) list.add(positions[row + 1][column]);
+        if (column < columnCount - 1) list.add(positions[row][column + 1]);
+        neighbors.put(positions[row][column], list);
+      }
+    this.initialFireCount = initialFireCount;
+    this.initialFirefighterCount = initialFirefighterCount;
+    initializeElements();
+  }
+
+  public void initializeElements() {
+    firefighterPositions = new ArrayList<>();
+    firePositions = new HashSet<>();
+    for (int index = 0; index < initialFireCount; index++)
+      firePositions.add(randomPosition());
+    for (int index = 0; index < initialFirefighterCount; index++)
+      firefighterPositions.add(randomPosition());
+  }
+
+  private Position randomPosition() {
+    return new Position(randomGenerator.nextInt(rowCount), randomGenerator.nextInt(columnCount));
+  }
+
+  @Override
+  public List<ModelElement> getState(Position position) {
+    List<ModelElement> result = new ArrayList<>();
+    for (Position firefighterPosition : firefighterPositions)
+      if (firefighterPosition.equals(position))
+        result.add(ModelElement.FIREFIGHTER);
+    if (firePositions.contains(position))
+      result.add(ModelElement.FIRE);
+    return result;
+  }
+
+  @Override
+  public int rowCount() {
+    return rowCount;
+  }
+
+  @Override
+  public int columnCount() {
+    return columnCount;
+  }
+
+  public List<Position> updateToNextGeneration() {
+    List<Position> modifiedPositions = updateFirefighters();
+    modifiedPositions.addAll(updateFires());
+    step++;
+    return modifiedPositions;
+  }
+
+  private List<Position> updateFires() {
+    List<Position> modifiedPositions = new ArrayList<>();
+    if (step % 2 == 0) {
+      List<Position> newFirePositions = new ArrayList<>();
+      for (Position fire : firePositions) {
+        newFirePositions.addAll(neighbors.get(fire));
+      }
+      firePositions.addAll(newFirePositions);
+      modifiedPositions.addAll(newFirePositions);
+    }
+    return modifiedPositions;
+
+  }
+
+  @Override
+  public int stepNumber() {
+    return step;
+  }
+
+  private List<Position> updateFirefighters() {
+    List<Position> modifiedPosition = new ArrayList<>();
+    List<Position> firefighterNewPositions = new ArrayList<>();
+    for (Position firefighterPosition : firefighterPositions) {
+      Position newFirefighterPosition =
+              targetStrategy.neighborClosestToFire(firefighterPosition,
+                      firePositions, neighbors);
+      firefighterNewPositions.add(newFirefighterPosition);
+      extinguish(newFirefighterPosition);
+      modifiedPosition.add(firefighterPosition);
+      modifiedPosition.add(newFirefighterPosition);
+      List<Position> neighborFirePositions = neighbors.get(newFirefighterPosition).stream()
+              .filter(firePositions::contains).toList();
+      for (Position firePosition : neighborFirePositions)
+        extinguish(firePosition);
+      modifiedPosition.addAll(neighborFirePositions);
+    }
+    firefighterPositions = firefighterNewPositions;
+    return modifiedPosition;
+  }
+
+  @Override
+  public void reset() {
+    step = 0;
+    initializeElements();
+  }
+
+  private void extinguish(Position position) {
+    firePositions.remove(position);
+  }
+
+
+  @Override
+  public void setState(List<ModelElement> state, Position position) {
+    firePositions.remove(position);
+    for (; ; ) {
+      if (!firefighterPositions.remove(position)) break;
+    }
+    for (ModelElement element : state) {
+      switch (element) {
+        case FIRE -> firePositions.add(position);
+        case FIREFIGHTER -> firefighterPositions.add(position);
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/main/java/model/ModelElement.java b/src/main/java/model/ModelElement.java
new file mode 100644
index 0000000000000000000000000000000000000000..759eee5e54c3a39472d8f7defbbbe6a2b67b8f00
--- /dev/null
+++ b/src/main/java/model/ModelElement.java
@@ -0,0 +1,5 @@
+package model;
+
+public enum ModelElement {
+  FIREFIGHTER, FIRE
+}
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..4c36d97709b342e457203c75d081fc5cc1955c0f
--- /dev/null
+++ b/src/main/java/module-info.java
@@ -0,0 +1,8 @@
+module firefighter {
+  requires javafx.controls;
+  requires javafx.fxml;
+  requires javafx.graphics;
+  opens controller to javafx.fxml;
+  exports app;
+  opens app to javafx.fxml;
+}
diff --git a/src/main/java/util/Position.java b/src/main/java/util/Position.java
new file mode 100644
index 0000000000000000000000000000000000000000..31dc4c1fb6a04b4e96649e133d1d116120d34683
--- /dev/null
+++ b/src/main/java/util/Position.java
@@ -0,0 +1,5 @@
+package util;
+
+public record Position(int row, int column) {
+
+}
diff --git a/src/main/java/util/TargetStrategy.java b/src/main/java/util/TargetStrategy.java
new file mode 100644
index 0000000000000000000000000000000000000000..583186787d4d8d47173fbe61cc424f2f7ee384c9
--- /dev/null
+++ b/src/main/java/util/TargetStrategy.java
@@ -0,0 +1,35 @@
+package model;
+
+import util.Position;
+
+import java.util.*;
+
+public class TargetStrategy {
+
+
+    /**
+     * @param position current position.
+     * @param targets positions that are targeted.
+     * @return the position next to the current position that is on the path to the closest target.
+     */
+    Position neighborClosestToFire(Position position, Collection<Position> targets,
+                                   Map<Position,List<Position>>neighbors) {
+        Set<Position> seen = new HashSet<Position>();
+        HashMap<Position, Position> firstMove = new HashMap<Position, Position>();
+        Queue<Position> toVisit = new LinkedList<Position>(neighbors.get(position));
+        for (Position initialMove : toVisit)
+            firstMove.put(initialMove, initialMove);
+        while (!toVisit.isEmpty()) {
+            Position current = toVisit.poll();
+            if (targets.contains(current))
+                return firstMove.get(current);
+            for (Position adjacent : neighbors.get(current)) {
+                if (seen.contains(adjacent)) continue;
+                toVisit.add(adjacent);
+                seen.add(adjacent);
+                firstMove.put(adjacent, firstMove.get(current));
+            }
+        }
+        return position;
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/view/FirefighterGrid.java b/src/main/java/view/FirefighterGrid.java
new file mode 100644
index 0000000000000000000000000000000000000000..4c9041f034ec9a4eb07ce4334de237f1e99ccdc9
--- /dev/null
+++ b/src/main/java/view/FirefighterGrid.java
@@ -0,0 +1,99 @@
+package view;
+
+import javafx.scene.canvas.Canvas;
+import javafx.scene.paint.Color;
+import javafx.util.Pair;
+import util.Position;
+
+import java.util.List;
+
+public class FirefighterGrid extends Canvas implements Grid<ViewElement>{
+
+    private void paintElementAtPosition(ViewElement element, Position position) {
+        paintBox(position.row(), position.column(), element.color);
+    }
+    private int boxWidth;
+    private int boxHeight;
+    private int columnCount;
+    private int rowCount;
+
+    @Override
+    public void repaint(List<Pair<Position, ViewElement>> positionedElements) {
+        clear(positionedElements);
+        paint(positionedElements);
+        paintLines();
+    }
+
+    private void clear(List<Pair<Position, ViewElement>> positionedElements) {
+        for (Pair<Position, ViewElement> positionElement : positionedElements) {
+            Position position = positionElement.getKey();
+            clearBox(position.row(), position.column());
+        }
+    }
+
+    private void paint(List<Pair<Position, ViewElement>> positionedElements) {
+        for(Pair<Position, ViewElement> pair : positionedElements){
+            paintElementAtPosition(pair.getValue(), pair.getKey());
+        }
+    }
+
+    @Override
+    public void repaint(ViewElement[][] elements) {
+        clear();
+        paint(elements);
+        paintLines();
+    }
+
+    private void clear() {
+        getGraphicsContext2D().clearRect(0,0,getWidth(), getHeight());
+    }
+
+    private void paint(ViewElement[][] elements) {
+        for(int column = 0; column < columnCount; column++)
+            for(int row = 0; row < rowCount; row++){
+                paintElementAtPosition(elements[row][column], new Position(row, column));
+            }
+    }
+
+    public int columnCount() {
+        return columnCount;
+    }
+
+    public int rowCount() {
+        return rowCount;
+    }
+
+    @Override
+    public void setDimensions(int columnCount, int rowCount, int boxWidth, int boxHeight) {
+        this.boxWidth = boxWidth;
+        this.boxHeight = boxHeight;
+        this.columnCount = columnCount;
+        this.rowCount = rowCount;
+        super.setWidth(boxWidth * columnCount);
+        super.setHeight(boxHeight * rowCount);
+    }
+
+    private void paintLines(){
+        paintHorizontalLines();
+        paintVerticalLines();
+    }
+
+    private void paintVerticalLines() {
+        for(int column = 0; column < columnCount; column++)
+            getGraphicsContext2D().strokeLine(column * boxWidth, 0,column * boxWidth, getHeight());
+    }
+
+    private void paintHorizontalLines() {
+        for(int row = 0; row < rowCount; row++)
+            getGraphicsContext2D().strokeLine(0, row * boxHeight, getWidth(), row * boxHeight);
+    }
+
+    private void paintBox(int row, int column, Color color){
+        getGraphicsContext2D().setFill(color);
+        getGraphicsContext2D().fillRect(column * boxWidth,row * boxHeight, boxWidth, boxHeight);
+    }
+
+    private void clearBox(int row, int column){
+        getGraphicsContext2D().clearRect(column * boxWidth,row * boxHeight, boxWidth, boxHeight);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/view/Grid.java b/src/main/java/view/Grid.java
new file mode 100644
index 0000000000000000000000000000000000000000..b95d59f622a86b41f2a41261b8b27aaf2e911dfb
--- /dev/null
+++ b/src/main/java/view/Grid.java
@@ -0,0 +1,55 @@
+package view;
+
+import javafx.util.Pair;
+import util.Position;
+
+import java.util.List;
+
+/**
+ * This interface represents a generic grid structure for displaying two-dimensional data.
+ *
+ * @param <E> The type of elements stored in the grid.
+ */
+public interface Grid<E> {
+
+  /**
+   * Repaint the grid with a list of elements, each associated with their respective positions.
+   *
+   * @param elements A list of pairs, each containing a position and the element to be displayed at that position.
+   */
+  void repaint(List<Pair<Position, E>> elements);
+
+  /**
+   * Repaint the grid with a two-dimensional array of elements. The array's dimensions should match
+   * the row and column count of the grid.
+   *
+   * @param elements A two-dimensional array of elements to be displayed on the grid.
+   */
+  void repaint(E[][] elements);
+
+  /**
+   * Set the dimensions of the grid to the specified number of columns, number of rows, square width,
+   * and square height.
+   *
+   * @param columnCount The new number of columns in the grid.
+   * @param rowCount The new number of rows in the grid.
+   * @param squareWidth The width of each square within the grid.
+   * @param squareHeight The height of each square within the grid.
+   */
+  void setDimensions(int columnCount, int rowCount, int squareWidth, int squareHeight);
+
+  /**
+   * Get the number of columns in the grid.
+   *
+   * @return The number of columns in the grid.
+   */
+  int columnCount();
+
+  /**
+   * Get the number of rows in the grid.
+   *
+   * @return The number of rows in the grid.
+   */
+  int rowCount();
+}
+
diff --git a/src/main/java/view/ViewElement.java b/src/main/java/view/ViewElement.java
new file mode 100644
index 0000000000000000000000000000000000000000..ffb76112e1af543df5af41fa906082ef11be9967
--- /dev/null
+++ b/src/main/java/view/ViewElement.java
@@ -0,0 +1,11 @@
+package view;
+
+import javafx.scene.paint.Color;
+
+public enum ViewElement {
+  FIREFIGHTER(Color.BLUE), FIRE(Color.RED), EMPTY(Color.WHITE);
+  final Color color;
+  ViewElement(Color color) {
+    this.color = color;
+  }
+}
diff --git a/src/main/resources/view/DarkTheme.css b/src/main/resources/view/DarkTheme.css
new file mode 100644
index 0000000000000000000000000000000000000000..46b78aaf90972dd435399466c9fd861ca73fc59f
--- /dev/null
+++ b/src/main/resources/view/DarkTheme.css
@@ -0,0 +1,142 @@
+.background {
+    -fx-background-color: #1d1d1d;
+}
+
+.label {
+    -fx-font-size: 11pt;
+    -fx-font-family: "Segoe UI Semibold";
+    -fx-text-fill: white;
+    -fx-opacity: 0.6;
+}
+
+.label-bright {
+    -fx-font-size: 11pt;
+    -fx-font-family: "Segoe UI Semibold";
+    -fx-text-fill: white;
+    -fx-opacity: 1;
+}
+
+.label-header {
+    -fx-font-size: 32pt;
+    -fx-font-family: "Segoe UI Light";
+    -fx-text-fill: white;
+    -fx-opacity: 1;
+}
+
+.table-view {
+    -fx-base: #1d1d1d;
+    -fx-control-inner-background: #1d1d1d;
+    -fx-background-color: #1d1d1d;
+    -fx-table-cell-border-color: transparent;
+    -fx-table-header-border-color: transparent;
+    -fx-padding: 5;
+}
+
+.table-view .column-header-background {
+    -fx-background-color: transparent;
+}
+
+.table-view .column-header, .table-view .filler {
+    -fx-border-width: 0 0 1 0;
+    -fx-background-color: transparent;
+    -fx-border-color: 
+        transparent
+        transparent
+        derive(-fx-base, 80%) 
+        transparent;
+    -fx-border-insets: 0 10 1 0;
+}
+
+.table-view .column-header .label {
+    -fx-font-size: 20pt;
+    -fx-font-family: "Segoe UI Light";
+    -fx-text-fill: white;
+    -fx-alignment: center-left;
+    -fx-opacity: 1;
+}
+
+.table-view:focused .table-row-cell:filled:focused:selected {
+    -fx-background-color: -fx-focus-color;
+}
+
+.split-pane:horizontal > .split-pane-divider {
+    -fx-border-color: transparent #1d1d1d transparent #1d1d1d;
+    -fx-background-color: transparent, derive(#1d1d1d,20%);
+}
+
+.split-pane {
+    -fx-padding: 1 0 0 0;
+}
+
+.menu-bar {
+    -fx-background-color: derive(#1d1d1d,20%);
+}
+
+.context-menu {
+    -fx-background-color: derive(#1d1d1d,50%);
+}
+
+.menu-bar .label {
+    -fx-font-size: 14pt;
+    -fx-font-family: "Segoe UI Light";
+    -fx-text-fill: white;
+    -fx-opacity: 0.9;
+}
+
+.menu .left-container {
+    -fx-background-color: black;
+}
+
+.text-field {
+    -fx-font-size: 12pt;
+    -fx-font-family: "Segoe UI Semibold";
+}
+
+/* 
+ * Metro style Push Button
+ * Author: Pedro Duque Vieira
+ * http://pixelduke.wordpress.com/2012/10/23/jmetro-windows-8-controls-on-java/
+ */
+.button {
+    -fx-padding: 5 22 5 22;   
+    -fx-border-color: #e2e2e2;
+    -fx-border-width: 2;
+    -fx-background-radius: 0;
+    -fx-background-color: #1d1d1d;
+    -fx-font-family: "Segoe UI", Helvetica, Arial, sans-serif;
+    -fx-font-size: 11pt;
+    -fx-text-fill: #d8d8d8;
+    -fx-background-insets: 0 0 0 0, 0, 1, 2;
+}
+
+.button:hover {
+    -fx-background-color: #3a3a3a;
+}
+
+.button:pressed, .button:default:hover:pressed {
+  -fx-background-color: white;
+  -fx-text-fill: #1d1d1d;
+}
+
+.button:focused {
+    -fx-border-color: white, white;
+    -fx-border-width: 1, 1;
+    -fx-border-style: solid;
+    -fx-border-radius: 0, 0;
+    -fx-border-insets: 1 1 1 1, 0;
+}
+
+.button:disabled, .button:default:disabled {
+    -fx-opacity: 0.4;
+    -fx-background-color: #1d1d1d;
+    -fx-text-fill: white;
+}
+
+.button:default {
+    -fx-background-color: -fx-focus-color;
+    -fx-text-fill: #ffffff;
+}
+
+.button:default:hover {
+    -fx-background-color: derive(-fx-focus-color,30%);
+}
\ No newline at end of file
diff --git a/src/main/resources/view/view.fxml b/src/main/resources/view/view.fxml
new file mode 100644
index 0000000000000000000000000000000000000000..336ffa315645baacbe25bf59171d2ff6d867b9c5
--- /dev/null
+++ b/src/main/resources/view/view.fxml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?import javafx.scene.control.Button?>
+<?import javafx.scene.layout.HBox?>
+<?import javafx.scene.layout.VBox?>
+<?import view.FirefighterGrid?>
+
+<?import javafx.scene.control.ToggleButton?>
+<?import javafx.scene.control.Separator?>
+<?import javafx.scene.control.Label?>
+<HBox styleClass="background" stylesheets="@DarkTheme.css"
+      xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"
+      fx:controller="controller.Controller">
+  <VBox>
+    <Separator maxHeight="-Infinity" maxWidth="-Infinity"
+               prefHeight="24.0" prefWidth="200.0"/>
+    <Label maxHeight="-Infinity" maxWidth="-Infinity" alignment="CENTER" prefHeight="24.0" prefWidth="200.0"
+           text="Generation number"/>
+    <Label fx:id="generationNumberLabel" alignment="CENTER" contentDisplay="TEXT_ONLY"
+           maxHeight="-Infinity" maxWidth="-Infinity" prefHeight="24.0" prefWidth="200.0"/>
+    <Separator maxHeight="-Infinity" maxWidth="-Infinity"
+               prefHeight="24.0" prefWidth="200.0"/>
+    <Button fx:id="restartButton" maxHeight="-Infinity" maxWidth="-Infinity"
+            mnemonicParsing="false" onAction="#restartButtonAction" prefHeight="24.0" prefWidth="200.0"
+            text="Restart"/>
+    <Button fx:id="oneStepButton" maxHeight="-Infinity" maxWidth="-Infinity"
+            mnemonicParsing="false" onAction="#oneStepButtonAction" prefHeight="24.0" prefWidth="200.0"
+            text="One step"/>
+    <ToggleButton fx:id="playToggleButton" maxHeight="-Infinity" maxWidth="-Infinity"
+                  mnemonicParsing="false" onAction="#playToggleButtonAction" prefHeight="24.0"
+                  prefWidth="200.0" styleClass="button" text="Play"/>
+    <ToggleButton fx:id="pauseToggleButton" maxHeight="-Infinity" maxWidth="-Infinity"
+                  mnemonicParsing="false" onAction="#pauseToggleButtonAction" prefHeight="24.0"
+                  prefWidth="200.0" styleClass="button" text="Pause"/>
+  </VBox>
+  <FirefighterGrid fx:id="grid"
+                   xmlns="http://javafx.com/javafx"
+                   xmlns:fx="http://javafx.com/fxml">
+  </FirefighterGrid>
+</HBox>
diff --git a/src/test/java/model/FirefighterBoardTest.java b/src/test/java/model/FirefighterBoardTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..25cc8dbca8acea698879df68a5006a179f281ecc
--- /dev/null
+++ b/src/test/java/model/FirefighterBoardTest.java
@@ -0,0 +1,39 @@
+package model;
+
+import org.junit.jupiter.api.Test;
+import util.Position;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.*;
+
+public class FirefighterBoardTest {
+  @Test
+  void testColumnCount(){
+    Board<List<ModelElement>> board = new FirefighterBoard(20, 10, 1, 3);
+    assertThat(board.columnCount()).isEqualTo(20);
+  }
+  @Test
+  void testRowCount(){
+    Board<List<ModelElement>> board = new FirefighterBoard(20, 10, 1, 3);
+    assertThat(board.rowCount()).isEqualTo(10);
+  }
+  @Test
+  void testStepNumber(){
+    Board<List<ModelElement>> board = new FirefighterBoard(20, 10, 1, 3);
+    for(int index = 0; index < 10; index++){
+      assertThat(board.stepNumber()).isEqualTo(index);
+      board.updateToNextGeneration();
+    }
+    assertThat(board.stepNumber()).isEqualTo(10);
+  }
+  @Test
+  void testGetState_afterSet(){
+    Board<List<ModelElement>> board = new FirefighterBoard(20, 10, 0, 0);
+    Position position = new Position(1,2);
+    assertThat(board.getState(position)).isEmpty();
+    board.setState(List.of(ModelElement.FIRE), position);
+    assertThat(board.getState(position)).containsExactly(ModelElement.FIRE);
+  }
+
+}
diff --git a/src/test/java/view/FirefighterGridTest.java b/src/test/java/view/FirefighterGridTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..4b45ebdca3b936b42c2b322b1294488341d180bb
--- /dev/null
+++ b/src/test/java/view/FirefighterGridTest.java
@@ -0,0 +1,20 @@
+package view;
+
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class FirefighterGridTest {
+  @Test
+  void testColumnCount(){
+    Grid<ViewElement> grid = new FirefighterGrid();
+    grid.setDimensions(20,10,10,10);
+    assertThat(grid.columnCount()).isEqualTo(20);
+  }
+  @Test
+  void testRowCount(){
+    Grid<ViewElement> grid = new FirefighterGrid();
+    grid.setDimensions(20,10,10,10);
+    assertThat(grid.rowCount()).isEqualTo(10);
+  }
+}