Merge branch 'zinch-lab4'

This commit is contained in:
Ivan Zinchenko 2023-12-30 04:19:20 +05:00
commit 74ebac6de5
Signed by: zinch
GPG Key ID: 6D45AA2C8FD6A37E
13 changed files with 266 additions and 179 deletions

148
README.md
View File

@ -3,24 +3,35 @@
**ИСУ:** 408657
**Вариант:** 528475
**Вариант:** ~528475.3
_Так как на se.ifmo сбросились варианты я взял текст напрямую из сказки._
## Задание
> У Карлсона дрогнули губы, и он надулся. Он сделал шаг к плите и взял со сковородки одну тефтельку. Вот этого ему не следовало делать. Фрекен Бок взревела от бешенства и кинулась на Карлсона, схватила его за шиворот и вытолкнула за дверь.
> У Карлсона дрогнули губы, и он надулся. Он сделал шаг к плите и взял со сковородки одну тефтельку.
> Вот этого ему не следовало делать. Фрекен Бок взревела от бешенства и кинулась на Карлсона, схватила его за шиворот
> и вытолкнула за дверь. Малыш был просто в отчаянии. Больше он ничего не успел сказать, потому что дверь кухни
> распахнулась и ворвался Карлсон, тоже злой как чёрт. Он подлетел к Фрекен Бок и топнул ногой об пол.
## Вывод программы
```
Кралсон дрогнул губой
Кралсон надулся
Он сделал шаг к плита
Кралсон взял одну тефтелька из сковородка
Предмет тефтелька принадлежит Фрекен Бок, а не Кралсон
Вот этого ему не следовало делать
Фрекен Бок взревела от бешенства
Она кинулась к Кралсон
Она схватила Кралсон за шиворот
Она вытолкнула Кралсон за дверь
Она вытолкнула Кралсон за Дверь
Малыш был просто в отчаянии
Он ничего не сказал
Дверь распахнулась
Он сделал шаг к Дверь
Кралсон злой как чёрт
Он подлетел к Фрекен Бок
Кралсон топнул ногой
```
## Структура проекта
@ -32,125 +43,16 @@ graph TD;
Entity-->Item;
Item-->Container;
```
Главный абстрактный класс - Entity, который имеет только имя. От него наследуются предметы и персонажи. Персонажи могут чувствовать *(IFeelabe)*, двигаться *(IMovable)* и брать вещи *(ITakeable)*. Также персонажи имеют гендер *(enum Feels)*.
Главный абстрактный класс - Entity, который имеет только имя. От него наследуются предметы и персонажи.
Персонажи могут чувствовать *(IFeelabe)*, двигаться *(IMovable)* и брать вещи *(ITakeable)*.
Также персонажи имеют гендер *(enum Feels)*.
За историю отвечает класс *StoryTeller*. Он меняет состояние персонажей и отображает их состояние.
## UML Диаграмма
```mermaid
classDiagram
class Entity {
# String name
+ getName() String
}
class Character {
# Item itemInHand
# Feels feel
- String currentState
- Gender gender
- Entity position
+ setFeel(Feels)* void
+ moveTo(Entity)* void
+ grab(Item)* void
+ getItemInHand() Item
+ getPosition() Entity
+ getGender() String
+ getState() String
# setState(String) void
# setPosition(Entity) void
}
class FrenBok {
- IGrabbable characterInHand
+ grabCharacter(IGrabbable) void
+ setFeel(Feels) void
+ moveTo(Entity) void
+ grab(Item) void
+ pushCharacterBehindItem(Item) void
}
class Karlson {
+ grab(Item) void
+ setFeel(Feels) void
+ moveTo(Entity) void
+ grabFrom(Container) void
+ getGrabbablePart() String
}
## Особенности 4 лабы
Есть два исключения: `OwnershipException` и `ExitFuelException`. `OwnershipException` - исключение при взятии чужой вещи.
`ExitFuelException` возникает, когда у Карлсона кончается топливо.
class Item {
- Character owner
+ getOwner() Character
+ setOwner(Character) void
}
class Container {
- Item innerItem
+ getInnerItem() Item
}
class Feels {
<<enumeration>>
+ SAD
+ ANGRY
+ SCARY
+ RAGE
+ NORMAL
- String feel
+ values() Feels[]
+ toString() String
+ valueOf(String) Feels
}
class Gender {
<<enumeration>>
- String gender
+ MAN
+ WOMAN
+ valueOf(String) Gender
+ toString() String
+ values() Gender[]
}
class StoryTeller {
- Item door
- Item meatball
- Container fryingPan
- FrenBok frenBok
- Karlson karlson
- Item kitchenHob
+ play() void
}
class ICanTake {
<<interface>>
+ grab(Item) void
}
class IMovable {
<<interface>>
+ moveTo(Entity) void
}
class IFeelable {
<<interface>>
+ setFeel(Feels) void
}
class IGrabbable {
<<interface>>
+ getGrabbablePart() String
}
IGrabbable --|> IMovable
Character --|> Entity
Container --|> Item
FrenBok --|> Character
Item --|> Entity
Karlson --|> Character
Character ..|> IFeelable
Character ..|> IMovable
Character ..|> ICanTake
Karlson ..|> IGrabbable
Character --> Feels
Character --> Gender
```
Есть вложенный статический класс `Engin` у Карлсона, отвечающий за его движок. В нём есть локальный класс `Path`, хранящий
в себе дистанцию полёта и формулу расчёта расхода. Для формулы используются анонимные классы интерфейса `IntFormula`.
Есть вложенный не статический класс `Mouth` у Малыша, который отвечает за его речь.

View File

@ -6,6 +6,23 @@ import Items.Item;
import java.util.Objects;
public abstract class Character extends Entity implements IMovable, IFeelable, ICanTake {
public enum Gender {
MAN("Он"),
WOMAN("Она");
private final String gender;
Gender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return gender;
}
}
private final Gender gender;
private Entity position;
private String currentState = "";
@ -26,29 +43,32 @@ public abstract class Character extends Entity implements IMovable, IFeelable, I
return this.gender.toString();
}
public abstract void setFeel(Feels feel);
public final void setFeel(Feels feel) {
this.feel = feel;
this.setState(String.format("%s %s", this.getName(), feel));
}
public abstract void moveTo(Entity obj);
public abstract void grab(Item obj);
public abstract void grab(Item obj) throws OwnershipException;
public Item getItemInHand() {
public final Item getItemInHand() {
return this.itemInHand;
}
public Entity getPosition() {
public final Entity getPosition() {
return this.position;
}
protected void setPosition(Entity obj) {
protected final void setPosition(Entity obj) {
this.position = obj;
}
public String getState() {
public final String getState() {
return this.currentState;
}
protected void setState(String state) {
protected final void setState(String state) {
this.currentState = state;
}
@ -57,7 +77,6 @@ public abstract class Character extends Entity implements IMovable, IFeelable, I
return this.getName();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;

View File

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

View File

@ -1,11 +1,12 @@
package Characters;
public enum Feels {
ANGRY("злиться"),
ANGRY("злой как чёрт"),
SCARY("дрогнул губой"),
SAD("надулся"),
RAGE("взревела от бешенства"),
NORMAL("Нормально");
NORMAL("нормально"),
DEAD_INSIDE("был просто в отчаянии");
private final String feel;

View File

@ -10,12 +10,6 @@ public class FrenBok extends Character {
super("Фрекен Бок", Gender.WOMAN);
}
@Override
public void setFeel(Feels feel) {
this.feel = feel;
this.setState(String.format("%s %s", this.getName(), feel));
}
@Override
public void moveTo(Entity obj) {
this.setPosition(obj);
@ -23,9 +17,12 @@ public class FrenBok extends Character {
}
@Override
public void grab(Item obj) {
public void grab(Item obj) throws OwnershipException {
this.itemInHand = obj;
this.setState(String.format("%s взяла %s", this.getGender(), obj.getName()));
this.setState(String.format("%s взяла %s", this.getGender(), obj));
if (obj.getOwner() != this && obj.getOwner() != null) {
throw new OwnershipException(String.format("Предмет %s принадлежит %s, а не %s", obj.getName(), obj.getOwner().getName(), this.getName()));
}
}
public void grabCharacter(IGrabbable character) {

View File

@ -1,17 +0,0 @@
package Characters;
public enum Gender {
MAN("Он"),
WOMAN("Она");
private final String gender;
Gender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return gender;
}
}

View File

@ -3,5 +3,5 @@ package Characters;
import Items.Item;
interface ICanTake {
void grab(Item obj);
void grab(Item obj) throws OwnershipException;
}

View File

@ -0,0 +1,7 @@
package Characters;
import Entity.*;
public interface IFlyable {
void flyTo(Entity obj);
}

View File

@ -4,7 +4,13 @@ import Entity.Entity;
import Items.Container;
import Items.Item;
public class Karlson extends Character implements IGrabbable {
import java.util.Arrays;
import java.util.function.IntFunction;
import java.util.function.IntSupplier;
public class Karlson extends Character implements IGrabbable, IFlyable {
private final Engine engine = new Engine();
public Karlson() {
super("Кралсон", Gender.MAN);
}
@ -14,10 +20,83 @@ public class Karlson extends Character implements IGrabbable {
this.feel = feel;
}
@Override
public void setFeel(Feels feel) {
this.feel = feel;
this.setState(String.format("%s %s", this.getName(), feel));
private static class Engine {
private int fuel = 13;
public Engine() {}
public boolean canFly() {
return fuel > 0;
}
public void startFly() {
this.fuel -= this.countMinPath();
if (fuel < 0) {
throw new ExitFuelException("У двигателя кончилось топливо");
}
}
public int countMinPath() {
interface IntFormula {
int getResult(int x);
int getAbs(int x);
}
class Path {
private final int distance;
private final IntFormula formula;
Path (int distance, IntFormula formula) {
this.distance = distance;
this.formula = formula;
}
public int getResult() {
return formula.getAbs(distance);
}
}
Path[] paths = {
new Path(4, new IntFormula() {
@Override
public int getResult(int x) {
return x*3;
}
@Override
public int getAbs(int x) {
return Math.abs(getResult(x));
}
}),
new Path(7, new IntFormula() {
@Override
public int getResult(int x) {
return x*6;
}
@Override
public int getAbs(int x) {
return Math.abs(getResult(x));
}
}),
new Path(1, new IntFormula() {
@Override
public int getResult(int x) {
return x*x-2;
}
@Override
public int getAbs(int x) {
return Math.abs(getResult(x));
}
})
};
int minPath = Integer.MAX_VALUE;
for (Path path: paths) {
minPath = Math.min(path.getResult(), minPath);
}
return minPath;
}
}
@Override
@ -26,13 +105,26 @@ public class Karlson extends Character implements IGrabbable {
this.setState(String.format("%s сделал шаг к %s", this.getGender(), obj));
}
@Override
public void grab(Item obj) {
this.itemInHand = obj;
this.setState(String.format("%s взял %s", this.getGender(), obj));
public void flyTo(Entity obj) {
if (engine.canFly()) {
this.moveTo(obj);
this.engine.startFly();
this.setState(String.format("%s подлетел к %s", this.getGender(), obj));
return;
}
this.setState("%s пытался взлететь, но у него не получилось");
}
public void grabFrom(Container container) {
@Override
public void grab(Item obj) throws OwnershipException {
this.itemInHand = obj;
this.setState(String.format("%s взял %s", this.getGender(), obj));
if (obj.getOwner() != this && obj.getOwner() != null) {
throw new OwnershipException(String.format("Предмет %s принадлежит %s, а не %s", obj.getName(), obj.getOwner().getName(), this.getName()));
}
}
public void grabFrom(Container container) throws OwnershipException {
this.grab(container.getInnerItem());
this.setState(String.format("%s взял одну %s из %s", this.getName(), container.getInnerItem(), container));
}
@ -41,4 +133,8 @@ public class Karlson extends Character implements IGrabbable {
public String getGrabbablePart() {
return "шиворот";
}
public void stomp() {
this.setState(String.format("%s топнул ногой", this.getName()));
}
}

View File

@ -0,0 +1,35 @@
package Characters;
import Entity.Entity;
import Items.Item;
public class Malysh extends Character {
public Mouth mouth = new Mouth();
public Malysh() {
super("Малыш", Gender.MAN ,Feels.NORMAL);
}
public class Mouth {
public void speak(String speech) {
if (speech == null) {
Malysh.this.setState(String.format("%s ничего не сказал", Malysh.this.getGender()));
return;
}
Malysh.this.setState(String.format("%s сказал: \"%s\"", Malysh.this.getName(), speech));
}
}
@Override
public void moveTo(Entity obj) {
this.setPosition(obj);
this.setState(String.format("%s подошёл к %s", this.getGender(), obj));
}
@Override
public void grab(Item obj) throws OwnershipException {
this.itemInHand = obj;
this.setState(String.format("%s присвоил себе %s", this.getGender(), obj));
if (obj.getOwner() != this && obj.getOwner() != null) {
throw new OwnershipException(String.format("Предмет %s принадлежит %s, а не %s", obj.getName(), obj.getOwner().getName(), this.getName()));
}
}
}

View File

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

18
src/Items/Door.java Normal file
View File

@ -0,0 +1,18 @@
package Items;
public class Door extends Item {
private boolean isOpen = false;
public Door() {
super("Дверь");
}
public void openDoor() {
this.isOpen = true;
System.out.println("Дверь закрылась");
}
public void closeDoor() {
this.isOpen = false;
System.out.println("Дверь распахнулась");
}
}

View File

@ -1,21 +1,22 @@
package StoryTeller;
import Characters.Feels;
import Characters.FrenBok;
import Characters.Karlson;
import Characters.*;
import Characters.Character;
import Items.Container;
import Items.Door;
import Items.Item;
public class StoryTeller {
// Персонажи
private final Karlson karlson = new Karlson();
private final FrenBok frenBok = new FrenBok();
private final Malysh malysh = new Malysh();
// Предметы
private final Item kitchenHob = new Item("плита");
private final Item meatball = new Item("тефтелька");
private final Container fryingPan = new Container("сковородка", meatball, frenBok);
private final Item door = new Item("дверь");
private final Door door = new Door();
public void play() {
karlson.setFeel(Feels.SCARY);
@ -24,9 +25,13 @@ public class StoryTeller {
System.out.println(karlson.getState());
karlson.moveTo(kitchenHob);
System.out.println(karlson.getState());
karlson.grabFrom(fryingPan);
System.out.println(karlson.getState());
if (fryingPan.getOwner() == frenBok) {
try {
karlson.grabFrom(fryingPan);
System.out.println(karlson.getState());
frenBok.setFeel(Feels.NORMAL);
System.out.println(frenBok.getState());
} catch (OwnershipException e) {
System.out.println(e.getMessage());
System.out.println("Вот этого ему не следовало делать");
frenBok.setFeel(Feels.RAGE);
System.out.println(frenBok.getState());
@ -36,9 +41,19 @@ public class StoryTeller {
System.out.println(frenBok.getState());
frenBok.pushCharacterBehindItem(door);
System.out.println(frenBok.getState());
} else {
frenBok.setFeel(Feels.NORMAL);
System.out.println(frenBok);
malysh.setFeel(Feels.DEAD_INSIDE);
System.out.println(malysh.getState());
malysh.mouth.speak(null);
System.out.println(malysh.getState());
door.closeDoor();
karlson.moveTo(door);
System.out.println(karlson.getState());
karlson.setFeel(Feels.ANGRY);
System.out.println(karlson.getState());
karlson.flyTo(frenBok);
System.out.println(karlson.getState());
karlson.stomp();
System.out.println(karlson.getState());
}
}
}