diff --git a/polevshikov.vladislav/T3/commands.cpp b/polevshikov.vladislav/T3/commands.cpp new file mode 100644 index 00000000..5250a6c0 --- /dev/null +++ b/polevshikov.vladislav/T3/commands.cpp @@ -0,0 +1,185 @@ +#include "commands.h" +#include +#include +#include +#include + +bool checkAndConsumeRestOfLine(std::istream& in) { + while (in.peek() == ' ' || in.peek() == '\t') { + in.get(); + } + char next = in.peek(); + if (next == '\n' || next == EOF) { + if (next == '\n') { + in.get(); + } + return true; + } + return false; +} + +void doArea(const std::vector& polygons, std::istream& in, std::ostream& out) { + std::string subCmd; + if (!(in >> subCmd) || !checkAndConsumeRestOfLine(in)) { + throw std::invalid_argument("extra symbols"); + } + + double res = 0.0; + if (subCmd == "EVEN") { + std::vector filtered; + + std::copy_if(polygons.begin(), polygons.end(), std::back_inserter(filtered), isEven); + res = std::accumulate(filtered.begin(), filtered.end(), 0.0, sumArea); + + } else if (subCmd == "ODD") { + std::vector filtered; + + std::copy_if(polygons.begin(), polygons.end(), std::back_inserter(filtered), isOdd); + res = std::accumulate(filtered.begin(), filtered.end(), 0.0, sumArea); + + } else if (subCmd == "MEAN") { + if (polygons.empty()) { + throw std::logic_error("Empty collection"); + } + + res = std::accumulate(polygons.begin(), polygons.end(), 0.0, sumArea) / polygons.size(); + + } else { + try { + size_t pos = 0; + long long val = std::stoll(subCmd, &pos); + if (pos != subCmd.size() || val < 3) { + printError(out); + return; + } + + size_t num = static_cast(val); + std::vector filtered; + std::copy_if(polygons.begin(), polygons.end(), std::back_inserter(filtered), HasNVertices{num}); + res = std::accumulate(filtered.begin(), filtered.end(), 0.0, sumArea); + + } catch (const std::exception&) { + printError(out); + return; + } + } + out << std::fixed << std::setprecision(1) << res << '\n'; +} + +void doMax(const std::vector& polygons, std::istream& in, std::ostream& out) { + if (polygons.empty()) { + throw std::logic_error("Empty collection"); + } + + std::string subCmd; + if (!(in >> subCmd) || !checkAndConsumeRestOfLine(in)) { + throw std::invalid_argument("extra symbols"); + } + + if (subCmd == "AREA") { + auto it = std::max_element(polygons.begin(), polygons.end(), compareByArea); + out << std::fixed << std::setprecision(1) << getArea(*it) << '\n'; + + } else if (subCmd == "VERTEXES") { + auto it = std::max_element(polygons.begin(), polygons.end(), compareBySize); + out << it->points.size() << "\n"; + + } else { + throw std::invalid_argument("bad subcommand"); + } +} + +void doMin(const std::vector& polygons, std::istream& in, std::ostream& out) { + if (polygons.empty()) { + throw std::logic_error("Empty collection"); + } + + std::string subCmd; + if (!(in >> subCmd) || !checkAndConsumeRestOfLine(in)) { + throw std::invalid_argument("extra symbols"); + } + + if (subCmd == "AREA") { + auto it = std::min_element(polygons.begin(), polygons.end(), compareByArea); + out << std::fixed << std::setprecision(1) << getArea(*it) << '\n'; + + } else if (subCmd == "VERTEXES") { + auto it = std::min_element(polygons.begin(), polygons.end(), compareBySize); + out << it->points.size() << "\n"; + + } else { + throw std::invalid_argument("bad subcommand"); + } +} + +void doCount(const std::vector& polygons, std::istream& in, std::ostream& out) { + std::string subCmd; + if (!(in >> subCmd) || !checkAndConsumeRestOfLine(in)) { + throw std::invalid_argument("extra symbols"); + } + + size_t cnt = 0; + + if (subCmd == "EVEN") { + cnt = std::count_if(polygons.begin(), polygons.end(), isEven); + + } else if (subCmd == "ODD") { + cnt = std::count_if(polygons.begin(), polygons.end(), isOdd); + + } else { + try { + size_t pos = 0; + long long val = std::stoll(subCmd, &pos); + if (pos != subCmd.size() || val < 3) { + printError(out); + return; + } + + size_t num = static_cast(val); + cnt = std::count_if(polygons.begin(), polygons.end(), HasNVertices{num}); + + } catch (std::exception&) { + printError(out); + return; + } + } + out << cnt << '\n'; +} + +void printError(std::ostream& out) { + out << "\n"; +} + +void doRightShapes(const std::vector& polygons, std::istream& in, std::ostream& out) { + if (!checkAndConsumeRestOfLine(in)) { + printError(out); + return; + } + + long long count = std::count_if(polygons.begin(), polygons.end(), hasRightAngle); + out << count << '\n'; +} + +void doInFrame(const std::vector& polygons, std::istream& in, std::ostream& out) { + Polygon target; + if (!(in >> target) || !checkAndConsumeRestOfLine(in)) { + in.clear(); + in.ignore(std::numeric_limits::max(), '\n'); + printError(out); + return; + } + + if (polygons.empty()) { + throw std::logic_error("Empty collection"); + } + + int minX = std::accumulate(polygons.begin(), polygons.end(), std::numeric_limits::max(), getMinX); + int maxX = std::accumulate(polygons.begin(), polygons.end(), std::numeric_limits::min(), getMaxX); + int minY = std::accumulate(polygons.begin(), polygons.end(), std::numeric_limits::max(), getMinY); + int maxY = std::accumulate(polygons.begin(), polygons.end(), std::numeric_limits::min(), getMaxY); + + bool inInside = std::all_of(target.points.begin(), target.points.end(), [minX, maxX, minY, maxY](const Point& p) { + return p.x >= minX && p.x <= maxX && p.y >= minY && p.y <= maxY; + }); + out << (inInside ? "" : "") << '\n'; +} diff --git a/polevshikov.vladislav/T3/commands.h b/polevshikov.vladislav/T3/commands.h new file mode 100644 index 00000000..da330a7f --- /dev/null +++ b/polevshikov.vladislav/T3/commands.h @@ -0,0 +1,18 @@ +#ifndef COMMANDS_H +#define COMMANDS_H + +#include +#include +#include +#include "polygon.h" + +void doArea(const std::vector& polygons, std::istream& in, std::ostream& out); +void doMax(const std::vector& polygons, std::istream& in, std::ostream& out); +void doMin(const std::vector& polygons, std::istream& in, std::ostream& out); +void doCount(const std::vector& polygons, std::istream& in, std::ostream& out); +void doInFrame(const std::vector& polygons, std::istream& in, std::ostream& out); +void doRightShapes(const std::vector& polygons, std::istream& in, std::ostream& out); + +void printError(std::ostream& out); + +#endif diff --git a/polevshikov.vladislav/T3/main.cpp b/polevshikov.vladislav/T3/main.cpp new file mode 100644 index 00000000..da7f3c73 --- /dev/null +++ b/polevshikov.vladislav/T3/main.cpp @@ -0,0 +1,63 @@ +#include +#include +#include +#include +#include +#include +#include +#include "polygon.h" +#include "commands.h" + +using namespace std::placeholders; + +int main(int argc, char* argv[]) { + if (argc != 2) { + std::cerr << "Usage: " << argv[0] << " \n"; + return 1; + } + + std::ifstream file(argv[1]); + if (!file.is_open()) { + std::cerr << "Cannot open file: " << argv[1] << '\n'; + return 1; + } + + std::vector polygons; + + while (file) { + Polygon p; + if (file >> p) { + polygons.push_back(p); + } else if (!file.eof()) { + file.clear(); + file.ignore(std::numeric_limits::max(), '\n'); + } + } + + std::map> cmds; + + cmds["AREA"] = std::bind(doArea, std::cref(polygons), _1, _2); + cmds["MAX"] = std::bind(doMax, std::cref(polygons), _1, _2); + cmds["MIN"] = std::bind(doMin, std::cref(polygons), _1, _2); + cmds["COUNT"] = std::bind(doCount, std::cref(polygons), _1, _2); + cmds["RIGHTSHAPES"] = std::bind(doRightShapes, std::cref(polygons), _1, _2); + cmds["INFRAME"] = std::bind(doInFrame, std::cref(polygons), _1, _2); + + std::string cmd; + while(std::cin >> cmd) { + try { + if (cmds.count(cmd)) { + cmds[cmd](std::cin, std::cout); + } else { + printError(std::cout); + std::cin.ignore(std::numeric_limits::max(), '\n'); + } + + } catch (...) { + printError(std::cout); + std::cin.clear(); + std::cin.ignore(std::numeric_limits::max(), '\n'); + } + } + return 0; +} diff --git a/polevshikov.vladislav/T3/polygon.cpp b/polevshikov.vladislav/T3/polygon.cpp new file mode 100644 index 00000000..0b24c62c --- /dev/null +++ b/polevshikov.vladislav/T3/polygon.cpp @@ -0,0 +1,132 @@ +#include "polygon.h" +#include +#include +#include +#include +#include +#include +#include + +struct DelimiterI0 { + char expected; +}; + +std::istream& operator>>(std::istream& in, DelimiterI0&& dest) { + std::istream::sentry sentry(in); + if (!sentry) { + return in; + } + + char c = ' '; + in >> c; + + if (in && (c != dest.expected)) { + in.setstate(std::ios::failbit); + } + + return in; +} + +std::istream& operator>>(std::istream& in, Point& dest) { + std::istream::sentry sentry(in); + if (!sentry) { + return in; + } + return in >> DelimiterI0{'('} >> dest.x >> DelimiterI0{';'} >> dest.y >> DelimiterI0{')'}; +} + +std::istream& operator>>(std::istream& in, Polygon& dest) { + std::istream::sentry sentry(in); + if (!sentry) { + return in; + } + + size_t cnt = 0; + if (!(in >> cnt) || cnt < 3) { + in.setstate(std::ios::failbit); + return in; + } + + std::vector tmp_points(cnt); + std::copy_n(std::istream_iterator(in), cnt, tmp_points.begin()); + if (!in) return in; + dest.points = std::move(tmp_points); + return in; +} + +struct CrossProductAccum { + const Polygon& poly; + double operator()(double sum, size_t i) const { + const Point& a = poly.points[i]; + const Point& b = poly.points[(i + 1) % poly.points.size()]; + return sum + (static_cast(a.x) * b.y - static_cast(a.y) * b.x); + } +}; + +double getArea(const Polygon& poly) { + size_t n = poly.points.size(); + std::vector idx(n); + std::iota(idx.begin(), idx.end(), 0); + double area = std::accumulate(idx.begin(), idx.end(), 0.0, CrossProductAccum{poly}); + return std::abs(area) / 2.0; +} + +struct rightAngle { + const Polygon& poly; + bool operator()(size_t i) const { + size_t n = poly.points.size(); + const Point& a = poly.points[i]; + const Point& b = poly.points[(i + 1) % n]; + const Point& c = poly.points[(i + 2) % n]; + long long v1x = b.x - a.x, v1y = b.y - a.y; + long long v2x = c.x - b.x, v2y = c.y - b.y; + return (v1x * v2x + v1y * v2y) == 0; + } +}; + +bool hasRightAngle(const Polygon& poly) { + size_t n = poly.points.size(); + std::vector idx(n); + std::iota(idx.begin(), idx.end(), 0); + return std::any_of(idx.begin(), idx.end(), rightAngle{poly}); +} + +bool isEven(const Polygon& p) { + return p.points.size() % 2 == 0; +} + +bool isOdd(const Polygon& p) { + return p.points.size() % 2 != 0; +} + +bool compareByArea(const Polygon& a, const Polygon& b) { + return getArea(a) < getArea(b); +} + +bool compareBySize(const Polygon& a, const Polygon& b) { + return a.points.size() < b.points.size(); +} + +double sumArea(double sum, const Polygon& p) { + return sum + getArea(p); +} + +bool cmpByX(const Point& a, const Point& b) { + return a.x < b.x; +} +bool cmpByY(const Point& a, const Point& b) { + return a.y < b.y; +} + +int getMinX(int cur, const Polygon& p) { + return std::min(cur, std::min_element(p.points.begin(), p.points.end(), cmpByX)->x); +} +int getMaxX(int cur, const Polygon& p) { + return std::max(cur, std::max_element(p.points.begin(), p.points.end(), cmpByX)->x); +} +int getMinY(int cur, const Polygon& p) { + return std::min(cur, std::min_element(p.points.begin(), p.points.end(), cmpByY)->y); +} +int getMaxY(int cur, const Polygon& p) { + return std::max(cur, std::max_element(p.points.begin(), p.points.end(), cmpByY)->y); +} diff --git a/polevshikov.vladislav/T3/polygon.h b/polevshikov.vladislav/T3/polygon.h new file mode 100644 index 00000000..81d48541 --- /dev/null +++ b/polevshikov.vladislav/T3/polygon.h @@ -0,0 +1,39 @@ +#ifndef POLYGON_H +#define POLYGON_H + +#include +#include + +struct Point { + int x, y; +}; + +struct Polygon { + std::vector points; +}; + +struct HasNVertices { + size_t n; + bool operator()(const Polygon& p) const { return p.points.size() == n; } +}; + +std::istream& operator>>(std::istream& in, Polygon& dest); + +double getArea(const Polygon& poly); +bool hasRightAngle(const Polygon& poly); + +bool compareByArea(const Polygon& a, const Polygon& b); +bool compareBySize(const Polygon& a, const Polygon& b); +bool isEven(const Polygon& p); +bool isOdd(const Polygon& p); +double sumArea(double sum, const Polygon& p); + +bool cmpByX(const Point& a, const Point& b); +bool cmpByY(const Point& a, const Point& b); + +int getMinX(int cur, const Polygon& p); +int getMaxX(int cur, const Polygon& p); +int getMinY(int cur, const Polygon& p); +int getMaxY(int cur, const Polygon& p); + +#endif