// Komentotulkin funktioiden toteutukset #include "merkkijonokasittely.hh" #include "komentotulkki.hh" #include "hakkeri.hh" #include "poikkeukset.hh" #include #include #include const int KOMENNOT_KOKO = 13; const Komento KOMENNOT[KOMENNOT_KOKO] = { {"KOODAA", SIIRTO, KOODAA, 1, 1}, {"PUSKUROI", SIIRTO, PUSKUROI, 1, 1}, {"REITITA", SIIRTO, REITITA, 2, -1}, {"RESETOI", SIIRTO, RESETOI, 0, 0}, {"HYOKKAA", SIIRTO, HYOKKAA, 1, 1}, {"TANKKAA", SIIRTO, TANKKAA, 1, 1}, {"TILANNE", TILANNE, EISIIRTOA, 0, 0}, {"TIEDOT", TIEDOT, EISIIRTOA, 0, 1}, {"ODOTA", SIIRTO, ODOTA, 0, 0}, {"APUA", OHJE, EISIIRTOA, 0, 0}, {"HELP", OHJE, EISIIRTOA, 0, 0}, {"LOPETA", LOPETUS, EISIIRTOA, 0, 0}, {"QUIT", LOPETUS, EISIIRTOA, 0, 0} }; // Toteuttaa rivin tai tulostaa virheen. Palauttaa true jos komento onnistui. bool toteutaRivi(const std::string &rivi, Pelitilanne &pelitilanne) { std::istringstream rivivirta(rivi); std::vector osat; lueOsat(rivivirta, osat); if (osat.size() < 1) { // Tyhjä rivi return false; } Komento komento = {"", EITOIMINTOA, EISIIRTOA, 0, 0}; if (!etsiKomento(osat.at(0), komento)) { std::cerr << "Virhe: Tuntematon komento." << std::endl; return false; } // Poistetaan komento, jätetään parametrit osat.erase(osat.begin()); int parametreja = osat.size(); // Signed-tyypiksi vertailua varten. if (komento.parametreja_enintaan != -1 && parametreja > komento.parametreja_enintaan) { std::cerr << "Virhe: Liikaa parametreja." << std::endl; return false; } if (komento.parametreja_vahintaan != -1 && parametreja < komento.parametreja_vahintaan) { std::cerr << "Virhe: Liian vähän parametreja." << std::endl; return false; } return toteutaKomento(komento, osat, pelitilanne); } // Palauttaa kehotteena käytettävän merkkijonon (mukaanlukien >-merkin). std::string haeKehote(Pelitilanne &pelitilanne) { return haeVuoro(pelitilanne)->haeNimi() + " > "; } // Tulkitsee komennon etsimällä vastaavan komennon vakiotaulukosta. // Palauttaa false jos vastaavuuksia ei ole tai on liikaa. bool etsiKomento(const std::string &annettu, Komento &tulos) { int vastaavuuksia = 0; // Käydään vakiotaulukko läpi for (int i = 0; i < KOMENNOT_KOKO; i++) { if (vertaaLyhennos(annettu, KOMENNOT[i].komento)) { tulos = KOMENNOT[i]; vastaavuuksia += 1; } } // Palautetaan true jos vastaavuuksia oli tasan yksi. return (vastaavuuksia == 1); } // Tulkitsee parametrit ja toteuttaa komennon. // Virheen sattuessa palauttaa false ja tulostaa virheen. bool toteutaKomento(const Komento &komento, const std::vector ¶metrit, Pelitilanne &pelitilanne) { Siirto siirto(EISIIRTOA); switch (komento.toiminto) { case SIIRTO: try { siirto = tulkitseSiirto(komento, parametrit, pelitilanne); } catch (Lukuvirhe &virhe) { std::cerr << "Virhe: " << virhe.what(); std::cerr << " ei ole tulkittavissa nollaa suurempana"; std::cerr << " positiivisena kokonaislukuna." << std::endl; return false; } catch (Hakkerivirhe &virhe) { std::cerr << "Virhe: Tuntematon hakkeri "; std::cerr << virhe.what() << "." << std::endl; return false; } // FIXME: Vaihe 2 tulostaKomento(komento, parametrit); break; case LOPETUS: pelitilanne.lopetettu = true; break; default: tulostaKomento(komento, parametrit); } return true; } // Tulkitsee siirroksi tiedetyn komennon parametrit // Siirto-rakenteeseen. Tuottaa poikkeuksen Lukuvirhe jos // parametreissa on virheitä. Siirto tulkitseSiirto(const Komento &komento, const std::vector ¶metrit, const Pelitilanne &pelitilanne) { Siirto siirto(komento.siirtotyyppi); // Ensimmäinen parametri switch (komento.siirtotyyppi) { case KOODAA: case PUSKUROI: case REITITA: case TANKKAA: if (parametrit.size() < 1) { // Parametreja pitäisi olla tarpeeksi, sillä komentotulkki // on jo tarkastanut tämän. Vältetään kuitenkin kaatuminen // virhetilanteessa. throw Lukuvirhe(); } siirto.maara = kokonaisluvuksi(parametrit.at(0)); break; case HYOKKAA: if (parametrit.size() < 1) { throw Lukuvirhe(); } siirto.kohde = etsiHakkeri(parametrit.at(0), pelitilanne); // FIXME: Vaihe 2 // if (siirto.kohde == NULL) { // // Tuntematon hakkeri // throw Hakkerivirhe(parametrit.at(0)); // } // FIXME break; default: // Komennolla ei parametreja break; } if (komento.siirtotyyppi == REITITA) { // Käsitellään reitityskohteet for (unsigned int i = 1; i < parametrit.size(); i++) { Hakkeri *hakkeri = etsiHakkeri(parametrit.at(i), pelitilanne); // FIXME: Vaihe 2 // if (hakkeri == NULL) { // // Tuntematon hakkeri // throw Hakkerivirhe(parametrit.at(i)); // } // FIXME siirto.reitityskohteet.push_back(hakkeri); } } return siirto; } // Tulostaa komennon 2. vaihepalautusta varten void tulostaKomento(const Komento &komento, const std::vector ¶metrit) { std::cout << "Komento: " << komento.komento << std::endl; for (unsigned int i = 0; i < parametrit.size(); ++i) { std::cout << "Parametri " << i + 1 << ": "; std::cout << parametrit.at(i) << std::endl; } }