#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>

// Êëàññ òî÷êè.
class Point {
    int x, y;

public:
    // Êîíñòðóêòîð. Ñîçäàåò îáúåêò ñ íóëåâûìè êîîðäèíàòàìè.
    Point() { this->x = this->y = 0; }

    // Êîíñòðóêòîð. Ñîçäàåò îáúåêò ñ óêàçàííûìè êîîðäèíàòàìè.
    Point(int _x, int _y) { this->x = _x; this->y = _y; }

    // Äåñòðóêòîð. Çàíóëÿåò òî÷êè.
    ~Point() { this->x = this->y = 0; }

    // 2.5 Ñëîæåíèå òî÷åê. Åñëè ðàññìàòðèâàòü òî÷êó êàê âåêòîð, òî äàííóþ îïåðàöèþ ìîæíî ïðèìåíÿòü äëÿ ñëîæåíèÿ âåêòîðîâ.
    // Ïåðåãðóçêà ñòàíäàðòíîãî îïåðàòîðà ñëîæåíèÿ.
    Point operator+(const Point& other) {
        return Point(x + other.x, y + other.y);
    }

    void setCoordinates(int _x) { this->x = _x; }
    void setCoordinates(int _x, int _y) { this->x = _x; this->y = _y; }

    int getX() const { return this->x; }
    int getY() const { return this->y; }

private:
    friend std::istream& operator>>(std::istream& stream, Point& p);
};

// 2.6 Îïåðàòîðû ââîäà âûâîäà äëÿ êëàññà òî÷êè.
// Âûâîä.
std::ostream& operator<<(std::ostream& stream, const Point& p) {
    stream << "Point (" << p.getX() << ";" << p.getY() << ")";
    return stream;
}

// Ââîä.
std::istream& operator>>(std::istream& stream, Point& p) {
    stream >> p.x >> p.y;
    return stream;
}

// Áàçîâûé êëàññ äëÿ âñåõ ôèãóð.
class Shape {
public:
    // Ôóíêöèÿ ÷èñòî âèðòóàëüíàÿ. Íåîáõîäèìà äëÿ âû÷èñëåíèÿ ïåðìèòåòðà äëÿ ëþáûõ ôèãóð.
    // Äîëæíà áûòü ïåðåîïðåäåëåíà â íàñëåäíèêå.
    virtual int calculatePerimeter() const = 0;
};

// Êëàññ 4óãîëüíèêà. Íàñëåäóåì îò áàçîâîãî êëàññà ôèãóðû.
class Polygon : public Shape {
public:
    Polygon() { // Êîíñòðóêòîð ïî óìîë÷àíèþ. Ñîçäàåò òî÷êè ñ íóëåâûìè êîîðäèíàòàìè.
        pts = new Point[4]; // 2.4.1
        pts[0] = pts[1] = pts[2] = pts[3] = Point(0, 0);
    }

    // Êîíñòðóêòîð ñ ïàðàìåòðàìè.
    Polygon(Point p1, Point p2, Point p3, Point p4) {
        pts[0] = p1;
        pts[1] = p2;
        pts[2] = p3;
        pts[3] = p4;
    }

    // 2.4.3 Äåñòðóêòîð. Îñâîáîæäàåò ïàìÿòü, âûäåëåííóþ ïîä òî÷êè..
    ~Polygon() {
        delete[] pts;
        std::cout << "~Polygon(), memory cleared." << std::endl;
    }

    Point& getPoint(int index) const {
        return pts[index];
    }

    // Ôóíêöèÿ âû÷èñëåíèÿ ïåðèìåòðà, îáúÿâëåííàÿ â áàçîâîì êëàññå. Òóò ìû åå îïðåäåëèëè.
    int calculatePerimeter() const {
        int perimeter = 0;
        for (int i = 0; i < 4; ++i) {
            int currIndex = i, nextIndex = i + 1;
            if (currIndex == 3)
                nextIndex = 0;

            const int xDelta = std::abs(pts[currIndex].getX() - pts[nextIndex].getX());
            const int yDelta = std::abs(pts[currIndex].getY() - pts[nextIndex].getY());
            if (xDelta > 0)
                perimeter += xDelta;
            else
                perimeter += yDelta;
        }

        return perimeter;
    }

private:
    Point* pts;
};

