Загрузка данных


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Random;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;

class Sultan {

    // =========================================================
    //  CAMPURI OBLIGATORII (cerute explicit de enuntul temei)
    // =========================================================
    private double bogatie;              // bogatia sultanului (tip real)
    private int numarSotii;              // numarul de sotii (tip intreg) = populatia haremului
    private double[] frumusete;          // vector DINAMIC: frumusetea fiecarei sotii, 0-100
    private double[] rautate;            // vector DINAMIC: rautatea fiecarei sotii, 0-100

    // campul STATIC: o singura copie, comuna tuturor obiectelor Sultan,
    // care numara cate obiecte Sultan au fost create in total (in orice fel: prin oricare constructor)
    public static int numarSultaniCreati = 0;

    // =========================================================
    //  CONSTANTE (limite) - static final, cerute pentru validari
    // =========================================================
    static final double COEF_MIN = 0;      // limita minima admisa pentru frumusete/rautate
    static final double COEF_MAX = 100;    // limita maxima admisa pentru frumusete/rautate
    static final int MAX_SOTII = 20;       // numar maxim de sotii acceptat (limita de siguranta)

    // BufferedReader legat la tastatura (System.in), folosit pentru citire MANUALA,
    // fara clasa Scanner - cerinta explicita a temei. E static: un singur obiect,
    // partajat de toate metodele, in loc sa fie recreat la fiecare citire.
    static BufferedReader tastatura = new BufferedReader(new InputStreamReader(System.in));


    // =========================================================
    //  CONSTRUCTORI (3 tipuri cerute, toti cu alocare DINAMICA)
    // =========================================================

    /**
     * 1) Constructor IMPLICIT (fara parametri).
     * Seteaza valori "goale" / implicite: sultan fara nicio sotie.
     * Vectorii sunt alocati cu dimensiune 0 (vectori valizi, dar fara elemente),
     * consistent cu numarSotii = 0.
     */
    Sultan() {
        bogatie = 1000;
        numarSotii = 0;
        frumusete = new double[0];   // alocare dinamica, dimensiune 0
        rautate = new double[0];     // alocare dinamica, dimensiune 0
        numarSultaniCreati++;        // inca un sultan a fost creat
    }

    /**
     * 2) Constructor CU PARAMETRI.
     * Primeste bogatia, numarul de sotii si valorile de frumusete/rautate
     * care se aplica IDENTIC fiecarei sotii (pot fi modificate individual ulterior
     * prin setFrumusete/setRautate).
     */
    Sultan(double bogatie, int numarSotii, double frumusete, double rautate) {
        this.bogatie = bogatie;            // "this." e necesar: parametrul are acelasi nume ca si campul
        this.numarSotii = numarSotii;

        this.frumusete = new double[numarSotii];  // alocare dinamica, la dimensiunea primita
        this.rautate = new double[numarSotii];

        // umplem fiecare sotie cu aceleasi valori initiale primite ca parametru
        for (int i = 0; i < numarSotii; i++) {
            this.frumusete[i] = frumusete;
            this.rautate[i] = rautate;
        }

        numarSultaniCreati++;
    }

    /**
     * 3) Constructor DE COPIERE.
     * Creeaza un obiect nou, independent, cu aceleasi valori ca "altul".
     * IMPORTANT: .clone() e obligatoriu pe vectori - fara el, cele doua obiecte
     * ar ajunge sa refere aceeasi zona de memorie, iar o modificare la unul
     * s-ar reflecta (gresit) si asupra celuilalt.
     */
    Sultan(Sultan altul) {
        bogatie = altul.bogatie;
        numarSotii = altul.numarSotii;
        frumusete = altul.frumusete.clone();   // copie REALA a vectorului, nu doar a adresei
        rautate = altul.rautate.clone();
        numarSultaniCreati++;
    }


    // =========================================================
    //  METODE DE ACCES (get) - doar citesc, nu modifica nimic
    // =========================================================
    double getBogatie() { return bogatie; }
    int getNumarSotii() { return numarSotii; }

    // get cu validare de index: daca "i" nu e o pozitie valida, intoarcem -1
    // (o valoare imposibila pentru frumusete reala, semnal ca ceva e gresit),
    // in loc sa lasam programul sa arunce ArrayIndexOutOfBoundsException
    double getFrumusete(int i) {
        if (i >= 0 && i < numarSotii) {
            return frumusete[i];
        }
        return -1; // index invalid -> valoare-semnal de eroare
    }

    double getRautate(int i) {
        if (i >= 0 && i < numarSotii) {
            return rautate[i];
        }
        return -1; // index invalid
    }


    // =========================================================
    //  METODE DE MODIFICARE (set) - valideaza INAINTE de a atribui
    // =========================================================

    // bogatia nu poate fi negativa
    void setBogatie(double b) {
        if (b >= 0) {
            bogatie = b;
        }
    }

