Updated model

This commit is contained in:
Alexander Karpov 2023-12-30 00:33:13 +03:00
parent d391c6904a
commit f9b8903711
23 changed files with 538 additions and 217 deletions

119
README.md
View File

@ -1,73 +1,82 @@
# itmo-prog-lab-4 # itmo-prog-lab-4
## Class Description ## Class Description
### StoryTeller ### Package: `characters`
- The primary class of the application. It establishes the story's framework, incorporating the city, house, and characters, and initiates the storytelling process. - **Character.java**: An abstract class representing a character in the story. Implements `Listenable` and `Conversable` interfaces.
- **Connections**: Inherits from `StoryElement` in `model` package. Used by `Child` and `Traveler`.
- **Child.java**: Represents child characters in the story, capable of thinking and conversing about story elements.
- **Connections**: Inherits from `Character`.
- **Traveler.java**: Represents traveler characters in the story, who can tell stories about their adventures.
- **Connections**: Inherits from `Character`. Interacts with `Adventure` in `story` package.
- **Znayka.java**: A specific implementation of `Traveler`, representing the character Znayka.
- **Connections**: Inherits from `Traveler`.
### Package: characters ### Package: `enums`
- **Character.java**: This abstract class forms the foundation for all character types, implementing `Listenable` and `Conversable` interfaces. - **CharacterType.java**: Defines character types (TRAVELER, CHILD).
- **Child.java**: Represents child characters who listen to and inquire about stories. - **AdventureType.java**: Defines types of adventures (FAMOUS, UNKNOWN).
- **Traveler.java**: Depicts traveler characters who share tales of their adventures. - **LifeType.java**: Defines types of life (NOT_AS_USUAL, AS_USUAL).
- **Znayka.java**: A specialized traveler character with extended capabilities.
### Package: enums ### Package: `exceptions`
- **CharacterType.java**: Enumerates different character types, such as `TRAVELER` and `CHILD`. - **StoryEventException.java**: Custom exception to handle specific story-related errors.
- **StoryLogicException.java**: Custom runtime exception for handling logic errors in the story.
### Package: interfaces ### Package: `interfaces`
- **Listenable.java**: An interface for characters that can listen to stories. - **Interactable.java**: Interface for story elements that can interact.
- **Conversable.java**: An interface for characters that can engage in discussions about specific story subjects. - **Conversable.java**: Interface for characters that can converse.
- **Listenable.java**: Interface for characters that can listen.
### Package: model ### Package: `model`
- **City.java**: Symbolizes a city in the story, featuring a method to simulate life resuming with changes. - **StoryElement.java**: An abstract class representing a story element with a description and metadata.
- **House.java**: Represents a house where characters reside and where storytelling happens. - **Connections**: Parent class for `Location`.
- **StoryElement.java**: An abstract base class for story components like City and House. - **City.java**: Represents a city in the story, managing travelers, children, and houses.
- **Connections**: Inherits from `Location`. Aggregates `Traveler`, `Child`, and `House` from `characters` package.
- **House.java**: Represents a house in the city, hosting residents and stories.
- **Connections**: Inherits from `Location`. Contains `Character` from `characters` package.
- **Location.java**: An abstract class representing a location in the story.
- **Connections**: Parent class for `City` and `House`.
### Package: story ### Package: `story`
- **Narrative.java**: Manages a series of story events. - **StoryEvent.java**: Represents an event in the story.
- **StoryContext.java**: Provides the narrative backdrop, linking the city, house, and the main story theme. - **Connections**: Used in `City` from `model` package.
- **StoryEvent.java**: Constitutes individual events within the narrative. - **StoryContext.java**: Provides context for the story elements.
- **Connections**: Used in `Adventure` and `House` from `model` package.
- **Adventure.java**: Represents an adventure in the story, involving travelers and locations.
- **Connections**: Uses `Traveler` from `characters` package, `City` and `House` from `model` package.
### Package: exceptions ### Main Class
- **StoryException.java**: Handles exceptions specific to the storytelling process. - **StoryTeller.java**: Main class orchestrating the storytelling process. Initializes the story's setting, characters, and events.
- **StoryRuntimeException.java**: Manages runtime exceptions within the story. - **Connections**: Uses instances of `City`, `Traveler`, `House`, `Child`, `Adventure` from the respective packages, and handles exceptions.
## Interactions and Configurations
- **StoryTeller**: Sets up the storytelling environment by creating a city, a house (Znayka's house), and characters (Znayka, Malish, and Malishka), then initiates the storytelling sequence in Znayka's house.
- **Character Classes**: Each character type (`Child`, `Traveler`, `Znayka`) interacts uniquely within the narrative. Children listen and pose questions, while travelers focus on recounting their adventures.
- **Interfaces**: `Listenable` and `Conversable` are implemented distinctly across character classes, enabling varied behaviors during the storytelling sessions.
- **Model Classes**: `City` and `House` form the physical backdrop of the story. The `House` class, in particular, is central to the gathering of characters and the exchange of stories.
- **Story Classes**: `StoryContext` connects the narrative's physical and thematic elements. `Narrative` and `StoryEvent` orchestrate the progression and individual occurrences of the story.
- **Exception Handling**: The `exceptions` package ensures robust error handling during the storytelling process, with `StoryException` and `StoryRuntimeException` tailored to specific storytelling scenarios.
## Query
```
На этом знаменитое путешествие Знайки и его товарищей окончилось.
Жизнь в Цветочном городе потекла по-старому... хотя нет, нельзя сказать, чтобы совсем по-старому.
С тех пор как наши отважные путешественники вернулись домой, в городе только и говорили о них.
Все жители, и малыши и малышки, приходили по вечерам к домику Знайки и слушали рассказы путешественников об их жизни в Зеленом городе.
```
## Output ## Output
``` ```
Translating story on Bus 0 Device 0: ID 0x0:JMTek, LLC. USB PnP Audio Device На этом знаменитое путешествие Знайка закончилось.
Translating story on Bus 1 Device 1: ID 0x10101:Creative Technology, Ltd SoundBlaster MP3+ Жители Цветочный город собрались вместе, чтобы отпраздновать возвращение путешественников.
Translating story on Bus 2 Device 2: ID 0x20202:Sennheiser Communications USB Headset Путешественники столкнулись с проблемой
Translating story on Bus 3 Device 3: ID 0x30303:Bluetooth Audio Device Путешественники вспомнили о путешествие в Зеленый город
[DEBUG] Story Element Created: Цветочный город
[DEBUG] Story Element Created: Домик Знайки
[DEBUG] Story Element Created: TRAVELER Знайка
[DEBUG] Story Element Created: CHILD Малыш
[DEBUG] Story Element Created: CHILD Малышка
[DEBUG] Interaction with 'Домик Знайки': Starting evening stories session
Жители собираются в Домик Знайки чтобы рассказать истории
Все жители, и малыши и малышки, приходили по вечерам к Домик Знайки и слушали рассказы путешественников.
Жизнь в Цветочный город потекла по-старому... хотя нет, нельзя сказать, чтобы совсем по-старому. Жизнь в Цветочный город потекла по-старому... хотя нет, нельзя сказать, чтобы совсем по-старому.
Жители собираются в Домик Знайки чтобы рассказать истории С тех пор как наши отважные путешественники Знайка вернулись домой, в городе только и говорили о них.
Знайка рассказывает историю о путешествие в Зеленый город Жители собираются в Дом Знайки чтобы рассказать истории
Малыш слушает историю о путешествия Знайки и спрашивает вопросы о путешествие в Зеленый город Все жители слушают историю о путешествии в путешествие в Зеленый город в Цветочный город
Внезапный флешбенгер И вот, когда все собрались в доме Знайка, Знайка рассказал историю о том, как он путешествие в Зеленый город в Цветочный город
[DEBUG] Interaction with 'Домик Знайки': Внезапный флешбенгер Малыш слушает: Малыш слушает историю о путешествие в Зеленый город и спрашивает вопросы о путешествие в Зеленый город
Малышка слушает историю о путешествия Знайки и спрашивает вопросы о путешествие в Зеленый город Малышка слушает: Малышка слушает историю о путешествие в Зеленый город и спрашивает вопросы о путешествие в Зеленый город
Знайка рассказывает историю о жизнь в Цветочном городе Знайка рассказывает: Знайка умно рассказывает историю о путешествие в Зеленый город
Малыш слушает историю о путешествия Знайки и спрашивает вопросы о жизнь в Цветочном городе и думает: Немного я знаю о городах, но история о путешествие в Зеленый город мне очень понравилась
Малышка слушает историю о путешествия Знайки и спрашивает вопросы о жизнь в Цветочном городе
Истории захватывали дух, и каждый вечер собирались всё больше жителей, чтобы слышать новые приключения. Истории захватывали дух, и каждый вечер собирались всё больше жителей, чтобы слушать новые приключения.
Error in storytelling: No stories available to tell.
``` ```
## UML Diagram ## UML Diagram
![UML Diagram](https://new.akarpov.ru/media/files/sanspie/DmZte/diagram.svg "https://new.akarpov.ru/files/YsvFMeuMCbOpfnOlOlyN") ![UML Diagram](https://new.akarpov.ru/media/files/sanspie/eNCBb/bebra2.svg "https://new.akarpov.ru/files/GKoEHHkHACqWRrehyNZe")
## Вывод
В ходе выполнения данной лабораторной работы я научился работать с интерфейсами, абстрактными классами, исключениями, локальными классами, анонимными классами.

View File

@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -1,69 +1,79 @@
import characters.Character; import enums.AdventureType;
import exceptions.StoryException; import enums.LifeType;
import exceptions.StoryEventException;
import exceptions.StoryLogicException;
import model.*; import model.*;
import characters.*; import characters.*;
import story.StoryContext; import story.Adventure;
import java.util.ArrayList;
import java.util.List; import java.util.List;
public class StoryTeller { public class StoryTeller {
public static void main(String[] args) { // На этом знаменитое путешествие Знайки и его товарищей окончилось.
class DevStoryListener { // Жизнь в Цветочном городе потекла по-старому... хотя нет, нельзя сказать, чтобы совсем по-старому.
private int devNum = 0; // С тех пор как наши отважные путешественники вернулись домой, в городе только и говорили о них.
// Все жители, и малыши и малышки, приходили по вечерам к домику Знайки и слушали рассказы путешественников об их жизни в Зеленом городе.
void listenToStory(String device) { public static void main(String[] args) {
System.out.println("Translating story on Bus " + devNum + " Device " + devNum + ": ID " + hashCode(devNum) + ":" + device );
devNum++;
}
private String hashCode(int devNum) {
return "0x" + Integer.toHexString(devNum * 0x10000 + devNum * 0x100 + devNum);
}
}
DevStoryListener listener = new DevStoryListener();
listener.listenToStory("JMTek, LLC. USB PnP Audio Device");
listener.listenToStory("Creative Technology, Ltd SoundBlaster MP3+");
listener.listenToStory("Sennheiser Communications USB Headset");
listener.listenToStory("Bluetooth Audio Device");
// На этом знаменитое путешествие Знайки и его товарищей окончилось.
// Жизнь в Цветочном городе потекла по-старому... хотя нет, нельзя сказать, чтобы совсем по-старому.
// С тех пор как наши отважные путешественники вернулись домой, в городе только и говорили о них.
// Все жители, и малыши и малышки, приходили по вечерам к домику Знайки и слушали рассказы путешественников об их жизни в Зеленом городе.
// Creating the setting for the story
City flowerCity = new City("Цветочный город");
House znaykasHouse = new House("Домик Знайки");
StoryContext context = new StoryContext(flowerCity, znaykasHouse, "путешествия Знайки");
// Creating the characters
Character znayka = new Znayka();
Character malish = new Child("Малыш");
Character malishka = new Child("Малышка");
// Adding characters to Znayka's house
znaykasHouse.addResident(znayka);
znaykasHouse.addResident(malish);
znaykasHouse.addResident(malishka);
List<String> stories = new ArrayList<>();
stories.add("путешествие в Зеленый город");
stories.add("жизнь в Цветочном городе");
znaykasHouse.tellEveningStories(context, stories);
stories.clear();
try { try {
if (stories.isEmpty()) { City city = new City("Цветочный город", LifeType.NOT_AS_USUAL);
throw new StoryException("No stories available to tell.");
// Create adventurers
Traveler znayka = new Znayka();
// znayka.addAdventure("Жизнь в Зеленом городе");
znayka.returnHome();
city.addTraveler(znayka);
// Create house
House znaykaHouse = new House("Дом Знайки", znayka, city);
// Add house to the city.
city.addHouse(znaykaHouse);
// Create children
Child child1 = new Child("Малыш");
Child child2 = new Child("Малышка");
// Add children to the city
city.addChild(child1);
city.addChild(child2);
// Duplicate creation of City object removed
Adventure adventure = new Adventure("путешествие в Зеленый город", AdventureType.FAMOUS, List.of(znayka));
adventure.setLocation(city);
if (adventure.getLocation() == null) {
throw new StoryLogicException("Путешествие не может начаться без указания места");
} }
znaykasHouse.tellEveningStories(context, stories);
} catch (StoryException e) { znayka.addAdventure(adventure); // REMOVE ME
System.err.println("Error in storytelling: " + e.getMessage()); adventure.end();
if (znayka.getAdventures().isEmpty()) {
throw new StoryEventException("У Знайки нет приключений");
} }
// Celebrate the return of the travelers
city.celebrateReturnOfTravelers();
// Recount a challenging part of Znayka's adventure
Adventure.Challenge adventureChallenge = new Adventure.Challenge();
adventureChallenge.present();
// Recall a memorable moment from the adventure
Adventure.Memory adventureMemory = adventure.new Memory();
adventureMemory.recall();
city.returnToDailyLife();
city.recognizeTravelers();
znaykaHouse.addResident(child1);
znaykaHouse.addResident(child2);
znaykaHouse.addResident(znayka);
znaykaHouse.tellEveningStories(adventure);
} catch (StoryEventException | StoryLogicException e) {
e.printStackTrace();
} }
} }
}

View File

@ -3,11 +3,15 @@ package characters;
import enums.CharacterType; import enums.CharacterType;
import interfaces.Conversable; import interfaces.Conversable;
import interfaces.Listenable; import interfaces.Listenable;
import model.StoryElement; import story.StoryContext;
import story.StoryElement;
import java.util.Objects;
public abstract class Character extends StoryElement implements Listenable, Conversable { public abstract class Character extends StoryElement implements Listenable, Conversable {
protected CharacterType type; protected CharacterType type;
protected String name; protected String name;
protected StoryContext context;
public Character(CharacterType type, String name) { public Character(CharacterType type, String name) {
super(type + " " + name); super(type + " " + name);
@ -15,16 +19,31 @@ public abstract class Character extends StoryElement implements Listenable, Conv
this.name = name; this.name = name;
} }
public boolean equals(Character character) { public void setContext(StoryContext context) {
return this.name.equals(character.name) && this.type.equals(character.type); this.context = context;
} }
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
Character other = (Character) obj;
return Objects.equals(name, other.name) && type == other.type;
}
@Override
public int hashCode() {
return Objects.hash(name, type);
}
public String toString() { public String toString() {
return name + " (" + type + ")"; return name + " (" + type + ")";
} }
public int hashCode() {
// seems legit to me public String getName() {
return name.hashCode() * type.hashCode(); return name;
} }
} }

