From f8df3671bbb3a20ce104afd7ab0fcddebb035e9c Mon Sep 17 00:00:00 2001 From: Eugene Gogolev Date: Wed, 3 Jun 2020 12:58:18 +0300 Subject: [PATCH] Labs 1-7 done --- 8381/Gogolev_Eugene/CMakeLists.txt | 14 + 8381/Gogolev_Eugene/enums.hpp | 23 ++ .../exceptions/loading_exception.cpp | 5 + .../exceptions/loading_exception.hpp | 12 + .../exceptions/out_of_bounds_exception.cpp | 5 + .../exceptions/out_of_bounds_exception.hpp | 12 + .../exceptions/saving_exception.cpp | 5 + .../exceptions/saving_exception.hpp | 12 + .../exceptions/strategy_exception.cpp | 9 + .../exceptions/strategy_exception.hpp | 15 + 8381/Gogolev_Eugene/game.cpp | 262 ++++++++++++++++++ 8381/Gogolev_Eugene/game.hpp | 59 ++++ 8381/Gogolev_Eugene/game_rule.cpp | 130 +++++++++ 8381/Gogolev_Eugene/game_rule.hpp | 50 ++++ 8381/Gogolev_Eugene/loggers/file_logger.cpp | 15 + 8381/Gogolev_Eugene/loggers/file_logger.hpp | 15 + 8381/Gogolev_Eugene/loggers/logger.cpp | 2 + 8381/Gogolev_Eugene/loggers/logger.hpp | 14 + 8381/Gogolev_Eugene/loggers/logger_proxy.cpp | 17 ++ 8381/Gogolev_Eugene/loggers/logger_proxy.hpp | 16 ++ .../loggers/terminal_logger.cpp | 5 + .../loggers/terminal_logger.hpp | 12 + 8381/Gogolev_Eugene/main.cpp | 101 +++++++ 8381/Gogolev_Eugene/stl.hpp | 15 + 8381/Gogolev_Eugene/tiles/fortress.cpp | 24 ++ 8381/Gogolev_Eugene/tiles/fortress.hpp | 15 + 8381/Gogolev_Eugene/tiles/meadow.cpp | 24 ++ 8381/Gogolev_Eugene/tiles/meadow.hpp | 16 ++ 8381/Gogolev_Eugene/tiles/tile.cpp | 6 + 8381/Gogolev_Eugene/tiles/tile.hpp | 17 ++ 8381/Gogolev_Eugene/tiles/water.cpp | 23 ++ 8381/Gogolev_Eugene/tiles/water.hpp | 16 ++ 8381/Gogolev_Eugene/ui.cpp | 58 ++++ 8381/Gogolev_Eugene/ui.hpp | 35 +++ .../Gogolev_Eugene/units/cavalries/knight.cpp | 38 +++ .../Gogolev_Eugene/units/cavalries/knight.hpp | 16 ++ 8381/Gogolev_Eugene/units/cavalries/rider.cpp | 40 +++ 8381/Gogolev_Eugene/units/cavalries/rider.hpp | 16 ++ 8381/Gogolev_Eugene/units/cavalry.cpp | 17 ++ 8381/Gogolev_Eugene/units/cavalry.hpp | 14 + 8381/Gogolev_Eugene/units/citadel.cpp | 112 ++++++++ 8381/Gogolev_Eugene/units/citadel.hpp | 27 ++ .../units/infantries/spearmen.cpp | 43 +++ .../units/infantries/spearmen.hpp | 18 ++ .../units/infantries/swordsmen.cpp | 44 +++ .../units/infantries/swordsmen.hpp | 19 ++ 8381/Gogolev_Eugene/units/infantry.cpp | 5 + 8381/Gogolev_Eugene/units/infantry.hpp | 11 + 8381/Gogolev_Eugene/units/neutral.cpp | 11 + 8381/Gogolev_Eugene/units/neutral.hpp | 12 + 8381/Gogolev_Eugene/units/neutrals/fair.cpp | 37 +++ 8381/Gogolev_Eugene/units/neutrals/fair.hpp | 16 ++ 8381/Gogolev_Eugene/units/neutrals/farmer.cpp | 49 ++++ 8381/Gogolev_Eugene/units/neutrals/farmer.hpp | 19 ++ 8381/Gogolev_Eugene/units/neutrals/sheep.cpp | 49 ++++ 8381/Gogolev_Eugene/units/neutrals/sheep.hpp | 18 ++ .../units/neutrals/villager.cpp | 43 +++ .../units/neutrals/villager.hpp | 16 ++ 8381/Gogolev_Eugene/units/shooter.cpp | 11 + 8381/Gogolev_Eugene/units/shooter.hpp | 15 + .../Gogolev_Eugene/units/shooters/archers.cpp | 48 ++++ .../Gogolev_Eugene/units/shooters/archers.hpp | 19 ++ .../units/shooters/crossbowman.cpp | 48 ++++ .../units/shooters/crossbowman.hpp | 20 ++ 8381/Gogolev_Eugene/units/unit.cpp | 241 ++++++++++++++++ 8381/Gogolev_Eugene/units/unit.hpp | 90 ++++++ 66 files changed, 2241 insertions(+) create mode 100644 8381/Gogolev_Eugene/CMakeLists.txt create mode 100644 8381/Gogolev_Eugene/enums.hpp create mode 100644 8381/Gogolev_Eugene/exceptions/loading_exception.cpp create mode 100644 8381/Gogolev_Eugene/exceptions/loading_exception.hpp create mode 100644 8381/Gogolev_Eugene/exceptions/out_of_bounds_exception.cpp create mode 100644 8381/Gogolev_Eugene/exceptions/out_of_bounds_exception.hpp create mode 100644 8381/Gogolev_Eugene/exceptions/saving_exception.cpp create mode 100644 8381/Gogolev_Eugene/exceptions/saving_exception.hpp create mode 100644 8381/Gogolev_Eugene/exceptions/strategy_exception.cpp create mode 100644 8381/Gogolev_Eugene/exceptions/strategy_exception.hpp create mode 100644 8381/Gogolev_Eugene/game.cpp create mode 100644 8381/Gogolev_Eugene/game.hpp create mode 100644 8381/Gogolev_Eugene/game_rule.cpp create mode 100644 8381/Gogolev_Eugene/game_rule.hpp create mode 100644 8381/Gogolev_Eugene/loggers/file_logger.cpp create mode 100644 8381/Gogolev_Eugene/loggers/file_logger.hpp create mode 100644 8381/Gogolev_Eugene/loggers/logger.cpp create mode 100644 8381/Gogolev_Eugene/loggers/logger.hpp create mode 100644 8381/Gogolev_Eugene/loggers/logger_proxy.cpp create mode 100644 8381/Gogolev_Eugene/loggers/logger_proxy.hpp create mode 100644 8381/Gogolev_Eugene/loggers/terminal_logger.cpp create mode 100644 8381/Gogolev_Eugene/loggers/terminal_logger.hpp create mode 100644 8381/Gogolev_Eugene/main.cpp create mode 100644 8381/Gogolev_Eugene/stl.hpp create mode 100644 8381/Gogolev_Eugene/tiles/fortress.cpp create mode 100644 8381/Gogolev_Eugene/tiles/fortress.hpp create mode 100644 8381/Gogolev_Eugene/tiles/meadow.cpp create mode 100644 8381/Gogolev_Eugene/tiles/meadow.hpp create mode 100644 8381/Gogolev_Eugene/tiles/tile.cpp create mode 100644 8381/Gogolev_Eugene/tiles/tile.hpp create mode 100644 8381/Gogolev_Eugene/tiles/water.cpp create mode 100644 8381/Gogolev_Eugene/tiles/water.hpp create mode 100644 8381/Gogolev_Eugene/ui.cpp create mode 100644 8381/Gogolev_Eugene/ui.hpp create mode 100644 8381/Gogolev_Eugene/units/cavalries/knight.cpp create mode 100644 8381/Gogolev_Eugene/units/cavalries/knight.hpp create mode 100644 8381/Gogolev_Eugene/units/cavalries/rider.cpp create mode 100644 8381/Gogolev_Eugene/units/cavalries/rider.hpp create mode 100644 8381/Gogolev_Eugene/units/cavalry.cpp create mode 100644 8381/Gogolev_Eugene/units/cavalry.hpp create mode 100644 8381/Gogolev_Eugene/units/citadel.cpp create mode 100644 8381/Gogolev_Eugene/units/citadel.hpp create mode 100644 8381/Gogolev_Eugene/units/infantries/spearmen.cpp create mode 100644 8381/Gogolev_Eugene/units/infantries/spearmen.hpp create mode 100644 8381/Gogolev_Eugene/units/infantries/swordsmen.cpp create mode 100644 8381/Gogolev_Eugene/units/infantries/swordsmen.hpp create mode 100644 8381/Gogolev_Eugene/units/infantry.cpp create mode 100644 8381/Gogolev_Eugene/units/infantry.hpp create mode 100644 8381/Gogolev_Eugene/units/neutral.cpp create mode 100644 8381/Gogolev_Eugene/units/neutral.hpp create mode 100644 8381/Gogolev_Eugene/units/neutrals/fair.cpp create mode 100644 8381/Gogolev_Eugene/units/neutrals/fair.hpp create mode 100644 8381/Gogolev_Eugene/units/neutrals/farmer.cpp create mode 100644 8381/Gogolev_Eugene/units/neutrals/farmer.hpp create mode 100644 8381/Gogolev_Eugene/units/neutrals/sheep.cpp create mode 100644 8381/Gogolev_Eugene/units/neutrals/sheep.hpp create mode 100644 8381/Gogolev_Eugene/units/neutrals/villager.cpp create mode 100644 8381/Gogolev_Eugene/units/neutrals/villager.hpp create mode 100644 8381/Gogolev_Eugene/units/shooter.cpp create mode 100644 8381/Gogolev_Eugene/units/shooter.hpp create mode 100644 8381/Gogolev_Eugene/units/shooters/archers.cpp create mode 100644 8381/Gogolev_Eugene/units/shooters/archers.hpp create mode 100644 8381/Gogolev_Eugene/units/shooters/crossbowman.cpp create mode 100644 8381/Gogolev_Eugene/units/shooters/crossbowman.hpp create mode 100644 8381/Gogolev_Eugene/units/unit.cpp create mode 100644 8381/Gogolev_Eugene/units/unit.hpp diff --git a/8381/Gogolev_Eugene/CMakeLists.txt b/8381/Gogolev_Eugene/CMakeLists.txt new file mode 100644 index 000000000..2359e161c --- /dev/null +++ b/8381/Gogolev_Eugene/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.10) +project(gogolev_strategy) + +set(CMAKE_CXX_STANDARD 14) + +file(GLOB_RECURSE SOURCES + *.hpp + *.cpp + ) + +file(GLOB_RECURSE REMOVE_CMAKE "cmake-build-debug/*") +list(REMOVE_ITEM SOURCES ${REMOVE_CMAKE}) + +add_executable(gogolev_strategy ${SOURCES}) \ No newline at end of file diff --git a/8381/Gogolev_Eugene/enums.hpp b/8381/Gogolev_Eugene/enums.hpp new file mode 100644 index 000000000..770ed8285 --- /dev/null +++ b/8381/Gogolev_Eugene/enums.hpp @@ -0,0 +1,23 @@ +#ifndef GOGOLEV_STRATEGY_ENUMS_HPP +#define GOGOLEV_STRATEGY_ENUMS_HPP + +enum Team { + NEUTRAL, + RED, + BLUE +}; + +enum MovingType { + IMMOBILE, + LEGS, + HORSE +}; + +enum DamageType { + NONE, + PRICKING, + CUTTING, + ARROW +}; + +#endif //GOGOLEV_STRATEGY_ENUMS_HPP diff --git a/8381/Gogolev_Eugene/exceptions/loading_exception.cpp b/8381/Gogolev_Eugene/exceptions/loading_exception.cpp new file mode 100644 index 000000000..d28b0a621 --- /dev/null +++ b/8381/Gogolev_Eugene/exceptions/loading_exception.cpp @@ -0,0 +1,5 @@ +#include "loading_exception.hpp" + +loadingException::loadingException (const string& msg) : strategyException("[Loading] " + msg) { + +} diff --git a/8381/Gogolev_Eugene/exceptions/loading_exception.hpp b/8381/Gogolev_Eugene/exceptions/loading_exception.hpp new file mode 100644 index 000000000..6c3985472 --- /dev/null +++ b/8381/Gogolev_Eugene/exceptions/loading_exception.hpp @@ -0,0 +1,12 @@ +#ifndef GOGOLEV_STRATEGY_LOADING_EXCEPTION_HPP +#define GOGOLEV_STRATEGY_LOADING_EXCEPTION_HPP + +#include "strategy_exception.hpp" + +class loadingException : public strategyException { +public: + explicit loadingException (const std::string& msg); +}; + + +#endif //GOGOLEV_STRATEGY_LOADING_EXCEPTION_HPP diff --git a/8381/Gogolev_Eugene/exceptions/out_of_bounds_exception.cpp b/8381/Gogolev_Eugene/exceptions/out_of_bounds_exception.cpp new file mode 100644 index 000000000..7d397bce6 --- /dev/null +++ b/8381/Gogolev_Eugene/exceptions/out_of_bounds_exception.cpp @@ -0,0 +1,5 @@ +#include "out_of_bounds_exception.hpp" + +outOfBoundsException::outOfBoundsException (const string& msg) : strategyException("[OutOfBounds] " + msg) { + +} diff --git a/8381/Gogolev_Eugene/exceptions/out_of_bounds_exception.hpp b/8381/Gogolev_Eugene/exceptions/out_of_bounds_exception.hpp new file mode 100644 index 000000000..b54f4472e --- /dev/null +++ b/8381/Gogolev_Eugene/exceptions/out_of_bounds_exception.hpp @@ -0,0 +1,12 @@ +#ifndef GOGOLEV_STRATEGY_OUT_OF_BOUNDS_EXCEPTION_HPP +#define GOGOLEV_STRATEGY_OUT_OF_BOUNDS_EXCEPTION_HPP + +#include "strategy_exception.hpp" + +class outOfBoundsException : public strategyException { +public: + explicit outOfBoundsException (const std::string& msg); +}; + + +#endif //GOGOLEV_STRATEGY_OUT_OF_BOUNDS_EXCEPTION_HPP diff --git a/8381/Gogolev_Eugene/exceptions/saving_exception.cpp b/8381/Gogolev_Eugene/exceptions/saving_exception.cpp new file mode 100644 index 000000000..89114ce33 --- /dev/null +++ b/8381/Gogolev_Eugene/exceptions/saving_exception.cpp @@ -0,0 +1,5 @@ +#include "saving_exception.hpp" + +savingException::savingException (const string& msg) : strategyException("[Saving] " + msg) { + +} diff --git a/8381/Gogolev_Eugene/exceptions/saving_exception.hpp b/8381/Gogolev_Eugene/exceptions/saving_exception.hpp new file mode 100644 index 000000000..cbc9e0cf8 --- /dev/null +++ b/8381/Gogolev_Eugene/exceptions/saving_exception.hpp @@ -0,0 +1,12 @@ +#ifndef GOGOLEV_STRATEGY_SAVING_EXCEPTION_HPP +#define GOGOLEV_STRATEGY_SAVING_EXCEPTION_HPP + +#include "strategy_exception.hpp" + +class savingException : public strategyException { +public: + explicit savingException (const std::string& msg); +}; + + +#endif //GOGOLEV_STRATEGY_SAVING_EXCEPTION_HPP diff --git a/8381/Gogolev_Eugene/exceptions/strategy_exception.cpp b/8381/Gogolev_Eugene/exceptions/strategy_exception.cpp new file mode 100644 index 000000000..f740241f7 --- /dev/null +++ b/8381/Gogolev_Eugene/exceptions/strategy_exception.cpp @@ -0,0 +1,9 @@ +#include "strategy_exception.hpp" + +const char *strategyException::what() const noexcept { + return info.c_str(); +} + +strategyException::strategyException(const std::string &msg) { + this->info = "[S]" + msg; +} diff --git a/8381/Gogolev_Eugene/exceptions/strategy_exception.hpp b/8381/Gogolev_Eugene/exceptions/strategy_exception.hpp new file mode 100644 index 000000000..5a9d670ea --- /dev/null +++ b/8381/Gogolev_Eugene/exceptions/strategy_exception.hpp @@ -0,0 +1,15 @@ +#ifndef GOGOLEV_STRATEGY_STRATEGY_EXCEPTION_HPP +#define GOGOLEV_STRATEGY_STRATEGY_EXCEPTION_HPP + +#include "../stl.hpp" + +class strategyException : public std::exception { +private: + std::string info; +public: + explicit strategyException (const std::string& msg); + + const char* what () const noexcept override; +}; + +#endif //GOGOLEV_STRATEGY_STRATEGY_EXCEPTION_HPP diff --git a/8381/Gogolev_Eugene/game.cpp b/8381/Gogolev_Eugene/game.cpp new file mode 100644 index 000000000..3e2a1918d --- /dev/null +++ b/8381/Gogolev_Eugene/game.cpp @@ -0,0 +1,262 @@ +#include "game.hpp" +#include "units/infantries/swordsmen.hpp" +#include "units/infantries/spearmen.hpp" +#include "units/shooters/archers.hpp" +#include "units/shooters/crossbowman.hpp" +#include "units/cavalries/rider.hpp" +#include "units/cavalries/knight.hpp" +#include "units/citadel.hpp" +#include "units/neutrals/villager.hpp" +#include "units/neutrals/fair.hpp" +#include "units/neutrals/farmer.hpp" +#include "units/neutrals/sheep.hpp" +#include "loggers/terminal_logger.hpp" + +Game::Game (GameRule* rule, UI* ui) { + srand(time(nullptr)); + this->gameRule = rule; + this->ui = ui; + if (gameRule != nullptr) { + gameRule->onGameStart(this); + ui->init(sizeX, sizeY); + } +} + +Game::~Game () { + delete tileMap; +} + +bool Game::onField (int x, int y) { + return !(x < 0 || y < 0 || x >= sizeX || y >= sizeY); +} + +void Game::setSize (int sizeX, int sizeY) { + this->sizeX = sizeX; + this->sizeY = sizeY; + delete tileMap; + int size = sizeX * sizeY; + tileMap = new Tile* [size]; + for (int i = 0; i < size; i++) { + tileMap[i] = &meadow; + } + + if (ui != nullptr) { + ui->init(sizeX, sizeY); + } +} + +int Game::getSizeX () const { + return sizeX; +} + +int Game::getSizeY () const { + return sizeY; +} + +void Game::setTile (int x, int y, char id) { + setTile(x, y, getTile(id)); +} + +Tile* Game::getTile (int x, int y) { + if (!onField(x, y)) return &water; + return tileMap[toIndex(x, y)]; +} + +void Game::setLogger (Logger* logger) { + delete this->logger; + this->logger = logger; +} + +void Game::setUI (UI* ui) { + this->ui = ui; + ui->init(sizeX, sizeY); +} + +UI* Game::getUI () { + return ui; +} + +Logger& Game::getLogger () { + if (logger == nullptr) { + setLogger(new TerminalLogger()); + } + return *logger; +} + +Unit* Game::createUnit (string key) { + if (unitMap.size() >= gameRule->getMaxUnits()) return nullptr; + return registerUnit(createUnitInstance(key)); +} + +const vector* Game::findUnits (int x, int y, int radius) { + cash.clear(); + int qrtRadius = radius * radius; + for (auto& it : unitMap) { + Unit* unit = it.second; + if (unit->sqrDistanceTo(x, y) <= qrtRadius) { + cash.push_back(unit); + } + } + return &cash; +} + +Unit* Game::findUnit (int id) { + auto it = unitMap.find(id); + if (it != unitMap.end()) { + return it->second; + } + else { + return nullptr; + } +} + +void Game::setTarget (Team team, int x, int y) { + for (auto& it : unitMap) { + if (it.second->getTeam() == team) it.second->setTargetXY(x, y); + } +} + +void Game::update () { + for (auto& it : unitMap) { + it.second->update(); + } + + if (ui != nullptr) { + for (int x = 0; x < sizeX; x++) { + for (int y = 0; y < sizeY; y++) { + ui->displayTile(x, y, getTile(x, y)); + } + } + + for (auto& it : unitMap) { + ui->displayUnit(it.second); + } + } + + for (auto it = unitMap.begin(); it != unitMap.end();) { + Unit* unit = it->second; + if (unit->isDead()) { + getLogger().log(unit->getType() + " " + to_string(unit->getId()) + " is dead"); + it = unitMap.erase(it); + delete unit; + } + else { + it++; + } + } + + gameRule->onGameUpdate(); +} + +int Game::toIndex (int x, int y) const { + return y * sizeX + x; +} + +Unit* Game::registerUnit (Unit* unit) { + int id = nextId++; + unit->onGameFieldEnter(id, this); + unitMap[id] = unit; + return unit; +} + +Unit* Game::createUnitInstance (string key) { + if (key == Swordsmen::type) { + return new Swordsmen(); + } + else if (key == Spearmen::type) { + return new Spearmen(); + } + else if (key == Archers::type) { + return new Archers(); + } + else if (key == Crossbowman::type) { + return new Crossbowman(); + } + else if (key == Rider::type) { + return new Rider(); + } + else if (key == Knight::type) { + return new Knight(); + } + else if (key == Citadel::type) { + return new Citadel(); + } + else if (key == Villager::type) { + return new Villager(); + } + else if (key == Fair::type) { + return new Fair(); + } + else if (key == Farmer::type) { + return new Farmer(); + } + else if (key == Sheep::type) { + return new Sheep(); + } + else { + return nullptr; + } + +} + +void Game::save (ostream& os) { + os << nextId << ' ' << sizeX << ' ' << sizeY << endl; + int size = sizeX * sizeY; + for (int y = 0; y < sizeY; y++) { + for (int x = 0; x < sizeX; x++) { + os << getTile(x, y)->getId() << ' '; + } + os << endl; + } + + os << unitMap.size() << endl; + for (auto& it : unitMap) { + Unit* unit = it.second; + os << unit->getType() << ' ' << unit->getId() << endl; + unit->save(os); + } +} + +void Game::load (istream& is) { + is >> nextId >> sizeX >> sizeY; + for (int y = 0; y < sizeY; y++) { + for (int x = 0; x < sizeX; x++) { + char id; + is >> id; + setTile(x, y, id); + } + } + int count; + is >> count; + for (int i = 0; i < count; i++) { + string type; + int id; + is >> type >> id; + Unit* unit = createUnitInstance(type); + unit->onGameFieldEnter(id, this); + unit->load(is); + unitMap[id] = unit; + } +} + +Tile* Game::getTile (char id) { + switch (id) { + case Meadow::id: + return &meadow; + case Fortress::id: + return &fortress; + case Water::id: + return &water; + default: + throw out_of_range("Unknows tile id: " + to_string(id)); + } +} + +void Game::setTile (int x, int y, Tile* tile) { + tileMap[toIndex(x, y)] = tile; +} + + + + + diff --git a/8381/Gogolev_Eugene/game.hpp b/8381/Gogolev_Eugene/game.hpp new file mode 100644 index 000000000..8ebbdaddf --- /dev/null +++ b/8381/Gogolev_Eugene/game.hpp @@ -0,0 +1,59 @@ +#ifndef GOGOLEV_STRATEGY_GAME_HPP +#define GOGOLEV_STRATEGY_GAME_HPP + +#include "loggers/logger_proxy.hpp" +#include "units/unit.hpp" +#include "tiles/tile.hpp" +#include "game_rule.hpp" +#include "ui.hpp" +#include "tiles/meadow.hpp" +#include "tiles/fortress.hpp" +#include "tiles/water.hpp" + +class Game : public Unit::GameHandler, GameRule::GameHandler { +public: + Game (GameRule* rule, UI* ui); + ~Game (); + bool onField (int x, int y) override; + void setSize (int sizeX, int sizeY) override; + int getSizeX () const override; + int getSizeY () const override; + Tile* getTile (int x, int y) override; + void setTile(int x, int y, char id) override; + void setLogger (Logger* logger); + UI* getUI () override; + void setUI (UI* ui); + Logger& getLogger () override; + Unit* createUnit (string key) override; + const vector* findUnits (int x, int y, int radius) override; + Unit* findUnit (int id) override; + void setTarget(Team team, int x, int y); + + void update (); + void save(ostream &os); + void load(istream &is); + + +private: + int nextId = 1; + int sizeX = 0; + int sizeY = 0; + Tile** tileMap = nullptr; + GameRule* gameRule = nullptr; + Logger* logger = nullptr; + UI* ui = nullptr; + map unitMap; + vector cash; + + Fortress fortress; + Meadow meadow; + Water water; + + int toIndex (int x, int y) const; + Unit* registerUnit (Unit* unit); + Unit* createUnitInstance (string key); + Tile* getTile(char id); + void setTile (int x, int y, Tile* tile); +}; + +#endif //GOGOLEV_STRATEGY_GAME_HPP diff --git a/8381/Gogolev_Eugene/game_rule.cpp b/8381/Gogolev_Eugene/game_rule.cpp new file mode 100644 index 000000000..d0df6d7b1 --- /dev/null +++ b/8381/Gogolev_Eugene/game_rule.cpp @@ -0,0 +1,130 @@ +#include "game_rule.hpp" +#include "units/unit.hpp" +#include "tiles/fortress.hpp" +#include "ui.hpp" +#include "tiles/water.hpp" +#include "units/citadel.hpp" +#include "units/neutrals/fair.hpp" +#include "units/neutrals/farmer.hpp" +#include "units/neutrals/sheep.hpp" +#include "units/neutrals/villager.hpp" +#include "exceptions/strategy_exception.hpp" + +bool GameRule::isGameEnded () { + return gameHandler->findUnit(redCitadelId) == nullptr || gameHandler->findUnit(blueCitadelId) == nullptr; +} + +void GameRule::onGameStart (GameRule::GameHandler* gameHandler) { + frameCount = 0; + this->gameHandler = gameHandler; + + gameHandler->setSize(sizeX, sizeY); + //gameFieldHandler->setTile(0, 0, &water); + + int fortressSizeX = sizeX * 0.2; + int fortressSizeY = sizeY * 0.2; + + int fortressOffsetX = sizeX * 0.1; + int fortressOffsetY = sizeY * 0.1; + + int fortressAOffsetX = fortressOffsetX; + int fortressAOffsetY = fortressOffsetY; + + Unit *redCitadel = plaseFortress( + fortressAOffsetX, + fortressAOffsetY, + fortressAOffsetX + fortressSizeX, + fortressAOffsetY + fortressSizeY, + RED + ); + + int fortressBOffsetX = sizeX - 1 - fortressSizeX - fortressOffsetX; + int fortressBOffsetY = sizeY - 1 - fortressSizeY - fortressOffsetY; + + Unit *blueCitadel = plaseFortress( + fortressBOffsetX, + fortressBOffsetY, + fortressBOffsetX + fortressSizeX, + fortressBOffsetY + fortressSizeY, + BLUE + ); + + redCitadelId = redCitadel->getId(); + blueCitadelId = blueCitadel->getId(); + + redCitadel->setTargetXY(blueCitadel->getX(), blueCitadel->getY()); + blueCitadel->setTargetXY(redCitadel->getX(), redCitadel->getY()); + // Design + fillRect(0, 0, 0, sizeY - 1, Water::id); + fillRect(sizeX - 1, 0, sizeX - 1, sizeY - 1, Water::id); + + plaseVillage(sizeX / 5 * 4, sizeY / 5); + plaseVillage(sizeX / 5, sizeY / 5 * 4); +} + +void GameRule::onGameUpdate () { + frameCount++; + UI* ui = gameHandler->getUI(); + if (ui == nullptr) return; + Unit* r = gameHandler->findUnit(redCitadelId); + if (r) ui->displayPixel(r->getTargetX(), r->getTargetY(), 'R'); + Unit* b = gameHandler->findUnit(blueCitadelId); + if (b) ui->displayPixel(b->getTargetX(), b->getTargetY(), 'B'); + gameHandler->getLogger().log("-F " + to_string(frameCount)); + // Your custom ads and logic here +} + +void GameRule::fillRect (int minX, int minY, int maxX, int maxY, char tileId) { + for(int y = minY; y <= maxY; y++) { + for(int x = minX; x <= maxX; x++) { + gameHandler->setTile(x, y, tileId); + } + } +} + +void GameRule::plaseVillage (int x, int y) { + fillRect(x, y, x, y, Water::id); + + // Neutral + plaseNeutral(x + 1, y, Fair::type); + plaseNeutral(x - 1, y, Farmer::type); + plaseNeutral(x, y + 1, Sheep::type); + plaseNeutral(x, y - 1, Villager::type); +} + +void GameRule::plaseNeutral (int x, int y, string type) { + Unit* u = gameHandler->createUnit(type); + if (u == nullptr) + return; + u->setXY(x, y); + u->setTargetXY(x, y); +} + +Unit* GameRule::plaseFortress (int minX, int minY, int maxX, int maxY, Team team) { + fillRect(minX, minY, maxX, maxY, Fortress::id); + Unit* citadel = gameHandler->createUnit(Citadel::type); + if (citadel == nullptr) throw strategyException("Can't create citadel"); + citadel->setTeam(team); + citadel->setXY((int)((minX + maxX) * 0.5), (int)((minY + maxY) * 0.5)); + return citadel; +} + +Unit* GameRule::getCitadel (Team team) { + switch (team) { + case RED: + return gameHandler->findUnit(redCitadelId); + case BLUE: + return gameHandler->findUnit(blueCitadelId); + default: + return nullptr; + } +} + +int GameRule::getMaxUnits() { + return maxUnits; +} + +void GameRule::reset() { + +} + diff --git a/8381/Gogolev_Eugene/game_rule.hpp b/8381/Gogolev_Eugene/game_rule.hpp new file mode 100644 index 000000000..5311cf52b --- /dev/null +++ b/8381/Gogolev_Eugene/game_rule.hpp @@ -0,0 +1,50 @@ +#ifndef GOGOLEV_STRATEGY_GAME_RULE_HPP +#define GOGOLEV_STRATEGY_GAME_RULE_HPP + +#include "stl.hpp" +#include "enums.hpp" +#include "loggers/logger.hpp" + +class Tile; +class Unit; +class UI; + +class GameRule { +public: + class GameHandler { + public: + virtual void setSize(int sizeX, int sizeY) = 0; + virtual void setTile(int x, int y, char tileId) = 0; + virtual Unit* createUnit(string key) = 0; + virtual Unit* findUnit(int id) = 0; + virtual UI* getUI () = 0; + virtual Logger& getLogger () = 0; + }; + +public: + virtual bool isGameEnded(); + virtual void onGameStart(GameHandler *gameHandler); + virtual void onGameUpdate(); + void reset(); + int getMaxUnits(); + + Unit* getCitadel(Team team); + +private: + GameHandler *gameHandler; + + const int sizeX = 30; + const int sizeY = 10; + const int maxUnits = 50; + int redCitadelId; + int blueCitadelId; + int frameCount; + + void fillRect(int minX, int minY, int maxX, int maxY, char tileId); + void plaseVillage(int x, int y); + void plaseNeutral(int x, int y, string type); + Unit* plaseFortress(int minX, int minY, int maxX, int maxY, Team team); +}; + + +#endif //GOGOLEV_STRATEGY_GAME_RULE_HPP diff --git a/8381/Gogolev_Eugene/loggers/file_logger.cpp b/8381/Gogolev_Eugene/loggers/file_logger.cpp new file mode 100644 index 000000000..1a4e4e66f --- /dev/null +++ b/8381/Gogolev_Eugene/loggers/file_logger.cpp @@ -0,0 +1,15 @@ +#include "file_logger.hpp" + +FileLogger::FileLogger (const string& fileName) { + this->fileName = fileName; + std::ofstream ofs; + ofs.open(fileName, std::ofstream::out | std::ofstream::trunc); // Clear file + ofs.close(); +} + +void FileLogger::log (const string& message) { + std::ofstream out; + out.open(fileName, std::fstream::out | std::fstream::app); + out << message << endl; + out.close(); +} diff --git a/8381/Gogolev_Eugene/loggers/file_logger.hpp b/8381/Gogolev_Eugene/loggers/file_logger.hpp new file mode 100644 index 000000000..a11c90bec --- /dev/null +++ b/8381/Gogolev_Eugene/loggers/file_logger.hpp @@ -0,0 +1,15 @@ +#ifndef GOGOLEV_STRATEGY_FILE_LOGGER_HPP +#define GOGOLEV_STRATEGY_FILE_LOGGER_HPP + +#include "logger.hpp" + +class FileLogger : public Logger { +public: + FileLogger(const string& fileName); + void log (const string& message) override; + +private: + string fileName; +}; + +#endif //GOGOLEV_STRATEGY_FILE_LOGGER_HPP diff --git a/8381/Gogolev_Eugene/loggers/logger.cpp b/8381/Gogolev_Eugene/loggers/logger.cpp new file mode 100644 index 000000000..6de3bb768 --- /dev/null +++ b/8381/Gogolev_Eugene/loggers/logger.cpp @@ -0,0 +1,2 @@ +#include "logger.hpp" + diff --git a/8381/Gogolev_Eugene/loggers/logger.hpp b/8381/Gogolev_Eugene/loggers/logger.hpp new file mode 100644 index 000000000..b77cd85d3 --- /dev/null +++ b/8381/Gogolev_Eugene/loggers/logger.hpp @@ -0,0 +1,14 @@ +#ifndef GOGOLEV_STRATEGY_LOGGER_HPP +#define GOGOLEV_STRATEGY_LOGGER_HPP + +#include "../stl.hpp" + + +class Logger { +public: + virtual ~Logger() = default; + virtual void log(const string &message) = 0; +}; + + +#endif //GOGOLEV_STRATEGY_LOGGER_HPP diff --git a/8381/Gogolev_Eugene/loggers/logger_proxy.cpp b/8381/Gogolev_Eugene/loggers/logger_proxy.cpp new file mode 100644 index 000000000..e817121d4 --- /dev/null +++ b/8381/Gogolev_Eugene/loggers/logger_proxy.cpp @@ -0,0 +1,17 @@ +#include "logger_proxy.hpp" + +LoggerProxy::LoggerProxy (Logger* concrete) { + child = concrete; +} + +void LoggerProxy::setChild (Logger* concrete) { + delete child; + child = concrete; +} + +void LoggerProxy::log (const string& message) { + if (child) child->log(message); +} + + + diff --git a/8381/Gogolev_Eugene/loggers/logger_proxy.hpp b/8381/Gogolev_Eugene/loggers/logger_proxy.hpp new file mode 100644 index 000000000..8fc8614ff --- /dev/null +++ b/8381/Gogolev_Eugene/loggers/logger_proxy.hpp @@ -0,0 +1,16 @@ +#ifndef GOGOLEV_STRATEGY_LOGGER_PROXY_HPP +#define GOGOLEV_STRATEGY_LOGGER_PROXY_HPP + +#include "logger.hpp" + +class LoggerProxy : public Logger { +public: + explicit LoggerProxy(Logger* concrete); + void setChild(Logger* concrete); + void log (const string& message) override; +private: + Logger* child; +}; + + +#endif //GOGOLEV_STRATEGY_LOGGER_PROXY_HPP diff --git a/8381/Gogolev_Eugene/loggers/terminal_logger.cpp b/8381/Gogolev_Eugene/loggers/terminal_logger.cpp new file mode 100644 index 000000000..9ad6a31a2 --- /dev/null +++ b/8381/Gogolev_Eugene/loggers/terminal_logger.cpp @@ -0,0 +1,5 @@ +#include "terminal_logger.hpp" + +void TerminalLogger::log (const string& message) { + cout << message << endl; +} diff --git a/8381/Gogolev_Eugene/loggers/terminal_logger.hpp b/8381/Gogolev_Eugene/loggers/terminal_logger.hpp new file mode 100644 index 000000000..552c32cb2 --- /dev/null +++ b/8381/Gogolev_Eugene/loggers/terminal_logger.hpp @@ -0,0 +1,12 @@ +#ifndef GOGOLEV_STRATEGY_TERMINAL_LOGGER_HPP +#define GOGOLEV_STRATEGY_TERMINAL_LOGGER_HPP + +#include "logger.hpp" + +class TerminalLogger : public Logger { +public: + void log(const string &message) override; +}; + + +#endif //GOGOLEV_STRATEGY_TERMINAL_LOGGER_HPP diff --git a/8381/Gogolev_Eugene/main.cpp b/8381/Gogolev_Eugene/main.cpp new file mode 100644 index 000000000..cbeb2d3b7 --- /dev/null +++ b/8381/Gogolev_Eugene/main.cpp @@ -0,0 +1,101 @@ +#include "stl.hpp" +#include "ui.hpp" +#include "game.hpp" +#include "game_rule.hpp" +#include "exceptions/saving_exception.hpp" +#include "exceptions/loading_exception.hpp" +#include "loggers/terminal_logger.hpp" +#include "loggers/file_logger.hpp" + + +int main () { + UI ui; + GameRule gameRule; + LoggerProxy* logger = new LoggerProxy(new FileLogger("log.txt")); + Game game = Game(&gameRule, &ui); + game.setLogger(logger); + + string buffer; + while (true) { + cin >> buffer; + Unit* ru = gameRule.getCitadel(RED); + if (ru == nullptr) break; + int prx = ru->getTargetX(); + int pry = ru->getTargetY(); + Unit* bu = gameRule.getCitadel(BLUE); + if (bu == nullptr) break; + int pbx = bu->getTargetX(); + int pby = bu->getTargetY(); + + if (buffer == "q") { + break; + } + else if (buffer == "save") { + ofstream os; + os.open ("backup.data"); + if (!os) { + throw savingException("Can't open file"); + } + else { + game.save(os); + os.close(); + logger->log("Game saved."); + cout << "Game saved." << endl; + } + continue; + } + else if (buffer == "load") { + ifstream is; + is.open ("backup.data"); + if (!is) { + throw loadingException("Can't open file"); + } + else { + game.load(is); + is.close(); + logger->log("Game loaded."); + cout << "Game loaded." << endl; + } + continue; + } + else if (buffer == "w") { + game.setTarget(RED, prx, pry - 1); + } + else if (buffer == "a") { + game.setTarget(RED, prx - 1, pry); + } + else if (buffer == "s") { + game.setTarget(RED, prx, pry + 1); + } + else if (buffer == "d") { + game.setTarget(RED, prx + 1, pry); + } + else if (buffer == "i") { + game.setTarget(BLUE, pbx, pby - 1); + } + else if (buffer == "j") { + game.setTarget(BLUE, pbx - 1, pby); + } + else if (buffer == "k") { + game.setTarget(BLUE, pbx, pby + 1); + } + else if (buffer == "l") { + game.setTarget(BLUE, pbx + 1, pby); + } + + //ui.clear(); + game.update(); + ui.showFrame(); + + if (gameRule.isGameEnded()) break; + } + + if (gameRule.isGameEnded()) { + cout << "Game ended" << endl; + } + else { + cout << "Game stoped" << endl; + } + + return 0; +} diff --git a/8381/Gogolev_Eugene/stl.hpp b/8381/Gogolev_Eugene/stl.hpp new file mode 100644 index 000000000..2a9edfe65 --- /dev/null +++ b/8381/Gogolev_Eugene/stl.hpp @@ -0,0 +1,15 @@ +#ifndef GOGOLEV_STRATEGY_STL_HPP +#define GOGOLEV_STRATEGY_STL_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; + +#endif //GOGOLEV_STRATEGY_STL_HPP diff --git a/8381/Gogolev_Eugene/tiles/fortress.cpp b/8381/Gogolev_Eugene/tiles/fortress.cpp new file mode 100644 index 000000000..d802b44cf --- /dev/null +++ b/8381/Gogolev_Eugene/tiles/fortress.cpp @@ -0,0 +1,24 @@ +#include "fortress.hpp" +#include "../exceptions/out_of_bounds_exception.hpp" + +static const char sprite[3][3] = {{'#', '#', '#'}, + {'#', ' ', '#'}, + {'#', '#', '#'}}; + +char Fortress::getId () { + return id; +} + +char Fortress::getChar (int x, int y) { + validateChar(x, y); + return sprite[x][y]; +} + +bool Fortress::allow (DamageType damageType) { + return damageType != ARROW; +} + +bool Fortress::allow (MovingType movingType) { + return movingType != HORSE; +} + diff --git a/8381/Gogolev_Eugene/tiles/fortress.hpp b/8381/Gogolev_Eugene/tiles/fortress.hpp new file mode 100644 index 000000000..2b0b1a015 --- /dev/null +++ b/8381/Gogolev_Eugene/tiles/fortress.hpp @@ -0,0 +1,15 @@ +#ifndef GOGOLEV_STRATEGY_FORTRESS_HPP +#define GOGOLEV_STRATEGY_FORTRESS_HPP + +#include "tile.hpp" + +class Fortress : public Tile { +public: + const static char id = 'F'; + char getId() override ; + char getChar(int x, int y) override; + bool allow(DamageType damageType) override; + bool allow(MovingType movingType) override; +}; + +#endif //GOGOLEV_STRATEGY_FORTRESS_HPP diff --git a/8381/Gogolev_Eugene/tiles/meadow.cpp b/8381/Gogolev_Eugene/tiles/meadow.cpp new file mode 100644 index 000000000..dbd2ee3fe --- /dev/null +++ b/8381/Gogolev_Eugene/tiles/meadow.cpp @@ -0,0 +1,24 @@ +#include "meadow.hpp" + +static const char sprite[3][3] = {{' ', ' ', ' '}, + {' ', ' ', ' '}, + {' ', ' ', ' '}}; + +char Meadow::getId () { + return id; +} + +char Meadow::getChar (int x, int y) { + validateChar(x, y); + return sprite[x][y]; +} + +bool Meadow::allow (DamageType damageType) { + return true; +} + +bool Meadow::allow (MovingType movingType) { + return true; +} + + diff --git a/8381/Gogolev_Eugene/tiles/meadow.hpp b/8381/Gogolev_Eugene/tiles/meadow.hpp new file mode 100644 index 000000000..b2d7398da --- /dev/null +++ b/8381/Gogolev_Eugene/tiles/meadow.hpp @@ -0,0 +1,16 @@ +#ifndef GOGOLEV_STRATEGY_MEADOW_HPP +#define GOGOLEV_STRATEGY_MEADOW_HPP + +#include "tile.hpp" + +class Meadow : public Tile { +public: + const static char id = 'M'; + char getId() override ; + char getChar(int x, int y) override; + bool allow(DamageType damageType) override; + bool allow(MovingType movingType) override; +}; + + +#endif //GOGOLEV_STRATEGY_MEADOW_HPP diff --git a/8381/Gogolev_Eugene/tiles/tile.cpp b/8381/Gogolev_Eugene/tiles/tile.cpp new file mode 100644 index 000000000..f5d3d9b97 --- /dev/null +++ b/8381/Gogolev_Eugene/tiles/tile.cpp @@ -0,0 +1,6 @@ +#include "tile.hpp" +#include "../exceptions/out_of_bounds_exception.hpp" + +void Tile::validateChar (int x, int y) { + if (x < 0 || y < 0 || x > 2 || y > 2) throw out_of_range("Tile char output error"); +} diff --git a/8381/Gogolev_Eugene/tiles/tile.hpp b/8381/Gogolev_Eugene/tiles/tile.hpp new file mode 100644 index 000000000..daab5420e --- /dev/null +++ b/8381/Gogolev_Eugene/tiles/tile.hpp @@ -0,0 +1,17 @@ +#ifndef GOGOLEV_STRATEGY_TILE_HPP +#define GOGOLEV_STRATEGY_TILE_HPP + +#include "../stl.hpp" +#include "../enums.hpp" + +class Tile { +public: + void validateChar(int x, int y); + virtual char getId() = 0; + virtual char getChar (int x, int y) = 0; + virtual bool allow (DamageType damageType) = 0; + virtual bool allow (MovingType movingType) = 0; +}; + + +#endif //GOGOLEV_STRATEGY_TILE_HPP diff --git a/8381/Gogolev_Eugene/tiles/water.cpp b/8381/Gogolev_Eugene/tiles/water.cpp new file mode 100644 index 000000000..2f69cb1d5 --- /dev/null +++ b/8381/Gogolev_Eugene/tiles/water.cpp @@ -0,0 +1,23 @@ +#include "water.hpp" + +static const char sprite[3][3] = {{'~', ' ', '~'}, + {' ', '~', ' '}, + {'~', ' ', '~'}}; + +char Water::getId () { + return id; +} + +char Water::getChar (int x, int y) { + validateChar(x, y); + return sprite[x][y]; +} + +bool Water::allow (DamageType damageType) { + return true; +} + +bool Water::allow (MovingType movingType) { + return movingType != HORSE; +} + diff --git a/8381/Gogolev_Eugene/tiles/water.hpp b/8381/Gogolev_Eugene/tiles/water.hpp new file mode 100644 index 000000000..d4abbfa72 --- /dev/null +++ b/8381/Gogolev_Eugene/tiles/water.hpp @@ -0,0 +1,16 @@ +#ifndef GOGOLEV_STRATEGY_WATER_HPP +#define GOGOLEV_STRATEGY_WATER_HPP + +#include "tile.hpp" + +class Water : public Tile { +public: + const static char id = 'W'; + char getId() override ; + char getChar(int x, int y) override; + bool allow(DamageType damageType) override; + bool allow(MovingType movingType) override; +}; + + +#endif //GOGOLEV_STRATEGY_WATER_HPP diff --git a/8381/Gogolev_Eugene/ui.cpp b/8381/Gogolev_Eugene/ui.cpp new file mode 100644 index 000000000..cc6a89bce --- /dev/null +++ b/8381/Gogolev_Eugene/ui.cpp @@ -0,0 +1,58 @@ +#include "ui.hpp" +#include "tiles/tile.hpp" +#include "units/unit.hpp" + +void UI::init (int x, int y) { + this->sizeX = x; + this->sizeY = y; + frame = new char[x * y * 9]; +} + +void UI::displayTile (int x, int y, Tile* tile) { + for (int charX = 0; charX < 3; charX++) { + for (int charY = 0; charY < 3; charY++) { + frame[toIndex(x, y, charX, charY)] = tile->getChar(charX, charY); + } + } +} + +void UI::displayUnit (Unit* unit) { + for (int charX = 0; charX < 3; charX++) { + for (int charY = 0; charY < 3; charY++) { + char c = unit->getChar(charX, charY); + if (c != ' ') frame[toIndex(unit->getX(), unit->getY(), charX, charY)] = unit->getChar(charX, charY); + } + } +} + +void UI::displayPixel (int x, int y, char p) { + frame[toIndex(x, y, 1, 1)] = p; +} + +void UI::clear () { + int size = sizeX * sizeY * 9; + for(int i = 0; i < size; i++) { + frame[i] = ' '; + } +} + +void UI::showFrame () { + cout << endl; + for(int y = 0; y < sizeY; y++) { + for (int charY = 0; charY < 3; charY++) { + for(int x = 0; x < sizeX; x++) { + for (int charX = 0; charX < 3; charX++) { + cout << frame[toIndex(x, y, charX, charY)]; + } + } + cout << endl; + } + } + for(int i = 0; i < sizeX * 3; i++) cout << "-"; +} + +int UI::toIndex (int x, int y, int charX, int charY) const { + return (y * 3 + charY) * sizeX * 3 + x * 3 + charX; +} + + diff --git a/8381/Gogolev_Eugene/ui.hpp b/8381/Gogolev_Eugene/ui.hpp new file mode 100644 index 000000000..e24b77608 --- /dev/null +++ b/8381/Gogolev_Eugene/ui.hpp @@ -0,0 +1,35 @@ +#ifndef GOGOLEV_STRATEGY_UI_HPP +#define GOGOLEV_STRATEGY_UI_HPP + +#include "stl.hpp" + +class Tile; +class Unit; + +class UI { +public: + // TODO init to ctor + + void init(int x, int y); + + void displayTile(int x, int y, Tile *tile); + + void displayUnit(Unit *unit); + + void displayPixel(int x, int y, char p); + + void clear(); + + void showFrame(); + +private: + int sizeX; + int sizeY; + char* frame = nullptr; + + int toIndex(int x, int y, int charX, int charY) const; +}; + + + +#endif //GOGOLEV_STRATEGY_UI_HPP diff --git a/8381/Gogolev_Eugene/units/cavalries/knight.cpp b/8381/Gogolev_Eugene/units/cavalries/knight.cpp new file mode 100644 index 000000000..7324e4bcf --- /dev/null +++ b/8381/Gogolev_Eugene/units/cavalries/knight.cpp @@ -0,0 +1,38 @@ +#include "knight.hpp" + +static const char sprite[3][3] = {{' ', '@', ' '}, + {' ', '|', '>'}, + {' ', '^', ' '}}; + +const string Knight::type = "Knight"; + +int Knight::getMaxHP () { + return 8; +} + +DamageType Knight::getDamageType () { + return PRICKING; +} + +char Knight::getChar (int x, int y) { + validateChar(x, y); + if (x == 1 && y == 1) { + switch (team) { + case RED: + return 'A'; + case BLUE: + return '0'; + default: + return '?'; + } + } + return sprite[y][x]; +} + +Knight::Knight () { + hp = Knight::getMaxHP(); +} + +const string& Knight::getType () { + return type; +} diff --git a/8381/Gogolev_Eugene/units/cavalries/knight.hpp b/8381/Gogolev_Eugene/units/cavalries/knight.hpp new file mode 100644 index 000000000..31ed33ce4 --- /dev/null +++ b/8381/Gogolev_Eugene/units/cavalries/knight.hpp @@ -0,0 +1,16 @@ +#ifndef GOGOLEV_STRATEGY_KNIGHT_HPP +#define GOGOLEV_STRATEGY_KNIGHT_HPP + +#include "../cavalry.hpp" + +class Knight : public Cavalry { +public: + static const string type; + Knight(); + int getMaxHP() override; + DamageType getDamageType() override; + char getChar(int x, int y) override; + const string& getType() override; +}; + +#endif //GOGOLEV_STRATEGY_KNIGHT_HPP diff --git a/8381/Gogolev_Eugene/units/cavalries/rider.cpp b/8381/Gogolev_Eugene/units/cavalries/rider.cpp new file mode 100644 index 000000000..38980bd86 --- /dev/null +++ b/8381/Gogolev_Eugene/units/cavalries/rider.cpp @@ -0,0 +1,40 @@ +#include "rider.hpp" + +static const char sprite[3][3] = {{'<', '@', ' '}, + {'<', '|', ' '}, + {'/', ' ', '\\'}}; + +const string Rider::type = "Rider"; + +Rider::Rider () { + hp = Rider::getMaxHP(); +} + +int Rider::getMaxHP () { + return 6; +} + +DamageType Rider::getDamageType () { + return CUTTING; +} + +char Rider::getChar (int x, int y) { + validateChar(x, y); + if (x == 1 && y == 1) { + switch (team) { + case RED: + return 'A'; + case BLUE: + return '0'; + default: + return '?'; + } + } + return sprite[y][x]; +} + +const string& Rider::getType () { + return type; +} + + diff --git a/8381/Gogolev_Eugene/units/cavalries/rider.hpp b/8381/Gogolev_Eugene/units/cavalries/rider.hpp new file mode 100644 index 000000000..c8ef0cfba --- /dev/null +++ b/8381/Gogolev_Eugene/units/cavalries/rider.hpp @@ -0,0 +1,16 @@ +#ifndef GOGOLEV_STRATEGY_RIDER_HPP +#define GOGOLEV_STRATEGY_RIDER_HPP + +#include "../cavalry.hpp" + +class Rider : public Cavalry { +public: + static const string type; + Rider(); + int getMaxHP() override; + DamageType getDamageType() override; + char getChar(int x, int y) override; + const string& getType() override; +}; + +#endif //GOGOLEV_STRATEGY_RIDER_HPP diff --git a/8381/Gogolev_Eugene/units/cavalry.cpp b/8381/Gogolev_Eugene/units/cavalry.cpp new file mode 100644 index 000000000..1f1bd92d4 --- /dev/null +++ b/8381/Gogolev_Eugene/units/cavalry.cpp @@ -0,0 +1,17 @@ +#include "cavalry.hpp" + +int Cavalry::getSpeed () { + return 3; +} + +MovingType Cavalry::getMovingType () { + return HORSE; +} + +void Cavalry::takeDamage (DamageType damageType, int value) { + if(damageType == PRICKING) { + Unit::takeDamage(damageType, value * 2); + } else { + Unit::takeDamage(damageType, value); + } +} diff --git a/8381/Gogolev_Eugene/units/cavalry.hpp b/8381/Gogolev_Eugene/units/cavalry.hpp new file mode 100644 index 000000000..373bd2c20 --- /dev/null +++ b/8381/Gogolev_Eugene/units/cavalry.hpp @@ -0,0 +1,14 @@ +#ifndef GOGOLEV_STRATEGY_CAVALRY_HPP +#define GOGOLEV_STRATEGY_CAVALRY_HPP + +#include "unit.hpp" + +class Cavalry : public Unit { +public: + int getSpeed() override; + MovingType getMovingType() override; + void takeDamage(DamageType damageType, int value) override; +}; + + +#endif //GOGOLEV_STRATEGY_CAVALRY_HPP diff --git a/8381/Gogolev_Eugene/units/citadel.cpp b/8381/Gogolev_Eugene/units/citadel.cpp new file mode 100644 index 000000000..b71331ddf --- /dev/null +++ b/8381/Gogolev_Eugene/units/citadel.cpp @@ -0,0 +1,112 @@ +#include "citadel.hpp" +#include "../exceptions/out_of_bounds_exception.hpp" + +static const char sprite[3][3] = {{' ', '^', ' '}, + {'<', ' ', '>'}, + {' ', 'V', ' '}}; + +const string Citadel::type = "Citadel"; + +Citadel::Citadel () { + hp = Citadel::getMaxHP(); +} + +int Citadel::getMaxHP () { + return 50; +} + +char Citadel::getChar (int x, int y) { + validateChar(x, y); + if (x == 1 && y == 1) { + switch (team) { + case RED: + return 'A'; + case BLUE: + return '0'; + default: + return '?'; + } + } + if (y == 2) { + switch (x) { + case 0: + return '0' + hp / 100 % 10; + break; + case 1: + return '0' + hp / 10 % 10; + break; + case 2: + return '0' + hp % 10; + break; + } + } + return sprite[y][x]; +} + +void Citadel::update () { + for (auto it = unitList.begin(); it != unitList.end();) { + Unit* unit = gameHandler->findUnit(*it); + if (unit == nullptr || unit->isDead()) { + it = unitList.erase(it); + } + else { + it++; + } + } + + if (unitList.size() < unitCap) { + Unit* unit = createUnit(); + if (unit != nullptr) { + unitList.push_back(unit->getId()); + unit->setTeam(team); + unit->setXY(x, y); + unit->setTargetXY(targetX, targetY); + } + } +} + +Unit* Citadel::createUnit () { + switch (rand() % 6) { + case 0: + return gameHandler->createUnit("Swordsmen"); + case 1: + return gameHandler->createUnit("Spearmen"); + case 2: + return gameHandler->createUnit("Archers"); + case 3: + return gameHandler->createUnit("Crossbowman"); + case 4: + return gameHandler->createUnit("Rider"); + case 5: + return gameHandler->createUnit("Knight"); + default: + throw outOfBoundsException("Unknown citadel unit generation type"); + } +} + +void Citadel::save (ostream& os) { + Unit::save(os); + int size = unitList.size(); + os << unitCap << ' ' << unitTypeIndex << ' ' << size << endl; + for(int i = 0; i < size; i++) { + int id = unitList[i]; + os << id << ' '; + } + os << endl; +} + +void Citadel::load (istream& is) { + Unit::load(is); + int size; + is >> unitCap >> unitTypeIndex >> size; + for(int i = 0; i < size; i++) { + int id; + is >> id; + unitList.push_back(id); + } +} + +const string& Citadel::getType () { + return type; +} + diff --git a/8381/Gogolev_Eugene/units/citadel.hpp b/8381/Gogolev_Eugene/units/citadel.hpp new file mode 100644 index 000000000..c752b6dbd --- /dev/null +++ b/8381/Gogolev_Eugene/units/citadel.hpp @@ -0,0 +1,27 @@ +#ifndef GOGOLEV_STRATEGY_CITADEL_HPP +#define GOGOLEV_STRATEGY_CITADEL_HPP + +#include "unit.hpp" + +class Citadel : public Unit { +public: + static const string type; + Citadel(); + int getMaxHP() override; + char getChar(int x, int y) override; + void update() override; + + void save(ostream &os); + void load(istream &is); + const string& getType(); + +private: + int unitCap = 5; + int unitTypeIndex = 0; + vector unitList; + + Unit* createUnit(); +}; + + +#endif //GOGOLEV_STRATEGY_CITADEL_HPP diff --git a/8381/Gogolev_Eugene/units/infantries/spearmen.cpp b/8381/Gogolev_Eugene/units/infantries/spearmen.cpp new file mode 100644 index 000000000..01b5412f8 --- /dev/null +++ b/8381/Gogolev_Eugene/units/infantries/spearmen.cpp @@ -0,0 +1,43 @@ +#include "spearmen.hpp" + +static const char sprite[3][3] = {{' ', '@', '^'}, + {'O', '|', '|'}, + {' ', '^', '|'}}; + +const string Spearmen::type = "Spearmen"; + +Spearmen::Spearmen () { + hp = Spearmen::getMaxHP(); +} + +int Spearmen::getMaxHP () { + return 4; +} + +DamageType Spearmen::getDamageType () { + return PRICKING; +} + +int Spearmen::getDamage () { + return 2; +} + +char Spearmen::getChar (int x, int y) { + validateChar(x, y); + if (x == 1 && y == 1) { + switch (team) { + case RED: + return 'A'; + case BLUE: + return '0'; + default: + return '?'; + } + } + return sprite[y][x]; +} + +const string& Spearmen::getType () { + return type; +} + diff --git a/8381/Gogolev_Eugene/units/infantries/spearmen.hpp b/8381/Gogolev_Eugene/units/infantries/spearmen.hpp new file mode 100644 index 000000000..5a1734904 --- /dev/null +++ b/8381/Gogolev_Eugene/units/infantries/spearmen.hpp @@ -0,0 +1,18 @@ +#ifndef GOGOLEV_STRATEGY_SPEARMEN_HPP +#define GOGOLEV_STRATEGY_SPEARMEN_HPP + +#include "../infantry.hpp" + +class Spearmen : public Infantry { +public: + static const string type; + Spearmen(); + int getMaxHP() override; + DamageType getDamageType() override; + int getDamage() override; + char getChar(int x, int y) override; + const string& getType() override; +}; + + +#endif //GOGOLEV_STRATEGY_SPEARMEN_HPP diff --git a/8381/Gogolev_Eugene/units/infantries/swordsmen.cpp b/8381/Gogolev_Eugene/units/infantries/swordsmen.cpp new file mode 100644 index 000000000..c44240deb --- /dev/null +++ b/8381/Gogolev_Eugene/units/infantries/swordsmen.cpp @@ -0,0 +1,44 @@ +#include "swordsmen.hpp" + +static const char sprite[3][3] = {{'|', 'o', ' '}, + {'W', '|', '\\'}, + {' ', '^', ' '}}; + +const string Swordsmen::type = "Swordsmen"; + +Swordsmen::Swordsmen () { + hp = Swordsmen::getMaxHP(); +} + +int Swordsmen::getMaxHP () { + return 5; +} + +DamageType Swordsmen::getDamageType () { + return CUTTING; +} + +int Swordsmen::getDamage () { + return 3; +} + +char Swordsmen::getChar (int x, int y) { + validateChar(x, y); + if (x == 1 && y == 1) { + switch (team) { + case RED: + return 'A'; + case BLUE: + return '0'; + default: + return '?'; + } + } + return sprite[y][x]; +} + +const string& Swordsmen::getType () { + return type; +} + + diff --git a/8381/Gogolev_Eugene/units/infantries/swordsmen.hpp b/8381/Gogolev_Eugene/units/infantries/swordsmen.hpp new file mode 100644 index 000000000..6d368aa06 --- /dev/null +++ b/8381/Gogolev_Eugene/units/infantries/swordsmen.hpp @@ -0,0 +1,19 @@ +#ifndef GOGOLEV_STRATEGY_SWORDSMEN_HPP +#define GOGOLEV_STRATEGY_SWORDSMEN_HPP + +#include "../infantry.hpp" + +class Swordsmen : public Infantry { +public: + static const string type; + Swordsmen(); + int getMaxHP() override; + DamageType getDamageType() override; + int getDamage() override; + char getChar(int x, int y) override; + const string& getType() override; +}; + + + +#endif //GOGOLEV_STRATEGY_SWORDSMEN_HPP diff --git a/8381/Gogolev_Eugene/units/infantry.cpp b/8381/Gogolev_Eugene/units/infantry.cpp new file mode 100644 index 000000000..3b3d0f2e4 --- /dev/null +++ b/8381/Gogolev_Eugene/units/infantry.cpp @@ -0,0 +1,5 @@ +#include "infantry.hpp" + +MovingType Infantry::getMovingType () { + return LEGS; +} diff --git a/8381/Gogolev_Eugene/units/infantry.hpp b/8381/Gogolev_Eugene/units/infantry.hpp new file mode 100644 index 000000000..53f9113a6 --- /dev/null +++ b/8381/Gogolev_Eugene/units/infantry.hpp @@ -0,0 +1,11 @@ +#ifndef GOGOLEV_STRATEGY_INFANTRY_HPP +#define GOGOLEV_STRATEGY_INFANTRY_HPP + +#include "unit.hpp" + +class Infantry : public Unit { +public: + MovingType getMovingType() override; +}; + +#endif //GOGOLEV_STRATEGY_INFANTRY_HPP diff --git a/8381/Gogolev_Eugene/units/neutral.cpp b/8381/Gogolev_Eugene/units/neutral.cpp new file mode 100644 index 000000000..53c50efd6 --- /dev/null +++ b/8381/Gogolev_Eugene/units/neutral.cpp @@ -0,0 +1,11 @@ +#include "neutral.hpp" + +void Neutral::spotted (Unit* other) { + if(team == NEUTRAL && other->getTeam() != NEUTRAL) { + gameHandler->getLogger().log(getType() + " " + to_string(getId()) + " became " + (other->getTeam() == RED ? "RED" : "BLUE")); + team = other->getTeam(); + setTargetXY(other->getTargetX(), other->getTargetY()); + } +} + + diff --git a/8381/Gogolev_Eugene/units/neutral.hpp b/8381/Gogolev_Eugene/units/neutral.hpp new file mode 100644 index 000000000..b6bcf6539 --- /dev/null +++ b/8381/Gogolev_Eugene/units/neutral.hpp @@ -0,0 +1,12 @@ +#ifndef GOGOLEV_STRATEGY_NEUTRAL_HPP +#define GOGOLEV_STRATEGY_NEUTRAL_HPP + +#include "unit.hpp" + +class Neutral : public Unit { +public: + void spotted(Unit* other) override; +}; + + +#endif //GOGOLEV_STRATEGY_NEUTRAL_HPP diff --git a/8381/Gogolev_Eugene/units/neutrals/fair.cpp b/8381/Gogolev_Eugene/units/neutrals/fair.cpp new file mode 100644 index 000000000..241f1f9dc --- /dev/null +++ b/8381/Gogolev_Eugene/units/neutrals/fair.cpp @@ -0,0 +1,37 @@ +#include "fair.hpp" + +static const char sprite[3][3] = {{'|', 'F', '|'}, + {'|', '%', '|'}, + {'|', '_', '|'}}; + +const string Fair::type = "Fair"; + +Fair::Fair () { + hp = Fair::getMaxHP(); + team = NEUTRAL; +} + +int Fair::getMaxHP () { + return 5; +} + +char Fair::getChar (int x, int y) { + validateChar(x, y); + if (x == 1 && y == 1) { + switch (team) { + case RED: + return 'A'; + case BLUE: + return '0'; + default: + return '?'; + } + } + return sprite[y][x]; +} + +const string& Fair::getType () { + return type; +} + + diff --git a/8381/Gogolev_Eugene/units/neutrals/fair.hpp b/8381/Gogolev_Eugene/units/neutrals/fair.hpp new file mode 100644 index 000000000..f337f02d9 --- /dev/null +++ b/8381/Gogolev_Eugene/units/neutrals/fair.hpp @@ -0,0 +1,16 @@ +#ifndef GOGOLEV_STRATEGY_FAIR_HPP +#define GOGOLEV_STRATEGY_FAIR_HPP + +#include "../neutral.hpp" + +class Fair : public Neutral { +public: + static const string type; + Fair(); + int getMaxHP() override; + char getChar (int x, int y) override; + const string& getType() override; +}; + + +#endif //GOGOLEV_STRATEGY_FAIR_HPP diff --git a/8381/Gogolev_Eugene/units/neutrals/farmer.cpp b/8381/Gogolev_Eugene/units/neutrals/farmer.cpp new file mode 100644 index 000000000..3d6b8d019 --- /dev/null +++ b/8381/Gogolev_Eugene/units/neutrals/farmer.cpp @@ -0,0 +1,49 @@ +#include "farmer.hpp" + +static const char sprite[3][3] = {{' ', '@', 'V'}, + {'/', '~', '|'}, + {' ', '^', '|'}}; + +const string Farmer::type = "Farmer"; + +Farmer::Farmer () { + hp = Farmer::getMaxHP(); + team = NEUTRAL; +} + +int Farmer::getMaxHP () { + return 3; +} + +DamageType Farmer::getDamageType () { + return PRICKING; +} + +MovingType Farmer::getMovingType () { + return LEGS; +} + +int Farmer::getDamage () { + return 1; +} + +char Farmer::getChar (int x, int y) { + validateChar(x, y); + if (x == 1 && y == 1) { + switch (team) { + case RED: + return 'A'; + case BLUE: + return '0'; + default: + return '?'; + } + } + return sprite[y][x]; +} + +const string& Farmer::getType () { + return type; +} + + diff --git a/8381/Gogolev_Eugene/units/neutrals/farmer.hpp b/8381/Gogolev_Eugene/units/neutrals/farmer.hpp new file mode 100644 index 000000000..7f42c7130 --- /dev/null +++ b/8381/Gogolev_Eugene/units/neutrals/farmer.hpp @@ -0,0 +1,19 @@ +#ifndef GOGOLEV_STRATEGY_FARMER_HPP +#define GOGOLEV_STRATEGY_FARMER_HPP + +#include "../neutral.hpp" + +class Farmer : public Neutral { +public: + static const string type; + Farmer(); + int getMaxHP() override; + DamageType getDamageType() override; + MovingType getMovingType() override; + int getDamage() override; + char getChar (int x, int y) override; + const string& getType() override; +}; + + +#endif //GOGOLEV_STRATEGY_FARMER_HPP diff --git a/8381/Gogolev_Eugene/units/neutrals/sheep.cpp b/8381/Gogolev_Eugene/units/neutrals/sheep.cpp new file mode 100644 index 000000000..765d9ccbe --- /dev/null +++ b/8381/Gogolev_Eugene/units/neutrals/sheep.cpp @@ -0,0 +1,49 @@ +#include "sheep.hpp" + +static const char sprite[3][3] = {{' ', '@', '>'}, + {'@', 'w', '@'}, + {'/', '@', '\\'}}; + +const string Sheep::type = "Sheep"; + +Sheep::Sheep () { + hp = Sheep::getMaxHP(); + team = NEUTRAL; +} + +int Sheep::getMaxHP () { + return 50; +} + +int Sheep::getDamage () { + return 1; +} + +DamageType Sheep::getDamageType () { + return PRICKING; +} + +MovingType Sheep::getMovingType () { + return HORSE; +} + +char Sheep::getChar (int x, int y) { + validateChar(x, y); + if (x == 1 && y == 1) { + switch (team) { + case RED: + return 'A'; + case BLUE: + return '0'; + default: + return '?'; + } + } + return sprite[y][x]; +} + +const string& Sheep::getType () { + return type; +} + + diff --git a/8381/Gogolev_Eugene/units/neutrals/sheep.hpp b/8381/Gogolev_Eugene/units/neutrals/sheep.hpp new file mode 100644 index 000000000..c27ab0e59 --- /dev/null +++ b/8381/Gogolev_Eugene/units/neutrals/sheep.hpp @@ -0,0 +1,18 @@ +#ifndef GOGOLEV_STRATEGY_SHEEP_HPP +#define GOGOLEV_STRATEGY_SHEEP_HPP + +#include "../neutral.hpp" + +class Sheep : public Neutral { +public: + static const string type; + Sheep(); + int getMaxHP() override; + int getDamage() override; + DamageType getDamageType() override; + MovingType getMovingType() override; + char getChar (int x, int y) override; + const string& getType() override; +}; + +#endif //GOGOLEV_STRATEGY_SHEEP_HPP diff --git a/8381/Gogolev_Eugene/units/neutrals/villager.cpp b/8381/Gogolev_Eugene/units/neutrals/villager.cpp new file mode 100644 index 000000000..80f8bf48a --- /dev/null +++ b/8381/Gogolev_Eugene/units/neutrals/villager.cpp @@ -0,0 +1,43 @@ +#include "villager.hpp" + +static const char sprite[3][3] = {{' ', 'o', ' '}, + {'/', '~', '\\'}, + {' ', '^', ' '}}; + +const string Villager::type = "Villager"; + +Villager::Villager () { + hp = Villager::getMaxHP(); + team = NEUTRAL; +} + +int Villager::getMaxHP () { + return 10; +} + +char Villager::getChar (int x, int y) { + validateChar(x, y); + if (x == 1 && y == 1) { + switch (team) { + case RED: + return 'A'; + case BLUE: + return '0'; + default: + return '?'; + } + } + return sprite[y][x]; +} + +MovingType Villager::getMovingType () { + return HORSE; +} + + +const string& Villager::getType () { + return type; +} + + + diff --git a/8381/Gogolev_Eugene/units/neutrals/villager.hpp b/8381/Gogolev_Eugene/units/neutrals/villager.hpp new file mode 100644 index 000000000..c97a55738 --- /dev/null +++ b/8381/Gogolev_Eugene/units/neutrals/villager.hpp @@ -0,0 +1,16 @@ +#ifndef GOGOLEV_STRATEGY_VILLAGER_HPP +#define GOGOLEV_STRATEGY_VILLAGER_HPP + +#include "../neutral.hpp" + +class Villager : public Neutral { +public: + static const string type; + Villager(); + int getMaxHP() override; + char getChar (int x, int y) override; + MovingType getMovingType() override; + const string& getType() override; +}; + +#endif //GOGOLEV_STRATEGY_VILLAGER_HPP diff --git a/8381/Gogolev_Eugene/units/shooter.cpp b/8381/Gogolev_Eugene/units/shooter.cpp new file mode 100644 index 000000000..d1e061d49 --- /dev/null +++ b/8381/Gogolev_Eugene/units/shooter.cpp @@ -0,0 +1,11 @@ +#include "shooter.hpp" + +MovingType Shooter::getMovingType () { + return LEGS; +} + +DamageType Shooter::getDamageType () { + return ARROW; +} + + diff --git a/8381/Gogolev_Eugene/units/shooter.hpp b/8381/Gogolev_Eugene/units/shooter.hpp new file mode 100644 index 000000000..11007d6c3 --- /dev/null +++ b/8381/Gogolev_Eugene/units/shooter.hpp @@ -0,0 +1,15 @@ +#ifndef GOGOLEV_STRATEGY_SHOOTER_HPP +#define GOGOLEV_STRATEGY_SHOOTER_HPP + +#include "unit.hpp" + +class Shooter : public Unit { +public: + MovingType getMovingType() override; + DamageType getDamageType() override; + + //TODO перезарядка +}; + + +#endif //GOGOLEV_STRATEGY_SHOOTER_HPP diff --git a/8381/Gogolev_Eugene/units/shooters/archers.cpp b/8381/Gogolev_Eugene/units/shooters/archers.cpp new file mode 100644 index 000000000..3cb9b145f --- /dev/null +++ b/8381/Gogolev_Eugene/units/shooters/archers.cpp @@ -0,0 +1,48 @@ +#include "archers.hpp" + +static const char sprite[3][3] = {{' ', '@', ' '}, + {'/', '|', '>'}, + {' ', '^', ' '}}; + +const string Archers::type = "Archers"; + +Archers::Archers () { + hp = Archers::getMaxHP(); +} + +int Archers::getMaxHP () { + return 4; +} + +int Archers::getDamage () { + return 1; +} + +int Archers::attackDistance () { + return 3; +} + +int Archers::visionDistance () { + return 4; +} + +char Archers::getChar (int x, int y) { + validateChar(x, y); + if (x == 1 && y == 1) { + switch (team) { + case RED: + return 'A'; + case BLUE: + return '0'; + default: + return '?'; + } + } + return sprite[y][x]; +} + +const string& Archers::getType () { + return type; +} + + diff --git a/8381/Gogolev_Eugene/units/shooters/archers.hpp b/8381/Gogolev_Eugene/units/shooters/archers.hpp new file mode 100644 index 000000000..505bac798 --- /dev/null +++ b/8381/Gogolev_Eugene/units/shooters/archers.hpp @@ -0,0 +1,19 @@ +#ifndef GOGOLEV_STRATEGY_ARCHERS_HPP +#define GOGOLEV_STRATEGY_ARCHERS_HPP + +#include "../shooter.hpp" + +class Archers : public Shooter { +public: + static const string type; + Archers(); + int getMaxHP() override; + int getDamage() override; + int attackDistance() override; + int visionDistance() override; + char getChar(int x, int y) override; + const string& getType() override; +}; + + +#endif //GOGOLEV_STRATEGY_ARCHERS_HPP diff --git a/8381/Gogolev_Eugene/units/shooters/crossbowman.cpp b/8381/Gogolev_Eugene/units/shooters/crossbowman.cpp new file mode 100644 index 000000000..fbe017b59 --- /dev/null +++ b/8381/Gogolev_Eugene/units/shooters/crossbowman.cpp @@ -0,0 +1,48 @@ +#include "crossbowman.hpp" + +static const char sprite[3][3] = {{' ', 'o', ' '}, + {'(', '|', '\\'}, + {' ', '^', ' '}}; + +const string Crossbowman::type = "Crossbowman"; + +Crossbowman::Crossbowman () { + hp = Crossbowman::getMaxHP(); +} + +int Crossbowman::getMaxHP () { + return 5; +} + +int Crossbowman::getDamage () { + return 4; +} + +int Crossbowman::attackDistance () { + return 4; +} + +int Crossbowman::visionDistance () { + return 4; +} + +char Crossbowman::getChar (int x, int y) { + validateChar(x, y); + if (x == 1 && y == 1) { + switch (team) { + case RED: + return 'A'; + case BLUE: + return '0'; + default: + return '?'; + } + } + return sprite[y][x]; +} + +const string& Crossbowman::getType () { + return type; +} + + diff --git a/8381/Gogolev_Eugene/units/shooters/crossbowman.hpp b/8381/Gogolev_Eugene/units/shooters/crossbowman.hpp new file mode 100644 index 000000000..679657a85 --- /dev/null +++ b/8381/Gogolev_Eugene/units/shooters/crossbowman.hpp @@ -0,0 +1,20 @@ +#ifndef GOGOLEV_STRATEGY_CROSSBOWMAN_HPP +#define GOGOLEV_STRATEGY_CROSSBOWMAN_HPP + +#include "../shooter.hpp" + +class Crossbowman : public Shooter { +public: + static const string type; + Crossbowman(); + int getMaxHP() override; + int getDamage() override; + int attackDistance() override; + int visionDistance() override; + char getChar(int x, int y) override; + const string& getType() override; +}; + + + +#endif //GOGOLEV_STRATEGY_CROSSBOWMAN_HPP diff --git a/8381/Gogolev_Eugene/units/unit.cpp b/8381/Gogolev_Eugene/units/unit.cpp new file mode 100644 index 000000000..3cb227a9a --- /dev/null +++ b/8381/Gogolev_Eugene/units/unit.cpp @@ -0,0 +1,241 @@ +#include "unit.hpp" +#include "../tiles/tile.hpp" +#include "../tiles/fortress.hpp" +#include "../exceptions/out_of_bounds_exception.hpp" +#include "../exceptions/saving_exception.hpp" +#include "../exceptions/loading_exception.hpp" + +static const char sprite[3][3] = {{' ', ' ', ' '}, + {' ', '@', ' '}, + {' ', ' ', ' '}}; + +Unit::Unit () { + hp = Unit::getMaxHP(); +} + +Unit::~Unit () { + +} + +bool Unit::isDead () const { + return hp <= 0; +} + +void Unit::validateChar (int x, int y) { + if (x < 0 || y < 0 || x > 2 || y > 2) throw outOfBoundsException("Unit sprite output error"); +} + +char Unit::getChar (int x, int y) { + validateChar(x, y); + return sprite[y][x]; +} + +MovingType Unit::getMovingType () { + return IMMOBILE; +} + +void Unit::setTeam (Team team) { + this->team = team; +} + +Team Unit::getTeam () { + return team; +} + +int Unit::getId () const { + return id; +} + +int Unit::getX () const { + return x; +} + +int Unit::getY () const { + return y; +} + +void Unit::setXY (int x, int y) { + this->x = x; + this->y = y; +} + +int Unit::sqrDistanceTo (int x, int y) const { + int dx = this->x - x; + int dy = this->y - y; + return dx * dx + dy * dy; +} + +int Unit::getTargetX () const { + return targetX; +} + +int Unit::getTargetY () const { + return targetY; +} + +void Unit::setTargetXY (int x, int y) { + int sx = gameHandler->getSizeX(); + int sy = gameHandler->getSizeY(); + targetX = (x + sx) % sx; + targetY = (y + sy) % sy; +} + +void Unit::onGameFieldEnter (const int id, Unit::GameHandler* game) { + this->id = id; + this->gameHandler = game; +} + +void Unit::update () { + Unit* targetUnit = gameHandler->findUnit(targetUnitId); + if (targetUnit != nullptr) { + if (targetUnit->isDead() || pow(visionDistance(), 2) < targetUnit->sqrDistanceTo(x, y) || !isAttackable(targetUnit)) { + targetUnitId = -1; + targetUnit = nullptr; + } + } + else { + targetUnitId = -1; + } + + if (targetUnit == nullptr && getDamageType() != NONE) { + auto unitList = gameHandler->findUnits(x, y, visionDistance()); + for (auto other : *unitList) { + other->spotted(this); + if (other->getTeam() != team) { + if (targetUnit == nullptr || targetUnit->sqrDistanceTo(x, y) < other->sqrDistanceTo(x, y)) { + if (isAttackable(other)) { + targetUnit = other; + targetUnitId = other->getId(); + } + } + } + } + } + + if (targetUnit == nullptr) { + walkTo(targetX, targetY); + } + else if (targetUnit->sqrDistanceTo(x, y) > attackDistance()) { + walkTo(targetUnit->getX(), targetUnit->getY()); + } + else { + dealDamage(targetUnit); + } +} + +void Unit::spotted (Unit* other) { + +} + +int Unit::getMaxHP () { + return 1; +} + +int Unit::attackDistance () { + return 1; +} + +int Unit::visionDistance () { + return 2; +} + +int Unit::getSpeed () { + return 1; +} + +DamageType Unit::getDamageType () { + return NONE; +} + +int Unit::getDamage () { + return 0; +} + +void Unit::takeDamage (DamageType damageType, int value) { + if (getMovingType() == HORSE && damageType == PRICKING) { + value *= 2; + } + hp -= min(value, hp); +} + +bool Unit::isAttackable (Unit* other) { + if (getDamageType() == ARROW) { + Tile* thisTile = gameHandler->getTile(x, y); + Tile* targetTile = gameHandler->getTile(other->getX(), other->getY()); + return thisTile == targetTile || targetTile->getId() != Fortress::id; + } + return true; +} + +void Unit::dealDamage (Unit* other) { + gameHandler->getLogger().log(getType() + " " + to_string(getId()) + " --> " + other->getType() + " " + to_string(other->getId())); + other->takeDamage(getDamageType(), getDamage()); +} + +bool Unit::moveTo (int x, int y) { + if (getMovingType() != IMMOBILE && gameHandler->onField(x, y)) { + Tile* thisTile = gameHandler->getTile(this->x, this->y); + Tile* targetTile = gameHandler->getTile(x, y); + + if (thisTile == targetTile || targetTile->allow(getMovingType())) { + this->x = x; + this->y = y; + return true; + } + } + return false; +} + +bool Unit::stepTo (int x, int y) { + int dx = x - this->x; + int dy = y - this->y; + if (abs(dx) > abs(dy)) { + return moveTo(this->x + (dx > 0 ? 1 : -1), this->y); + } + else { + return moveTo(this->x, this->y + (dy > 0 ? 1 : -1)); + } +} + +bool Unit::walkTo (int x, int y) { + for (int i = 0; i < getSpeed(); i++) { + if (!stepTo(x, y)) { + return false; + } + else if (this->x == x && this->y == y) { + return true; + } + } + return true; +} + +void Unit::save (ostream& os) { + os << team << ' '; + os << x << ' ' << y << ' '; + os << targetX << ' ' << targetY << ' '; + os << targetUnitId << ' '; + os << hp << endl; +} + +void Unit::load (istream& is) { + int t; + if (!(is >> t)) throw loadingException("team incorrect"); + team = static_cast(t); + if (!(is >> x >> y)) throw loadingException("x or y incorrect"); + if (!(is >> targetX >> targetY)) throw loadingException("targetx or targety incorrect"); + if (!(is >> targetUnitId)) throw loadingException("targetUnitId incorrect"); + if (!(is >> hp)) throw loadingException("hp incorrect"); +} + +void Unit::operator*(Unit *other) { + dealDamage(other); +} + +void Unit::operator<(Unit *other) { + spotted(other); +} + + + + + diff --git a/8381/Gogolev_Eugene/units/unit.hpp b/8381/Gogolev_Eugene/units/unit.hpp new file mode 100644 index 000000000..0b51b72ca --- /dev/null +++ b/8381/Gogolev_Eugene/units/unit.hpp @@ -0,0 +1,90 @@ +#ifndef GOGOLEV_STRATEGY_UNIT_HPP +#define GOGOLEV_STRATEGY_UNIT_HPP + +#include "../stl.hpp" +#include "../enums.hpp" +#include "../loggers/logger.hpp" + +class Tile; + +class Unit { +public: + class GameHandler { + public: + virtual bool onField(int x, int y) = 0; + virtual Tile* getTile(int x, int y) = 0; + virtual Unit* createUnit(string key) = 0; + virtual const vector * findUnits(int x, int y, int radius) = 0; + virtual Unit* findUnit(int id) = 0; + virtual int getSizeX () const = 0; + virtual int getSizeY () const = 0; + virtual Logger& getLogger () = 0; + }; + +public: + Unit(); + virtual ~Unit(); + + bool isDead() const; + void validateChar(int x, int y); + virtual char getChar(int x, int y); + virtual MovingType getMovingType(); + + void setTeam(Team team); + Team getTeam(); + + int getId() const; + int getX() const; + int getY() const; + virtual void setXY(int x, int y); + + int sqrDistanceTo(int x, int y) const; + + int getTargetX() const; + int getTargetY() const; + void setTargetXY(int x, int y); + + virtual void onGameFieldEnter(int id, GameHandler *game); + virtual void update(); + virtual void spotted(Unit* other); + void operator<(Unit* other); + + virtual const string& getType() = 0; + + virtual void save(ostream &os); + virtual void load(istream &is); + +protected: + // Non serializable + GameHandler *gameHandler; + int id = -1; + // Serializable + Team team; + int x; + int y; + int targetX; + int targetY; + int targetUnitId = -1; + int hp; + + virtual int getMaxHP(); + virtual int attackDistance(); + virtual int visionDistance(); + virtual int getSpeed(); + virtual DamageType getDamageType(); + virtual int getDamage(); + virtual void takeDamage(DamageType damageType, int value); + + bool isAttackable(Unit *other); + void dealDamage(Unit *other); + void operator*(Unit* other); + +private: + bool moveTo(int x, int y); + bool stepTo(int x, int y); + bool walkTo(int x, int y); +}; + + + +#endif //GOGOLEV_STRATEGY_UNIT_HPP