Letalo

Letalo

Avtor: Andrej Pavšič

Navodilo naloge

Sestavi razred Letalo, ki naj vsebuje naslednje privatne lastnosti: doseg (int), maxVisina (int), maxHitrost (int), tip (string) in stPotnikov (int).

  • Izpiši tipe vseh letal, s katerimi se lahko odpravimo na polet dane dolžine.
  • Ugotovili so, da so pri vnosu podatkov vsem letalom, katerih tip se začne na črke od 'A' do 'M', vnesli za 500m prenizko maksimalno višino. Popravi podatke za vsa taka letala v tabeli.
  • Izpiši načrt letenja, s katerim je možno čim hitreje prepeljati m potnikov v d kilometrov oddaljen kraj.
  • Iz dane datoteke s podatki o letalih odstrani vse, ki ne morejo prepeljati danega števila potnikov.
  • Iz dane datoteke letal tvori nove datoteke letal, ki so združene glede na tip letala. V vsako datoteko na koncu zapiši koliko je letal v njej in koliko potnikov skupaj lahko prepeljejo

Vsi razredi naj obvezno vsebujejo

  • Minimalni (tj. prazni) konstruktor public Razred(), ki tvori objekt s privzetimi (smiselnimi!) vrednostmi.
  • Metodo public override string ToString(), ki vse podatke v objektu zapiše v obliki niza. Podatki naj bodo med seboj ločeni z znakom ';'.
  • Polni konstruktor public Razred(string s), ki s klicem Razred(niz) generira tak objekt Razred r, za katerega velja niz = r.ToString().
  • Metodo DodajNaDatoteko(string imeDatoteke), ki objekt this zapiše (oz. doda; glej metodo File.AppendText()) kot vrstico this.ToString() v tekstovni datoteki.
  • Metodo PreberiZDatoteke(string imeDatoteke), ki vrne tabelo objektov, kjer posamezni objekt vsebuje podatke, ki so zapisani v posamezni vrstici tekstovne datoteke.

Vsi razredi morajo biti robustni – vsi konstruktorji in metode morajo biti taki, da objekta ne spravijo v nesmiselno stanje. Če je potrebno, pri klicu metode s nedopustnimi parametri sproži izjemo.

Pri sestavljanju razredov si prej oglejte probleme, ki jih rešujete, da boste vedeli, kako mora biti razred zgrajen (katere podatke in metode naj vsebuje).

V testnem programu, s katerim prikažete ključne funkcionalnosti razreda, naredite naslednje:

  • Napišite metodo, ki ustvari vsaj ducat različnih objektov in jih zapišite na datoteko.
  • Napišite ustrezne metode za reševanje zastavljenih problemov.
  • V programu samem pa po vrsti

    • Pokličite metodo, ki na datoteko zapiše ducat objektov.
    • Preberite vse podatke z datoteke v tabelo.
    • Tabelo pregledno izpišite.
    • Nato kličite metode, ki so potrebne, da rešite zastavljene probleme in pregledno izpišite rezultate.
    • Na koncu na isto datoteko ponovno zapišite vse objekte (ne glede na to, ali so jih zgornje metode spremenile ali ne).

Opis problema in ideja rešitve

Lastnosti objektov tipa Letalo so že predpisane v navodilih, to ne predstavlja problema. V razredu je potrebno definirati dva konstruktorja – praznega in polnega. S klicem praznega konstruktorja podamo letalu poljubne smiselne vrednosti. Pri klicu polnega konstruktorja pa je že potrebno biti pazljiv, da smo vnesli točno število podatkov ustreznih tipov v nizu, ki jih med seboj ločimo s podpičjem.