View File

@ -1,9 +1,11 @@
package characters; package characters;
import enums.CharacterType; import enums.CharacterType;
import story.StoryContext;
import java.util.List;
public class Child extends Character { public class Child extends Character {
String thoughts = "";
public Child(String name) { public Child(String name) {
super(CharacterType.CHILD, name); super(CharacterType.CHILD, name);
@ -11,21 +13,37 @@ public class Child extends Character {
// Child can listen to stories about the city and ask questions about the subject of the story // Child can listen to stories about the city and ask questions about the subject of the story
public String listenAbout(String context) { public void think(String story) {
return name + " слушает историю о " + context; if (story.contains("город")) {
this.thoughts += "Я никогда не был в городе, но история о " + context.getStoryContext() + " мне очень понравилась\n";
} else if (story.contains("путешествие")) {
this.thoughts += "Не люблю я путешествовать, но история о " + context.getStoryContext() + " мне очень понравилась\n";
}
else {
this.thoughts += "Интересная получается история о " + context.getStoryContext() + "\n";
}
} }
public String listenAbout(String context, String subject) { public String converse(String subject) {
return name + " слушает историю о " + context + " и спрашивает вопросы о " + subject; String response = this.name + " слушает историю о " + context.getStoryContext() + " и спрашивает вопросы о " + subject;
this.thoughts = "";
return response;
} }
@Override @Override
public String converse(StoryContext context, String subject) { public String listen(String subject) {
return listenAbout(context.getStoryContext(), subject); String response = this.name + " слушает историю о " + context.getStoryContext() + " и спрашивает вопросы о " + subject;
this.thoughts = "";
return response;
} }
@Override public void discussTravelers(List<Traveler> travelers){
public String listen(StoryContext context) { System.out.println(this.name + " обсуждает путешественников: ");
return listenAbout(context.getStoryContext());
for(Traveler t: travelers){
if(t.isHome()){
System.out.println(t.getName());
}
}
} }
} }

View File

@ -1,23 +1,55 @@
package characters; package characters;
import enums.AdventureType;
import enums.CharacterType; import enums.CharacterType;
import story.StoryContext; import story.Adventure;
import java.util.ArrayList;
import java.util.List;
public abstract class Traveler extends Character { public abstract class Traveler extends Character {
private boolean isHome;
private final List<Adventure> adventures;
public Traveler(String name) { public Traveler(String name) {
super(CharacterType.TRAVELER, name); super(CharacterType.TRAVELER, name);
this.adventures = new ArrayList<>();
} }
// Traveler can tell stories about his adventures and listen to stories about the city, but dont ask questions // Traveler can tell stories about his adventures and listen to stories about the city, but dont ask questions
@Override @Override
public String listen(StoryContext context) { public String converse(String subject) {
return name + " слушает историю о " + context.getStoryContext(); return this.name + " рассказывает историю о " + context.getStoryContext() + "\n";
}
public void addAdventure(String adventureStory) {
Adventure newAdventure = new Adventure(adventureStory, AdventureType.FAMOUS, List.of(this));
this.adventures.add(newAdventure);
}
public void addAdventure(Adventure adventureStory) {
this.adventures.add(adventureStory);
}
public void addAdventure(String adventureStory, List<Traveler> travelers) {
travelers.add(this);
Adventure newAdventure = new Adventure(adventureStory, AdventureType.FAMOUS, travelers);
this.adventures.add(newAdventure);
}
public List<Adventure> getAdventures() {
return this.adventures;
}
public void returnHome() {
this.isHome = true;
}
public boolean isHome() {
return isHome;
} }
@Override @Override
public String converse(StoryContext context, String subject) { public String listen(String subject) {
return name + " рассказывает историю о " + subject; return this.name + " слушает историю о " + context.getStoryContext() + "\n";
} }
} }

View File

@ -1,21 +1,42 @@
package characters; package characters;
import interfaces.Conversable; import java.util.List;
import interfaces.Listenable;
import story.StoryContext;
public class Znayka extends Traveler implements Listenable, Conversable { public class Znayka extends Traveler {
String thoughts = "";
public Znayka() { public Znayka() {
super("Знайка"); super("Знайка");
} }
@Override
public String listen(StoryContext context) { public String thinkAbout(String story) {
return name + " умно слушает историю о " + context.getStoryContext(); if (story.contains("город")) {
return "Немного я знаю о городах, но история о " + context.getStoryContext() + " мне очень понравилась\n";
} else if (story.contains("путешествие")) {
return "Я люблю путешествовать, история о " + context.getStoryContext() + " мне очень понравилась\n";
}
else {
return "Интересная получается история о " + context.getStoryContext() + "\n";
}
}
public void think(String story) {
this.thoughts += thinkAbout(story);
} }
@Override @Override
public String converse(StoryContext context, String subject) { public String converse(String subject) {
return name + " умно рассказывает историю о " + subject; String response = name + " умно рассказывает историю о " + subject
+ "\n" + "и думает: " + thinkAbout(subject);
this.thoughts = "";
return response;
}
@Override
public String listen(String subject) {
String response = name + " умно слушает историю о " + context.getStoryContext() + " особенно про " + subject
+ "\n" + "и думает: " + this.thoughts;
this.thoughts = "";
return response;
} }
} }

View File

@ -0,0 +1,6 @@
package enums;
public enum AdventureType {
FAMOUS, // Represents adventures that are famous
UNKNOWN // Represents adventures that are unknown
}

7
src/enums/LifeType.java Normal file
View File

@ -0,0 +1,7 @@
package enums;
public enum LifeType {
NOT_AS_USUAL, // Represents life not as usual
AS_USUAL, // Represents life as usual
}

View File

@ -0,0 +1,13 @@
package exceptions;
public class StoryEventException extends Exception {
public StoryEventException(String message) {
super(message);
}
@Override
public void printStackTrace() {
System.out.println("Неожиданное исключение во время выполнения события: " + this.getMessage());
super.printStackTrace();
}
}

View File

@ -1,7 +0,0 @@
package exceptions;
public class StoryException extends Exception {
public StoryException(String message) {
super(message);
}
}

View File

@ -0,0 +1,13 @@
package exceptions;
public class StoryLogicException extends RuntimeException {
public StoryLogicException(String message) {
super(message);
}
@Override
public void printStackTrace() {
System.err.println("Ошибка логики истории: " + this.getMessage());
super.printStackTrace();
}
}

View File

@ -1,7 +0,0 @@
package exceptions;
public class StoryRuntimeException extends RuntimeException {
public StoryRuntimeException(String message) {
super(message);
}
}

View File

@ -1,7 +1,8 @@
package interfaces; package interfaces;
import story.StoryContext;
public interface Conversable { public interface Conversable {
String converse(StoryContext context, String subject); String converse(String subject);
void think(String story);
} }

View File

@ -1,7 +1,6 @@
package interfaces; package interfaces;
import story.StoryContext;
public interface Listenable { public interface Listenable {
String listen(StoryContext context); String listen(String subject);
} }

View File

@ -1,19 +1,72 @@
package model; package model;
public class City extends StoryElement { import characters.Child;
private final String name; import characters.Traveler;
import enums.LifeType;
import exceptions.StoryEventException;
import story.Adventure;
import story.StoryEvent;
public City(String name) { import java.util.ArrayList;
super(name); // Assuming the super class StoryElement's constructor takes a name or description import java.util.List;
public class City extends Location {
private final String name;
private final LifeType lifeType;
private final List<Traveler> travelers;
private final List<Child> children;
private final List<House> houses;
public City(String name, LifeType lifeType) {
super(name);
this.name = name; this.name = name;
this.lifeType = lifeType;
travelers = new ArrayList<>();
children = new ArrayList<>();
houses = new ArrayList<>();
}
public void addTraveler(Traveler traveler) {
travelers.add(traveler);
}
public void addChild(Child child) {
children.add(child);
}
public void addHouse(House house) {
houses.add(house);
} }
public String getName() { public String getName() {
return this.name; return this.name;
} }
public void returnToDailyLifeWithChanges() { public void returnToDailyLife() {
// Implementation of the method as before if (this.lifeType == LifeType.NOT_AS_USUAL) {
System.out.println("Жизнь в " + this.getName() + " потекла по-старому... хотя нет, нельзя сказать, чтобы совсем по-старому."); System.out.println("Жизнь в " + this.name + " потекла по-старому... хотя нет, нельзя сказать, чтобы совсем по-старому.");
} else {
System.out.println("Жизнь в " + this.name + " потекла по-старому.");
}
}
public void celebrateReturnOfTravelers() throws StoryEventException {
if (travelers.isEmpty()) {
throw new StoryEventException("Никто не пришел на вечеринку :(");
}
StoryEvent celebrationEvent = new StoryEvent("Возвращение путешественников") {
@Override
public void occur() {
System.out.println("Жители " + City.this.name + " собрались вместе, чтобы отпраздновать возвращение путешественников.");
}
};
celebrationEvent.occur();
}
public void recognizeTravelers() {
for (Traveler traveler : travelers) {
System.out.println("С тех пор как наши отважные путешественники " + traveler.getName() + " вернулись домой, в городе только и говорили о них.");
}
} }
} }

View File

@ -1,30 +1,32 @@
package model; package model;
import characters.Character; import characters.Character;
import exceptions.StoryRuntimeException; import characters.Traveler;
import interfaces.Interactable; import exceptions.StoryLogicException;
import story.Adventure;
import story.StoryContext; import story.StoryContext;
import characters.Child;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class House extends StoryElement { public class House extends Location {
private final String name; private final String name;
private final List<Character> residents; private final List<Character> residents;
private final Character owner;
private final City city;
public Character getOwner() {
return this.owner;
}
public House(String name) { public House(String name, Character owner, City city) {
super(name); super(name);
this.name = name; this.name = name;
this.residents = new ArrayList<>(); this.residents = new ArrayList<>();
this.owner = owner;
this.city = city;
} }
public void checkReadinessForStorytelling() {
if (this.residents.isEmpty()) {
throw new StoryRuntimeException("The house is empty, no one to tell stories to.");
}
}
public String getName() { public String getName() {
return this.name; return this.name;
} }
@ -43,38 +45,58 @@ public class House extends StoryElement {
return residents; return residents;
} }
public void tellEveningStories(StoryContext context, List<String> subjects) { public List<Traveler> getTravelers() {
checkReadinessForStorytelling(); List<Traveler> travelers = new ArrayList<>();
logger.logInteraction("Starting evening stories session");
context.gatherResidentsForStories();
context.getCity().returnToDailyLifeWithChanges();
this.gatherResidents();
for (String subject: subjects) {
for (Character resident : this.getResidents()) { for (Character resident : this.getResidents()) {
String event; if (resident instanceof Traveler) {
// if (resident instanceof Traveler) { travelers.add((Traveler) resident);
// event = resident.converse(context, subject);
// } else {
// event = resident.listen(context);
// }
// now can just converse for everyone
event = resident.converse(context, subject);
System.out.println(event);
if (Math.random() > 0.80) {
new Interactable() {
@Override
public void interact(StoryContext context) {
System.out.println("Внезапный флешбенгер");
logger.logInteraction("Внезапный флешбенгер");
}
}.interact(context);
} }
} }
return travelers;
} }
// The method could end with a closing statement or a setup for the next day's stories. public void tellEveningStories(Adventure adventure) {
System.out.println("Истории захватывали дух, и каждый вечер собирались всё больше жителей, чтобы слышать новые приключения."); List<Traveler> travelingResidents = this.getTravelers();
if (!travelingResidents.isEmpty()) {
this.gatherResidents();
StoryContext context = adventure.getContext(city, this);
System.out.println("Все жители слушают историю о путешествии в " + adventure.getAdventureName() + " в " + adventure.getAdventurePlace());
narrateSpecialStory(adventure);
for (Character resident : this.getResidents()) {
resident.setContext(context);
if (resident instanceof Traveler) {
String response = resident.converse(context.getStoryContext());
System.out.println(resident.getName() + " рассказывает: " + response);
}
else if (resident instanceof Child) {
String response = resident.listen(context.getStoryContext());
System.out.println(resident.getName() + " слушает: " + response);
}
}
}
System.out.println("Истории захватывали дух, и каждый вечер собирались всё больше жителей, чтобы слушать новые приключения.");
}
public void gatherChildren(List<Child> children) {
List<String> childrenNames = new ArrayList<>();
for (Child child : children) {
childrenNames.add(child.getName());
}
System.out.println(String.join(",", childrenNames) + " собираются в доме " + owner.getName() + " чтобы послушать истории");
}
public void narrateSpecialStory(Adventure adventure) throws StoryLogicException {
if (residents.isEmpty()) {
throw new StoryLogicException("Никто не может рассказать историю, если никто не живет в доме");
}
class SpecialStory {
void narrate() {
System.out.println("И вот, когда все собрались в доме " + owner.getName() + ", " + owner.getName() + " рассказал историю о том, как он " + adventure.getAdventureName() + " в " + adventure.getAdventurePlace());
}
}
SpecialStory specialStory = new SpecialStory();
specialStory.narrate();
} }
} }