    // numarul de sotii trebuie sa fie intre 0 si MAX_SOTII;
    // la schimbarea numarului, REALOCAM ambii vectori la noua dimensiune
    // (simplificare: nu pastram valorile vechi, pornim de la 0.0 pe fiecare pozitie noua)
    void setNumarSotii(int n) {
        if (n >= 0 && n <= MAX_SOTII) {
            numarSotii = n;
            frumusete = new double[n];
            rautate = new double[n];
        }
    }

    // set cu DUBLA validare: indexul trebuie sa fie valid SI valoarea trebuie
    // sa fie in intervalul [COEF_MIN, COEF_MAX] = [0, 100]
    void setFrumusete(int i, double v) {
        if (i >= 0 && i < numarSotii && v >= COEF_MIN && v <= COEF_MAX) {
            frumusete[i] = v;
        }
    }

    void setRautate(int i, double v) {
        if (i >= 0 && i < numarSotii && v >= COEF_MIN && v <= COEF_MAX) {
            rautate[i] = v;
        }
    }


    // =========================================================
    //  AFISARE - toate campurile obiectului
    // =========================================================

    // varianta scurta, foloseste un titlu generic
    void printInfo() {
        printInfo("Sultan");
    }

    // varianta cu ETICHETA (overloading - doua metode cu acelasi nume,
    // parametri diferiti): utila cand afisam mai multi sultani la rand,
    // ca sa stim exact care e care (ex: "s1 (implicit)", "harem[3]")
    void printInfo(String eticheta) {
        System.out.println("--- " + eticheta + " ---");
        System.out.println("Bogatie: " + bogatie);
        System.out.println("Numar sotii: " + numarSotii);

        System.out.println("    #    Frumusete    Rautate");
        for (int i = 0; i < numarSotii; i++) {
            System.out.println("    " + i + "    " + frumusete[i] + "    " + rautate[i]);
        }

        System.out.println("Sanatate: " + coeficientSanatate());
        System.out.println();
    }


    // =========================================================
    //  CITIRE DE LA TASTATURA - MANUAL, FARA Scanner
    //  (cerinta explicita a temei)
    // =========================================================

    // citeste o linie bruta de text de la tastatura;
    // readLine() poate arunca IOException, de aceea e nevoie de try/catch
    static String inString() {
        String str = "";

        try {
            str = tastatura.readLine();   // AICI programul se opreste si asteapta Enter
        } catch (IOException e) {
            return str;  // in caz de eroare de citire, intoarcem sir gol
        }

        return str;
    }

    // "traduce" textul citit intr-un numar intreg
    static int inInt() {
        return Integer.valueOf(inString()).intValue();
    }

    // "traduce" textul citit intr-un numar real
    static double inDouble() {
        return Double.valueOf(inString()).doubleValue();
    }

    // NOTA IMPORTANTA: aceasta metoda NU e apelata nicaieri in main()!
    // Exista, functioneaza corect, dar main() ruleaza complet automat,
    // fara sa astepte input de la tastatura (altfel programul s-ar bloca
    // la rulare automata, asteptand un utilizator care nu exista).
    // Pentru a o testa manual, trebuie apelata explicit: sultan.inputInfo();
    void inputInfo() {
        System.out.println("Bogatie:");
        setBogatie(inDouble());                 // citeste + valideaza prin setter

        System.out.println("Numar sotii:");
        setNumarSotii(inInt());

        for (int i = 0; i < numarSotii; i++) {

            System.out.println("Frumusete sotia " + i + ":");
            setFrumusete(i, inDouble());

            System.out.println("Rautate sotia " + i + ":");
            setRautate(i, inDouble());
        }
    }


    // =========================================================
    //  GENERARE DE VALORI ALEATOARE
    // =========================================================

    // suprascrie TOATE campurile obiectului cu valori aleatoare;
    // util pentru a obtine rapid un sultan "plin" cu date plauzibile,
    // fara sa le introduci manual de la tastatura
    void randomize() {
        Random r = new Random();
        setBogatie(r.nextInt(1000000));          // bogatie: 0 - 999 999
        setNumarSotii(1 + r.nextInt(5));         // 1 - 5 sotii (niciodata 0, ca sa aiba sens exemplul)
        for (int i = 0; i < numarSotii; i++) {
            // scriem direct in vector (nu prin setter): nextInt(101) da mereu 0-100,
            // deci valoarea e deja garantat valida, validarea din setter ar fi redundanta
            frumusete[i] = r.nextInt(101);       // 0 - 100 inclusiv
            rautate[i] = r.nextInt(101);         // 0 - 100 inclusiv
        }
    }


    // =========================================================
    //  COMPARARE STATICA dupa numarul de sotii
    // =========================================================

    // e STATIC pentru ca nu apartine unui singur sultan, ci compara doi
    // sultani primiti ca parametri: se apeleaza Sultan.compareSotii(x, y)
    static void compareSotii(Sultan a, Sultan b) {
        if (a.numarSotii > b.numarSotii) {
            System.out.println("Primul sultan are mai multe sotii (" + a.numarSotii + " > " + b.numarSotii + ")");
        } else if (a.numarSotii < b.numarSotii) {
            System.out.println("Al doilea sultan are mai multe sotii (" + b.numarSotii + " > " + a.numarSotii + ")");
        } else {
            System.out.println("Au acelasi numar de sotii (" + a.numarSotii + ")");
        }
    }


