Базовый Pokedex в C ++

Недавно я начал изучать C ++ около недели назад, и я немного продвинулся вперед. В честь релиза Pokemon Go я решил сделать Pokedex с оригинальным 151 покемоном. Пока у меня их около 120, и это работает ОТЛИЧНО! (Слава Богу). Я считаю, что мой код может быть намного эффективнее и работать лучше. Я, вероятно, тоже использую плохие практики. Если я, пожалуйста, не стесняйтесь сказать мне, и если вы найдете проблему, скажите мне!

Pokemon.h:

#pragma once
#include <string>


class Pokemon {
public:
    std::string type;
    double weight, height;
    std::string Gender;
    int evoLevel;
    bool finalEvo;
    int dexNum;
    std::string name;

    Pokemon(std::string name2, std::string type2, double weight2, double height2, std::string Gender2, int evoLevel2, bool finalEvo2, int dexNum2);
    Pokemon();
}; 

Pokemon.cpp:

#include "Pokemon.h"

Pokemon::Pokemon(std::string name2, std::string type2, double weight2,  double height2, std::string Gender2, int evoLevel2, bool finalEvo2, int dexNum2) {
    name = name2;
    type = type2;
    weight = weight2;
    height = height2;
    Gender = Gender2;
    evoLevel = evoLevel2;
    finalEvo = finalEvo2;
    dexNum = dexNum2;
}

//Default constructer
Pokemon::Pokemon() {
    name = "Pichario";
    type = "Death";
    weight = 10;
    height = 12;
    Gender = "Male and Female";
    evoLevel = 1;
    finalEvo = true;
    dexNum = 999;
}

main.cpp:

#include <iostream>
#include <string>
#include <vector>
#include "Pokemon.h"