Metode v navodilih so nezahtevne in kratke, zato so tudi ideje rešitve zelo preproste:

  • public override string ToString(): samo izpis niza atributov letala po predpisanem vrstnem redu.
  • DodajNaDatoteko(string imeDatoteke): vključimo tok za pisanje in z metodo za dodajanje zapišemo objekt na konec datoteke, ki ga metoda sprejme kot parameter.
  • PreberiZDatoteke(string imeDatoteke): preberemo vsebino datoteke in jo po delih shranimo v tabelo nizov. Nato iz vsakega elementa te tabele, kjer so hranjeni podatki o letalih, ustvarimo objekt tipa Letalo.
  • izpisiTipe(Letalo[] seznamLetal, int dolzina): Ustrezna letala bomo iz tabele izpisali, če je doseg letala večji od podane dolžine.
  • popraviMaxVisino(Letalo[] seznamLetal): Pregledati je potrebno začetne črke pri tipih letal. Za pregled črk med A in M si lahko pomagamo z ascii vrednostmi. Ustreznim samo povečamo maksimalno višino.
  • nacrtLetenja(Letalo[] leti, int potniki, int kilometri): Ker nas zanima kako čim hitreje prepeljati določeno število potnikov, je smiselno pripraviti urejene seznam letal padajoče glede na hitrost, ki jo letalo doseže. Nato gremo z zanko po seznamu in letala, ki imajo prekratek doseg iz seznama brišemo, letala z ustreznim dosegom pa shranimo na pomožen seznam. Ko imamo zadostno sedežev, zanko prekinemo in pregledamo, če bi imeli zadostno število sedežev tudi, če ne uporabimo katerega izmed hitrejših letal – pri prevozu smo namreč hitri toliko, kot je hitro najpočasnejše letalo.
  • odtraniNeustrezne(string dat, int stPot): Prebrati bo potrebno vsebino datoteke in iz podatkov v vrsticah kreirati objekte tipa Letalo. Sledilo bo preverjanje števila potnikov. Če bo letalo zadovoljivo, bomo vrstico, iz katere smo kreirali letalo, zapisali na podano datoteko.
  • zdruziGledeNaTip(string dat): Letala istega tipa bomo združili v datoteko z imenom »tip.txt«. Tako bomo lažje dodajali letala istega tipa v pravo datoteko. Za štetje letal in sedežev pa bomo uporabili zanko znotraj zanke – najprej zanka po tipih, znotraj te zanke pa bomo šteli letala in število sedežev.

Razlaga algoritma

