Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 41 additions & 43 deletions pom.xml
Original file line number Diff line number Diff line change
@@ -1,94 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<groupId>com.javarush.khmelov</groupId>
<artifactId>project-ledzeppelin</artifactId>
<version>1.0-SNAPSHOT</version>
<name>ProjectLedzeppelin</name>
<groupId>com.javarush.golikov</groupId>
<artifactId>project-pantera</artifactId>
<version>1.0</version>
<packaging>war</packaging>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>21</maven.compiler.target>
<maven.compiler.source>21</maven.compiler.source>
<junit.version>5.10.2</junit.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.5</version>
</parent>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<type>pom</type>
<scope>import</scope>
<version>3.3.5</version>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>

<!-- Tomcat 10 Servlet API -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<scope>provided</scope>
</dependency>

<!-- JSTL API -->
<dependency>
<groupId>jakarta.servlet.jsp.jstl</groupId>
<artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
<version>3.0.0</version>
</dependency>

<!-- JSTL implementation -->
<dependency>
<groupId>org.glassfish.web</groupId>
<artifactId>jakarta.servlet.jsp.jstl</artifactId>
<version>3.0.1</version>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<!-- JUnit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.1</version>
<scope>test</scope>
</dependency>

<!-- Mockito core -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>

</dependencies>

<build>
<finalName>project-pantera</finalName>

<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.4.0</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
</path>
</annotationProcessorPaths>
<source>17</source>
<target>17</target>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
</plugin>
</plugins>

</build>

</project>
5 changes: 5 additions & 0 deletions src/main/java/com/javarush/golikov/quest/auth/Role.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.javarush.golikov.quest.auth;

public enum Role {
ADMIN, USER
}
119 changes: 119 additions & 0 deletions src/main/java/com/javarush/golikov/quest/loader/TxtQuestLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package com.javarush.golikov.quest.loader;

import com.javarush.golikov.quest.model.*;

import java.io.*;
import java.util.*;

public class TxtQuestLoader {

public static Quest load(InputStream in, String questId) throws Exception {

BufferedReader br = new BufferedReader(new InputStreamReader(in));

String title = null;
String startNodeId = null;

Map<String, QuestNode> nodes = new LinkedHashMap<>();

String currentId = null;
String currentText = null;
List<Choice> choices = new ArrayList<>();

String line;
while ((line = br.readLine()) != null) {
line = line.trim();
if (line.isEmpty()) continue;

// ===== TITLE =====
if (line.startsWith("!")) {
title = line.substring(1).trim();
continue;
}

// ===== START NODE =====
if (line.startsWith("*")) {
startNodeId = line.substring(1).trim();
continue;
}

// ===== NODE ID =====
if (line.startsWith("@")) {

if (currentId != null) {
if (currentText == null) {
throw new RuntimeException(
"Node '" + currentId + "' has no text (? ...)"
);
}
nodes.put(currentId,
new QuestNode(currentId, currentText, choices));
}

currentId = line.substring(1).trim();
currentText = null;
choices = new ArrayList<>();
continue;
}

// ===== NODE TEXT =====
if (line.startsWith("?")) {
if (currentId == null) {
throw new RuntimeException(
"Text before node id: " + line
);
}
currentText = line.substring(1).trim();
continue;
}

// ===== CHOICES =====
if (line.startsWith("+") || line.startsWith("-")) {
if (currentId == null) {
throw new RuntimeException(
"Choice before node id: " + line
);
}

String[] parts = line.substring(1).trim().split("->");
if (parts.length != 2) {
throw new RuntimeException(
"Invalid choice format: " + line
);
}

choices.add(new Choice(
parts[0].trim(),
parts[1].trim(),
line.startsWith("+")
));
}
}

// ===== последний узел =====
if (currentId != null) {
if (currentText == null) {
throw new RuntimeException(
"Node '" + currentId + "' has no text (? ...)"
);
}
nodes.put(currentId,
new QuestNode(currentId, currentText, choices));
}

// ===== ВАЛИДАЦИЯ =====
if (title == null) {
throw new RuntimeException("Quest has no title (!...)");
}
if (startNodeId == null) {
throw new RuntimeException("Quest has no start node (*...)");
}
if (!nodes.containsKey(startNodeId)) {
throw new RuntimeException(
"Start node not found: " + startNodeId
);
}

return new Quest(questId, title, startNodeId, nodes);
}
}
4 changes: 4 additions & 0 deletions src/main/java/com/javarush/golikov/quest/model/Choice.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.javarush.golikov.quest.model;

public record Choice(String text, String next, boolean positive) {
}
31 changes: 31 additions & 0 deletions src/main/java/com/javarush/golikov/quest/model/Quest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.javarush.golikov.quest.model;

import java.util.Map;

public class Quest {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Отсутствует конструктор по умолчанию или конструктор со всеми полями. Стоит явно определить инициализацию объекта.

private final String id;
private final String title;
private final String startNode;
private final Map<String, QuestNode> nodes;

public Quest(String id, String title, String startNode, Map<String, QuestNode> nodes) {
this.id = id;
this.title = title;
this.startNode = startNode;
this.nodes = nodes;
}

public QuestNode getStart() {
return nodes.get(startNode);
}

public QuestNode getNode(String id) {
return nodes.get(id);
}

public String getTitle() { return title; }

public String getId() {
return id;
}
}
17 changes: 17 additions & 0 deletions src/main/java/com/javarush/golikov/quest/model/QuestNode.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.javarush.golikov.quest.model;

import java.util.List;
import java.util.Objects;

public record QuestNode(String id, String text, List<Choice> choices) {

public QuestNode(String id, String text, List<Choice> choices) {
this.id = Objects.requireNonNull(id, "Node id must not be null");
this.text = Objects.requireNonNull(text, "Node text must not be null");
this.choices = List.copyOf(choices);
}

public boolean isFinal() {
return choices.isEmpty();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.javarush.golikov.quest.model;

public record QuestResult(
String login,
String questId,
boolean win
) {}
62 changes: 62 additions & 0 deletions src/main/java/com/javarush/golikov/quest/model/QuestSession.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.javarush.golikov.quest.model;

import java.util.ArrayList;
import java.util.List;

public class QuestSession {

private final String questId;
private String currentNode;

// история шагов
private final List<Step> history = new ArrayList<>();

// состояние завершения
private boolean finished = false;
private boolean win = false;

public QuestSession(String questId, String startNode) {
this.questId = questId;
this.currentNode = startNode;
}

public String getQuestId() {
return questId;
}

public String getCurrentNode() {
return currentNode;
}

public void setCurrentNode(String currentNode) {
this.currentNode = currentNode;
}

public List<Step> getHistory() {
return history;
}

// добавить шаг в историю
public void addStep(String questionText, String answerText, boolean positive) {
history.add(new Step(questionText, answerText, positive));
}

// завершение
public void win() {
finished = true;
win = true;
}

public void lose() {
finished = true;
win = false;
}

public boolean isFinished() {
return finished;
}

public boolean isWin() {
return win;
}
}
Loading