int main() {
    //Create Pokemon objects
    Pokemon bulbasaur("Bulbasaur", "Grass and Poison", 15.2, 28, "Male and Female", 1, false, 1);
    Pokemon ivysaur("Ivysaur", "Grass and Poison", 28.7, 39, "Male and Female", 2, false, 2);
    Pokemon venusaur("Venusaur", "Grass and Poison", 220.5, 79, "Male and Female", 3, true, 3);

    Pokemon charmander("Charmander", "Fire", 18.7, 24, "Male and Female", 1, false, 4);
    Pokemon charmeleon("Charmeleon", "Fire", 41.9, 44, "Male and Female", 2, false, 5);
    Pokemon charizard("Charizard", "Fire and Flying", 199.5, 67, "Male and Female", 3, true, 6);

    Pokemon squirtle("Squirtle", "Water", 19.8, 20, "Male and Female", 1, false, 7);
    Pokemon wartortle("Wartortle", "Water", 49.6, 39, "Male and Female", 2, false, 8);
    Pokemon blastoise("Blastoise", "Water", 188.5, 63, "Male and Female", 3, true, 9);

    Pokemon caterpie("Caterpie", "Bug", 6.4, 12, "Male and Female", 1, false, 10);
    Pokemon metapod("Metapod", "Bug", 21.8, 28, "Male and Female", 2, false, 11);
    Pokemon butterfree("Butterfree", "Bug and Flying", 70.5, 43, "Male and Female", 3, true, 12);

    Pokemon weedle("Weedle", "Bug and Poison", 7.1, 12, "Male and Female", 1, false, 13);
    Pokemon kakuna("Kakuna", "Bug and Poison", 22, 24, "Male and Female", 2, false, 14);
    Pokemon beedrill("Beedrill", "Bug and Poison", 65, 39, "Male and Female", 3, true, 15);

    Pokemon pidgey("Pidgey", "Normal and Flying", 4, 12, "Male and Female", 1, false, 16);
    Pokemon pidgeotto("Pidgeotto", "Normal and Flying", 66.1, 43, "Male and Female", 2, false, 17);
    Pokemon pidgeot("Pidgeot", "Normal and Flying", 87.1, 59, "Male and Female", 3, true, 18);

    Pokemon rattata("Rattata", "Normal", 7.7, 12, "Male and Female", 1, false, 19);
    Pokemon raticate("Raticate", "Normal", 40.8, 28, "Male and Female", 2, true, 20);

    Pokemon spearow("Spearow", "Normal and Flying", 4.4, 12, "Male and Female", 1, false, 21);
    Pokemon fearow("Fearow", "Normal and Flying", 83.8, 47, "Male and Female", 2, true, 22);

    Pokemon ekans("Ekans", "Poison", 15.2, 79, "Male and Female", 1, false, 23);
    Pokemon arbok("Arbok", "Poison", 143.3, 138, "Male and Female", 2, true, 24);

    Pokemon pikachu("Pikachu", "Electric", 13.2, 16, "Male and Female", 1, false, 25);
    Pokemon raichu("Raichu", "Electric", 66.1, 31, "Male and Female", 2, true, 26);

    Pokemon sandshrew("Sandshrew", "Ground", 26.5, 24, "Male and Female", 1, false, 27);
    Pokemon sandslash("Sandslash", "Ground", 65, 39, "Male and Female", 2, true, 28);

    Pokemon nidoranf("Nidoran female", "Poison", 15.4, 16, "Female", 1, false, 29);
    Pokemon nidorina("Nidorina", "Poison", 44.1, 31, "Female", 2, false, 30);
    Pokemon nidoqueen("Nidoqueen", "Poison and Ground", 132.3, 51, "Female", 3, true, 31);

    Pokemon nidoranm("Nidoran Male", "Poison", 19.8, 20, "Male", 1, false, 32);
    Pokemon nidorino("Nidorino", "Poison", 43, 35, "Male", 2, false, 33);
    Pokemon nidoking("Nidoking", "Poison and Ground", 136.7, 55, "Male", 3, true, 34);

    Pokemon clefairy("Clefairy", "Fairy", 16.5, 24, "Male and Female", 1, false, 35);
    Pokemon clefable("Clefable", "Fairy", 88.2, 51, "Male and Female", 2, true, 36);

    Pokemon vulpix("Vulpix", "Fire", 21.8, 24, "Male and Female", 1, false, 37);
    Pokemon ninetales("Ninetales", "Fire", 43.9, 43, "Male and Female", 2, true, 38);

    Pokemon jigglypuff("Jigglypuff", "Normal and Fairy", 12.1, 20, "Male and Female", 1, false, 39);
    Pokemon wigglytuff("Wigglytuff", "Normal and Fairy", 26.5, 39, "Male and Female", 2, true, 40);

    Pokemon zubat("Zubat", "Poison and Flying", 16.5, 31, "Male and Female", 1, false, 41);
    Pokemon golbat("Golbat", "Poison and Flying", 121.3, 63, "Male and Female", 2, true, 42);

    Pokemon oddish("Oddish", "Grass and Poison", 11.9, 20, "Male and Female", 1, false, 43);
    Pokemon gloom("Gloom", "Grass and Poison", 19, 31, "Male and Female", 2, false, 44);
    Pokemon vileplume("Vileplume", "Grass and Poison", 41, 47, "Male and Female", 3, true, 45);

    Pokemon paras("Paras", "Bug and Grass", 11.9, 12, "Male and Female", 1, false, 46);
    Pokemon parasect("Parasect", "Bug and Grass", 65, 39, "Male and Female", 2, true, 47);

    Pokemon venonat("Venonat", "Bug and Poison", 66.1, 39, "Male and Female", 1, false, 48);
    Pokemon venomoth("Venomoth", "Bug and Poison", 27.6, 59, "Male and Female", 2, true, 49);

    Pokemon diglett("Diglett", "Ground", 1.8, 8, "Male and Female", 1, false, 50);
    Pokemon dugtrio("Dugtrio", "Ground", 73.4, 28, "Male and Female", 2, true, 51);

    Pokemon meowth("Meowth", "Normal", 9.3, 16, "Male and Female", 1, false, 52);
    Pokemon persian("Persian", "Normal", 70.5, 39, "Male and Female", 2, true, 53);

    Pokemon psyduck("Psyduck", "Water", 43.2, 31, "Male and Female", 1, false, 54);
    Pokemon golduck("Golduck", "Water", 168.9, 67, "Male and Female", 2, true, 55);

    Pokemon mankey("Mankey", "Fighting", 61.7, 20, "Male and Female", 1, false, 56);
    Pokemon primeape("Primeape", "Fighting", 70.5, 39, "Male and Female", 2, true, 57);

    Pokemon growlithe("Growlithe", "Fire", 41.9, 28, "Male and Female", 1, false, 58);
    Pokemon arcanine("Arcanine", "Fire", 341.7, 63, "Male and Female", 2, true, 59);

    Pokemon poliwag("Poliwag", "Water", 27.3, 24, "Male and Female", 1, false, 60);
    Pokemon poliwhirl("Poliwhirl", "Water", 44.1, 39, "Male and Female", 2, false, 61);
    Pokemon poliwrath("Poliwrath", "Water and Fighting", 119, 51, "Male and Female", 3, true, 62);

    Pokemon abra("Abra", "Psychic", 43, 35, "Male and Female", 1, false, 63);
    Pokemon kadabra("Kadabra", "Psychic", 124.6, 51, "Male and Female", 2, false, 64);
    Pokemon alakazam("Alakazam", "Psychic", 105.8, 59, "Male and Female", 3, true, 65);

    Pokemon machop("Machop", "Fighting", 43, 31, "Male and Female", 1, false, 66);
    Pokemon machoke("Machoke", "Fighting", 155.4, 59, "Male and Female", 2, false, 67);
    Pokemon machamp("Machamp", "Fighting", 286.6, 63, "Male and Female", 3, true, 68);

    Pokemon bellsprout("Bellsprout", "Grass and Poison", 8.8, 28, "Male and Female", 1, false, 69);
    Pokemon weepinbell("Weepinbell", "Grass and Poison", 14.1, 39, "Male and Female", 2, false, 70);
    Pokemon victreebel("Victreebel", "Grass and Poison", 34.2, 67, "Male and Female", 3, true, 71);

    Pokemon tentacool("Tentacool", "Water and Poison", 100.3, 35, "Male and Female", 1, false, 72);
    Pokemon tentacruel("Tentacruel", "Water and Poison", 121.3, 63, "Male and Female", 2, true, 73);

    Pokemon geodude("Geodude", "Rock and Ground", 44.1, 16, "Male and Female", 1, false, 74);
    Pokemon graveler("Graveler", "Rock and Ground", 231.5, 39, "Male and Female", 2, false, 75);
    Pokemon golem("Golem", "Rock and Ground", 661.4, 31, "Male and Female", 3, true, 76);

    Pokemon ponyta("Ponyta", "Fire", 66.1, 39, "Male and Female", 1, false, 77);
    Pokemon rapidash("Rapidash", "Fire", 209.4, 67, "Male and Female", 2, true, 78);

    Pokemon slowpoke("Slowpoke", "Water and Psychic", 79.4, 47, "Male and Female", 1, false, 79);
    Pokemon slowbro("Slowbro", "Water and Psychic", 173.1, 63, "Male and Female", 2, true, 80);

    Pokemon magnemite("Magnemite", "Electric and Steel", 13.2, 12, "Unknown", 1, false, 81);
    Pokemon magneton("Magneton", "Electric and Steel", 132.3, 39, "Unknown", 2, true, 82);

    Pokemon farfetchd("Farfetch'd", "Normal and Flying", 33.1, 31, "Male and Female", 1, true, 83);

    Pokemon doduo("Doduo", "Normal and Flying", 86.4, 45, "Male and Female", 1, false, 84);
    Pokemon dodrio("Dodrio", "Normal and Flying", 187.8, 71, "Male and Female", 2, true, 85);

    Pokemon seel("Seel", "Water", 198.4, 43, "Male and Female", 1, false, 86);
    Pokemon dewgong("Dewgong", "Water and Ice", 264.6, 67, "Male and Female", 2, true, 87);

    Pokemon grimer("Grimer", "Poison", 66.1, 35, "Male and Female", 1, false, 88);
    Pokemon muk("Muk", "Poison", 66.1, 47, "Male and Female", 2, true, 89);

    Pokemon shellder("Shellder", "Water", 8.8, 12, "Male and Female", 1, false, 90);
    Pokemon cloyster("Cloyster", "Water and Ice", 292.1, 59, "Male and Female", 2, true, 91);

    Pokemon gastly("Gastly", "Ghost and Poison", 0.2, 51, "Male and Female", 1, false, 92);
    Pokemon haunter("Haunter", "Ghost and Poison", 0.2, 63, "Male and Female", 2, false, 93);
    Pokemon gangar("Gengar", "Ghost and Poison", 89.3, 59, "Male and Female", 3, true, 94);

    Pokemon onix("Onix", "Rock and Ground", 463, 346, "Male and Female", 1, true, 95);

    Pokemon drowzee("Drowzee", "Psychic", 71.4, 39, "Male and Female", 1, false, 96);
    Pokemon hypno("Hypno", "Psychic", 166.7, 63, "Male and Female", 2, true, 97);

    Pokemon krabby("Krabby", "Water", 14.3, 16, "Male and Female", 1, false, 98);
    Pokemon kingler("Kingler", "Water", 132.3, 51, "Male and Female", 2, true, 99);

    Pokemon voltorb("Voltorb", "Electric", 22.9, 20, "Unknown", 1, false, 100);
    Pokemon electrode("Electrode", "Electric", 146.8, 47, "Male and Female", 2, true, 101);

    Pokemon exeggcute("Exeggcute", "Grass and Psychic", 5.5, 16, "Male and Female", 1, false, 102);
    Pokemon exeggutor("Exeggutor", "Grass and Psychic", 264.6, 79, "Male and Female", 2, true, 103);

    Pokemon cubone("Cubone", "Ground", 14.3, 16, "Male and Female", 1, false, 104);
    Pokemon marowak("Marowak", "Ground", 99.2, 39, "Male and Female", 2, true, 105);

    Pokemon hitmonlee("Hitmonlee", "Fighting", 109.8, 59, "Male", 1, true, 106);
    Pokemon hitmonchan("Hitmonchan", "Fighting", 110.7, 55, "Male", 1, true, 107);

    Pokemon lickitung("Lickitung", "Normal", 144.4, 47, "Male and Female", 1, true, 108);

    Pokemon koffing("Koffing", "Poison", 2.2, 24, "Male and Female", 1, false, 109);
    Pokemon weezing("Weezing", "Poison", 20.9, 47, "Male and Female", 2, true, 110);

    Pokemon rhyhorn("Rhyhorn", "Ground and Rock", 253.5, 39, "Male and Female", 1, false, 111);
    Pokemon rhydon("Rhydon", "Ground and Rock", 264.6, 75, "Male and Female", 2, true, 112);

    Pokemon chansey("Chansey", "Normal", 76.3, 43, "Female", 1, true, 113);

    Pokemon tangela("Tangela", "Grass", 77.2, 39, "Male and Female", 1, true, 114);

    Pokemon kangaskhan("Kangaskhan", "Normal", 176.4, 87, "Female", 1, true, 115);

    Pokemon horsea("Horsea", "Water", 17.6, 16, "Male and Gender", 1, false, 116);
    Pokemon seadra("Seadra", "Water", 55.1, 47, "Male and Female", 2, true, 117);

    Pokemon goldeen("Goldeen", "Water", 33.1, 24, "Male and Female", 1, false, 118);
    Pokemon seaking("Seaking", "Water", 86, 51, "Male and Female", 2, true, 119);

    Pokemon staryu("Staryu", "Water", 76.1, 31, "Unknown", 1, false, 120);
    Pokemon starmie("Starmie", "Water and Psychic", 176.4, 43, "Unknown", 2, true, 121);

    Pokemon mrmime("Mr. Mime", "Fairy and Psychic", 120, 51, "Male and Female", 1, true, 122);

    Pokemon scyther("Scyther", "Bug and Flying", 123.5, 59, "Male and Female", 1, true, 123);
    //Create a vector with all of the pokemon
    std::vector<Pokemon> pokemon = { bulbasaur, ivysaur, venusaur,
        charmander, charmeleon, charizard,
        squirtle, wartortle, blastoise,
        caterpie, metapod, butterfree,
        weedle, kakuna, beedrill,
        pidgey, pidgeotto, pidgeot,
        rattata, raticate,
        spearow, fearow,
        ekans, arbok,
        pikachu, raichu,
        sandshrew, sandslash,
        nidoranf, nidorina, nidoqueen,
        nidoranm, nidorino, nidoking,
        clefairy, clefable,
        vulpix, ninetales,
        jigglypuff, wigglytuff,
        zubat, golbat,
        oddish, gloom, vileplume,
        paras, parasect,
        meowth, persian,
        psyduck, golduck,
        mankey, primeape,
        growlithe, arcanine,
        poliwag, poliwhirl, poliwrath,
        abra, kadabra, alakazam,
        machop, machoke, machamp,
        bellsprout, weepinbell, victreebel,
        tentacool, tentacruel,
        geodude, graveler, golem,
        ponyta, rapidash,
        slowpoke, slowbro,
        magnemite, magneton,
        farfetchd,
        doduo, dodrio,
        seel, dewgong,
        grimer, muk,
        shellder, cloyster,
        gastly, haunter, gangar,
        onix,
        drowzee, hypno,
        krabby, kingler,
        voltorb, electrode,
        exeggcute, exeggutor,
        cubone, marowak,
        hitmonlee, hitmonchan,
        lickitung,
        koffing, weezing,
        rhyhorn, rhydon,
        chansey,
        tangela,
        kangaskhan,
        horsea, seadra,
        goldeen, seaking,
        staryu, starmie,
        mrmime,
        scyther };

    //Ask the user which way they would like to search
    std::cout << "Welcome to the Pokedex! We have the first " << pokemon.size() + 4 << " pokemon indexed!" << std::endl;
    std::cout << "Would you like to search by name, number, or type?" << std::endl;
    std::string input = "";
    std::cin >> input;
    //make input uppercase
    for (int p = 0; p < input.size(); p++) {
        input[p] = toupper(input[p]);
    }
    //check for input
    if (input == "NAME") {
        //Ask for name
        std::cout << "Enter the name of the pokemon" << std::endl;
        std::cin >> input;
        bool found = false;
        //make name lowercase
        for (int j = 0; j < input.length(); j++) {
            input[j] = tolower(input[j]);
        }
        //make first letter uppercase
        input[0] = toupper(input[0]);

        //loop through vector
        for (int i = 0; i < pokemon.size(); i++) {
            //check if input is the same as a pokemon name
            if (input == pokemon.at(i).name) {
                std::cout << "The pokemon " << pokemon.at(i).name << " has been found!" << std::endl;
                std::cout << pokemon.at(i).name << " is a " << pokemon.at(i).type << " type." << std::endl;
                std::cout << pokemon.at(i).name << "'s weight and height are: " << pokemon.at(i).weight << " lbs and " << pokemon.at(i).height << " inches." << std::endl;
                std::cout << pokemon.at(i).name << "'s gender is " << pokemon.at(i).Gender << std::endl;

                if (pokemon.at(i).finalEvo) {
                    std::cout << pokemon.at(i).name << " is the final evolution in its line." << std::endl;

                    if (pokemon.at(i).evoLevel > 1) {
                        std::cout << pokemon.at(i).name << " is what " << pokemon.at(i - 1).name << " evolves into." << std::endl;
                    } 
                    else {
                        std::cout << pokemon.at(i).name << " is the only pokemon in its evolution line" << std::endl;
                    }

                }
                else {
                    std::cout << pokemon.at(i).name << " evolves into " << pokemon.at(i + 1).name << std::endl;
                    if (pokemon.at(i).evoLevel > 1) {
                        std::cout << pokemon.at(i).name << " is what " << pokemon.at(i - 1).name << " evolves into." << std::endl;
                    }
                }
                found = true;
                break;
            }
        }
        //what to do if invalid pokemon is entered
        if (found == false) {
            std::cerr << "Pokemon not found!" << std::endl;
        }
    }
    else if (input == "TYPE") {
        //get input
        std::string input = "";
        std::cout << "Enter the type you would like!" << std::endl;
        std::cin >> input;
        //make input lowercase
        for (int k = 0; k < input.size(); k++) {
            input[k] = tolower(input[k]);
        }
        //make first letter uppercase
        input[0] = toupper(input[0]);

        //loop through vector
        for (int i = 0; i < pokemon.size(); i++) {
            //see if pokemon type contains the input
            if (pokemon.at(i).type.find(input) != std::string::npos) {
                std::cout << pokemon.at(i).name << " is a " << pokemon.at(i).type << " type!" << std::endl;
            }
        }
    }
    else {
        std::cout << "Enter the number of the pokemon" << std::endl;
        int input = 1;
        std::cin >> input;
        bool found = false;

        std::cout << input << std::endl;

        for (int i = 0; i < pokemon.size(); i++) {
            //see if pokemon has same num as input
            if (input == pokemon.at(i).dexNum) {
                std::cout << "The pokemon " << pokemon.at(i).name << " has been found!" << std::endl;
                std::cout << pokemon.at(i).name << " is a " << pokemon.at(i).type << " type." << std::endl;
                std::cout << pokemon.at(i).name << "'s weight and height are: " << pokemon.at(i).weight << " lbs and " << pokemon.at(i).height << " inches." << std::endl;
                std::cout << pokemon.at(i).name << "'s gender is " << pokemon.at(i).Gender << std::endl;

                if (pokemon.at(i).finalEvo) {
                    std::cout << pokemon.at(i).name << " is the final evolution in its line." << std::endl;
                    if (pokemon.at(i).evoLevel > 1) {
                        std::cout << pokemon.at(i).name << " is what " << pokemon.at(i - 1).name << " evolves into." << std::endl;
                    }
                    else {
                        std::cout << pokemon.at(i).name << " is the only pokemon in its evolution line" << std::endl;
                    }

                }
                else {
                    std::cout << pokemon.at(i).name << " evolves into " << pokemon.at(i + 1).name << std::endl;
                    if (pokemon.at(i).evoLevel > 1) {
                        std::cout << pokemon.at(i).name << " is what " << pokemon.at(i - 1).name << " evolves into." << std::endl;
                    }
                }
                found = true;
                break;
            }
        }
        //Say pokemon wasnt 
        if (found == false) {
            std::cerr << "Pokemon not found!" << std::endl;
        }

    }

    return 0;
}
102 голоса | спросил Dylan Black 19 J000000Tuesday16 2016, 18:58:42

