From dbab0775be7609cee64ab36e0a926e2b0bbbc0be Mon Sep 17 00:00:00 2001
From: jez04 <david.jezek@post.cz>
Date: Sun, 9 Mar 2025 23:51:21 +0100
Subject: [PATCH] feat: :tada: solution

---
 .gitignore                                    |  3 +-
 pom.xml                                       | 16 +++
 src/main/java/lab/Config.java                 | 99 +++++++++++++++++--
 src/main/java/lab/data/Score.java             | 18 ++++
 src/main/java/lab/game/Monster.java           |  9 +-
 src/main/java/lab/gui/App.java                | 11 ++-
 src/main/java/lab/gui/GameController.java     |  6 ++
 .../java/lab/gui/MainScreenController.java    |  6 ++
 src/main/java/module-info.java                |  1 +
 src/main/resources/log4j2.xml                 | 36 +++++++
 10 files changed, 191 insertions(+), 14 deletions(-)
 create mode 100644 src/main/resources/log4j2.xml

diff --git a/.gitignore b/.gitignore
index 96d545b..236e427 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+/logs/
 /target/
 /bin/
 .settings/
@@ -5,4 +6,4 @@
 .classpath
 .idea/
 *.mv.db
-*.trace.db
\ No newline at end of file
+*.trace.db
diff --git a/pom.xml b/pom.xml
index 3b70e3b..618b538 100644
--- a/pom.xml
+++ b/pom.xml
@@ -13,6 +13,22 @@
 		<maven.compiler.target>21</maven.compiler.target>
 	</properties>
 	<dependencies>
+		<!--
+		https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-core -->
+		<dependency>
+			<groupId>org.apache.logging.log4j</groupId>
+			<artifactId>log4j-core</artifactId>
+			<version>2.24.3</version>
+		</dependency>
+
+		<!--
+		https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-api -->
+		<dependency>
+			<groupId>org.apache.logging.log4j</groupId>
+			<artifactId>log4j-api</artifactId>
+			<version>2.24.3</version>
+		</dependency>
+
 		<dependency>
 			<groupId>com.h2database</groupId>
 			<artifactId>h2</artifactId>