Ustvarimo razred Letalo in v njem definiramo privatne spremenljivke, ki jih bomo rabili v konstruktorju. Definiramo še lastnosti za spremenljivke – uporabljali bomo get in set metode.

  • public override string ToString(): lastnosti letala vrnemo v nizu v zaporedju doseg, maksimalna višina, maksimalna hitrost, tip, število potnikov. Lastnosti med seboj ločimo s podpičjem. Če s takšnim nizom podatkov kličemo polni konstruktor, kreiramo objekt tipa Letalo (zahteva v navodilih!).
  • DodajNaDatoteko(string imeDatoteke): V metodi vključimo podatkovni tok za pisanje. Pisali bomo z metodo AppendText, ki dodaja besedilo na konec datoteke. Posebnih varoval ne potrebujemo, če datoteka v vhodnem nizu še ne obstaja, jo metoda AppendText ustvari sama. Nato zapišemo objekt na konec datoteke s pomočjo že prej definirane metode ToString().
  • PreberiZDatoteke(string imeDatoteke): v metodi najprej z metodo File.Exists(datoteka) preverimo, če datoteka zapisana v vhodnem nizu sploh obstaja. Če ne obstaja vržemo izjemo, sicer pa vključimo podatkovni tok za branje. V niz vsebina shranimo vsebino celotne datoteke z ukazom ReadToEnd(). Toka za branje ne bomo več potrebovali, zato ga izključimo. Vsebino niza spravimo v tabelo nizov, tako da vsaka vrstica v datoteki zasede svoj prostor v tej tabeli. To naredimo z metodo Split, ki ji za separator podamo skok v novo vrstico. Ustvarimo še tabelo objektov razreda Letalo, ki ima enako dolžino kot število neničelnih elementov tabele vrstice. Nato z zanko vsakemu elementu seznama, ki hrani atribute letala, priredimo objekt Letalo, ki ga shranimo v prej definirano tabelo. Program nam vrne tabelo objektov tipa Letalo.
  • izpisiTipe(Letalo[] seznamLetal, int dolzina): Z zanko gremo po seznamu letal. Znotraj zanke z if stavkom preverjamo če je doseg letala večji od vhodnega podatka o dolžini. Če je, potem izpišemo tip tega letala na konzolo.
  • popraviMaxVisino(Letalo[] seznamLetal): Poženemo zanko po tabeli letal, znotraj zanke najprej poiščemo ascii vrednost prvega znaka v nizu tipa. Če se vrednost nahaja med 65 in 77, to pomeni, da imamo veliko črko med A in M. Takim letalom povečamo maksimalno višino za 500.
  • nacrtLetenja(Letalo[] leti, int potniki, int kilometri): V tej metodi najprej ustvarimo seznam letal, urejen padajoče glede na najvišjo hitrost. Pred zanko deklariramo še pomožen seznam za hranjenje ustreznih letal in spremenljivko s katero bomo prešteli koliko sedežev je skupno na voljo v teh letalih. Z zanko pregledujemo letala v urejenem seznamu. Najprej pregledamo, če ima letalo dovolj velik doseg – če je doseg premajhen, letalo iz seznama odstranimo in skočimo na naslednji korak zanke. Sicer nadaljujemo in pogledamo, če mo vsem potnikom že zagotovilo sedežno mesto. Če smo, potem zanko prekinemo. Če gremo skozi oba if stavka, potem samo povečamo število sedežev in letalo dodamo v pomožen seznam. V drugem delu metode se držimo še pravila, da smo hitri toliko, kot je hitro najpočasnejše letalo. Zato letala v pomožnem seznamu najprej uredimo padajoče glede na število sedežev. Najpočasnejše letalo iz ožjega izbora bomo zagotovo uporabili, sicer ne bi prišlo v ožji izbor. Z zanko po urejenem seznamu ožjega izbora »posedamo« potnike na letala. Ob tem v vsakem koraku zanke preverimo, če lahko s tekočim letalom prepeljemo vse čakajoče potnike. Prav tako v vsakem koraku na konzolo izpišemo koliko potnikov smo posedli na katero letalo. Ko posedemo zadnje potnike, prekinemo z izvajanjem zanke.
  • odtraniNeustrezne(string dat, int stPot): Pomagali si bomo z že napisano metodo PreberiZDatoteke. Neustrezna letala bomo iz datoteke izločili tako, da bomo ustrezna letala prepisali na neko pomožno datoteko , nato bomo originalno pobrisali in pomožno skopirali na originalno datoteko. Zato vse ustrezna letala najprej zapišemo na začasno datoteko in shranimo pot te datoteke v nek niz. Na koncu pobrišemo originalno datoteko in ustvarimo kopijo pomožne v isti mapi z istim imenom originalne datoteke.
  • zdruziGledeNaTip(string dat): Vsa letala iz datoteke shranimo v tabelo letal s pomočjo že definirane metode PreberiZDatoteke. Ker bomo v drugem delu naloge pognali zanko po vseh tipih letal, s katerimi bomo imeli opravka, bomo vse tipe shranili v pomožen seznam. S prva zanko, ki jo v metodi definiramo, vsa letala ločimo zapišemo po različnih datotekah glede na tip letala. Na vsakem koraku zanke je potrebno definirati lokacijo pisanja, zato bomo na vsakem koraku zanke ponovno odprli podatkovni tok za pisanje. Pri tem toku bomo uporabljali metodo za dodajanje, saj ne bi radi, da izgubimo že zapisane podatke. Podatke zapisujemo na datoteko, ki je poimenovana enako kot tip letala (če imamo dva enaka tipa, se bosta letali nahajali v isti datoteki). V tej zanki je glavno, da ločimo letala glede na tipe, ne smemo pa pozabiti dodati tip letala v pomožen seznam vsakič, ko naletimo na nov tip oz. na tip, kateri še nima svoje tekstovne datoteke. Pred drugo zanko deklariramo spremenljivki tipa int, s katerima bomo pri vsakem tipu šteli število letal in število sedežev. V zanki, s katero pregledamo vse elemente v pomožnem seznamu (oz. vse tipe letal), najprej tema spremenljivkama nastavimo vrednost 0 – pri vsakem tipu pričnemo šteti z 0. Odpremo podatkovni tok za branje in znotraj ustvarimo še while zanko, s katero bomo pregledali vse vrstice v datoteki. V tej zanki prištevamo sedeže in letala. Po izteku zanke se zapre podatkovni tok za branje, v naslednji vrstici pa uporabimo podatkovni tok za pisanje – z metodo za dodajanje na konec datoteke zapišemo število letal in število sedežev. Po izteku prve zanke tako zapišemo število letal in sedežev v vsako datoteko.