6 ответов


141

Ваш класс Pokemon (декларация)

class Pokemon {
public:
    std::string type;
    double weight, height;
    std::string Gender;
    int evoLevel;
    bool finalEvo;
    int dexNum;
    std::string name;

    Pokemon(std::string name2, std::string type2, double weight2, double height2, std::string Gender2, int evoLevel2, bool finalEvo2, int dexNum2);
    Pokemon();
}; 

Вот несколько вещей, которые приходят в голову. Прежде всего, все ваши поля являются общедоступными. Это означает, что вы хотите struct, а не class. В C ++ они отличаются только видимостью по умолчанию. class по умолчанию private, struct по умолчанию является public. Итак, давайте изменим это:

struct Pokemon {

Далее мы должны отключить Pokemon(). Таким образом, нельзя случайно создать покемона:

    Pokemon() = delete;

Обратите внимание, что это необязательно, поскольку любой конструктор не даст компилятору предоставить по умолчанию.

Улучшенные типы

В другом конструкторе мы немного изменим имя аргументов и их типов:

    Pokemon(Name name, Type type, Weight weight, Height height, Gender gender, 
            EvoLevel level, bool finalEvolution, PokedexID pid);

Подождите. Какого черта все эти типы? Прежде всего, они являются излишними . Во-вторых, они следуют основным рекомендациям C ++ , Вы не хотите использовать имя покемонов для своего пола случайно, не так ли?

Обработка типа Покемона

Это приводит нас к перечислениям. Type и Gender являются идеальными кандидатами для них:

enum class BasicType {
   Fire,
   Grass,
   Water,
   Electro,
   Poison,
   ...
};

Так как Pokemon может иметь несколько типов, мы используем другой тип Type для их объединения:

class Type{ 
    Type(BasicType main);
    Type(BasicType main, BasicType sub);