    // =========================================================
    //  COEFICIENT DE SANATATE
    //  = direct proportional cu media frumusetii,
    //    invers proportional cu media rautatii sotiilor
    // =========================================================
    double coeficientSanatate() {
        if (numarSotii == 0) return 0;   // fara sotii nu are sens un calcul de medie (0/0)

        double sumaFrumusete = 0, sumaRautate = 0;
        for (int i = 0; i < numarSotii; i++) {
            sumaFrumusete += frumusete[i];
            sumaRautate += rautate[i];
        }

        double mediaFrumusete = sumaFrumusete / numarSotii;
        double mediaRautate = sumaRautate / numarSotii;

        if (mediaRautate == 0) mediaRautate = 1; // evitam impartirea la 0 (ar da Infinity)

        return mediaFrumusete / mediaRautate;    // relatia ceruta: frumusete / rautate
    }


    // =========================================================
    //  MAIN - demonstreaza tot ce s-a cerut in tema
    // =========================================================
    public static void main(String[] args) throws IOException {

        // ---- PASUL 1: teanc de sultani, folosind toti cei 3 constructori ----
        Sultan s1 = new Sultan();                       // 1) implicit
        Sultan s2 = new Sultan(50000, 3, 60, 30);        // 2) cu parametri
        s2.randomize();                                  // suprascriem s2 cu valori aleatoare
        Sultan s3 = new Sultan(s2);                      // 3) copiere (dupa randomize!)

        s1.printInfo("s1 (implicit)");
        s2.printInfo("s2 (cu parametri + randomize)");
        s3.printInfo("s3 (copie dupa s2)");

        // ---- PASUL 2: vector dinamic de sultani, populat "pe bucati de 3" ----
        // la fiecare grup de 3 pozitii: [implicit, cu parametri+randomize, copiere]
        // -> demonstreaza ca toti cei 3 constructori pot popula acelasi vector
        Sultan[] harem = new Sultan[6];
        for (int i = 0; i < harem.length; i += 3) {
            harem[i] = new Sultan();
            harem[i + 1] = new Sultan(1000 * (i + 1), 2 + i % 3, 50, 50);
            harem[i + 1].randomize();
            harem[i + 2] = new Sultan(harem[i + 1]);
        }

        // ---- PASUL 3: afisam toti sultanii din vector, prin ciclu ----
        System.out.println(">>> Vectorul harem <<<");
        for (int i = 0; i < harem.length; i++) {
            harem[i].printInfo("harem[" + i + "]");
        }

        // ---- PASUL 4: comparam cativa sultani dupa numarul de sotii ----
        Sultan.compareSotii(s2, s3);
        Sultan.compareSotii(harem[0], harem[1]);

        // ---- PASUL 5: gasim cel mai sanatos sultan din vector ----
        // tipar clasic de "gasire a maximului intr-un vector"
        Sultan celMaiSanatos = harem[0];
        for (int i = 1; i < harem.length; i++) {
            if (harem[i].coeficientSanatate() > celMaiSanatos.coeficientSanatate()) {
                celMaiSanatos = harem[i];
            }
        }
        celMaiSanatos.printInfo("CEL MAI SANATOS SULTAN");

        // ---- PASUL 6: suma TUTUROR sotiilor, folosind metodele de acces ----
        // (cerinta explicita: "cu ajutorul metodelor de acces la campurile clasei")
        int totalSotii = s1.getNumarSotii() + s2.getNumarSotii() + s3.getNumarSotii();
        for (int i = 0; i < harem.length; i++) {
            totalSotii += harem[i].getNumarSotii();
        }
        System.out.println("Total sotii (toti sultanii): " + totalSotii);

        // ---- PASUL 7: numarul total de sultani creati (campul static) ----
        System.out.println("Sultani creati: " + Sultan.numarSultaniCreati);

        // ---- PASUL 8 (bonus, nota 10): salvam un sultan intr-un fisier text ----
        s1.saveToFile("s1.txt");
    }


    // =========================================================
    //  SALVARE IN FISIER (cerinta pentru nota maxima)
    // =========================================================
    // scrie toate campurile obiectului intr-un fisier text, cate o valoare
    // pe linie: bogatie, numarSotii, apoi perechi frumusete/rautate pentru
    // fiecare sotie - acelasi format simplu, usor de citit ulterior
    void saveToFile(String lab1jav) throws IOException {
        BufferedWriter fisier = new BufferedWriter(
                new FileWriter(lab1jav)
        );

        fisier.write(String.valueOf(bogatie));
        fisier.newLine();

        fisier.write(String.valueOf(numarSotii));
        fisier.newLine();

        for (int i = 0; i < numarSotii; i++) {
            fisier.write(String.valueOf(frumusete[i]));
            fisier.newLine();

            fisier.write(String.valueOf(rautate[i]));
            fisier.newLine();
        }

        fisier.close();   // obligatoriu: elibereaza fisierul si scrie efectiv pe disc
    }
}