Koda v C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Letala
{
    public class Letalo
    {
        #region privatne lastnosti
        private int _doseg;
        private int _maxVisina;
        private int _maxHitrost;
        private string _tip;
        private int _stPotnikov;
        #endregion

        #region GET, SET
        public int doseg
        {
            get { return this._doseg; }
            set
            {
                if (value < 0)
                    throw new Exception("Vnesti je potrebno doseg večji od 0.");
                else
                    this._doseg = value;
            }
        }
        public int maxVisina
        {
            get { return this._maxVisina; }
            set
            {
                if (value < 0)
                    throw new Exception("Vnesti je potrebno max višino večjo od 0.");
                else
                    this._maxVisina = value;
            }
        }
        public int maxHitrost
        {
            get { return this._maxHitrost; }
            set
            {
                if (value < 0)
                    throw new Exception("Vnesti je potrebno max hitrost večjo od 0.");
                else
                    this._maxHitrost = value;
            }
        }
        public string tip
        {
            get { return this._tip; }
            set { this._tip = value; }
        }
        public int stPotnikov
        {
            get { return this._stPotnikov; }
            set
            {
                if (value < 0)
                    throw new Exception("Število potnikov mora biti večje ali enako 0.");
                else
                    this._stPotnikov = value;
            }
        }
        #endregion

        #region KONSTRUKTORJI
        /// <summary>
        /// Minimalni konstruktor
        /// </summary>
        public Letalo()
        {
            doseg = 2000; // kilometri
            maxVisina = 2000; // metri
            maxHitrost = 200;
            tip = "Stara šara";
            stPotnikov = 5;
        }

        /// <summary>
        /// polni konstruktor
        /// </summary>
        /// <param name="s">niz s podatki (doseg; maxVisina; maxHitrost; tip; stPotnikov)</param>
        public Letalo(string s)
        {
            string[] podatki = s.Trim().Split(';');
            if (podatki.Length == 5) // v vhodnem nizu moramo podatki 5 podatkov ločenih s podpičjem
            {
                try
                {
                    doseg = int.Parse(podatki[0]);
                    maxVisina = int.Parse(podatki[1]);
                    maxHitrost = int.Parse(podatki[2]);
                    tip = podatki[3].Trim();
                    stPotnikov = int.Parse(podatki[4]);
                }
                catch (FormatException e)
                { throw new Exception("Podatki niso podani v pravem formatu" + e); }
            }
            else
            { throw new Exception("Premalo podatkov. Morda niste podatkov med seboj ločili s podpičjem."); }
        }
        #endregion

        /// <summary>
        /// Podatke zapiše v obliki niza, ločene s podpičjem.
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        { return doseg + "; " + maxVisina + "; " + maxHitrost + "; " + tip + "; " + stPotnikov; }

        /// <summary>
        /// Doda objekt this na podano tekstovno datoteko.
        /// </summary>
        /// <param name="imeDatoteke"></param>
        public void DodajNaDatoteko(string imeDatoteke)
        {
            using (StreamWriter zapisi = File.AppendText(imeDatoteke))
            {
                zapisi.WriteLine(this.ToString());
            }
        }

        /// <summary>
        /// Vrne tabelo objektov, kjer posamezni objekt vsebuje podatke, ki so zapisani v posamezni vrstici tekstovne datoteke.
        /// </summary>
        /// <param name="imeDatoteke"></param>
        /// <returns></returns>
        public static Letalo[] PreberiZDatoteke(string imeDatoteke)
        {
            if (File.Exists(imeDatoteke))
            {
                StreamReader beri = new StreamReader(imeDatoteke);
                string vsebina = beri.ReadToEnd();
                beri.Close();

                string[] vrstice = vsebina.Split('\n'); // vsebino datoteke razdelimo glede na skok v novo vrsto

                int st=0;
                for (int i = 0; i < (vrstice.Length - 1); i++)
                { // preštejemo neničelne elemente tabele
                    if (vrstice[i] != "")
                    { st += 1; }
                }

                int o = 0; // ker je lahko dolžina tabele objekti manjša od dolžine taele vrstice
                Letalo[] objekti = new Letalo[st]; // tabele objektov tipa Letalo
                for (int j = 0; j < vrstice.Length - 1;j++ )
                {
                    if (vrstice[j] != "")
                    {
                        objekti[o] = new Letalo(vrstice[j]);
                        o++;
                    }
                }
                return objekti;
            }
            else
            { throw new Exception("Datoteka ne obstaja!"); }
        }

        #region NALOGE
        /// <summary>
        /// Izpiše tipe vseh letal, s katerimi se lahko odpravimo na polet dane dolžine.
        /// </summary>
        /// <param name="seznamLetal"></param>
        /// <param name="dolzina"></param>
        public static void izpisiTipe(Letalo[] seznamLetal, int dolzina)
        {
            foreach (Letalo let in seznamLetal)
            {
                if (let.doseg >= dolzina)
                { Console.WriteLine(" "+let.tip+" lahko preleti "+let.doseg+" km."); }
            }
        }

        /// <summary>
        /// Popravi podatke o maksimalni višini za +500m vsem letalom v tabeli, katerih tip se začne na črke od 'A' do 'M'.
        /// </summary>
        /// <param name="seznamLetal"></param>
        public static void popraviMaxVisino(Letalo[] seznamLetal)
        {
            foreach (Letalo let in seznamLetal)
            {
                int asciiVal = let.tip[0]; // poiščemo desetiško ascii vrednost
                if (asciiVal >= 65 && asciiVal <= 77) // A ima vrednost 65, M pa 77
                { let.maxVisina += 500; }
            }
        }

        /// <summary>
        /// Izpiše načrt letenja, s katerim je možno čim hitreje prepeljati m potnikov v d kilometrov oddaljen kraj.
        /// </summary>
        /// <param name="leti">seznam letal</param>
        /// <param name="potniki">število potnikov</param>
        /// <param name="kilometri">dolžina poti</param>
        /// <returns></returns>
        public static void nacrtLetenja(Letalo[] leti, int potniki, int kilometri)
        {
            List<Letalo> newList = leti.OrderByDescending(x => x.maxHitrost).ToList(); // uredimo po hitrosti padajoč seznam

            List<Letalo> ozjiIzbor= new List<Letalo>(); // pomožni seznam za letala v ožjem izboru
            int stSedezev = 0; // vsota sedežev vseh letal, s katerimi bomo leteli

            foreach (Letalo let in newList)
            {
                if (let.doseg < kilometri) // če letalo ne more preleteti dane dolžine, ga odstranimo iz urejenega seznama letal
                {
                    newList.Remove(let);
                    continue;
                }

                if (stSedezev >= potniki)
                    break; // ko imamo zadosti sedežev, zanko ustavimo
                stSedezev += let.stPotnikov;
                ozjiIzbor.Add(let);
            }

            ozjiIzbor.OrderByDescending(x => x.stPotnikov);// ožji izbor letal uredimo podajoče glede na število sedežev na letalu
            int naLetalu = 0; // koliko potnikov sede na letalo
            foreach (Letalo l in ozjiIzbor)
            { // skupina je tako hitra, kot je hiter njen najpočasnejši član, zato pogledamo, če bi lahko vse potnike prepeljali tudi brez najhitrejših
                if (l.stPotnikov < potniki) // če s tem letalom še ne prepeljemo vseh potnikov
                {
                    naLetalu = l.stPotnikov; // letalo bo polno
                    potniki -= l.stPotnikov; // vrsta potnikov se zmanjša za polno letalo
                    Console.WriteLine("Letalo: " + l.tip + " bo peljalo " + naLetalu + " potnikov. (hitrost:"+l.maxHitrost+")");
                }
                else // sicer na zadnje letalo posedemo preostale potnike
                {
                    naLetalu = potniki;
                    potniki = 0;
                    Console.WriteLine("Letalo: " + l.tip + " bo peljalo " + naLetalu + " potnikov. (hitrost:"+l.maxHitrost+")");
                    break; // prekinemo izvjanje zanke, saj smo vsem potnikov zagotovili sedež
                }
            }
        }

        /// <summary>
        /// Iz dane datoteke s podatki o letalih odstrani vse, ki ne morejo prepeljati danega števila potnikov.
        /// </summary>
        /// <param name="dat">ime datoteke s podatki o letali</param>
        /// <param name="stPot">število potnikov pri prevozu</param>
        public static void odtraniNeustrezne(string dat, int stPot)
        {
            string fullPath = Path.GetFullPath(dat);
            string tempPath = Path.GetTempPath();
            Letalo[] letala = PreberiZDatoteke(dat);

            using (StreamWriter pisi = new StreamWriter(tempPath + "\\00LetalaRez.txt"))
            {
                foreach (Letalo x in letala)
                {
                    if (x.stPotnikov >= stPot)
                    { pisi.WriteLine(x.ToString()); }
                }
            }

            File.Delete(fullPath); // pobrišemo original
            File.Move(tempPath + "\\00LetalaRez.txt", fullPath); // podatke z ustreznimi letali prekopiramo v datoteko z originalnim imenom

        }

        /// <summary>
        /// Iz dane datoteke letal tvori nove datoteke letal, združene glede na tip letala. V vsaki datoteki na koncu zapiše koliko je letal v njej in koliko potnikov skupaj lahko prepeljejo.
        /// </summary>
        /// <param name="dat"></param>
        public static void zdruziGledeNaTip(string dat)
        {
            Letalo[] letalaDat = PreberiZDatoteke(dat);
            List<string> tipiNiz = new List<string>(); // v niz bomo shranili vse tipe, ki jih najdemo v datoteki - ločeni bodo s podpičjem

            Directory.CreateDirectory("tipi");
            foreach (Letalo letalo in letalaDat)
            {
                StreamWriter pisi;

                // če že imamo datoteko s takim tipom
                if (File.Exists("tipi\\" + letalo.tip + ".txt"))
                {
                    pisi = File.AppendText("tipi\\" + letalo.tip + ".txt");
                    pisi.WriteLine(letalo.ToString());
                }

                else
                {
                    pisi = File.AppendText("tipi\\" + letalo.tip + ".txt");
                    tipiNiz.Add(letalo.tip);
                    pisi.WriteLine(letalo.ToString());
                }
                pisi.Close();
            }

            int stLetal;
            int stSedezev;
            foreach (string i in tipiNiz) // za vsak tip
            {
                stLetal = 0;
                stSedezev = 0;
                Letalo[] istegaTipa = PreberiZDatoteke("tipi\\" + i + ".txt");

                foreach (Letalo x in istegaTipa) // preštejemo število sedežev in letal
                {
                    stLetal ++;
                    stSedezev+=x.stPotnikov;
                }

                using (StreamWriter zapisi = File.AppendText("tipi\\" + i + ".txt"))
                {
                    zapisi.WriteLine("________________________________________");
                    zapisi.Write("število letal: " + stLetal + ", število sedežev: " + stSedezev);
                }
            }
            Console.WriteLine("Letala so bila združena glede na tip.");
        }
        #endregion
    }
}

