//input format:
        //pokemon/quick_move/charge_move/level/aIV/dIV/sIV
        //it's gonna work more efficient if all data would be entered as separate attributes
        //main purpose of using strings in attributes is easy input of my test values
        static void set_battle_options(string defender_string, string attacker_string)
        {
            string[] df = defender_string.Split('/');
            string[] at = attacker_string.Split('/');

            int defSpecies = 0;
            int atkSpecies = 0;

            //find defender's id
            for (int i = 1; i < pokemonLimit; i++)
            {
                if (pokemonTable.Rows[i][0].ToString() == df[0])
                {
                    defSpecies = i;
                }
            }

            //find attacker's id
            for (int i = 1; i < pokemonLimit; i++)
            {
                if (pokemonTable.Rows[i][0].ToString() == at[0])
                {
                    atkSpecies = i;
                }
            }

            defender.cpm =
                cp_mult.get_cpm_by_level(Convert.ToSingle(df[3], System.Globalization.CultureInfo.InvariantCulture));
            defender.attack  = Convert.ToInt32(pokemonTable.Rows[defSpecies][3]) + Convert.ToInt32(df[4]);
            defender.defense = Convert.ToInt32(pokemonTable.Rows[defSpecies][4]) + Convert.ToInt32(df[5]);
            defender.hp      = (int)Math.Floor((Convert.ToInt32(pokemonTable.Rows[defSpecies][5]) + Convert.ToInt32(df[6]))
                                               * defender.cpm)
                               * global_hp_rate; //(base_stamina + sIV) * cpm

            attacker.cpm =
                cp_mult.get_cpm_by_level(Convert.ToSingle(at[3], System.Globalization.CultureInfo.InvariantCulture));
            attacker.attack  = Convert.ToInt32(pokemonTable.Rows[atkSpecies][3]) + Convert.ToInt32(at[4]);
            attacker.defense = Convert.ToInt32(pokemonTable.Rows[atkSpecies][4]) + Convert.ToInt32(at[5]);
            attacker.hp      = (int)Math.Floor((Convert.ToInt32(pokemonTable.Rows[atkSpecies][5]) + Convert.ToInt32(at[6]))
                                               * attacker.cpm)
                               * global_hp_rate; //(base_stamina + sIV) * cpm

            QMove q = qMovesList.Find(x => x.name == at[1]);
            CMove c = cMovesList.Find(x => x.name == at[2]);

            q = qMovesList.Find(x => x.name == df[1]);
            c = cMovesList.Find(x => x.name == df[2]);

            defender.q_move = df[1];
            defender.c_move = df[2];

            defender.q_power   = q.power;
            defender.q_cd      = q.cd + 2;
            defender.enrg_gain = q.energy_gain;

            defender.c_power = c.power;
            defender.c_cd    = c.cd + 2;

            defender.start_dodge_q = defender.q_cd - q.dmg_start - user_reaction_constant;
            defender.end_dodge_q   = defender.start_dodge_q - 0.7F + user_reaction_constant;
            defender.start_dodge_c = defender.c_cd - c.dmg_start - user_reaction_constant;
            defender.end_dodge_c   = defender.start_dodge_c - 0.7F + user_reaction_constant;
            defender.enrg_cost     = c.energy_cost;

            string defence_type = pokemonTable.Rows[atkSpecies][1].ToString().Trim();
            bool   type_found   = false;

            for (int i = 1; i < typeLimit; i++)
            {
                if (typeTable.Rows[i][0].ToString() == defence_type)
                {
                    type_found = true;
                    //Type effectiveness
                    defender.q_mult = NumToDamageRatio(typeTable.Rows[i][q.type].ToString().Trim()) / 10000F;
                    defender.c_mult = NumToDamageRatio(typeTable.Rows[i][c.type].ToString().Trim()) / 10000F;
                    //STAB
                    string[] hitter_type = pokemonTable.Rows[defSpecies][1].ToString().Trim().Split('/');
                    foreach (string d in hitter_type)
                    {
                        if (q.type == d)
                        {
                            defender.q_mult *= 1.25F;
                        }
                    }
                    foreach (string d in hitter_type)
                    {
                        if (c.type == d)
                        {
                            defender.c_mult *= 1.25F;
                        }
                    }
                    break;
                }
            }

            if (!type_found)
            {
                throw new Exception("Type " + defence_type + " of " + attacker.pokemonName + " is not found");
            }

            attacker.q_move = at[1];
            attacker.c_move = at[2];

            attacker.q_power   = q.power;
            attacker.q_cd      = q.cd;
            attacker.enrg_gain = q.energy_gain;

            attacker.c_power   = c.power;
            attacker.c_cd      = c.cd;
            attacker.enrg_cost = c.energy_cost;

            defence_type = pokemonTable.Rows[defSpecies][1].ToString().Trim();
            type_found   = false;
            for (int i = 1; i < typeLimit; i++)
            {
                if (typeTable.Rows[i][0].ToString() == defence_type)
                {
                    type_found = true;
                    //Type effectiveness
                    attacker.q_mult = NumToDamageRatio(typeTable.Rows[i][q.type].ToString().Trim()) / 10000F;
                    attacker.c_mult = NumToDamageRatio(typeTable.Rows[i][c.type].ToString().Trim()) / 10000F;
                    //STAB
                    string[] hitter_type = pokemonTable.Rows[atkSpecies][1].ToString().Trim().Split('/');
                    foreach (string a in hitter_type)
                    {
                        if (q.type == a)
                        {
                            attacker.q_mult *= 1.25F;
                        }
                    }
                    foreach (string a in hitter_type)
                    {
                        if (c.type == a)
                        {
                            attacker.c_mult *= 1.25F;
                        }
                    }
                    break;
                }
            }

            if (!type_found)
            {
                throw new Exception("Type " + defence_type + " of " + defender.pokemonName + " is not found");
            }

            defender.q_damage =
                1 + (int)Math.Floor(0.5 * (float)defender.q_power * defender.q_mult
                                    * (float)defender.attack * defender.cpm
                                    / (float)attacker.defense / attacker.cpm);

            defender.c_damage =
                1 + (int)Math.Floor(0.5 * (float)defender.c_power * defender.c_mult
                                    * (float)defender.attack * defender.cpm
                                    / (float)attacker.defense / attacker.cpm);

            attacker.q_damage =
                1 + (int)Math.Floor(0.5 * (float)attacker.q_power * attacker.q_mult
                                    * (float)attacker.attack * attacker.cpm
                                    / (float)defender.defense / defender.cpm);

            attacker.c_damage =
                1 + (int)Math.Floor(0.5 * (float)attacker.c_power * attacker.c_mult
                                    * (float)attacker.attack * attacker.cpm
                                    / (float)defender.defense / defender.cpm);

            attacker.use_charges = true;
            if ((float)attacker.q_power * attacker.q_mult / attacker.q_cd >
                (float)attacker.c_power * attacker.c_mult / attacker.c_cd)
            {
                attacker.enrg_cost   = 900; //this will not let attacker to use charges
                attacker.c_move      = "Dont use charge";
                attacker.use_charges = false;
            }

            //to find situation when defender have low hp
            //and it's better to use quick move then charged
            defender.overkill_hp_point =
                attacker.q_damage * (int)Math.Floor(attacker.c_cd / attacker.q_cd);
        }
        static void Main(string[] args)
        {
            string           filePath    = Directory.GetCurrentDirectory() + "\\data2.1.xlsx";
            FileStream       stream      = File.Open(filePath, FileMode.Open, FileAccess.Read);
            IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream);
            DataSet          result      = excelReader.AsDataSet();

            typeTable    = result.Tables[0];
            pokemonTable = result.Tables[1];
            nTable       = result.Tables[2];
            sTable       = result.Tables[3];

            typeTable.Columns[0].ColumnName  = "type";
            typeTable.Columns[1].ColumnName  = "nor";
            typeTable.Columns[2].ColumnName  = "fir";
            typeTable.Columns[3].ColumnName  = "wat";
            typeTable.Columns[4].ColumnName  = "ele";
            typeTable.Columns[5].ColumnName  = "gra";
            typeTable.Columns[6].ColumnName  = "ice";
            typeTable.Columns[7].ColumnName  = "fig";
            typeTable.Columns[8].ColumnName  = "poi";
            typeTable.Columns[9].ColumnName  = "gro";
            typeTable.Columns[10].ColumnName = "fly";
            typeTable.Columns[11].ColumnName = "psy";
            typeTable.Columns[12].ColumnName = "bug";
            typeTable.Columns[13].ColumnName = "roc";
            typeTable.Columns[14].ColumnName = "gho";
            typeTable.Columns[15].ColumnName = "dra";
            typeTable.Columns[16].ColumnName = "dar";
            typeTable.Columns[17].ColumnName = "ste";
            typeTable.Columns[18].ColumnName = "fai";

            for (int i = 1; i < nLimit; i++)
            {
                QMove q = new QMove();
                q.name        = nTable.Rows[i][1].ToString().Trim();
                q.type        = nTable.Rows[i][2].ToString().Trim();
                q.power       = Convert.ToInt32(nTable.Rows[i][3]);
                q.cd          = Convert.ToSingle(nTable.Rows[i][4]);
                q.dmg_start   = Convert.ToSingle(nTable.Rows[i][5]);
                q.energy_gain = Convert.ToInt32(nTable.Rows[i][6]);
                qMovesList.Add(q);
            }

            for (int i = 1; i < sLimit; i++)
            {
                CMove c = new CMove();
                c.name        = sTable.Rows[i][1].ToString().Trim();
                c.type        = sTable.Rows[i][2].ToString().Trim();
                c.power       = Convert.ToInt32(sTable.Rows[i][3]);
                c.cd          = Convert.ToSingle(sTable.Rows[i][4]);
                c.dmg_start   = Convert.ToSingle(sTable.Rows[i][5]);
                c.energy_cost = Convert.ToInt32(sTable.Rows[i][6]);
                cMovesList.Add(c);
            }

            set_battle_options("Snorlax/Lick/Hyper Beam/27.5/13/15/14",
                               "Rhydon/Rock Smash/Stone Edge/24/14/14/7");

            Simulate_battles();

            filePath = Directory.GetCurrentDirectory() + "\\battle log.csv";

            File.WriteAllText(filePath, Battle_logger.battle_log);
            return;
        }