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

---
 .gitignore                                |   1 +
 pom.xml                                   |  16 ++++
 src/main/java/lab/Setting.java            | 102 ++++++++++++++++++++--
 src/main/java/lab/data/Score.java         |  19 ++++
 src/main/java/lab/game/Ufo.java           |   8 ++
 src/main/java/lab/gui/App.java            |  12 ++-
 src/main/java/lab/gui/GameController.java |   8 +-
 src/main/java/module-info.java            |  15 ++--
 src/main/resources/log4j2.xml             |  36 ++++++++
 9 files changed, 199 insertions(+), 18 deletions(-)
 create mode 100644 src/main/resources/log4j2.xml

diff --git a/.gitignore b/.gitignore
index e312b71..9df5a18 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+/logs/
 /target/
 .settings/
 .project
diff --git a/pom.xml b/pom.xml
index 4ea98d1..3905639 100644
--- a/pom.xml
+++ b/pom.xml
@@ -14,6 +14,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/Setting.java b/src/main/java/lab/Setting.java
index b8fe27c..e314258 100644
--- a/src/main/java/lab/Setting.java
+++ b/src/main/java/lab/Setting.java
@@ -7,20 +7,35 @@ public class Setting {
 
 	private static Setting instance;
 
-	private ScoreStorageInterface scoreStorageInterface = new DbConnector();
-	private double gravity = 9.81;
-	private double normalBulletSpeed = 30;
-	private int numberOfUfos = 3;
-	private double ufoMinPercentageHeight = 0.3;
-	private double ufoMinSpeed = 70;
-	private double ufoMaxSpeed = 150;
-	private double bulletMinSpeed = 30;
-	private double bulletMaxSpeed = 300;
+	private ScoreStorageInterface scoreStorageInterface;
+	private double gravity;
+	private double normalBulletSpeed;
+	private int numberOfUfos;
+	private double ufoMinPercentageHeight;
+	private double ufoMinSpeed;
+	private double ufoMaxSpeed;
+	private double bulletMinSpeed;
+	private double bulletMaxSpeed;
 
 	public static void configure(Setting setting) {
 		instance = setting;
 	}
 
+	private Setting(ScoreStorageInterface scoreStorageInterface, double gravity, double normalBulletSpeed,
+			int numberOfUfos, double ufoMinPercentageHeight, double ufoMinSpeed, double ufoMaxSpeed,
+			double bulletMinSpeed, double bulletMaxSpeed) {
+		super();
+		this.scoreStorageInterface = scoreStorageInterface;
+		this.gravity = gravity;
+		this.normalBulletSpeed = normalBulletSpeed;
+		this.numberOfUfos = numberOfUfos;
+		this.ufoMinPercentageHeight = ufoMinPercentageHeight;
+		this.ufoMinSpeed = ufoMinSpeed;
+		this.ufoMaxSpeed = ufoMaxSpeed;
+		this.bulletMinSpeed = bulletMinSpeed;
+		this.bulletMaxSpeed = bulletMaxSpeed;
+	}
+
 	public static Setting getInstance() {
 		return instance;
 	}
@@ -61,4 +76,73 @@ public class Setting {
 		return bulletMaxSpeed;
 	}
 
+	public static Builder builder() {
+		return new Builder();
+	}
+
+	public static Setting getInstanceForHardcoreGame() {
+		return builder().numberOfUfos(50).ufoMinPercentageHeight(0.9).ufoMinSpeed(200).ufoMaxSpeed(500).build();
+	}
+
+	public static class Builder {
+		private ScoreStorageInterface scoreStorageInterface = new DbConnector();
+		private double gravity = 9.81;
+		private double normalBulletSpeed = 30;
+		private int numberOfUfos = 3;
+		private double ufoMinPercentageHeight = 0.3;
+		private double ufoMinSpeed = 70;
+		private double ufoMaxSpeed = 150;
+		private double bulletMinSpeed = 30;
+		private double bulletMaxSpeed = 300;
+
+		public Builder bulletMaxSpeed(double bulletMaxSpeed) {
+			this.bulletMaxSpeed = bulletMaxSpeed;
+			return this;
+		}
+
+		public Builder scoreStorageInterface(ScoreStorageInterface scoreStorageInterface) {
+			this.scoreStorageInterface = scoreStorageInterface;
+			return this;
+		}
+
+		public Builder gravity(double gravity) {
+			this.gravity = gravity;
+			return this;
+		}
+
+		public Builder normalBulletSpeed(double normalBulletSpeed) {
+			this.normalBulletSpeed = normalBulletSpeed;
+			return this;
+		}
+
+		public Builder numberOfUfos(int numberOfUfos) {
+			this.numberOfUfos = numberOfUfos;
+			return this;
+		}
+
+		public Builder ufoMinPercentageHeight(double ufoMinPercentageHeight) {
+			this.ufoMinPercentageHeight = ufoMinPercentageHeight;
+			return this;
+		}
+
+		public Builder ufoMinSpeed(double ufoMinSpeed) {
+			this.ufoMinSpeed = ufoMinSpeed;
+			return this;
+		}
+
+		public Builder ufoMaxSpeed(double ufoMaxSpeed) {
+			this.ufoMaxSpeed = ufoMaxSpeed;
+			return this;
+		}
+
+		public Builder bulletMinSpeed(double bulletMinSpeed) {
+			this.bulletMinSpeed = bulletMinSpeed;
+			return this;
+		}
+
+		public Setting build() {
+			return new Setting(scoreStorageInterface, gravity, normalBulletSpeed, numberOfUfos, ufoMinPercentageHeight,
+					ufoMinSpeed, ufoMaxSpeed, bulletMinSpeed, bulletMaxSpeed);
+		}
+	}
 }