16
src/model/Location.java Normal file
View File

@ -0,0 +1,16 @@
package model;
import story.StoryElement;
abstract public class Location extends StoryElement {
private final String name;
public Location(String name) {
super(name);
this.name = name;
}
public String getName() {
return this.name;
}
}

70
src/story/Adventure.java Normal file
View File

@ -0,0 +1,70 @@
package story;
import characters.Traveler;
import enums.AdventureType;
import exceptions.StoryEventException;
import model.City;
import model.House;
import model.Location;
import java.util.ArrayList;
import java.util.List;
public class Adventure {
public String name;
private Location location;
private final AdventureType type;
private List<Traveler> travelers = new ArrayList<>();
public Adventure(String name, AdventureType type, List<Traveler> travelers) {
this.name = name;
this.type = type;
this.travelers = travelers;
}
public void setLocation(Location location) {
this.location = location;
}
public Location getLocation() {
return this.location;
}
public void end() throws StoryEventException{
if (travelers.isEmpty()) {
throw new StoryEventException("Некому закончить приключение");
}
List<String> travelersNames = new ArrayList<>();
for (Traveler traveler : this.travelers) {
travelersNames.add(traveler.getName());
}
if (this.type == AdventureType.FAMOUS) {
System.out.println("На этом знаменитое путешествие " + String.join(", ", travelersNames) + " закончилось.");
} else {
System.out.println("На этом путешествие " + String.join(", ", travelersNames) + " закончилось.");
}
}
public String getAdventurePlace() {
return this.location.getName();
}
public String getAdventureName() {
return this.name;
}
public StoryContext getContext(City city, House house){
return new StoryContext(city, house, this.getAdventureName());
}
public static class Challenge {
public void present() {
System.out.println("Путешественники столкнулись с проблемой");
}
}
// Non-Static Nested Class for Memory
public class Memory {
public void recall() {
System.out.println("Путешественники вспомнили о " + Adventure.this.name);
}
}
}

View File

@ -3,6 +3,8 @@ package story;
import model.City; import model.City;
import model.House; import model.House;
public class StoryContext { public class StoryContext {
private final City city; private final City city;
private final House house; private final House house;

View File

@ -0,0 +1,35 @@
package story;
import java.util.Objects;
public abstract class StoryElement {
protected String description;
public StoryElement(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
@Override
public String toString() {
return this.getClass().getSimpleName() + "{" +
"description='" + description + '\'' +
'}';
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
StoryElement that = (StoryElement) obj;
return Objects.equals(description, that.description);
}
@Override
public int hashCode() {
return description != null ? description.hashCode() : 0;
}
}

View File

@ -1,6 +1,6 @@
package story; package story;
class StoryEvent { public class StoryEvent {
private final String description; private final String description;
public StoryEvent(String description) { public StoryEvent(String description) {