diff --git a/README.md b/README.md index bd43f28..c68fb69 100644 --- a/README.md +++ b/README.md @@ -1,73 +1,82 @@ # 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**: 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 -- **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**: Defines character types (TRAVELER, CHILD). +- **AdventureType.java**: Defines types of adventures (FAMOUS, UNKNOWN). +- **LifeType.java**: Defines types of life (NOT_AS_USUAL, AS_USUAL). -### Package: enums -- **CharacterType.java**: Enumerates different character types, such as `TRAVELER` and `CHILD`. +### Package: `exceptions` +- **StoryEventException.java**: Custom exception to handle specific story-related errors. +- **StoryLogicException.java**: Custom runtime exception for handling logic errors in the story. -### 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: `interfaces` +- **Interactable.java**: Interface for story elements that can interact. +- **Conversable.java**: Interface for characters that can converse. +- **Listenable.java**: Interface for characters that can listen. -### 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: `model` +- **StoryElement.java**: An abstract class representing a story element with a description and metadata. + - **Connections**: Parent class for `Location`. +- **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 -- **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: `story` +- **StoryEvent.java**: Represents an event in the story. + - **Connections**: Used in `City` from `model` package. +- **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 -- **StoryException.java**: Handles exceptions specific to the storytelling process. -- **StoryRuntimeException.java**: Manages runtime exceptions within the story. +### Main Class +- **StoryTeller.java**: Main class orchestrating the storytelling process. Initializes the story's setting, characters, and events. + - **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 ``` -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/DmZte/diagram.svg "https://new.akarpov.ru/files/YsvFMeuMCbOpfnOlOlyN") \ No newline at end of file +![UML Diagram](https://new.akarpov.ru/media/files/sanspie/eNCBb/bebra2.svg "https://new.akarpov.ru/files/GKoEHHkHACqWRrehyNZe") + +## Вывод +В ходе выполнения данной лабораторной работы я научился работать с интерфейсами, абстрактными классами, исключениями, локальными классами, анонимными классами. \ No newline at end of file diff --git a/itmo-prog-lab.iml b/itmo-prog-lab-4.iml similarity index 100% rename from itmo-prog-lab.iml rename to itmo-prog-lab-4.iml diff --git a/lab-3.iml b/lab-3.iml deleted file mode 100644 index c90834f..0000000 --- a/lab-3.iml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - \ No newline at end of file diff --git a/src/StoryTeller.java b/src/StoryTeller.java index 7b8d561..ceb8f43 100644 --- a/src/StoryTeller.java +++ b/src/StoryTeller.java @@ -1,69 +1,79 @@ -import characters.Character; -import exceptions.StoryException; +import enums.AdventureType; +import enums.LifeType; +import exceptions.StoryEventException; +import exceptions.StoryLogicException; import model.*; import characters.*; -import story.StoryContext; - -import java.util.ArrayList; +import story.Adventure; import java.util.List; + public class StoryTeller { - public static void main(String[] args) { - class DevStoryListener { - private int devNum = 0; +// На этом знаменитое путешествие Знайки и его товарищей окончилось. +// Жизнь в Цветочном городе потекла по-старому... хотя нет, нельзя сказать, чтобы совсем по-старому. +// С тех пор как наши отважные путешественники вернулись домой, в городе только и говорили о них. +// Все жители, и малыши и малышки, приходили по вечерам к домику Знайки и слушали рассказы путешественников об их жизни в Зеленом городе. +public static void main(String[] args) { + try { + City city = new City("Цветочный город", LifeType.NOT_AS_USUAL); - void listenToStory(String device) { - System.out.println("Translating story on Bus " + devNum + " Device " + devNum + ": ID " + hashCode(devNum) + ":" + device ); - devNum++; - } + // Create adventurers + Traveler znayka = new Znayka(); +// znayka.addAdventure("Жизнь в Зеленом городе"); + znayka.returnHome(); - private String hashCode(int devNum) { - return "0x" + Integer.toHexString(devNum * 0x10000 + devNum * 0x100 + devNum); - } + 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("Путешествие не может начаться без указания места"); } - 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 stories = new ArrayList<>(); - 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()); + znayka.addAdventure(adventure); // REMOVE ME + 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(); } } +} diff --git a/src/characters/Character.java b/src/characters/Character.java index bcb287a..3089944 100644 --- a/src/characters/Character.java +++ b/src/characters/Character.java @@ -3,11 +3,15 @@ package characters; import enums.CharacterType; import interfaces.Conversable; 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 { protected CharacterType type; protected String name; + protected StoryContext context; public Character(CharacterType type, String name) { super(type + " " + name); @@ -15,16 +19,31 @@ public abstract class Character extends StoryElement implements Listenable, Conv this.name = name; } - public boolean equals(Character character) { - return this.name.equals(character.name) && this.type.equals(character.type); + public void setContext(StoryContext context) { + 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() { return name + " (" + type + ")"; } - public int hashCode() { - // seems legit to me - return name.hashCode() * type.hashCode(); + + public String getName() { + return name; } } diff --git a/src/characters/Child.java b/src/characters/Child.java index 34f4424..2553d30 100644 --- a/src/characters/Child.java +++ b/src/characters/Child.java @@ -1,9 +1,11 @@ package characters; import enums.CharacterType; -import story.StoryContext; + +import java.util.List; public class Child extends Character { + String thoughts = ""; public Child(String 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 - public String listenAbout(String context) { - return name + " слушает историю о " + context; + public void think(String story) { + 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) { - return name + " слушает историю о " + context + " и спрашивает вопросы о " + subject; + public String converse(String subject) { + String response = this.name + " слушает историю о " + context.getStoryContext() + " и спрашивает вопросы о " + subject; + this.thoughts = ""; + return response; } @Override - public String converse(StoryContext context, String subject) { - return listenAbout(context.getStoryContext(), subject); + public String listen(String subject) { + String response = this.name + " слушает историю о " + context.getStoryContext() + " и спрашивает вопросы о " + subject; + this.thoughts = ""; + return response; } - @Override - public String listen(StoryContext context) { - return listenAbout(context.getStoryContext()); + public void discussTravelers(List travelers){ + System.out.println(this.name + " обсуждает путешественников: "); + + for(Traveler t: travelers){ + if(t.isHome()){ + System.out.println(t.getName()); + } + } } } \ No newline at end of file diff --git a/src/characters/Traveler.java b/src/characters/Traveler.java index 7343d5f..ee8db37 100644 --- a/src/characters/Traveler.java +++ b/src/characters/Traveler.java @@ -1,23 +1,55 @@ package characters; +import enums.AdventureType; import enums.CharacterType; -import story.StoryContext; +import story.Adventure; + +import java.util.ArrayList; +import java.util.List; public abstract class Traveler extends Character { + private boolean isHome; + private final List adventures; public Traveler(String 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 @Override - public String listen(StoryContext context) { - return name + " слушает историю о " + context.getStoryContext(); + public String converse(String subject) { + 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 travelers) { + travelers.add(this); + Adventure newAdventure = new Adventure(adventureStory, AdventureType.FAMOUS, travelers); + this.adventures.add(newAdventure); + } + + public List getAdventures() { + return this.adventures; + } + + public void returnHome() { + this.isHome = true; + } + + public boolean isHome() { + return isHome; } @Override - public String converse(StoryContext context, String subject) { - return name + " рассказывает историю о " + subject; + public String listen(String subject) { + return this.name + " слушает историю о " + context.getStoryContext() + "\n"; } } diff --git a/src/characters/Znayka.java b/src/characters/Znayka.java index 592cf79..90f6d91 100644 --- a/src/characters/Znayka.java +++ b/src/characters/Znayka.java @@ -1,21 +1,42 @@ package characters; -import interfaces.Conversable; -import interfaces.Listenable; -import story.StoryContext; +import java.util.List; -public class Znayka extends Traveler implements Listenable, Conversable { +public class Znayka extends Traveler { + String thoughts = ""; public Znayka() { super("Знайка"); } - @Override - public String listen(StoryContext context) { - return name + " умно слушает историю о " + context.getStoryContext(); + + public String thinkAbout(String story) { + 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 - public String converse(StoryContext context, String subject) { - return name + " умно рассказывает историю о " + subject; + public String converse(String 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; } } diff --git a/src/enums/AdventureType.java b/src/enums/AdventureType.java new file mode 100644 index 0000000..b22317c --- /dev/null +++ b/src/enums/AdventureType.java @@ -0,0 +1,6 @@ +package enums; + +public enum AdventureType { + FAMOUS, // Represents adventures that are famous + UNKNOWN // Represents adventures that are unknown +} diff --git a/src/enums/LifeType.java b/src/enums/LifeType.java new file mode 100644 index 0000000..f4703e7 --- /dev/null +++ b/src/enums/LifeType.java @@ -0,0 +1,7 @@ +package enums; + +public enum LifeType { + NOT_AS_USUAL, // Represents life not as usual + AS_USUAL, // Represents life as usual + +} diff --git a/src/exceptions/StoryEventException.java b/src/exceptions/StoryEventException.java new file mode 100644 index 0000000..b2b714b --- /dev/null +++ b/src/exceptions/StoryEventException.java @@ -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(); + } +} diff --git a/src/exceptions/StoryException.java b/src/exceptions/StoryException.java deleted file mode 100644 index d13c9e9..0000000 --- a/src/exceptions/StoryException.java +++ /dev/null @@ -1,7 +0,0 @@ -package exceptions; - -public class StoryException extends Exception { - public StoryException(String message) { - super(message); - } -} diff --git a/src/exceptions/StoryLogicException.java b/src/exceptions/StoryLogicException.java new file mode 100644 index 0000000..19075e7 --- /dev/null +++ b/src/exceptions/StoryLogicException.java @@ -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(); + } +} \ No newline at end of file diff --git a/src/exceptions/StoryRuntimeException.java b/src/exceptions/StoryRuntimeException.java deleted file mode 100644 index 5ad2581..0000000 --- a/src/exceptions/StoryRuntimeException.java +++ /dev/null @@ -1,7 +0,0 @@ -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 index 09813a9..b701caa 100644 --- a/src/interfaces/Conversable.java +++ b/src/interfaces/Conversable.java @@ -1,7 +1,8 @@ package interfaces; -import story.StoryContext; public interface Conversable { - String converse(StoryContext context, String subject); + String converse(String subject); + + void think(String story); } diff --git a/src/interfaces/Listenable.java b/src/interfaces/Listenable.java index 3d8ab7e..a5b29c3 100644 --- a/src/interfaces/Listenable.java +++ b/src/interfaces/Listenable.java @@ -1,7 +1,6 @@ package interfaces; -import story.StoryContext; public interface Listenable { - String listen(StoryContext context); + String listen(String subject); } \ No newline at end of file diff --git a/src/model/City.java b/src/model/City.java index bbb9502..3f7ddc0 100644 --- a/src/model/City.java +++ b/src/model/City.java @@ -1,19 +1,72 @@ package model; -public class City extends StoryElement { - private final String name; +import characters.Child; +import characters.Traveler; +import enums.LifeType; +import exceptions.StoryEventException; +import story.Adventure; +import story.StoryEvent; - public City(String name) { - super(name); // Assuming the super class StoryElement's constructor takes a name or description +import java.util.ArrayList; +import java.util.List; + +public class City extends Location { + private final String name; + private final LifeType lifeType; + private final List travelers; + private final List children; + private final List houses; + + + public City(String name, LifeType lifeType) { + super(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() { return this.name; } - public void returnToDailyLifeWithChanges() { - // Implementation of the method as before - System.out.println("Жизнь в " + this.getName() + " потекла по-старому... хотя нет, нельзя сказать, чтобы совсем по-старому."); + public void returnToDailyLife() { + if (this.lifeType == LifeType.NOT_AS_USUAL) { + 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() + " вернулись домой, в городе только и говорили о них."); + } } } diff --git a/src/model/House.java b/src/model/House.java index 435b7a0..5c62792 100644 --- a/src/model/House.java +++ b/src/model/House.java @@ -1,30 +1,32 @@ package model; import characters.Character; -import exceptions.StoryRuntimeException; -import interfaces.Interactable; +import characters.Traveler; +import exceptions.StoryLogicException; +import story.Adventure; import story.StoryContext; +import characters.Child; import java.util.ArrayList; import java.util.List; -public class House extends StoryElement { +public class House extends Location { private final String name; private final List 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); this.name = name; 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() { return this.name; } @@ -43,38 +45,58 @@ public class House extends StoryElement { return residents; } - public void tellEveningStories(StoryContext context, List subjects) { - checkReadinessForStorytelling(); - logger.logInteraction("Starting evening stories session"); - context.gatherResidentsForStories(); - context.getCity().returnToDailyLifeWithChanges(); + public List getTravelers() { + List travelers = new ArrayList<>(); + for (Character resident : this.getResidents()) { + if (resident instanceof Traveler) { + travelers.add((Traveler) resident); + } + } + return travelers; + } - this.gatherResidents(); - for (String subject: subjects) { + public void tellEveningStories(Adventure adventure) { + List 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()) { - 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); + 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("Истории захватывали дух, и каждый вечер собирались всё больше жителей, чтобы слушать новые приключения."); + } - // The method could end with a closing statement or a setup for the next day's stories. - System.out.println("Истории захватывали дух, и каждый вечер собирались всё больше жителей, чтобы слышать новые приключения."); + public void gatherChildren(List children) { + List 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(); } } diff --git a/src/model/Location.java b/src/model/Location.java new file mode 100644 index 0000000..b661f81 --- /dev/null +++ b/src/model/Location.java @@ -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; + } +} diff --git a/src/story/Adventure.java b/src/story/Adventure.java new file mode 100644 index 0000000..d63863d --- /dev/null +++ b/src/story/Adventure.java @@ -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 travelers = new ArrayList<>(); + + public Adventure(String name, AdventureType type, List 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 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); + } + } +} diff --git a/src/story/StoryContext.java b/src/story/StoryContext.java index dedb7cf..d21f693 100644 --- a/src/story/StoryContext.java +++ b/src/story/StoryContext.java @@ -3,6 +3,8 @@ package story; import model.City; import model.House; + + public class StoryContext { private final City city; private final House house; diff --git a/src/story/StoryElement.java b/src/story/StoryElement.java new file mode 100644 index 0000000..40a7a4a --- /dev/null +++ b/src/story/StoryElement.java @@ -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; + } +} \ No newline at end of file diff --git a/src/story/StoryEvent.java b/src/story/StoryEvent.java index 5face20..3a5b16d 100644 --- a/src/story/StoryEvent.java +++ b/src/story/StoryEvent.java @@ -1,6 +1,6 @@ package story; -class StoryEvent { +public class StoryEvent { private final String description; public StoryEvent(String description) {