Testni primeri

Testne primere sestavimo po danih navodilih. Za testne primere ustvarimo nov projekt, kateremu kot referenco pridružimo razred Letalo. Sestavimo metodo, ki ustvari ducat objektov tipa letalo s smiselnimi vrednostmi.

Nato testni program poženemo, kjer najprej vnesemo ime datoteke, kamor bomo zapisali ducat objektov. Te nato iz datoteke preberemo in izpišemo na konzolo. Nato testiramo delovanje spisanih metod, ki smo jih spisali po navodilih naloge. Konkretno:

  • letalom, katerih tip se začne s črko med A in M popravimo maksimalno višino za 500 metrov;
  • izpišemo vsa letala, ki lahko preletijo več kot 6000 kilometrov;
  • sestavimo načrt letenja za 500 potnikov za 4000 km dolg let;
  • iz datoteke odstranimo vsa letala, ki imajo manj kot 150 potniških sedežev;
  • letala združimo glede na tip – datoteke se nato shranijo v podmapi. Po koncu testnih primerov še enkrat izpišemo vse objekte, ki smo jih na začetku ustvarili (shranjeni so v tabeli).

Koda testnega programa

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Letala
{
    public class Letalo
    {
        #region privatne lastnosti
        private int _doseg;
        private int _maxVisina;
        private int _maxHitrost;
        private string _tip;
        private int _stPotnikov;
        #endregion

        #region GET, SET
        public int doseg
        {
            get { return this._doseg; }
            set
            {
                if (value < 0)
                    throw new Exception("Vnesti je potrebno doseg večji od 0.");
                else
                    this._doseg = value;
            }
        }
        public int maxVisina
        {
            get { return this._maxVisina; }
            set
            {
                if (value < 0)
                    throw new Exception("Vnesti je potrebno max višino večjo od 0.");
                else
                    this._maxVisina = value;
            }
        }
        public int maxHitrost
        {
            get { return this._maxHitrost; }
            set
            {
                if (value < 0)
                    throw new Exception("Vnesti je potrebno max hitrost večjo od 0.");
                else
                    this._maxHitrost = value;
            }
        }
        public string tip
        {
            get { return this._tip; }
            set { this._tip = value; }
        }
        public int stPotnikov
        {
            get { return this._stPotnikov; }
            set
            {
                if (value < 0)
                    throw new Exception("Število potnikov mora biti večje ali enako 0.");
                else
                    this._stPotnikov = value;
            }
        }
        #endregion

        #region KONSTRUKTORJI
        /// <summary>
        /// Minimalni konstruktor
        /// </summary>
        public Letalo()
        {
            doseg = 2000; // kilometri
            maxVisina = 2000; // metri
            maxHitrost = 200;
            tip = "Stara šara";
            stPotnikov = 5;
        }

        /// <summary>
        /// polni konstruktor
        /// </summary>
        /// <param name="s">niz s podatki (doseg; maxVisina; maxHitrost; tip; stPotnikov)</param>
        public Letalo(string s)
        {
            string[] podatki = s.Trim().Split(';');
            if (podatki.Length == 5) // v vhodnem nizu moramo podatki 5 podatkov ločenih s podpičjem
            {
                try
                {
                    doseg = int.Parse(podatki[0]);
                    maxVisina = int.Parse(podatki[1]);
                    maxHitrost = int.Parse(podatki[2]);
                    tip = podatki[3].Trim();
                    stPotnikov = int.Parse(podatki[4]);
                }
                catch (FormatException e)
                { throw new Exception("Podatki niso podani v pravem formatu" + e); }
            }
            else
            { throw new Exception("Premalo podatkov. Morda niste podatkov med seboj ločili s podpičjem."); }
        }
        #endregion

        /// <summary>
        /// Podatke zapiše v obliki niza, ločene s podpičjem.
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        { return doseg + "; " + maxVisina + "; " + maxHitrost + "; " + tip + "; " + stPotnikov; }

        /// <summary>
        /// Doda objekt this na podano tekstovno datoteko.
        /// </summary>
        /// <param name="imeDatoteke"></param>
        public void DodajNaDatoteko(string imeDatoteke)
        {
            using (StreamWriter zapisi = File.AppendText(imeDatoteke))
            {
                zapisi.WriteLine(this.ToString());
            }
        }

        /// <summary>
        /// Vrne tabelo objektov, kjer posamezni objekt vsebuje podatke, ki so zapisani v posamezni vrstici tekstovne datoteke.
        /// </summary>
        /// <param name="imeDatoteke"></param>
        /// <returns></returns>
        public static Letalo[] PreberiZDatoteke(string imeDatoteke)
        {
            if (File.Exists(imeDatoteke))
            {
                StreamReader beri = new StreamReader(imeDatoteke);
                string vsebina = beri.ReadToEnd();
                beri.Close();

                string[] vrstice = vsebina.Split('\n'); // vsebino datoteke razdelimo glede na skok v novo vrsto

                int st=0;
                for (int i = 0; i < (vrstice.Length - 1); i++)
                { // preštejemo neničelne elemente tabele
                    if (vrstice[i] != "")
                    { st += 1; }
                }

                int o = 0; // ker je lahko dolžina tabele objekti manjša od dolžine taele vrstice
                Letalo[] objekti = new Letalo[st]; // tabele objektov tipa Letalo
                for (int j = 0; j < vrstice.Length - 1;j++ )
                {
                    if (vrstice[j] != "")
                    {
                        objekti[o] = new Letalo(vrstice[j]);
                        o++;
                    }
                }
                return objekti;
            }
            else
            { throw new Exception("Datoteka ne obstaja!"); }
        }

        #region NALOGE
        /// <summary>
        /// Izpiše tipe vseh letal, s katerimi se lahko odpravimo na polet dane dolžine.
        /// </summary>
        /// <param name="seznamLetal"></param>
        /// <param name="dolzina"></param>
        public static void izpisiTipe(Letalo[] seznamLetal, int dolzina)
        {
            foreach (Letalo let in seznamLetal)
            {
                if (let.doseg >= dolzina)
                { Console.WriteLine(" "+let.tip+" lahko preleti "+let.doseg+" km."); }
            }
        }

        /// <summary>
        /// Popravi podatke o maksimalni višini za +500m vsem letalom v tabeli, katerih tip se začne na črke od 'A' do 'M'.
        /// </summary>
        /// <param name="seznamLetal"></param>
        public static void popraviMaxVisino(Letalo[] seznamLetal)
        {
            foreach (Letalo let in seznamLetal)
            {
                int asciiVal = let.tip[0]; // poiščemo desetiško ascii vrednost
                if (asciiVal >= 65 && asciiVal <= 77) // A ima vrednost 65, M pa 77
                { let.maxVisina += 500; }
            }
        }

        /// <summary>
        /// Izpiše načrt letenja, s katerim je možno čim hitreje prepeljati m potnikov v d kilometrov oddaljen kraj.
        /// </summary>
        /// <param name="leti">seznam letal</param>
        /// <param name="potniki">število potnikov</param>
        /// <param name="kilometri">dolžina poti</param>
        /// <returns></returns>
        public static void nacrtLetenja(Letalo[] leti, int potniki, int kilometri)
        {
            List<Letalo> newList = leti.OrderByDescending(x => x.maxHitrost).ToList(); // uredimo po hitrosti padajoč seznam

            List<Letalo> ozjiIzbor= new List<Letalo>(); // pomožni seznam za letala v ožjem izboru
            int stSedezev = 0; // vsota sedežev vseh letal, s katerimi bomo leteli

            foreach (Letalo let in newList)
            {
                if (let.doseg < kilometri) // če letalo ne more preleteti dane dolžine, ga odstranimo iz urejenega seznama letal
                {
                    newList.Remove(let);
                    continue;
                }

                if (stSedezev >= potniki)
                    break; // ko imamo zadosti sedežev, zanko ustavimo
                stSedezev += let.stPotnikov;
                ozjiIzbor.Add(let);
            }

            ozjiIzbor.OrderByDescending(x => x.stPotnikov);// ožji izbor letal uredimo podajoče glede na število sedežev na letalu
            int naLetalu = 0; // koliko potnikov sede na letalo
            foreach (Letalo l in ozjiIzbor)
            { // skupina je tako hitra, kot je hiter njen najpočasnejši član, zato pogledamo, če bi lahko vse potnike prepeljali tudi brez najhitrejših
                if (l.stPotnikov < potniki) // če s tem letalom še ne prepeljemo vseh potnikov
                {
                    naLetalu = l.stPotnikov; // letalo bo polno
                    potniki -= l.stPotnikov; // vrsta potnikov se zmanjša za polno letalo
                    Console.WriteLine("Letalo: " + l.tip + " bo peljalo " + naLetalu + " potnikov. (hitrost:"+l.maxHitrost+")");
                }
                else // sicer na zadnje letalo posedemo preostale potnike
                {
                    naLetalu = potniki;
                    potniki = 0;
                    Console.WriteLine("Letalo: " + l.tip + " bo peljalo " + naLetalu + " potnikov. (hitrost:"+l.maxHitrost+")");
                    break; // prekinemo izvjanje zanke, saj smo vsem potnikov zagotovili sedež
                }
            }
        }

        /// <summary>
        /// Iz dane datoteke s podatki o letalih odstrani vse, ki ne morejo prepeljati danega števila potnikov.
        /// </summary>
        /// <param name="dat">ime datoteke s podatki o letali</param>
        /// <param name="stPot">število potnikov pri prevozu</param>
        public static void odtraniNeustrezne(string dat, int stPot)
        {
            string fullPath = Path.GetFullPath(dat);
            string tempPath = Path.GetTempPath();
            Letalo[] letala = PreberiZDatoteke(dat);

            using (StreamWriter pisi = new StreamWriter(tempPath + "\\00LetalaRez.txt"))
            {
                foreach (Letalo x in letala)
                {
                    if (x.stPotnikov >= stPot)
                    { pisi.WriteLine(x.ToString()); }
                }
            }

            File.Delete(fullPath); // pobrišemo original
            File.Move(tempPath + "\\00LetalaRez.txt", fullPath); // podatke z ustreznimi letali prekopiramo v datoteko z originalnim imenom

        }

        /// <summary>
        /// Iz dane datoteke letal tvori nove datoteke letal, združene glede na tip letala. V vsaki datoteki na koncu zapiše koliko je letal v njej in koliko potnikov skupaj lahko prepeljejo.
        /// </summary>
        /// <param name="dat"></param>
        public static void zdruziGledeNaTip(string dat)
        {
            Letalo[] letalaDat = PreberiZDatoteke(dat);
            List<string> tipiNiz = new List<string>(); // v niz bomo shranili vse tipe, ki jih najdemo v datoteki - ločeni bodo s podpičjem

            Directory.CreateDirectory("tipi");
            foreach (Letalo letalo in letalaDat)
            {
                StreamWriter pisi;

                // če že imamo datoteko s takim tipom
                if (File.Exists("tipi\\" + letalo.tip + ".txt"))
                {
                    pisi = File.AppendText("tipi\\" + letalo.tip + ".txt");
                    pisi.WriteLine(letalo.ToString());
                }

                else
                {
                    pisi = File.AppendText("tipi\\" + letalo.tip + ".txt");
                    tipiNiz.Add(letalo.tip);
                    pisi.WriteLine(letalo.ToString());
                }
                pisi.Close();
            }

            int stLetal;
            int stSedezev;
            foreach (string i in tipiNiz) // za vsak tip
            {
                stLetal = 0;
                stSedezev = 0;
                Letalo[] istegaTipa = PreberiZDatoteke("tipi\\" + i + ".txt");

                foreach (Letalo x in istegaTipa) // preštejemo število sedežev in letal
                {
                    stLetal ++;
                    stSedezev+=x.stPotnikov;
                }

                using (StreamWriter zapisi = File.AppendText("tipi\\" + i + ".txt"))
                {
                    zapisi.WriteLine("________________________________________");
                    zapisi.Write("število letal: " + stLetal + ", število sedežev: " + stSedezev);
                }
            }
            Console.WriteLine("Letala so bila združena glede na tip.");
        }
        #endregion
    }
}
0%
0%