    void addSubType(BasicType);
    bool hasType(BasicType) const;
};

Я не уверен, будет ли у Pokemon когда-либо более двух типов, но, как заметил @Eeevee, они упорядочены.

Если вы хотите, вы можете определить синтаксический сахар на этом с помощью перегрузки operator|:

Type operator|(BasicType main, BasicType sub) { return Type(main, sub); }
Type operator|(Type a,         BasicType sub) { return a.addSubtype(sub); }

Оператор позволяет использовать Type::Fire | Type::Poison . Обратите внимание, что это, вероятно, снова перебор. Однако это не позволит вам использовать

Pokemon("Bulbasaur", "Gras and Poison", ...);

Вместо этого, если вы используете

Pokemon("Bulbasaur", Type::Gras | Type::Poison, ...);

в итоге вы получаете ошибку компилятора, а не разочарованный пользователь, который не может найти «Bulbasaur» по типу «Трава». Для тестирования может понадобиться оператор operator&:

Type operator&(Type      a, BasicType b) { return a.hasType(b); }
Type operator&(BasicType a, Type      b) { return b.hasType(a); }

Это очень просто, но он выполняет свою работу. Как вы фактически сохраняете типы, остается как упражнение, но не слишком сложно. Обратите внимание, что вы можете добавить произвольные методы в Type или функции, которые принимают Type в качестве аргумента, поэтому есть достаточно места для дополнительных безумных научных экспериментов .

Гендерное исследование

Мы можем сделать то же самое для пола, хотя здесь немного легче, так как есть только некоторые и, следовательно, нам не нужен трюк operator| или addSubType:

enum class Gender {
   Male,
   Female,
   Both,
   Unknown
};

Опять же, это не позволяет вам писать

Pokemon("Bulbasaur", Type::Grass | Type::Poison, 15.2, 28, "Apache helicopter", ...);

Объединяя все вместе

Для других типов, для простоты, говорим

typedef std::string Name;
typedef double Weight;
typedef double Height;
typedef unsigned int EvoLevel;
typedef unsigned int PokedexID;

Следовательно, мы получим следующую структуру:

struct Pokemon {
    Pokemon() = delete;
    Pokemon(Name name, Type type, Weight weight, Height height, Gender gender, 
            EvoLevel level, bool isFinalEvolution, PokedexID pid);

