// Pelitilanteen hallintaan liittyvät funktiot ja structien rakentajat. #include "hakkeripeli.hh" #include "hakkeri.hh" #include "merkkijonokasittely.hh" #include "poikkeukset.hh" #include #include #include #include using std::endl; Siirto::Siirto(Siirtotyyppi ntyyppi): tyyppi(ntyyppi), maara(0), kohde(NULL), reitityskohteet() { } Asetukset::Asetukset(): koodauskulutus(0), reitityskulutus(0), puskurointikulutus(0), tankkauskulutus(0), ryhmanvarastot(0), kolauusiutuminen(0) { } Hakkeriryhma::Hakkeriryhma(const std::string &ryhmannimi): nimi(ryhmannimi), hakkerit(), vuoro(0) { } Pelitilanne::Pelitilanne(): asetukset(), ryhmat(), vuoro(0), lopetettu(false) { } // Yleisasetustiedoston lukeminen. // Virheen sattuessa tuottaa poikkeuksen Lukuvirhe. void lueYleisasetukset(std::istream &virta, Asetukset &tulos) { std::vector osat; lueOsat(virta, osat); if (osat.size() != 6) { // Puuttuvia tai ylimääräisiä lukuja throw Lukuvirhe(); } tulos.koodauskulutus = kokonaisluvuksi(osat.at(0)); tulos.reitityskulutus = kokonaisluvuksi(osat.at(1)); tulos.puskurointikulutus = kokonaisluvuksi(osat.at(2)); tulos.tankkauskulutus = kokonaisluvuksi(osat.at(3)); tulos.ryhmanvarastot = kokonaisluvuksi(osat.at(4)); tulos.kolauusiutuminen = kokonaisluvuksi(osat.at(5)); } // Hakkeriryhmän tiedoston lukeminen ja Hakkeri-olioiden luominen. // Virheen sattuessa tuottaa poikkeuksen Lukuvirhe. void lueHakkeriryhma(std::istream &virta, Pelitilanne &pelitilanne) { std::string ryhmannimi(""); if (!std::getline(virta, ryhmannimi)) { throw Lukuvirhe(); } for (unsigned int ryhma = 0; ryhma < pelitilanne.ryhmat.size(); ++ryhma) { if (vertaaKKR(ryhmannimi, pelitilanne.ryhmat.at(ryhma).nimi)) { // Ryhmän nimi on jo käytössä throw Lukuvirhe(); } } Hakkeriryhma uusiryhma(ryhmannimi); std::string rivi(""); int osuussumma = 0; try { while (std::getline(virta, rivi)) { std::istringstream rivivirta(rivi); std::vector osat; // Paloiteltu rivi // Luetaan hakkerin tiedot lueOsat(rivivirta, osat); if (osat.size() != 4) { // Väärä määrä tietoja throw Lukuvirhe(); } std::string &hakkerinnimi = osat.at(0); int varastoosuus = kokonaisluvuksi(osat.at(1)); int hermosuhde = kokonaisluvuksi(osat.at(2)); int kolasuhde = kokonaisluvuksi(osat.at(3)); // Tarkistetaan, onko nimi jo käytössä if (etsiHakkeri(hakkerinnimi, pelitilanne.ryhmat)) { throw Lukuvirhe(); } // Samat kuin tehtävänannossa, mutta ensin suoritettavalla // kertolaskulla vältetään liukulukujen käyttö. int kolavarastot = (pelitilanne.asetukset.ryhmanvarastot * varastoosuus * kolasuhde) / (100 * (hermosuhde + kolasuhde)); int hermovarastot = (pelitilanne.asetukset.ryhmanvarastot * varastoosuus * hermosuhde) / (100 * (hermosuhde + kolasuhde)); // Luodaan hakkeriolio Hakkeri *hakkeri = new Hakkeri(pelitilanne.asetukset, ryhmannimi, hakkerinnimi, kolavarastot, hermovarastot); uusiryhma.hakkerit.push_back(hakkeri); osuussumma += varastoosuus; } } catch (...) { // Poikkeus - vapautetaan luodut oliot for (unsigned int i = 0; i < uusiryhma.hakkerit.size(); ++i) { delete uusiryhma.hakkerit.at(i); uusiryhma.hakkerit.at(i) = NULL; } uusiryhma.hakkerit.clear(); throw; } if (osuussumma > 100 || uusiryhma.hakkerit.size() == 0) { // Osuudet ylittävät 100% tai yhtään hakkeria ei ole määritelty. throw Lukuvirhe(); } // Lisätään luotu hakkeriryhmä peliin pelitilanne.ryhmat.push_back(uusiryhma); } // Ylikuormitetut tiedostojen lukemiset void lueYleisasetukset(const std::string &tiedostonimi, Asetukset &tulos) { std::ifstream virta(tiedostonimi.c_str()); if (!virta.is_open()) { throw Avausvirhe(tiedostonimi); } try { lueYleisasetukset(virta, tulos); } catch (Lukuvirhe &virhe) { // Lisätään poikkeukseen tiedostonimi. throw Lukuvirhe(tiedostonimi); } } void lueHakkeriryhma(const std::string &tiedostonimi, Pelitilanne &pelitilanne) { std::ifstream virta(tiedostonimi.c_str()); if (!virta.is_open()) { throw Avausvirhe(tiedostonimi); } try { lueHakkeriryhma(virta, pelitilanne); } catch (Lukuvirhe &virhe) { throw Lukuvirhe(tiedostonimi); } } // Etsii hakkerin nimeä annetuista ryhmistä. Palauttaa osoittimen tai NULL. Hakkeri *etsiHakkeri(const std::string &nimi, const std::vector &ryhmat) { for (unsigned int ryhma = 0; ryhma < ryhmat.size(); ++ryhma) { for (unsigned int hakkeri = 0; hakkeri < ryhmat.at(ryhma).hakkerit.size(); ++hakkeri) { if (vertaaKKR(ryhmat.at(ryhma).hakkerit.at(hakkeri)->haeNimi(), nimi)) { return ryhmat.at(ryhma).hakkerit.at(hakkeri); } } } return NULL; } // Palauttaa osoittimen vuorossa olevaan hakkeriin. Hakkeri *haeVuoro(const Pelitilanne &pelitilanne) { // Vuorossa oleva ryhmä const Hakkeriryhma &ryhma = pelitilanne.ryhmat.at(pelitilanne.vuoro); return ryhma.hakkerit.at(ryhma.vuoro); } // Laskee siirron kolakulutuksen. int laskeKulutus(const Siirto &siirto, const Asetukset &asetukset) { switch (siirto.tyyppi) { case KOODAA: return siirto.maara * asetukset.koodauskulutus; case REITITA: return siirto.maara * asetukset.reitityskulutus; case PUSKUROI: return siirto.maara * asetukset.puskurointikulutus; case TANKKAA: // Tankkauksessa annetaan kolamäärä, ei hermomäärää return siirto.maara; default: return 0; } } // Suorittaa siirron, tulostaa ilmoitukset, vaihtaa tarvittaessa vuoron. void suoritaSiirto(const Siirto &siirto, Pelitilanne &pelitilanne, std::ostream &out) { bool vuoropysyy = haeVuoro(pelitilanne)->suoritaSiirto(siirto, out); if (peliLoppu(pelitilanne.ryhmat)) { pelitilanne.lopetettu = true; return; } if (!vuoropysyy) { // Seuraavan kerran ryhmässä vuoroon tuleva hakkeri Hakkeriryhma &nykyinen = pelitilanne.ryhmat.at(pelitilanne.vuoro); nykyinen.vuoro = (nykyinen.vuoro + 1) % nykyinen.hakkerit.size(); do { // Seuraava hakkeriryhmä pelitilanne.vuoro += 1; pelitilanne.vuoro %= pelitilanne.ryhmat.size(); // Tuki useammalle kuin kahdelle ryhmälle, peli voi jatkua vaikka // jokin ryhmä ei olisi enää mukana. } while (!ryhmaMukana(pelitilanne.ryhmat.at(pelitilanne.vuoro))); // Varmistetaan, ettei vuoron aikana ryhmän seuraava hakkeri ole // siirtynyt offline-tilaan. Hakkeriryhma &uusi = pelitilanne.ryhmat.at(pelitilanne.vuoro); while (!haeVuoro(pelitilanne)->online()) { uusi.vuoro = (uusi.vuoro + 1) % uusi.hakkerit.size(); } // Aloitetaan uuden hakkerin vuoro. haeVuoro(pelitilanne)->lisaaKolaa(); tulostaVuoro(pelitilanne, out); } } // Tarkistaa, että ryhmä on yhä mukana pelissä. bool ryhmaMukana(const Hakkeriryhma &ryhma) { for (unsigned int hakkeri = 0; hakkeri < ryhma.hakkerit.size(); ++hakkeri) { if (ryhma.hakkerit.at(hakkeri)->online()) { // Löytyi aktiivinen hakkeri. return true; } } // Ei aktiivisia hakkereita. return false; } // Tarkistaa, onko peli loppu. bool peliLoppu(const std::vector &ryhmat) { int mukana = 0; // Käydään ryhmät läpi. for (unsigned int ryhma = 0; ryhma < ryhmat.size(); ++ryhma) { if (ryhmaMukana(ryhmat.at(ryhma))) { mukana += 1; } } return (mukana <= 1); // Peli jatkuu jos yli yksi ryhmä on vielä mukana. } // Tulostaa vuorossa olevan ryhmän ja hakkerin nimen. void tulostaVuoro(const Pelitilanne &pelitilanne, std::ostream &out) { out << endl; out << "Vuorossa: "; out << pelitilanne.ryhmat.at(pelitilanne.vuoro).nimi << " - "; out << haeVuoro(pelitilanne)->haeNimi() << endl; out << endl; } void vapautaHakkerit(std::vector &ryhmat) { for (unsigned int ryhma = 0; ryhma < ryhmat.size(); ++ryhma) { for (unsigned int hakkeri = 0; hakkeri < ryhmat.at(ryhma).hakkerit.size(); ++hakkeri) { delete ryhmat.at(ryhma).hakkerit.at(hakkeri); ryhmat.at(ryhma).hakkerit.at(hakkeri) = NULL; } ryhmat.at(ryhma).hakkerit.clear(); } ryhmat.clear(); } // Tulostaa pelitilanteen TILANNE-komentoa varten. void tulostaTilanne(const std::vector &ryhmat, std::ostream &out) { for (unsigned int ryhma = 0; ryhma < ryhmat.size(); ++ryhma) { if (ryhma != 0) { // Ryhmien väliin tyhjä rivi out << std::endl; } out << ryhmat.at(ryhma).nimi << std::endl; for (unsigned int hakkeri = 0; hakkeri < ryhmat.at(ryhma).hakkerit.size(); ++hakkeri) { ryhmat.at(ryhma).hakkerit.at(hakkeri)->tulostaTilanne(out); } } } // Tuottaa riippumattoman kopion pelitilanteesta, eli luo uudet hakkeri-oliot. void kopioiTilanne(Pelitilanne &uusi, const Pelitilanne &vanha) { // Yksinkertaiset kentät. uusi.asetukset = vanha.asetukset; uusi.vuoro = vanha.vuoro; uusi.lopetettu = vanha.lopetettu; uusi.ryhmat.clear(); // Käydään hakkerit läpi std::vector::const_iterator ryhma; std::vector::const_iterator hakkeri; for (ryhma = vanha.ryhmat.begin(); ryhma != vanha.ryhmat.end(); ++ryhma) { Hakkeriryhma uusiryhma(ryhma->nimi); for (hakkeri = ryhma->hakkerit.begin(); hakkeri != ryhma->hakkerit.end(); ++hakkeri) { Hakkeri *kopio = new Hakkeri(*(*hakkeri)); uusiryhma.hakkerit.push_back(kopio); } uusi.ryhmat.push_back(uusiryhma); } }