// Ôóíêöèÿ îïðåäåëÿåò òèï ïîëèãîíà - êâàäðàò èëè ïðÿ-íèê.
// Âîçâðàùàåìûå çíà÷åíèÿ:
// 1 - Êâàäðàò
// 2 - Ïðÿ-íèê
int getPolygonType(const Polygon& pol) {
    double width = 0.f, height = 0.f;
    for (int i = 1; i < 4; ++i) {
        if (pol.getPoint(0).getX() != pol.getPoint(i).getX()) {
            width = abs(pol.getPoint(0).getX() - pol.getPoint(i).getX());
        }
        else if (pol.getPoint(0).getY() != pol.getPoint(i).getY()) {
            height = abs(pol.getPoint(0).getY() - pol.getPoint(i).getY());
        }
    }

    double diag = sqrt(((pol.getPoint(2).getX() - pol.getPoint(0).getX()) * (pol.getPoint(2).getX() - pol.getPoint(0).getX())) + (pol.getPoint(2).getY() - pol.getPoint(0).getY()) * (pol.getPoint(2).getY() - pol.getPoint(0).getY()));
    if (((width * width) + (height * height) - (diag * diag)) / (2 * height * width) == 1) { //Íå êâàäðàò è íå ïðÿ-íèê
        return 3; // Íå êâàäðàò è íå ïðÿ-íèê
    }

    if (width == height) {
        return 1; // Êâàäðàò.
    }

    return 2; // Ïðÿ-íèê.
}

// "Îêâàäðà÷èâàåò" ïðÿ-íèê.
void squarePolygon(Polygon& pol) {
    int width = 0, height = 0;
    for (int i = 1; i < 4; ++i) {
        if (pol.getPoint(0).getX() != pol.getPoint(i).getX()) {
            width = abs(pol.getPoint(0).getX() - pol.getPoint(i).getX());
        }
        else if (pol.getPoint(0).getY() != pol.getPoint(i).getY()) {
            height = abs(pol.getPoint(0).getY() - pol.getPoint(i).getY());
        }
    }

    int targetSide = std::min(width, height);
    for (int i = 1; i < 4; ++i) {
        if ((pol.getPoint(0).getX() - pol.getPoint(i).getX()) > targetSide) {
            pol.getPoint(0).setCoordinates(pol.getPoint(i).getX() + targetSide);
        }
        else if ((pol.getPoint(i).getX() - pol.getPoint(0).getX()) > targetSide) {
            pol.getPoint(0).setCoordinates(pol.getPoint(0).getX() + targetSide);
        }
        else if ((pol.getPoint(0).getY() - pol.getPoint(i).getY()) > targetSide) {
            pol.getPoint(0).setCoordinates(pol.getPoint(i).getY() + targetSide);
        }
        else if ((pol.getPoint(i).getY() - pol.getPoint(0).getY()) > targetSide) {
            pol.getPoint(0).setCoordinates(pol.getPoint(0).getY() + targetSide);
        }
    }
}

// Ñòàòè÷åñêèå ïåðåìåííàÿ è ôóíêöèÿ, êîòîðûå èíèöèèðóþò êîë-âî ôèãóð.
static int polygonCount = 0;
static void setPolygonCount() {
    polygonCount = 3;
}

int main() {
    setPolygonCount(); // Èíèöèèðóåì êîë-âî ôèãóð.
    std::cout << "polygonCount = " << polygonCount << ". Do you want to change it? (y/n): ";
    std::string answer; std::cin >> answer;

    if (answer == "y") { // Ìåíÿåì êîë-âî ôèãóð ïî çàïðîñó.
        polygonCount = 0;
        while (polygonCount < 1) {
            std::cout << "How many polygons you want to enter? " << std::endl;
            std::cin >> polygonCount;
            if (polygonCount < 1)
                std::cout << "Polygon count must be > 0." << std::endl;
        }
    }

    std::vector<Polygon> polygons(polygonCount);

    // Ñ÷èòûàåì êîîðäèíàòû òî÷åê êàæäîãî ïîëèãîíà.
    for (int i = 0; i < polygonCount; ++i) {
        int x, y;
        std::cout << "POLYGON #" << i + 1 << std::endl;
        for (int j = 0; j < 4; ++j) {
            std::cout << "Enter point " << j + 1 << " (x y): " << std::endl;
            std::cin >> polygons[i].getPoint(j);
        }
    }

    // Ñ÷èòàåì, ñêîëüêî ïðÿ-íèêîâ è ïîïóòíî îêâàäðà÷èâàåì èõ.
    int rectCount = 0;
    for (int i = 0; i < polygonCount; ++i) {
        if (getPolygonType(polygons[i]) == 2) {
            squarePolygon(polygons[i]);
            rectCount++;
        }
    }
    std::cout << "There is " << rectCount << " not squares." << std::endl;

    // Ñíîâà ñ÷èòàåì ñêîëüêî ïðÿ-íèêîâ (äîëæíî áûòü 0).
    rectCount = 0;
    for (int i = 0; i < polygonCount; ++i) {
        if (getPolygonType(polygons[i]) == 1) {
            rectCount++;
        }
    }

    // Âûâîäèì ðåçóëüòàò è âûõîäèì èç ïðîãðàììû.
    std::cout << "There is " << rectCount << " squares after squaring." << std::endl;
    return 0;
}