  Name name;
    Type type;
    Weight weight;
    Height height;
    Gender gender;
    EvoLevel evolutionLevel;
    bool isFinalEvolution;
    PokedexID pid;
};

Обратите внимание, что вопреки вашему коду все переменные здесь строго следуйте за camelCase, тогда как ваш код содержит Gender. Также обратите внимание, что в объектах class члены обычно имеют префикс m_, суффикс с _ или следуют другому соглашению об именах. Поскольку вы хотите использовать его без инкапсуляции, и все общедоступные (например, pokemon.type) префиксы или суффиксы сделают ваш код более трудным для чтения здесь.

«Но подождите», , я здесь говорю. "Теперь аргументы имеют то же имя, что и мои члены!" . И это хорошо. Если кто-то использует Pokemon::Pokemon(...) в своей программе, они хотят, чтобы их IDE отображали имена аргументов красивым способом, без , как 2-суффикс.

Что приводит нас к реализации вашего конструктора:

// your code
#include "Pokemon.h"

Pokemon::Pokemon(std::string name2, std::string type2, double weight2,  double height2, std::string Gender2, int evoLevel2, bool finalEvo2, int dexNum2) {
    name = name2;
    type = type2;
    weight = weight2;
    height = height2;
    Gender = Gender2;
    evoLevel = evoLevel2;
    finalEvo = finalEvo2;
    dexNum = dexNum2;
}

Ага. Прежде всего, если у вас есть аргумент, который имеет то же имя, что и член, вы можете использовать this->[membername], чтобы различать, например.

this->name = name2;

Однако мы находимся в конструкторе. Поэтому мы можем инициализировать наши значения . Обратите внимание, что это не обязательно для POD . , но некоторые из ваших членов являются классами, например Name (это std::string). Это сохраняет копию. В итоге получим:

Pokemon(Name name, Type type, Weight weight, Height height, Gender gender, 
        EvoLevel level, bool isFinalEvolution, PokedexID pid) 
 : name(std::move(name)), type(type), weight(weight), height(height), gender(gender),
   evolutionLevel(evolutionLevel), isFinalEvolution(isFinalEvolution), pid(pid) {
}

Обратите внимание, что это означает, что мы действительно не need определили конструктор, мы могли бы просто использовать наш обычный struct

Pokemon bulbasaur = { "Bulbasaur", ... };

Но в зависимости от ваших типов это немного более подвержено ошибкам.

Выход и DRY

Вы не следуете принципу Don't-Repeat-Yourself. Ваш код содержит возможности для печати Pokemon дважды . Это плохо, так как изменения с одной стороны, вероятно, также должны выполняться с другой, но теряться. Вместо этого укажите оператора, если вы хотите использовать std::cout:

std::ostream & operator<<(std::ostream & out, const Pokemon & pokemon) {
    out << pokemon.name << " is a " << pokemon.type << " type.\n"
        << pokemon.name << "'s weight and height are: " 
        << pokemon.weight << " lbs and " << pokemon.height << " inches.\n";
        << pokemon.name << "'s gender is " << pokemon.gender << "\n";

    if (pokemon.isFinalEvolution) {
        out << pokemon.name << " is the final evolution in its line.\n";
    }
    ...
    return out;
}

Обратите внимание, что для этого также нужен оператор operator<<

База данных

Итак, вот мой самый лучший питомец с вашим кодом. Ваш main:

Pokemon bulbasaur("Bulbasaur", "Grass and Poison", 15.2, 28, "Male and Female", 1, false, 1);
Pokemon ivysaur("Ivysaur", "Grass and Poison", 28.7, 39, "Male and Female", 2, false, 2);
Pokemon venusaur("Venusaur", "Grass and Poison", 220.5, 79, "Male and Female", 3, true, 3);
...

Есть две вещи, которые я не люблю здесь. Прежде всего, вы используете только имена «bulbasaur» или «ivysaur» один раз позже, в std::vector<Pokemon> pokemon, поэтому вы загрязняете локальное пространство имен. Вместо этого заполните ваш вектор напрямую:

std::vector<Pokemon> pokedex = { 
    Pokemon("Bulbasaur", Type::Grass | Type::Poison, 15.2, 28, Gender::Both, 1, false, 1),
    Pokemon("Ivysaur", Type::Grass | Type::Poison, 28.7, 39, Gender::Both, 2, false, 2),
    ...
};

Но это не то, как вы должны это делать.

  

До сих пор у меня их около 120, и это работает ОТЛИЧНО!

Вы вводите все их вручную. Это безумно. Скажем, вы перепутали фунты Пикачу, или вы хотите добавить еще Покемона позже. Вам всегда нужно будет отредактировать свою программу и скомпилировать ее. Плохо. Это склонность к ошибкам. Иошибки жесткие (компиляция) для исправления.

Вместо этого, все ваши Pokemon во внешнем файле. Затем вы можете легко прочитать из этого файла в свой вектор (если вы пишете оператор потоковой передачи):

while(pokeFile >> pokemon){
    pokedex.push_back(pokemon);
}

Это все, что необходимо, помимо получения данных Pokemon во внешний файл и записи istream& operator>>(istream&, Pokemon&). Вместо main, который увеличивается с каждым поколением Pokemon, вам нужно только изменить файл Pokemon.txt. Вы можете даже перевести его на другие языки (например, «Bisasam», «Bisaknosp», «Bisaflor», ...), но это немного далеко на данный момент.

Другие вещи

Если вам не нужен индекс, используйте цикл for на основе диапазона вместо оператора operator[]. Кроме того, вы несколько раз затеналировали переменную input несколько раз. Не. Кроме того, старайтесь выполнять меньшие функции, ваш main был слишком большим.

Если вы используете C ++ 11, чаще используйте цикл for на основе диапазона.

Также, если вы не хотите изменять переменную, используйте const. Ваш std::vector<Pokemon> является идеальным кандидатом для этого, поскольку вы не хотите впоследствии его изменять.

Относительно ostream& operator<<(ostream&,const Pokemon&), мы потеряли способность печатать предыдущую /следующую эволюцию, но это по дизайну, поскольку для этого вам нужен доступ в целом Pokedex (и есть возможно, несколько эволюций для одного покемонов, глядя на вас, Эве). Это то, о чем вы, вероятно, должны думать немного больше. Вместо этого вы можете сохранить идентификатор предыдущего Pokemon или использовать недопустимый идентификатор, если он не существует. Но это остается как упражнение.

И последнее, но не менее важное: если вы должны написать продуктивный Pokedex, используйте библиотеки, которые позволят вам использовать функции базы данных (например), например SQLite, и /или абстрагировать запросы за классом, например

class Pokedex {
public:
    template<class F>
    Result find_one(F && f){
        return from_it(std::find(internal_list.begin(), internal_list.end(), f));
    }
    ResultList find_all(F && f){
        ResultList results;
        std::copy_if(internal_list.begin(), internal_list.end(), ...);
        return results;
    }
};

зависит от того, насколько сложны ваши запросы.

Ваш «новый» основной

Итак, следуя приведенным выше замечаниям, я несколько переписал ваш main. Покемон исчез из клетки вашего кода, вместо этого они перемещаются в другом файле Pokeball .

#include <iostream>
#include <string>
#include <vector>
#include "Pokemon.h"

typedef std::vector<Pokemon> Pokedex;

std::string to_pokecase(const std::string & str){
    // excercise, should make "Bulbasaur" from "buLbaSAUR".
}

bool print_pokemon_by_name(const Pokedex & pokedex){
    //Ask for name
    std::cout << "Enter the name of the pokemon" << std::endl;
    Name input_name;
    std::cin >> input_name;

    input_name = to_pokecase(input_name);

    for (auto & thePokemon : pokedex) {
        if (input_name == thePokemon.name) {
            std::cout << "The pokemon " << thePokemon.name << " has been found!\n" 
                      << thePokemon<< std::endl;
            return true;
        }
    }

    std::cerr << "Pokemon not found!" << std::endl;
    return false;
}

bool print_pokemons_by_type(const Pokedex & pokedex){
    // exercise
}

bool print_pokemon_by_number(const Pokedex & pokedex){
    // exercise
}

std::vector<Pokemon> read_pokemons_from_file(const std::string & fileName){
    // exercise
}

int main() {
    const auto pokedex = read_pokemons_from_file("Pokemon.txt");

    //Ask the user which way they would like to search
    std::cout << "Welcome to the Pokedex! We have the first " << pokedex.size() + 4 << " pokemon indexed!" << std::endl;
    std::cout << "Would you like to search by name, number, or type?" << std::endl;
    std::string input = "";
    std::cin >> input;

    //make input uppercase
    for (auto & p : input) {
        p = toupper(p);
    }

    if (input == "NAME") {
        print_pokemon_by_name(pokedex);
    }
    else if (input == "TYPE") {
        print_pokemons_by_type(pokedex);
    }
    else if (input == "NUMBER") {
        print_pokemon_by_number(pokedex);    
    } else {
        // handle invalid input
    }    
    return 0;
}

Как вы можете видеть, новый main намного меньше. Его можно прочитать на экране без прокрутки. Все функции, которые отличаются друг от друга, были извлечены в другие функции, которые сами по себе немного малы.

Есть несколько вещей, которые могут быть дополнительно реорганизованы ипереписан, но это осталось как упражнение.

Приложение: спецификация

Благодаря всем комментариям к этому обзору и всем спецификациям Pokemon, которые я пропустил в нескольких версиях этого обзора, я думаю, это хорошее место, чтобы добавить две вещи.

Прежде всего, прежде чем реализовать свой класс, задайте себе больше вопросов: можете ли вы легко тестировать типы (покемон)? Вы часто испытываете их? Должно ли это быть в его собственной функции? Вы проверяете имена? Нужно ли нормализовать имена? Больше чем единожды? Нужно ли заказывать типы покемонов?

Во-вторых, отразите ответы на эти вопросы в вашем коде или, если ответ был отрицательным, в ваших комментариях /документации. Кроме того, попробуйте использовать код более высокого уровня. Главное, это уже довольно высокий уровень, и я могу полностью изменить Pokedex и Pokemon и никогда не нужно касаться main вообще .

В любом случае, удача ловить их всех! Пусть ваш Pokedex будет полным.

ответил Zeta 19 J000000Tuesday16 2016, 21:13:59
30

Просто несколько вещей, которые кажутся им, могут быть открыты для улучшения.

Эволюция

Вместо того, чтобы иметь логическое значение, чтобы указать, является ли конкретный тип последним этапом в его эволюции, я думаю, что у меня будет поле «evolvesTo», чтобы дать dexNum того типа, к которому этот развивается и (возможно) использует специальное значение, такое как -1, чтобы указать, что оно не превращается ни в что другое. Вероятно, я также добавлю аналогичное поле для «evolvesFrom». По крайней мере, по моему мнению, кодирование информации напрямую намного проще, чем в зависимости от порядка записей.

База данных

Вместо того, чтобы иметь все эти необработанные данные, встроенные в программу, я бы, по крайней мере, подумал о переносе их во внешний файл, который вы затем читали при запуске программы. Не обязательно быть чем-то сложным или особенным - например, я бы рассмотрел что-то вроде одного покемона на строку, с вкладкой между каждым полем.

Конструктор

Обычно предпочтительнее инициализировать члены с помощью списка инициализаторов членов, а не назначать их в теле конструктора. Когда вы это сделаете, компилятор может определить, какой параметр и является членом, поэтому вам не нужно добавлять 2 к каждому имени параметра, чтобы они были прямыми:

Pokemon::Pokemon(std::string name, std::string type, double weight,  double height, std::string Gender, int evoLevel, bool finalEvo, int dexNum) 
    : name(name),
      type(type),
      weight(weight),
      height(height),
      Gender(Gender),
      evoLevel(evoLevel),
      finalEvo(finalEvo),
      dexNum(dexNum),
{}

Поиск

У вас есть довольно много примеров поиска в вашей базе данных, чтобы найти Pokemon на основе различных атрибутов. Почти все это можно реализовать с помощью std::find_if, чтобы выполнить фактический поиск.

auto p = std::find_if(pokemon.begin(), pokemon.end(),
    [&](int dexNum) { return dexNum == input; });

if (p == pokemon.end())
    std::cout << "Sorry, I can't find that Pokemon.\n";
else {
    std::cout << "The Pokemon: " << p->name << " has been found.\n";
    std::cout << p->name << " is a " << p->type << " type Pokemon\n";
    // ...
}

Если вы имели дело с гораздо большим количеством данных (десятки тысяч или десятков миллионов единиц), есть более эффективные способы поиска данных, например, создание индекса для каждого поля, которое вы хотите искать. Если вы хотите поэкспериментировать с одной из них, Boost Multi Index библиотека предоставляет этот тип функциональности.

С другой стороны, если вам приходится иметь дело с этим объемом данных, вы, вероятно, захотите использовать какую-либо базу данных (например, SQLite ).

ответил Jerry Coffin 19 J000000Tuesday16 2016, 20:47:13
7

Самая большая проблема, которую я вижу с вашим кодом, - Eevee.

Эве имеет разветвленную эволюцию.

Мое исправление состоит в том, чтобы иметь вектор с числом dex эволюций (И если вы хотите получить фантазию, это будет структура с деталями эволюции. (Тип, уровень и число dex)

ответил Catprog 20 J000000Wednesday16 2016, 06:28:26
7

Я расскажу о очень специфической проблеме с вашим кодом, так как @Zeta провела очень хороший глобальный обзор вашего кода. Я также собираюсь предположить, что вы пойдете на более ориентированный на базу данных проект.

Эволюция

Ваш код не очень хорошо справляется с эволюцией. В частности, Eeveelutions нарушены. В Покере существует взаимосвязь «один ко многим» в отношении эволюции. То есть, pokà mon может иметь возможность развиваться в два или более pokà © mons, но данный pokà mon - это эволюция, по крайней мере, одного уникального pokà © mon.

Такие отношения один-ко-многим могут быть реализованы с использованием std::vector или std::list, но большинство из этих контейнеров будет содержать либо 0, либо 1 элемент , сделать его контрпродуктивным. Фактически, как и в случае с генералом I, только Эве использует эту разветвленную эволюционную систему.

Вот что я предлагаю: выньте данные эволюции из struct Pokemon и поместите его в свой собственный выделенный struct.

enum class EvolutionMethod {
    Level,
    Stone,
    Trade
};

enum class EvolutionStone {
    Fire,
    Water,
    Lightning,
    Grass,
    Moon
};

struct Evolution {
    unsigned int sourcePokemonId;
    unsigned int targetPokemonId;
    EvolutionMethod method;
    union {
        int level;
        EvolutionStone stone;
    };
};

std::multimap<unsigned int, Evolution> evolutions;

/* Populate the map, either directly or by reading a file */

union может использоваться для сохранения нескольких байтов, потому что Evolution::level и Evolution::stone являются взаимоисключающими.

multimap хорош для отображения «один ко многим». Вы можете заменить его на unordered_multimap, если используете C ++ 11.

Сохранение исходного кода в struct и поскольку ключ карты может казаться излишним, но он полезен при обратном поиске: например, при поиске каждого pokà © mon, развивающегося с огнем камень.

ответил Nax 21 J000000Thursday16 2016, 10:08:05
5

Итак, ты хочешь быть мастером покемонов? У вас есть навыки, чтобы сделать Pokedex?

Pokedex - это сложная техника. В результате этот обзор кода будет более сфокусирован на концептуальном подходе; как ваши данные относятся к другим данным и лучшим способам представления этих данных. Он не будет охватывать детали реализации, такие как то, будут ли фактические данные получены из текстовых файлов, баз данных, жестко запрограммированы и т. Д. Также не будет рассмотрено, как лучше всего организовать код в разных файлах. Итак ... здесь мы идем ...

Есть много вещей, о которых нужно подумать при создании Pokedex, даже такого простого, как то, что у вас есть. Поэтому сначала мы рассмотрим проектные решения.

1: Типы

Есть (в настоящее время) восемнадцать типов, которые могут быть Pokemon. Эти типы хорошо определены и дискретны; т. е. нет градиентов между типами, а набор доступных типов не изменяется динамически. В результате типы лучше всего представлены в виде перечисления.

enum class Type {
  Fire,
  Water,
  Grass,
  Electric,
  Fighting,
  Flying,
  Poison,
  Ground,
  Ice,
  Psychic,
  Ghost,
  Dragon,
  Fairy,
  Steel,
  Dark,
  Rock,
  Normal,
  Bug
};

Также нет корреляций между типами и интегральными значениями, поэтому порядок в перечислении не имеет значения.

Кроме того, вам понадобится функция где-то, которая берет тип и возвращает строку, будучи удобочитаемой.

std::string TypeToStr(Type type) {
  switch(type) {
  case Type::Fire:
    return "Fire";
  case Type::Water:
    return "Water";
  ...
  default:
    return "ERROR"; //should never get here if you accounted for all types
}

2: Элементы

Нам понадобится это позже. Поверьте мне

enum class Item {
  WaterStone,
  FireStone,
  Thunderstone,
  MoonStone,
  LeafStone
};

И метод получения удобочитаемого имени

std::string ItemToStr(Item item) {
  switch(item) {
  case Item::WaterStone:
    return "Water Stone";
  case Item::FireStone:
    return "Fire Stone";
  case Item::Thunderstone:
    return "Thunderstone";
  ...
  default:
    return "ERROR"; //Should not get here if you accounted for all items
  }
}

3: Эволюция

Большинство людей знают, что Покемон может развиваться. Многие из этих эволюций являются линейными (Крабби может развиваться только в Kingler). Но некоторые из них имеют разветвленные эволюции. Eevee, в Поколении I, может развиться в Jolteon, Flareon или Vaporeon. Так что делать? Мы могли бы хранить три фрагмента эволюционных данных три раза для каждого Покемона, хотя Эве является единственным в Gen I, который будет использовать более одного. Я считаю, что это расточительно. Мы могли бы хранить данные эволюции в векторе. Это лучше, но есть умное и простое решение: вернуться назад.

Покемон не может развиваться из более чем одной базовой формы. Позвольте мне повторить: нет двух покемонов, которые эволюционируют в одно и то же. Таким образом, мы можем хранить данные эволюции по одному по Покемону и вместо данных эволюции, говорящих: «Это то, что вам нужно сделать, чтобы перейти к следующему этапу, и это следующий этап», он скажет «Вот как на предыдущем этапе попал в эту форму, и это то, что было на предыдущем этапе ».

Итак, каковы данные эволюции? Ну, в Поколении I есть три способа развития Покемона: Уровень вверх (на определенном уровне), Торговля и Камень (с определенным камнем). Итак, у нас есть метод, данные и форма. Это то, что может выглядеть в коде:

class Evo {
public:
  Evo(int from) :
    fromID(from)
  {}

  virtual std::string ToStr() = 0;

  int fromID;
};

class EvoTrade : public Evo {
public:
  EvoTrade(int from) :
    Evo(from)
  {}

  virtual std::string ToStr() {
    return " by trading.";
  }
};

class EvoLevel : public Evo {
public:
  EvoLevel(int from, int lvl) :
    Evo(from),
    level(lvl)
  {}

  virtual std::string ToStr() {
    return " by reaching level " + std::to_string(level) + ".";
  }

  int level;
};

class EvoStone : public Evo {
public:
  EvoStone(int from, Item evo_stone) :
    Evo(from),
    stone(evo_stone)
  {}

  virtual std::string ToStr() {
    return " by using a " + ItemToStr(stone) + ".";
  }

  Item stone;
};

5: Гендеры

У Покемонов разные шансы быть мужчинами или женщинами. Есть также некоторые, которые не имеют пола (многие легенды, а также Ditto, а некоторые, чей дизайн просто требует гендерного агностицизма).

6: Pokemon

Наконец мы можем получить здесь. Хорошо.

Pokemon может иметь один или два типа (в dex, в битве есть случаи, когда они могут иметь три). Есть несколько способов справиться с этим. Вы могли бы содержать одну переменную типа и, по существу, использовать битовое поле, как уже упоминалось ранее, но поскольку у Pokemon может быть только до двух типов, я думаю, что это слишком много. Вместо этого я бы рекомендовал просто иметь две переменные типа. Конечно,это представляет дополнительную загадку.

Если у нашего Pokemon есть две переменные типа, что мы будем делать, если у Pokemon есть только один тип? Скажем, это Voltorb, который, как вы знаете, только Electric. Вторая переменная типа должна содержать допустимое значение, так что мы будем делать? В нашем перечислении мы могли бы ввести девятнадцатый тип, который служит для обозначения типа None, но есть и другой способ. Так, как это делают игры (последний раз я проверил), для обеих переменных заданы одинаковые переменные. Итак, это подход, которым мы будем следовать.

class Pokemon {
public:
  std::string name;
  double height, weight; //Metric
  double gender_ratio; //Chance of Male, -1 means genderless
  Evo* evo_data;
  int dex_num;
  Type type_1;
  Type type_2;
  std::function<std::vector<std::string>(int)> get_next_stages;

  Pokemon(int dex_number, const std::string& new_name, double new_height, double new_weight, double male_chance) :
    name(new_name),
    height(new_height),
    weight(new_weight),
    gender_ratio(male_chance),
    dex_num(dex_number),
    evo_data(nullptr)
  {}
  ~Pokemon() {
    delete evo_data;
  }

  std::string ToStr() {
    auto evolves_to = get_next_stages(dex_num);
    std::string answer = 
      "Number: " + std::to_string(dex_num) +
      "\nName: " + name;

      if(type_1 == type_2)
        answer += "\nType: " + TypeToStr(type_1);
      else
        answer += "\nTypes: " + TypeToStr(type_1) + '/' + TypeToStr(type_2);

      answer += "\nHeight: " + std::to_string(height) + 'm' +
      "\nWeight: " + std::to_string(weight) + "kg" +
      "\nMale/Female: ";

      if(gender_ratio < 0)
      {
        answer += "Genderless";
      }
      else
      {
        answer += std::to_string(gender_ratio) + '/';
        answer += std::to_string(1 - gender_ratio);
      }

      for(auto str : evolves_to)
        answer += '\n' + str;

      return answer;
  }

  //These next methods are used to chain setups; they are much more
  //flexible than defining constructors for every possible
  //combination of data setup. And we need to go through methods
  //to set this data up (at least, some of the data) because there
  //are some things we want to do with them

  Pokemon& set_types(Type type) {
    type_1 = type_2 = type;
    return *this;
  }
  Pokemon& set_types(Type type_a, Type type_b) {
    type_1 = type_a;
    type_2 = type_b;
    return *this;
  }

  Pokemon& set_evo_data(Evo* evo) {
    evo_data = evo;
    return *this;
  }
};

7: Заключительные заметки

Итак, как выглядит метод цепочки? Рассмотрим класс Покемона выше.

Pokemon p1(1, "Bulbasaur", 0.7, 6.9, 87.5)
  .set_types(Type::Grass, Type::Poison);
Pokemon p2(5, "Charmeleon", 1.1, 19, 87.5)
  .set_types(Type::Fire)
  .set_evo_data(new EvoLevel(4, 16));

А как насчет печати этих данных?

//Assuming a collection of Pokemon
std::vector<Pokemon> mons;
//Fill out the data
//...

auto next_stages = [&mons](const int id){
  std::vector<std::string> answer;

  auto found = std::find_if(mons.begin(), mons.end(), [id](const Pokemon& mon){
    return mon.evo_data != nullptr && mon.evo_data->fromID == id;
  });

  if(found != mons.end())
  {
    answer.push_back("Evolves into " + found->name + found->evo_data->toStr());
  }

  return answer;
};

//While filling out the data, put this function as the get_next_stages function
ответил Altainia 24 J000000Sunday16 2016, 01:00:17
2

V хороший код. Плюс точки для

  • не делать using namespace std
  • с использованием стандартных контейнеров

Комментарии

Будьте в согласии с именами вещей, членами класса Pokemon type, Gender.

Я бы настоятельно рекомендовал использовать специальное соглашение об именах для переменных-членов. Некоторым это не нравится, но я знаю. поэтому используйте m_gender или gender_, это делает код более понятным в функциях, вы знаете, какие данные вы манипулируете

Я не думаю, что у вас должен быть конструктор по умолчанию. Его бессмысленный и не нужен

Разбить код на функциональные куски, LoadPokemons, PrintPoke, PromptUser, ....

Используйте карту, а не вектор. Это позволяет осуществлять прямой поиск, а не линейный поиск

Обратите внимание, что вы повторяете код для строки upper-> ниже и наоборот. Выполняйте функции для этого.

Будущая идея. Загрузите данные pokemon из файла, а не компилируйте в программу.

ответил pm100 19 J000000Tuesday16 2016, 20:49:17

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132