diff --git a/README.md b/README.md index c100ac8..99cef09 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,137 @@ # itmo-prog-lab-3 +## Class Description +### StoryTeller +- The main class of the application. It sets up the story's context, including the city, house, and characters, and initiates the storytelling process. + +### Package: characters +- **Character.java**: An abstract class that serves as a base for all character types. It implements `Listenable` and `Conversable` interfaces. +- **Child.java**: Represents a child character. Capable of listening to and asking questions about stories. +- **Traveler.java**: Represents a traveler character. Focuses on telling stories about their adventures. +- **Znayka.java**: A specialized traveler character with additional behaviors. + +### Package: enums +- **CharacterType.java**: An enumeration that defines different character types, such as `TRAVELER` and `CHILD`. + +### Package: interfaces +- **Listenable.java**: Interface for characters that can listen to stories. +- **Conversable.java**: Interface for characters that can converse about specific subjects in the story. + +### Package: model +- **City.java**: Represents a city in the story with a method to simulate the return to daily life with changes. +- **House.java**: Represents a house where characters reside and storytelling occurs. +- **StoryElement.java**: An abstract base class for elements within the story, like City and House. + +### Package: story +- **Narrative.java**: Manages a collection of story events. +- **StoryContext.java**: Provides context for the story, linking the city, house, and the overarching story theme. +- **StoryEvent.java**: Represents individual events within the story. + +## Interactions and Configurations + +- **StoryTeller**: Initializes the storytelling environment by creating a city, a house (Znayka's house), and characters (Znayka, Malish, and Malishka). It then triggers the storytelling process in Znayka's house. +- **Character Classes**: Each character type (`Child`, `Traveler`, `Znayka`) interacts differently within the story. For instance, children listen and ask questions, while travelers focus on narrating their adventures. +- **Interfaces**: `Listenable` and `Conversable` are implemented differently in each character class, providing unique behaviors during storytelling. +- **Model Classes**: `City` and `House` serve as the physical setting for the story. The `House` class, in particular, is the focal point where characters gather and share stories. +- **Story Classes**: `StoryContext` links the narrative's physical setting with the thematic elements, while `Narrative` and `StoryEvent` manage the flow and individual events of the story. + +## Given Query +``` +На этом знаменитое путешествие Знайки и его товарищей окончилось. +Жизнь в Цветочном городе потекла по-старому... хотя нет, нельзя сказать, чтобы совсем по-старому. +С тех пор как наши отважные путешественники вернулись домой, в городе только и говорили о них. +Все жители, и малыши и малышки, приходили по вечерам к домику Знайки и слушали рассказы путешественников об их жизни в Зеленом городе. +``` + +## Output +``` +Жители Домик Знайки собираются чтобы рассказать истории +Все жители, и малыши и малышки, приходили по вечерам к Домик Знайки и слушали рассказы путешественников. +Жизнь в Цветочный город потекла по-старому... хотя нет, нельзя сказать, чтобы совсем по-старому. +Жители Домик Знайки собираются чтобы рассказать истории +Знайка рассказывает историю о путешествие Знайки в Зеленый город +Малыш слушает историю о путешествие Знайки и спрашивает вопросы о путешествие Знайки в Зеленый город +Малышка слушает историю о путешествие Знайки и спрашивает вопросы о путешествие Знайки в Зеленый город +Знайка рассказывает историю о жизнь в Цветочном городе +Малыш слушает историю о путешествие Знайки и спрашивает вопросы о жизнь в Цветочном городе +Малышка слушает историю о путешествие Знайки и спрашивает вопросы о жизнь в Цветочном городе +Истории захватывали дух, и каждый вечер собирались всё больше жителей, чтобы слышать новые приключения. +``` + +## UML Diagram + +![UML Diagram](https://new.akarpov.ru/media/files/sanspie/tFfur/diagram.svg "https://new.akarpov.ru/files/PRaEOtISfNJAvOZYJbiO") + +# itmo-prog-lab-4 +## Class Description + +### StoryTeller +- The primary class of the application. It establishes the story's framework, incorporating the city, house, and characters, and initiates the storytelling process. + +### Package: characters +- **Character.java**: This abstract class forms the foundation for all character types, implementing `Listenable` and `Conversable` interfaces. +- **Child.java**: Represents child characters who listen to and inquire about stories. +- **Traveler.java**: Depicts traveler characters who share tales of their adventures. +- **Znayka.java**: A specialized traveler character with extended capabilities. + +### Package: enums +- **CharacterType.java**: Enumerates different character types, such as `TRAVELER` and `CHILD`. + +### Package: interfaces +- **Listenable.java**: An interface for characters that can listen to stories. +- **Conversable.java**: An interface for characters that can engage in discussions about specific story subjects. + +### Package: model +- **City.java**: Symbolizes a city in the story, featuring a method to simulate life resuming with changes. +- **House.java**: Represents a house where characters reside and where storytelling happens. +- **StoryElement.java**: An abstract base class for story components like City and House. + +### Package: story +- **Narrative.java**: Manages a series of story events. +- **StoryContext.java**: Provides the narrative backdrop, linking the city, house, and the main story theme. +- **StoryEvent.java**: Constitutes individual events within the narrative. + +### Package: exceptions +- **StoryException.java**: Handles exceptions specific to the storytelling process. +- **StoryRuntimeException.java**: Manages runtime exceptions within the story. + +## 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. + + +## 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](https://new.akarpov.ru/media/files/sanspie/uJsZS/123.svg "https://new.akarpov.ru/files/MUdUTDBZxAXTuRXuqREt") \ No newline at end of file diff --git a/itmo-prog-lab.iml b/itmo-prog-lab.iml new file mode 100644 index 0000000..c90834f --- /dev/null +++ b/itmo-prog-lab.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/StoryTeller.java b/src/StoryTeller.java index a0d824e..7b8d561 100644 --- a/src/StoryTeller.java +++ b/src/StoryTeller.java @@ -1,4 +1,5 @@ import characters.Character; +import exceptions.StoryException; import model.*; import characters.*; import story.StoryContext; @@ -8,15 +9,40 @@ import java.util.List; public class StoryTeller { public static void main(String[] args) { + class DevStoryListener { + private int devNum = 0; + + void listenToStory(String device) { + 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); + StoryContext context = new StoryContext(flowerCity, znaykasHouse, "путешествия Знайки"); // Creating the characters - Character znayka = new Znayka("Знайка"); - Character malish = new Child("Малыш", "Малыш"); - Character malishka = new Child("Малышка", "Малышка"); + Character znayka = new Znayka(); + Character malish = new Child("Малыш"); + Character malishka = new Child("Малышка"); // Adding characters to Znayka's house znaykasHouse.addResident(znayka); @@ -24,8 +50,20 @@ public class StoryTeller { znaykasHouse.addResident(malishka); List stories = new ArrayList<>(); - stories.add("о жизни в Зеленом городе"); + stories.add("путешествие в Зеленый город"); + stories.add("жизнь в Цветочном городе"); znaykasHouse.tellEveningStories(context, stories); + stories.clear(); + + + try { + if (stories.isEmpty()) { + throw new StoryException("No stories available to tell."); + } + znaykasHouse.tellEveningStories(context, stories); + } catch (StoryException e) { + System.err.println("Error in storytelling: " + e.getMessage()); + } } } diff --git a/src/characters/Character.java b/src/characters/Character.java index 6fd4b4e..bcb287a 100644 --- a/src/characters/Character.java +++ b/src/characters/Character.java @@ -1,45 +1,30 @@ package characters; import enums.CharacterType; -import interfaces.Interactable; +import interfaces.Conversable; import interfaces.Listenable; -import story.StoryContext; import model.StoryElement; -public abstract class Character extends StoryElement implements Interactable, Listenable { +public abstract class Character extends StoryElement implements Listenable, Conversable { protected CharacterType type; protected String name; - public Character(String description, CharacterType type, String name) { - super(description); + public Character(CharacterType type, String name) { + super(type + " " + name); this.type = type; this.name = name; } - // Method where characters can reminisce about past events - public abstract void reminisce(String memory); + public boolean equals(Character character) { + return this.name.equals(character.name) && this.type.equals(character.type); + } - // Method for characters to react to stories being told - public abstract void reactToStory(); + public String toString() { + return name + " (" + type + ")"; + } - // Method for telling a story about a specific place or event - public abstract void tellStoryOf(String place); - - // Method for characters, especially children, to ask questions about the story - public abstract void askQuestionsAbout(String subject); - - public abstract void listen(); - - public abstract void tell(); - - - public abstract void converse(StoryContext context, String subject); - - // Interaction method for general purposes - @Override - public abstract void interact(StoryContext context); - - // Listening method within a story context - @Override - public abstract void listen(StoryContext context); + public int hashCode() { + // seems legit to me + return name.hashCode() * type.hashCode(); + } } diff --git a/src/characters/Child.java b/src/characters/Child.java index d3b76db..34f4424 100644 --- a/src/characters/Child.java +++ b/src/characters/Child.java @@ -5,54 +5,27 @@ import story.StoryContext; public class Child extends Character { - public Child(String description, String name) { - super(description, CharacterType.CHILD, name); + public Child(String name) { + super(CharacterType.CHILD, name); + } + + // Child can listen to stories about the city and ask questions about the subject of the story + + public String listenAbout(String context) { + return name + " слушает историю о " + context; + } + + public String listenAbout(String context, String subject) { + return name + " слушает историю о " + context + " и спрашивает вопросы о " + subject; } @Override - public void reminisce(String memory) { - + public String converse(StoryContext context, String subject) { + return listenAbout(context.getStoryContext(), subject); } @Override - public void reactToStory() { - - } - - @Override - public void tellStoryOf(String place) { - - } - - @Override - public void askQuestionsAbout(String subject) { - System.out.println(name + " спрашивает вопросы о " + subject); - } - - @Override - public void listen() { - System.out.println(name + " слушает с удивлением"); - } - - @Override - public void tell() { - - } - - // If Children have other specific interactions, you could override the interact method - @Override - public void interact(StoryContext context) { - // Child-specific interactions - System.out.println(name + " говорят свое мнение об истории."); - } - - @Override - public void converse(StoryContext context, String subject) { - askQuestionsAbout(subject); - } - - @Override - public void listen(StoryContext context) { - + public String listen(StoryContext context) { + return listenAbout(context.getStoryContext()); } } \ No newline at end of file diff --git a/src/characters/Traveler.java b/src/characters/Traveler.java index 746b47b..3467e18 100644 --- a/src/characters/Traveler.java +++ b/src/characters/Traveler.java @@ -5,52 +5,19 @@ import story.StoryContext; public class Traveler extends Character { - public Traveler(String description, String name) { - super(description, CharacterType.TRAVELER, name); + public Traveler(String name) { + super(CharacterType.TRAVELER, name); + } + + // Traveler can tell stories about his adventures and listen to stories about the city, but dont ask questions + + @Override + public String listen(StoryContext context) { + return name + " слушает историю о " + context.getStoryContext(); } @Override - public void reminisce(String memory) { - - } - - @Override - public void reactToStory() { - - } - - @Override - public void tellStoryOf(String place) { - - } - - @Override - public void askQuestionsAbout(String subject) { - - } - - @Override - public void listen() { - - } - - @Override - public void tell() { - // Logic for telling a story - } - - @Override - public void converse(StoryContext context, String subject) { - tellStoryOf(subject); - } - - @Override - public void interact(StoryContext context) { - System.out.println(name + " рассказывает историю о Зеленом городе."); - } - - @Override - public void listen(StoryContext context) { - // Listening logic for a traveler + public String converse(StoryContext context, String subject) { + return name + " рассказывает историю о " + subject; } } diff --git a/src/characters/Znayka.java b/src/characters/Znayka.java index 5755aba..592cf79 100644 --- a/src/characters/Znayka.java +++ b/src/characters/Znayka.java @@ -1,19 +1,21 @@ package characters; -import interfaces.Listener; +import interfaces.Conversable; +import interfaces.Listenable; +import story.StoryContext; -public class Znayka extends Traveler implements Listener { +public class Znayka extends Traveler implements Listenable, Conversable { - public Znayka(String description) { - super(description, "Знайка"); + public Znayka() { + super("Знайка"); } - - public void tellStoryOf(String about) { - System.out.println("Знайка рассказывает истории " + about); + @Override + public String listen(StoryContext context) { + return name + " умно слушает историю о " + context.getStoryContext(); } @Override - public void listen() { - System.out.println(name + " слушает."); + public String converse(StoryContext context, String subject) { + return name + " умно рассказывает историю о " + subject; } } diff --git a/src/exceptions/StoryException.java b/src/exceptions/StoryException.java new file mode 100644 index 0000000..d13c9e9 --- /dev/null +++ b/src/exceptions/StoryException.java @@ -0,0 +1,7 @@ +package exceptions; + +public class StoryException extends Exception { + public StoryException(String message) { + super(message); + } +} diff --git a/src/exceptions/StoryRuntimeException.java b/src/exceptions/StoryRuntimeException.java new file mode 100644 index 0000000..5ad2581 --- /dev/null +++ b/src/exceptions/StoryRuntimeException.java @@ -0,0 +1,7 @@ +package exceptions; + +public class StoryRuntimeException extends RuntimeException { + public StoryRuntimeException(String message) { + super(message); + } +} diff --git a/src/interfaces/Conversable.java b/src/interfaces/Conversable.java new file mode 100644 index 0000000..09813a9 --- /dev/null +++ b/src/interfaces/Conversable.java @@ -0,0 +1,7 @@ +package interfaces; + +import story.StoryContext; + +public interface Conversable { + String converse(StoryContext context, String subject); +} diff --git a/src/interfaces/Listenable.java b/src/interfaces/Listenable.java index 1926a6a..3d8ab7e 100644 --- a/src/interfaces/Listenable.java +++ b/src/interfaces/Listenable.java @@ -3,5 +3,5 @@ package interfaces; import story.StoryContext; public interface Listenable { - void listen(StoryContext context); + String listen(StoryContext context); } \ No newline at end of file diff --git a/src/interfaces/Listener.java b/src/interfaces/Listener.java deleted file mode 100644 index b23b7a6..0000000 --- a/src/interfaces/Listener.java +++ /dev/null @@ -1,5 +0,0 @@ -package interfaces; - -public interface Listener { - void listen(); -} diff --git a/src/model/House.java b/src/model/House.java index 8beae03..2ac7aa2 100644 --- a/src/model/House.java +++ b/src/model/House.java @@ -1,7 +1,8 @@ package model; import characters.Character; -import characters.Traveler; +import exceptions.StoryRuntimeException; +import interfaces.Interactable; import story.StoryContext; import java.util.ArrayList; @@ -18,6 +19,12 @@ public class House extends StoryElement { this.residents = new ArrayList<>(); } + public void checkReadinessForStorytelling() { + if (this.residents.isEmpty()) { + throw new StoryRuntimeException("The house is empty, no one to tell stories to."); + } + } + public String getName() { return this.name; } @@ -28,7 +35,7 @@ public class House extends StoryElement { // Method to gather all the residents of the house public void gatherResidents() { - System.out.println("Жители " + this.getDescription() + " собираются чтобы рассказать истории"); + System.out.println("Жители собираются в " + this.getDescription() + " чтобы рассказать истории"); } // Method to retrieve the list of residents @@ -37,16 +44,32 @@ public class House extends StoryElement { } public void tellEveningStories(StoryContext context, List subjects) { + checkReadinessForStorytelling(); + logger.logInteraction("Starting evening stories session"); context.gatherResidentsForStories(); context.getCity().returnToDailyLifeWithChanges(); this.gatherResidents(); for (String subject: subjects) { for (Character resident : this.getResidents()) { - if (resident instanceof Traveler) { - resident.converse(context, subject); - } else { - resident.converse(context, subject); + String event; +// if (resident instanceof Traveler) { +// 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); } } } diff --git a/src/model/StoryElement.java b/src/model/StoryElement.java index 46ab2da..628baa2 100644 --- a/src/model/StoryElement.java +++ b/src/model/StoryElement.java @@ -1,12 +1,19 @@ package model; +import java.time.LocalDateTime; import java.util.Objects; public abstract class StoryElement { protected String description; + protected StoryMetadata metadata; + + protected StoryLogger logger = new StoryLogger(); + public StoryElement(String description) { this.description = description; + this.metadata = new StoryMetadata(); + logger.logCreation(); } public String getDescription() { @@ -32,4 +39,40 @@ public abstract class StoryElement { public int hashCode() { return description != null ? description.hashCode() : 0; } + + public class StoryLogger { + public void logCreation() { + System.out.println("[DEBUG] Story Element Created: " + description); + } + + public void logInteraction(String interaction) { + System.out.println("[DEBUG] Interaction with '" + description + "': " + interaction); + } + } + + public static class StoryMetadata { + private final LocalDateTime creationDate; + private LocalDateTime lastUpdatedDate; + + public StoryMetadata() { + this.creationDate = LocalDateTime.now(); + this.lastUpdatedDate = creationDate; + } + + // Getter and setters + public LocalDateTime getCreationDate() { + return creationDate; + } + + public void setLastUpdatedDate(LocalDateTime lastUpdatedDate) { + this.lastUpdatedDate = lastUpdatedDate; + } + + public String toString() { + return "StoryMetadata{" + + "creationDate=" + creationDate + + ", lastUpdatedDate=" + lastUpdatedDate + + '}'; + } + } } \ No newline at end of file diff --git a/src/story/ListeningSession.java b/src/story/ListeningSession.java deleted file mode 100644 index b57bf78..0000000 --- a/src/story/ListeningSession.java +++ /dev/null @@ -1,25 +0,0 @@ -package story; - -import interfaces.Listener; -import characters.Character; - -import java.util.ArrayList; - -class ListeningSession extends StoryEvent { - private ArrayList listeners; - - public ListeningSession(String description, ArrayList listeners) { - super(description); - this.listeners = listeners; - } - - @Override - public void occur() { - super.occur(); - for (Character listener : listeners) { - if (listener instanceof Listener) { - ((Listener) listener).listen(); - } - } - } -} \ No newline at end of file diff --git a/src/story/StoryContext.java b/src/story/StoryContext.java index e0e2dd5..dedb7cf 100644 --- a/src/story/StoryContext.java +++ b/src/story/StoryContext.java @@ -4,12 +4,14 @@ import model.City; import model.House; public class StoryContext { - private City city; - private House house; + private final City city; + private final House house; + private final String storyContext; - public StoryContext(City city, House house) { + public StoryContext(City city, House house, String storyContext) { this.city = city; this.house = house; + this.storyContext = storyContext; } // Getters and setters for city and house @@ -17,10 +19,8 @@ public class StoryContext { return this.city; } - // Methods for story actions - public void returnToDailyLifeWithChanges() { - // Implement the logic for the city's daily life with subtle changes after the travelers' return - System.out.println("Жизнь в " + city.getName() + " потекла по-старому... хотя нет, нельзя сказать, чтобы совсем по-старому."); + public String getStoryContext() { + return this.storyContext; } public void gatherResidentsForStories() {