diff --git a/src/main/java/lab/Config.java b/src/main/java/lab/Config.java
index f1aa8b7..0a18ac1 100644
--- a/src/main/java/lab/Config.java
+++ b/src/main/java/lab/Config.java
@@ -7,19 +7,33 @@ public class Config {
 
 	private static Config instance;
 
-	private ScoreStorageInterface scoreStorageInterface = new DbConnector();
-	private double monsterMinXPopsition = 0.5;
-	private double monsterMinSpeed = 50;
-	private double monsterMaxSpeed = 150;
-	private double obstacleWidth = 30;
-	private double obstacleHeight = 20;
-	private double playerStartSpeed= 50;
-	private int monsterMultiplier= 1;
-	
+	private ScoreStorageInterface scoreStorageInterface;
+	private double monsterMinXPopsition;
+	private double monsterMinSpeed;
+	private double monsterMaxSpeed;
+	private double obstacleWidth;
+	private double obstacleHeight;
+	private double playerStartSpeed;
+	private int monsterMultiplier;
+
 	public static void configure(Config setting) {
 		instance = setting;
 	}
 
+	private Config(ScoreStorageInterface scoreStorageInterface, double monsterMinXPopsition, double monsterMinSpeed,
+			double monsterMaxSpeed, double obstacleWidth, double obstacleHeight, double playerStartSpeed,
+			int monsterMultiplier) {
+		super();
+		this.scoreStorageInterface = scoreStorageInterface;
+		this.monsterMinXPopsition = monsterMinXPopsition;
+		this.monsterMinSpeed = monsterMinSpeed;
+		this.monsterMaxSpeed = monsterMaxSpeed;
+		this.obstacleWidth = obstacleWidth;
+		this.obstacleHeight = obstacleHeight;
+		this.playerStartSpeed = playerStartSpeed;
+		this.monsterMultiplier = monsterMultiplier;
+	}
+
 	public static Config getInstance() {
 		return instance;
 	}
@@ -55,6 +69,71 @@ public class Config {
 	public int getMonsterMultiplier() {
 		return monsterMultiplier;
 	}
-	
+
+	public static Builder builder() {
+		return new Builder();
+	}
+
+	public static Config getInstanceForHardcoreGame() {
+		return builder().monsterMinSpeed(150).monsterMaxSpeed(500).monsterMultiplier(5).monsterMinXPopsition(0.2)
+				.build();
+	}
+
+	public static class Builder {
+		private ScoreStorageInterface scoreStorageInterface = new DbConnector();
+		private double monsterMinXPopsition = 0.5;
+		private double monsterMinSpeed = 50;
+		private double monsterMaxSpeed = 150;
+		private double obstacleWidth = 30;
+		private double obstacleHeight = 20;
+		private double playerStartSpeed = 50;
+		private int monsterMultiplier = 1;
+
+		public Builder scoreStorageInterface(ScoreStorageInterface scoreStorageInterface) {
+			this.scoreStorageInterface = scoreStorageInterface;
+			return this;
+		}
+
+		public Builder monsterMinXPopsition(double monsterMinXPopsition) {
+			this.monsterMinXPopsition = monsterMinXPopsition;
+			return this;
+		}
+
+		public Builder monsterMinSpeed(double monsterMinSpeed) {
+			this.monsterMinSpeed = monsterMinSpeed;
+			return this;
+		}
+
+		public Builder monsterMaxSpeed(double monsterMaxSpeed) {
+			this.monsterMaxSpeed = monsterMaxSpeed;
+			return this;
+		}
+
+		public Builder obstacleWidth(double obstacleWidth) {
+			this.obstacleWidth = obstacleWidth;
+			return this;
+		}
+
+		public Builder obstacleHeight(double obstacleHeight) {
+			this.obstacleHeight = obstacleHeight;
+			return this;
+		}
+
+		public Builder playerStartSpeed(double playerStartSpeed) {
+			this.playerStartSpeed = playerStartSpeed;
+			return this;
+		}
+
+		public Builder monsterMultiplier(int monsterMultiplier) {
+			this.monsterMultiplier = monsterMultiplier;
+			return this;
+		}
+
+		public Config build() {
+			return new Config(scoreStorageInterface, monsterMinXPopsition, monsterMinSpeed, monsterMaxSpeed,
+					obstacleWidth, obstacleHeight, playerStartSpeed, monsterMultiplier);
+		}
+
+	}
 
 }
diff --git a/src/main/java/lab/data/Score.java b/src/main/java/lab/data/Score.java
index 01dc746..a9993a9 100644
--- a/src/main/java/lab/data/Score.java
+++ b/src/main/java/lab/data/Score.java
@@ -1,5 +1,6 @@
 package lab.data;
 
+import java.util.Objects;
 import java.util.Random;
 
 public class Score {
@@ -30,6 +31,23 @@ public class Score {
 		this.points = points;
 	}
 
+	@Override
+	public int hashCode() {
+		return Objects.hash(name, points);
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		Score other = (Score) obj;
+		return Objects.equals(name, other.name) && points == other.points;
+	}
+
 	@Override
 	public String toString() {
 		return "Score [name=" + name + ", points=" + points + "]";
diff --git a/src/main/java/lab/game/Monster.java b/src/main/java/lab/game/Monster.java
index 0bca7df..a256acc 100644
--- a/src/main/java/lab/game/Monster.java
+++ b/src/main/java/lab/game/Monster.java
@@ -4,6 +4,9 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Random;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
 import javafx.geometry.Dimension2D;
 import javafx.geometry.Point2D;
 import javafx.geometry.Rectangle2D;
@@ -13,6 +16,8 @@ import lab.Config;
 
 public class Monster extends WorldEntity implements Collisionable {
 
+	private static Logger log = LogManager.getLogger(Monster.class);
+
 	private static final Random RANDOM = new Random();
 
 	private Image image;
@@ -41,6 +46,7 @@ public class Monster extends WorldEntity implements Collisionable {
 
 	public void changeDirection() {
 		speed = speed.multiply(-1);
+		log.debug("Monster chaned direction.");
 	}
 
 	public void simulate(double delay) {
@@ -49,7 +55,7 @@ public class Monster extends WorldEntity implements Collisionable {
 		if (position.getY() + image.getHeight() < 0) {
 			position = new Point2D(position.getX(), level.getHeight());
 		}
-	}
+		log.trace("Monster position: {}", position);	}
 
 	@Override
 	public Rectangle2D getBoundingBox() {
@@ -63,6 +69,7 @@ public class Monster extends WorldEntity implements Collisionable {
 
 	@Override
 	public void hitBy(Collisionable another) {
+		log.trace("Moster hitted by {}.", another);
 		if (another instanceof Player) {
 			level.remove(this);
 			level.add(new Obstacle(level, getPosition(), new Dimension2D(Config.getInstance().getObstacleWidth(),
diff --git a/src/main/java/lab/gui/App.java b/src/main/java/lab/gui/App.java
index 62f014e..270f551 100644
--- a/src/main/java/lab/gui/App.java
+++ b/src/main/java/lab/gui/App.java
@@ -3,6 +3,9 @@ package lab.gui;
 import java.io.IOException;
 import java.net.URL;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
 import javafx.application.Application;
 import javafx.fxml.FXMLLoader;
 import javafx.scene.Parent;
@@ -19,12 +22,14 @@ import lab.Config;
  */
 public class App extends Application {
 
+	private static Logger log = LogManager.getLogger(App.class);
 	private GameController gameController;
 	
 	private Stage primaryStage;
 	
 	public static void main(String[] args) {
-		Config.configure(new Config());
+		log.info("Application lauched");
+		Config.configure(Config.getInstanceForHardcoreGame());
 		launch(args);
 	}
 
@@ -38,7 +43,7 @@ public class App extends Application {
 			// Exit program when main window is closed
 			primaryStage.setOnCloseRequest(this::exitProgram);
 		} catch (Exception e) {
-			e.printStackTrace();
+			log.error("Error during game play.", e);
 		}
 	}
 
@@ -71,9 +76,11 @@ public class App extends Application {
 			gameController.stop();
 		}
 		super.stop();
+		log.info("Gamne stoped");
 	}
 
 	private void exitProgram(WindowEvent evt) {
+		log.info("Exiting game");
 		System.exit(0);
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/lab/gui/GameController.java b/src/main/java/lab/gui/GameController.java
index 13c98d5..fde1322 100644
--- a/src/main/java/lab/gui/GameController.java
+++ b/src/main/java/lab/gui/GameController.java
@@ -1,5 +1,8 @@
 package lab.gui;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
 import javafx.animation.AnimationTimer;
 import javafx.beans.value.ObservableValue;
 import javafx.event.ActionEvent;
@@ -15,6 +18,8 @@ import lab.game.MujListener;
 
 public class GameController {
 
+	private static Logger log = LogManager.getLogger(GameController.class);
+
 	private AnimationTimer timer;
 	private Level level;
 
@@ -60,6 +65,7 @@ public class GameController {
 					level.getPlayer().setSpeed(newValue.doubleValue());
 				});
 
+		log.info("Screeen initialized.");
 	}
 
 	public void startGame(String name, int numberOfMonsters) {
diff --git a/src/main/java/lab/gui/MainScreenController.java b/src/main/java/lab/gui/MainScreenController.java
index f362c76..45c849a 100644
--- a/src/main/java/lab/gui/MainScreenController.java
+++ b/src/main/java/lab/gui/MainScreenController.java
@@ -3,6 +3,9 @@ package lab.gui;
 import java.io.IOException;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
 import javafx.event.ActionEvent;
 import javafx.fxml.FXML;
 import javafx.scene.control.Button;
@@ -21,6 +24,8 @@ import lab.game.Difficult;
  */
 public class MainScreenController {
 
+	private static Logger log = LogManager.getLogger(MainScreenController.class);
+
     @FXML
     private Button btnGenerateScore;
 
@@ -100,6 +105,7 @@ public class MainScreenController {
 		pointsColumn.setCellValueFactory(new PropertyValueFactory<>("points"));
 		
 		initDB();
+		log.info("Screeen initialized.");
 	}
 	
 	private void initDB() {
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index 732cf18..75517d2 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -3,6 +3,7 @@ module cz.vsb.fei.java2.lab03_module {
 	requires javafx.fxml;
 	requires javafx.base;
 	requires java.sql;
+	requires org.apache.logging.log4j;
 
 	opens lab.gui to javafx.fxml;
 	opens lab.data to javafx.base;
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
new file mode 100644
index 0000000..da032d3
--- /dev/null
+++ b/src/main/resources/log4j2.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration xmlns="https://logging.apache.org/xml/ns"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="
+                   https://logging.apache.org/xml/ns
+                   https://logging.apache.org/xml/ns/log4j-config-2.xsd">
+	<Appenders>
+		<Console name="Console">
+			<PatternLayout
+				pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
+		</Console>
+		<RollingFile name="File" fileName="logs/app.log"
+			filePattern="logs/app.%d{yyyy-MM-dd}.%i.log.gz">
+			<PatternLayout
+				pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n" />
+			<DefaultRolloverStrategy max="5">
+				<Delete basePath="logs">
+					<IfAccumulatedFileSize  exceeds="2.2M" />
+				</Delete>
+			</DefaultRolloverStrategy>
+			<Policies>
+				<OnStartupTriggeringPolicy />
+				<SizeBasedTriggeringPolicy size="10M" />
+				<TimeBasedTriggeringPolicy interval="1" />
+			</Policies>
+		</RollingFile>
+	</Appenders>
+	<Loggers>
+		<Root level="INFO">
+			<AppenderRef ref="Console" level="INFO"/>
+			<AppenderRef ref="File" />
+		</Root>
+		<Logger name="lab.game" level="TRACE">
+		</Logger>
+	</Loggers>
+</Configuration>
-- 
GitLab