diff --git a/polykov.fedor/T3/main.cpp b/polykov.fedor/T3/main.cpp new file mode 100644 index 00000000..f3df5eb3 --- /dev/null +++ b/polykov.fedor/T3/main.cpp @@ -0,0 +1,238 @@ +#include "polygon_commands.h" +#include +#include +#include +#include +#include + +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) + { + std::cerr << "Error: cannot open file " << argv[1] << '\n'; + return 1; + } + + std::vector polygons; + std::string line; + while (std::getline(file, line)) + { + std::istringstream iss(line); + Polygon temp; + if (iss >> temp) + { + iss >> std::ws; + if (iss.eof()) + { + polygons.push_back(std::move(temp)); + } + } + } + + while (std::getline(std::cin, line)) + { + if (line.empty()) + continue; + + std::istringstream iss(line); + std::string command; + if (!(iss >> command)) + continue; + + try + { + if (command == "AREA") + { + std::string arg; + if (!(iss >> arg)) + throw std::invalid_argument(""); + + std::string extra; + if (iss >> extra) + throw std::invalid_argument(""); + + std::cout << std::fixed << std::setprecision(1); + + if (arg == "EVEN") + { + double sum = std::accumulate(polygons.begin(), polygons.end(), + 0.0, SumAreaIfEven()); + std::cout << sum << '\n'; + } + else if (arg == "ODD") + { + double sum = std::accumulate(polygons.begin(), polygons.end(), + 0.0, SumAreaIfOdd()); + std::cout << sum << '\n'; + } + else if (arg == "MEAN") + { + if (polygons.empty()) + throw std::invalid_argument(""); + double sum = std::accumulate(polygons.begin(), polygons.end(), + 0.0, SumArea()); + std::cout << sum / polygons.size() << '\n'; + } + else + { + std::size_t pos = 0; + std::size_t n = std::stoull(arg, &pos); + if (pos != arg.size()) + throw std::invalid_argument(""); + double sum = std::accumulate(polygons.begin(), polygons.end(), + 0.0, SumAreaByVertexes(n)); + std::cout << sum << '\n'; + } + } + else if (command == "MAX") + { + if (polygons.empty()) + throw std::invalid_argument(""); + + std::string arg; + if (!(iss >> arg)) + throw std::invalid_argument(""); + + std::string extra; + if (iss >> extra) + throw std::invalid_argument(""); + + if (arg == "AREA") + { + auto it = std::max_element(polygons.begin(), polygons.end(), + CompareByArea()); + std::cout << std::fixed << std::setprecision(1) + << getArea(*it) << '\n'; + } + else if (arg == "VERTEXES") + { + auto comp = std::bind(std::less(), + std::bind(&std::vector::size, + std::bind(&Polygon::points, _1)), + std::bind(&std::vector::size, + std::bind(&Polygon::points, _2))); + auto it = std::max_element(polygons.begin(), polygons.end(), comp); + std::cout << std::defaultfloat; + std::cout << it->points.size() << '\n'; + } + else + { + throw std::invalid_argument(""); + } + } + else if (command == "MIN") + { + if (polygons.empty()) + throw std::invalid_argument(""); + + std::string arg; + if (!(iss >> arg)) + throw std::invalid_argument(""); + + std::string extra; + if (iss >> extra) + throw std::invalid_argument(""); + + if (arg == "AREA") + { + auto it = std::min_element(polygons.begin(), polygons.end(), + CompareByArea()); + std::cout << std::fixed << std::setprecision(1) + << getArea(*it) << '\n'; + } + else if (arg == "VERTEXES") + { + auto comp = std::bind(std::less(), + std::bind(&std::vector::size, + std::bind(&Polygon::points, _1)), + std::bind(&std::vector::size, + std::bind(&Polygon::points, _2))); + auto it = std::min_element(polygons.begin(), polygons.end(), comp); + std::cout << std::defaultfloat; + std::cout << it->points.size() << '\n'; + } + else + { + throw std::invalid_argument(""); + } + } + else if (command == "COUNT") + { + std::string arg; + if (!(iss >> arg)) + throw std::invalid_argument(""); + + std::string extra; + if (iss >> extra) + throw std::invalid_argument(""); + + if (arg == "EVEN" || arg == "ODD") + { + int count = std::count_if(polygons.begin(), polygons.end(), + CountIfEvenOrOdd(arg)); + std::cout << std::defaultfloat; + std::cout << count << '\n'; + } + else + { + std::size_t pos = 0; + std::size_t n = std::stoull(arg, &pos); + if (pos != arg.size()) + throw std::invalid_argument(""); + auto pred = std::bind(std::equal_to(), + std::bind(&std::vector::size, + std::bind(&Polygon::points, _1)), + n); + int count = std::count_if(polygons.begin(), polygons.end(), pred); + std::cout << std::defaultfloat; + std::cout << count << '\n'; + } + } + else if (command == "PERMS") + { + Polygon sample; + if (!(iss >> sample)) + throw std::invalid_argument(""); + + std::string extra; + if (iss >> extra) + throw std::invalid_argument(""); + + int count = std::count_if(polygons.begin(), polygons.end(), + IsPermutationOf(sample)); + std::cout << std::defaultfloat; + std::cout << count << '\n'; + } + else if (command == "RIGHTSHAPES") + { + std::string extra; + if (iss >> extra) + throw std::invalid_argument(""); + + int count = std::count_if(polygons.begin(), polygons.end(), + HasRightAngle()); + std::cout << std::defaultfloat; + std::cout << count << '\n'; + } + else + { + throw std::invalid_argument(""); + } + } + catch (...) + { + std::cout << "\n"; + } + } + + return 0; +} \ No newline at end of file diff --git a/polykov.fedor/T3/polygon_commands.h b/polykov.fedor/T3/polygon_commands.h new file mode 100644 index 00000000..4e02abbf --- /dev/null +++ b/polykov.fedor/T3/polygon_commands.h @@ -0,0 +1,268 @@ +#ifndef POLYGON_COMMANDS_H +#define POLYGON_COMMANDS_H + +#include +#include +#include +#include +#include + +struct Point +{ + int x, y; +}; + +struct Polygon +{ + std::vector points; +}; + +std::istream& operator>>(std::istream& in, Point& p) +{ + int x = 0, y = 0; + char open, semicolon, close; + + if (in >> open >> x >> semicolon >> y >> close) + { + if (open == '(' && semicolon == ';' && close == ')') + { + p.x = x; + p.y = y; + } + else + { + in.setstate(std::ios::failbit); + } + } + return in; +} + +std::istream& operator>>(std::istream& in, Polygon& pol) +{ + size_t size = 0; + if (!(in >> size) || size < 3) + { + in.setstate(std::ios::failbit); + return in; + } + + std::vector temp; + temp.reserve(size); + + Point p; + for (std::size_t i = 0; i < size; ++i) + { + if (in >> p) + { + temp.push_back(p); + } + else + { + in.setstate(std::ios::failbit); + return in; + } + } + + pol.points = std::move(temp); + return in; +} + +bool operator==(const Point& a, const Point& b) +{ + return a.x == b.x && a.y == b.y; +} + +bool operator==(const Polygon& a, const Polygon& b) +{ + return a.points == b.points; +} + +struct AreaCalculator +{ + const std::vector& pts; + size_t size; + mutable size_t idx; + + explicit AreaCalculator(const std::vector& pts) + : pts(pts), size(pts.size()), idx(0) + { + } + + long long operator()(long long acc, const Point& curr) const + { + const Point& next = pts[(idx + 1) % size]; + long long term = static_cast(curr.x) * next.y + - static_cast(next.x) * curr.y; + ++idx; + return acc + term; + } +}; + +double getArea(const Polygon& p) +{ + if (p.points.size() < 3) + return 0.0; + + long long sum = std::accumulate(p.points.begin(), p.points.end(), + 0LL, AreaCalculator(p.points)); + return std::abs(sum) / 2.0; +} + +struct CountIfEvenOrOdd +{ + std::string arg; + + explicit CountIfEvenOrOdd(const std::string& s) + : arg(s) + { + } + + bool operator()(const Polygon& p) const + { + if (arg == "EVEN") + { + return p.points.size() % 2 == 0; + } + return p.points.size() % 2 != 0; + } +}; + +struct SumArea +{ + double operator()(double acc, const Polygon& p) const + { + return acc + getArea(p); + } +}; + +struct SumAreaIfEven +{ + double operator()(double acc, const Polygon& p) const + { + if (p.points.size() % 2 == 0) + { + return acc + getArea(p); + } + else + { + return acc; + } + } +}; + +struct SumAreaIfOdd +{ + double operator()(double acc, const Polygon& p) const + { + if (p.points.size() % 2 != 0) + { + return acc + getArea(p); + } + else + { + return acc; + } + } +}; + +struct SumAreaByVertexes +{ + size_t verx; + + explicit SumAreaByVertexes(size_t n) + : verx(n) + { + } + + double operator()(double acc, const Polygon& p) const + { + if (p.points.size() == verx) + { + return acc + getArea(p); + } + else + { + return acc; + } + } +}; + +struct CompareByArea +{ + bool operator()(const Polygon& a, const Polygon& b) const + { + return getArea(a) < getArea(b); + } +}; + +struct HasRightAngle +{ + bool operator()(const Polygon& p) const + { + size_t n = p.points.size(); + if (n < 3) + return false; + + std::vector indices(n); + std::iota(indices.begin(), indices.end(), 0); + + return std::any_of(indices.begin(), indices.end(), + [&p, n](size_t i) + { + const Point& A = p.points[i]; + const Point& B = p.points[(i + 1) % n]; + const Point& C = p.points[(i + 2) % n]; + + long long ABx = static_cast(B.x) - A.x; + long long ABy = static_cast(B.y) - A.y; + long long BCx = static_cast(C.x) - B.x; + long long BCy = static_cast(C.y) - B.y; + + return ABx * BCx + ABy * BCy == 0; + }); + } +}; + +inline void normalizePoint(Point& p) +{ + if (p.x > p.y) + { + std::swap(p.x, p.y); + } +} + +struct ComparePoints +{ + bool operator()(const Point& a, const Point& b) const + { + if (a.x == b.x) + { + return a.y < b.y; + } + return a.x < b.x; + } +}; + +struct IsPermutationOf +{ + Polygon target; + + explicit IsPermutationOf(const Polygon& sample) + : target(sample) + { + for (auto& pt : target.points) + normalizePoint(pt); + std::sort(target.points.begin(), target.points.end(), ComparePoints()); + } + + bool operator()(const Polygon& p) const + { + Polygon copy = p; + for (auto& pt : copy.points) + normalizePoint(pt); + std::sort(copy.points.begin(), copy.points.end(), ComparePoints()); + return copy.points == target.points; + } +}; + +#endif // POLYGON_COMMANDS_H \ No newline at end of file diff --git a/polykov.fedor/T3/test.txt b/polykov.fedor/T3/test.txt new file mode 100644 index 00000000..7e64725a --- /dev/null +++ b/polykov.fedor/T3/test.txt @@ -0,0 +1,8 @@ +3 (1;1) (1;3) (3;3) +4 (0;0) (0;1) (1;1) (1;0) +5 (0;0) (0;1) (1;2) (2;1) (2;0) +3 (0;0) (-2;0) (0;-2) +4 (0;0) (1;0) (1;1) (0;1) +5 (-1;-1) (-2;1) (3;0) (3;-5) (0;-6) +3 (0;0) (1;1) (0;1) +4 (1;1) (0;2) (1;3) (2;2) \ No newline at end of file