lab 3
diff --git a/src/sample/ArtRico.java b/src/sample/ArtRico.java
index d8c0494..e436f3f 100644
--- a/src/sample/ArtRico.java
+++ b/src/sample/ArtRico.java
@@ -16,32 +16,8 @@
 import java.util.ArrayList;
 import java.util.HashSet;
 
-public class ArtRico extends Application {
-  final int SCENE_WIDTH = 1280;
-  final int SCENE_HEIGHT = 640;
-  final int WALL_WIDTH = 10;
-  final int STROKE_WIDTH = 2;
-  final int TOP_HEIGHT = 30;
-  final int BOTTOM_HEIGHT = 10;
-  final int PLAYER_HEIGHT = 20;
-  final int PLAYER_POS_Y = 570;
-  final int PLAYER_WIDTH_EASY = 280;
-  final int PLAYER_WIDTH_MEDIUM = 200;
-  final int PLAYER_WIDTH_HARD = 200;
-  final int PLAYER_SPEED_EASY = 10;
-  final int PLAYER_SPEED_MEDIUM = 10;
-  final int PLAYER_SPEED_HARD = 20;
-  final int BALL_SPEED_EASY = 5;
-  final int BALL_SPEED_MEDIUM = 5;
-  final int BALL_SPEED_HARD = 10;
-  final int BALL_SIZE = 20;
-  final int BRICKS_IN_RAW = 15;
-  final int BRICKS_IN_COLOMN = 8;
-  final int BRICKS_HEIGHT = 40;
-  final int BRICKS_WIDTH = 80;
-  final int BUTTON_WIDTH = 260;
-  final int BUTTON_HEIGHT = 80;
-
+public class ArtRico extends Application
+    implements Constants, MoveConstants {
   Pane gameRoot;
   Pane menuRoot;
   Scene scene;
@@ -59,6 +35,12 @@
   static HashSet<String> lastKey;
   boolean pause;
   AnimationTimer timer;
+  String replay;
+  char gameMode;
+  char replayMode;
+  boolean replayNow;
+  int replayIterator;
+
 
 
   @Override
@@ -67,7 +49,7 @@
     showMenu(primaryStage);
   }
 
-  private void startGame(Stage primaryStage, int mode) {
+  private void startGame(Stage primaryStage, char mode) {
     scene = new Scene(createContent(mode));
     prepareActionHandlers();
     primaryStage.setScene(scene);
@@ -77,10 +59,28 @@
       @Override
       public void handle(long now) {
         if (ball.isGameWon()) {
-          showMessage("You won! Your score is: ");
+          if(replayNow){
+            gameRoot.getChildren().clear();
+            timer.stop();
+            showMenu(primaryStage);
+          } else{
+            replay = mode + replay;
+            Serializer.saveReplay(REPLAY_FILE,replay);
+            replay = "";
+            showMessage("You won! Your score is: ");
+          }
         }
         if (ball.isGameOver()) {
-          showMessage("You lose! Your score is: ");
+          if(replayNow){
+            gameRoot.getChildren().clear();
+            timer.stop();
+            showMenu(primaryStage);
+          } else {
+            replay = mode + replay;
+            Serializer.saveReplay(REPLAY_FILE, replay);
+            replay = "";
+            showMessage("You lose! Your score is: ");
+          }
         }
         if (lastKey.contains("SPACE")) {
           if (pause == false) {
@@ -110,7 +110,7 @@
     timer.start();
   }
 
-  private Parent createContent(int mode) {
+  private Parent createContent(char mode) {
     pause = true;
     gameRoot = new Pane();
     gameRoot.setPrefSize(SCENE_WIDTH, SCENE_HEIGHT);
@@ -130,7 +130,7 @@
     scoreLabel.setFont(javafx.scene.text.Font.font(20));
 
     switch (mode) {
-      case 0: {
+      case 'e': {
         player = new Player(SCENE_WIDTH / 2 - PLAYER_WIDTH_EASY / 2,
             PLAYER_POS_Y, PLAYER_WIDTH_EASY, PLAYER_HEIGHT,
             STROKE_WIDTH, Color.ORANGE, Color.BEIGE,
@@ -141,7 +141,7 @@
             TOP_HEIGHT, SCENE_HEIGHT, BALL_SPEED_EASY);
         break;
       }
-      case 1: {
+      case 'm': {
         player = new Player(SCENE_WIDTH / 2 - PLAYER_WIDTH_MEDIUM / 2,
             PLAYER_POS_Y, PLAYER_WIDTH_MEDIUM,
             PLAYER_HEIGHT, STROKE_WIDTH, Color.ORANGE, Color.BEIGE,
@@ -152,7 +152,7 @@
             TOP_HEIGHT, SCENE_HEIGHT, BALL_SPEED_MEDIUM);
         break;
       }
-      case 2: {
+      case 'h': {
         player = new Player(SCENE_WIDTH / 2 - PLAYER_WIDTH_HARD / 2,
             PLAYER_POS_Y, PLAYER_WIDTH_HARD, PLAYER_HEIGHT,
             STROKE_WIDTH, Color.ORANGE, Color.BEIGE,
@@ -205,12 +205,25 @@
   }
 
   private void update() {
-    if (bot.isOn()) {
-      bot.Execute();
-    } else if (currentlyActiveKeys.contains("LEFT")) {
-      player.moveLeft();
-    } else if (currentlyActiveKeys.contains("RIGHT")) {
-      player.moveRight();
+    char direction;
+    if(replayNow) {
+      switch(replay.toCharArray()[replayIterator]) {
+        case MOVED_LEFT: player.moveLeft(); break;
+        case MOVED_RIGHT: player.moveRight(); break;
+        default: break;
+      }
+      replayIterator++;
+    } else {
+      if (bot.isOn()) {
+        direction = bot.Execute();
+      } else if (currentlyActiveKeys.contains("LEFT")) {
+        direction = player.moveLeft();
+      } else if (currentlyActiveKeys.contains("RIGHT")) {
+        direction = player.moveRight();
+      } else {
+        direction = NOT_MOVED;
+      }
+      replay += direction;
     }
     ball.move();
     scoreLabel.setText("Score : " + score);
@@ -253,57 +266,75 @@
   }
 
   private void showMenu(Stage primaryStage) {
+    replayNow = false;
+    replay = "";
     menuRoot = new Pane();
     menuRoot.setPrefSize(SCENE_WIDTH, SCENE_HEIGHT);
     Rectangle bg = new Rectangle(SCENE_WIDTH, SCENE_HEIGHT, Color.GREY);
-    Button[] button1 = new Button[4];
+    Button[] mainMenuButtons = new Button[MENU_SIZE];
 
-    for (int i = 0; i < 4; i++) {
-      button1[i] = new Button();
-      button1[i].setLayoutX(510);
-      button1[i].setLayoutY(i * 100 + 140);
-      button1[i].setPrefSize(BUTTON_WIDTH, BUTTON_HEIGHT);
-      menuRoot.getChildren().add(button1[i]);
+    for (int i = 0; i < MENU_SIZE; i++) {
+      mainMenuButtons[i] = new Button();
+      mainMenuButtons[i].setLayoutX(510);
+      mainMenuButtons[i].setLayoutY(i * 100 + 140);
+      mainMenuButtons[i].setPrefSize(BUTTON_WIDTH, BUTTON_HEIGHT);
+      menuRoot.getChildren().add(mainMenuButtons[i]);
     }
 
-    button1[0].setText("NEW GAME");
-    button1[1].setText("SETTINGS");
-    button1[2].setText("ABOUT");
-    button1[3].setText("EXIT");
+    mainMenuButtons[0].setText("NEW GAME");
+    mainMenuButtons[1].setText("SETTINGS");
+    mainMenuButtons[2].setText("ABOUT");
+    mainMenuButtons[3].setText("REPLAY");
+    mainMenuButtons[4].setText("EXIT");
 
-    button1[0].setOnAction(e -> {
-      menuRoot.getChildren().removeAll(button1);
-      Button[] button2 = new Button[4];
-      for (int i = 0; i < 4; i++) {
-        button2[i] = new Button();
-        button2[i].setLayoutX(510);
-        button2[i].setLayoutY(i * 100 + 140);
-        button2[i].setPrefSize(BUTTON_WIDTH, BUTTON_HEIGHT);
-        menuRoot.getChildren().add(button2[i]);
+    mainMenuButtons[0].setOnAction(e -> {
+      menuRoot.getChildren().removeAll(mainMenuButtons);
+      Button[] newGameMenuButtons = new Button[4];
+      for (int i = 0; i < NEW_GAME_MENU_SIZE; i++) {
+        newGameMenuButtons[i] = new Button();
+        newGameMenuButtons[i].setLayoutX(510);
+        newGameMenuButtons[i].setLayoutY(i * 100 + 140);
+        newGameMenuButtons[i].setPrefSize(BUTTON_WIDTH, BUTTON_HEIGHT);
+        menuRoot.getChildren().add(newGameMenuButtons[i]);
       }
-      button2[0].setText("Easy");
-      button2[1].setText("Medium");
-      button2[2].setText("Hard");
-      button2[3].setText("Back");
-      button2[0].setOnAction(event -> {
+      newGameMenuButtons[0].setText("Easy");
+      newGameMenuButtons[1].setText("Medium");
+      newGameMenuButtons[2].setText("Hard");
+      newGameMenuButtons[3].setText("Back");
+      newGameMenuButtons[0].setOnAction(event -> {
         menuRoot.getChildren().clear();
-        startGame(primaryStage, 0);
+        gameMode = EASY_MODE;
+        startGame(primaryStage, EASY_MODE);
       });
-      button2[1].setOnAction(event -> {
+      newGameMenuButtons[1].setOnAction(event -> {
         menuRoot.getChildren().clear();
-        startGame(primaryStage, 1);
+        gameMode = MEDIUM_MODE;
+        startGame(primaryStage, MEDIUM_MODE);
       });
-      button2[2].setOnAction(event -> {
+      newGameMenuButtons[2].setOnAction(event -> {
         menuRoot.getChildren().clear();
-        startGame(primaryStage, 2);
+        gameMode = HARD_MODE;
+        startGame(primaryStage, HARD_MODE);
       });
-      button2[3].setOnAction(event -> {
-        menuRoot.getChildren().removeAll(button2);
-        menuRoot.getChildren().addAll(button1);
+      newGameMenuButtons[3].setOnAction(event -> {
+        menuRoot.getChildren().removeAll(newGameMenuButtons);
+        menuRoot.getChildren().addAll(mainMenuButtons);
       });
     });
 
-    button1[3].setOnAction(event -> {
+    mainMenuButtons[3].setOnAction(event -> {
+      replay = Serializer.loadReplay(REPLAY_FILE);
+      if(!replay.isEmpty()) {
+        replayNow = true;
+        replayMode = replay.toCharArray()[0];
+        replayIterator = 1;
+        menuRoot.getChildren().clear();
+        startGame(primaryStage, replayMode);
+      }
+
+    });
+
+    mainMenuButtons[4].setOnAction(event -> {
       System.exit(0);
     });
 
diff --git a/src/sample/Bot.java b/src/sample/Bot.java
index ec2477a..e6a4dec 100644
--- a/src/sample/Bot.java
+++ b/src/sample/Bot.java
@@ -14,27 +14,28 @@
     on = false;
   }
 
-  public void Execute() {
+  public char Execute() {
+    char direction;
     if (time < timeOfMoving) {
       if (player.getTranslateX() + player.getWidth() / 2
           < ball.getTranslateX() + ball.getWidth()) {
-        player.moveRight();
+        direction = player.moveRight();
       } else {
-        player.moveLeft();
+        direction = player.moveLeft();
       }
-    }
-    if (time > timeOfMoving) {
-      if (player.getTranslateX() + player.getWidth() / 2
-          < ball.getTranslateX()) {
-        player.moveRight();
-      } else {
-        player.moveLeft();
-      }
-    }
-    if (time == timeOfMoving * 2) {
-      time = 0;
+    } else {
+        if (player.getTranslateX() + player.getWidth() / 2
+            < ball.getTranslateX()) {
+          direction = player.moveRight();
+        } else {
+          direction = player.moveLeft();
+        }
+        if (time == timeOfMoving * 2) {
+          time = 0;
+        }
     }
     time++;
+    return direction;
   }
 
   public boolean isOn() {
diff --git a/src/sample/Constants.java b/src/sample/Constants.java
new file mode 100644
index 0000000..5e2300c
--- /dev/null
+++ b/src/sample/Constants.java
@@ -0,0 +1,34 @@
+package sample;
+
+interface Constants {
+  final int SCENE_WIDTH = 1280;
+  final int SCENE_HEIGHT = 640;
+  final int WALL_WIDTH = 10;
+  final int STROKE_WIDTH = 2;
+  final int TOP_HEIGHT = 30;
+  final int BOTTOM_HEIGHT = 10;
+  final int PLAYER_HEIGHT = 20;
+  final int PLAYER_POS_Y = 570;
+  final char EASY_MODE = 'e';
+  final char MEDIUM_MODE = 'm';
+  final char HARD_MODE = 'h';
+  final int PLAYER_WIDTH_EASY = 280;
+  final int PLAYER_WIDTH_MEDIUM = 200;
+  final int PLAYER_WIDTH_HARD = 200;
+  final int PLAYER_SPEED_EASY = 10;
+  final int PLAYER_SPEED_MEDIUM = 10;
+  final int PLAYER_SPEED_HARD = 20;
+  final int BALL_SPEED_EASY = 5;
+  final int BALL_SPEED_MEDIUM = 5;
+  final int BALL_SPEED_HARD = 10;
+  final int BALL_SIZE = 20;
+  final int BRICKS_IN_RAW = 15;
+  final int BRICKS_IN_COLOMN = 8;
+  final int BRICKS_HEIGHT = 40;
+  final int BRICKS_WIDTH = 80;
+  final int BUTTON_WIDTH = 260;
+  final int BUTTON_HEIGHT = 80;
+  final int MENU_SIZE = 5;
+  final int NEW_GAME_MENU_SIZE = 4;
+  final String REPLAY_FILE = "last_replay";
+}
diff --git a/src/sample/FileWorker.java b/src/sample/FileWorker.java
new file mode 100644
index 0000000..7394719
--- /dev/null
+++ b/src/sample/FileWorker.java
@@ -0,0 +1,34 @@
+package sample;
+
+import java.io.*;
+
+public class FileWorker {
+
+  public static void saveReplay(String fileName, String string) {
+    File file = new File(fileName);
+    try(FileWriter writer = new FileWriter(file, false)) {
+      writer.write(string);
+      writer.flush();
+    }
+    catch(IOException ex) {
+      System.out.println(ex.getMessage());
+    }
+  }
+
+  public static String loadReplay(String fileName) {
+    File file = new File(fileName);
+    String replay = "";
+    try(FileReader reader = new FileReader(file))
+    {
+      char[] buffer = new char[(int)file.length()];
+      reader.read(buffer);
+      replay = new String(buffer);
+    }
+    catch(IOException ex){
+      System.out.println(ex.getMessage());
+    }
+    finally {
+      return replay;
+    }
+  }
+}
diff --git a/src/sample/MoveConstants.java b/src/sample/MoveConstants.java
new file mode 100644
index 0000000..d362fb5
--- /dev/null
+++ b/src/sample/MoveConstants.java
@@ -0,0 +1,7 @@
+package sample;
+
+interface MoveConstants {
+  final char MOVED_RIGHT = 'r';
+  final char MOVED_LEFT = 'l';
+  final char NOT_MOVED = 'n';
+}
diff --git a/src/sample/Player.java b/src/sample/Player.java
index de98d70..d6272f9 100644
--- a/src/sample/Player.java
+++ b/src/sample/Player.java
@@ -3,7 +3,7 @@
 import javafx.scene.paint.Color;
 import javafx.scene.shape.Rectangle;
 
-public class Player extends SimpleObject {
+public class Player extends SimpleObject implements MoveConstants {
   double speed;
   double leftBorder;
   double rightBorder;
@@ -17,17 +17,19 @@
     this.speed = speed;
   }
 
-  public void moveLeft() {
+  public char moveLeft() {
     if (this.getTranslateX() <= leftBorder) {
-      return;
+      return NOT_MOVED;
     }
     setTranslateX(this.getTranslateX() - speed);
+    return MOVED_LEFT;
   }
 
-  public void moveRight() {
+  public char moveRight() {
     if (this.getTranslateX() + this.getWidth() >= rightBorder) {
-      return;
+      return NOT_MOVED;
     }
     setTranslateX(this.getTranslateX() + speed);
+    return MOVED_RIGHT;
   }
 }
diff --git a/src/sample/Serializer.java b/src/sample/Serializer.java
new file mode 100644
index 0000000..3689051
--- /dev/null
+++ b/src/sample/Serializer.java
@@ -0,0 +1,34 @@
+package sample;
+
+import java.io.*;
+
+public class Serializer {
+
+  public static void saveReplay(String fileName, String string) {
+    File file = new File(fileName);
+    try(FileWriter writer = new FileWriter(file, false)) {
+      writer.write(string);
+      writer.flush();
+    }
+    catch(IOException ex) {
+      System.out.println(ex.getMessage());
+    }
+  }
+
+  public static String loadReplay(String fileName) {
+    File file = new File(fileName);
+    String replay = "";
+    try(FileReader reader = new FileReader(file))
+    {
+      char[] buffer = new char[(int)file.length()];
+      reader.read(buffer);
+      replay = new String(buffer);
+    }
+    catch(IOException ex){
+      System.out.println(ex.getMessage());
+    }
+    finally {
+      return replay;
+    }
+  }
+}