diff --git a/src/main/java/lab/data/Score.java b/src/main/java/lab/data/Score.java
index 01dc746..543ebfb 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,24 @@ 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/Ufo.java b/src/main/java/lab/game/Ufo.java
index 3aca92b..0d93233 100644
--- a/src/main/java/lab/game/Ufo.java
+++ b/src/main/java/lab/game/Ufo.java
@@ -2,6 +2,9 @@ package lab.game;
 
 import java.util.Random;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
 import javafx.geometry.Point2D;
 import javafx.geometry.Rectangle2D;
 import javafx.scene.canvas.GraphicsContext;
@@ -10,6 +13,8 @@ import lab.Setting;
 
 public class Ufo extends WorldEntity implements Collisionable {
 
+	private static Logger log = LogManager.getLogger(Ufo.class);
+
 	private static final Random RANDOM = new Random();
 	private Image image;
 	private Point2D velocity;
@@ -42,6 +47,7 @@ public class Ufo extends WorldEntity implements Collisionable {
 
 	public void changeDirection() {
 		velocity = velocity.multiply(-1);
+		log.debug("Ufo chaned direction.");
 	}
 
 	@Override
@@ -51,6 +57,7 @@ public class Ufo extends WorldEntity implements Collisionable {
 		if (position.getX() < -getImage().getWidth()) {
 			position = new Point2D(world.getWidth(), position.getY());
 		}
+		log.trace("Ufo position: {}", position);
 	}
 
 	@Override
@@ -65,6 +72,7 @@ public class Ufo extends WorldEntity implements Collisionable {
 
 	@Override
 	public void hitBy(Collisionable another) {
+		log.trace("Ufo hitted by {}.", another);
 		if (another instanceof BulletAnimated || another instanceof Bullet) {
 			world.remove(this);
 		}
diff --git a/src/main/java/lab/gui/App.java b/src/main/java/lab/gui/App.java
index d36a948..8f3f163 100644
--- a/src/main/java/lab/gui/App.java
+++ b/src/main/java/lab/gui/App.java
@@ -1,5 +1,8 @@
 package lab.gui;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
 import javafx.application.Application;
 import javafx.fxml.FXMLLoader;
 import javafx.scene.Parent;
@@ -16,9 +19,12 @@ import lab.Setting;
  */
 public class App extends Application {
 
+	private static Logger log = LogManager.getLogger(App.class);
 	private GameController gameController;
+
 	public static void main(String[] args) {
-		Setting.configure(new Setting());
+		log.info("Application lauched");
+		Setting.configure(Setting.getInstanceForHardcoreGame());
 		launch(args);
 	}
 
@@ -36,7 +42,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);
 		}
 	}
 
@@ -44,9 +50,11 @@ public class App extends Application {
 	public void stop() throws Exception {
 		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 26a8a6a..7d15ecb 100644
--- a/src/main/java/lab/gui/GameController.java
+++ b/src/main/java/lab/gui/GameController.java
@@ -2,6 +2,9 @@ package lab.gui;
 
 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.geometry.Point2D;
@@ -20,6 +23,8 @@ import lab.game.World;
 
 public class GameController {
 
+	private static Logger log = LogManager.getLogger(GameController.class);
+
 	@FXML
 	private Button btnGenerateScore;
 
@@ -63,7 +68,7 @@ public class GameController {
 				timer.getWorld().getCannon().getPosition(), velocity, World.GRAVITY);
 		timer.getWorld().add(bulletAnimated);
 		bulletAnimated.addHitListener(this::increaseHits);
-		bulletAnimated.addHitListener(() -> System.out.println("au!!!!"));
+		bulletAnimated.addHitListener(() -> log.info("au!!!!"));
 	}
 
 	@FXML
@@ -113,6 +118,7 @@ public class GameController {
 		pointsColumn.setCellValueFactory(new PropertyValueFactory<>("points"));
 
 		initStorage();
+		log.info("Screeen initialized.");
 	}
 
 	private void initStorage() {
diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java
index 02438d1..75517d2 100644
--- a/src/main/java/module-info.java
+++ b/src/main/java/module-info.java
@@ -1,9 +1,12 @@
 module cz.vsb.fei.java2.lab03_module {
-    requires transitive javafx.controls;
-    requires javafx.fxml;
-    requires javafx.base;
+	requires transitive javafx.controls;
+	requires javafx.fxml;
+	requires javafx.base;
 	requires java.sql;
-    opens lab.gui to javafx.fxml;
-    opens lab.data to javafx.base;
-    exports lab.gui to javafx.fxml,javafx.graphics;
+	requires org.apache.logging.log4j;
+
+	opens lab.gui to javafx.fxml;
+	opens lab.data to javafx.base;
+
+	exports lab.gui to javafx.fxml, javafx.graphics;
 }
\ No newline at end of file
diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml
new file mode 100644
index 0000000..53c0964
--- /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="21M" />
+				</Delete>
+			</DefaultRolloverStrategy>
+			<Policies>
+				<OnStartupTriggeringPolicy />
+				<SizeBasedTriggeringPolicy size="20M" />
+				<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