diff --git a/SimpleTUOLiveSim-x86.exe b/SimpleTUOLiveSim-x86.exe index f11e362c..3318410a 100644 Binary files a/SimpleTUOLiveSim-x86.exe and b/SimpleTUOLiveSim-x86.exe differ diff --git a/SimpleTUOLiveSim.exe b/SimpleTUOLiveSim.exe index 403f29a0..cec315cb 100644 Binary files a/SimpleTUOLiveSim.exe and b/SimpleTUOLiveSim.exe differ diff --git a/sim.cpp b/sim.cpp index 13169587..7eb04e61 100644 --- a/sim.cpp +++ b/sim.cpp @@ -3167,7 +3167,7 @@ int evaluate_skill(Field* fd,const Card* c , SkillSpec* ss) { // TODO optimize this int tvalue = ss->x; - + if(ss->card_id != 0)tvalue += 1*evaluate_card(fd,card_by_id_safe(fd->cards,ss->card_id)); tvalue += 10*(ss->id==Skill::flurry); tvalue += 10*(ss->id==Skill::jam); @@ -3242,8 +3242,8 @@ int evaluate_skill(Field* fd,const Card* c , SkillSpec* ss) int evaluate_card(Field* fd,const Card* cs) { int value = 0; - value += cs->m_health; - value += 2*cs->m_attack; + value += cs->m_health; + value += 2*cs->m_attack; for( auto ss : cs->m_skills) { value += evaluate_skill(fd,cs,&ss); } @@ -3254,8 +3254,8 @@ int evaluate_card(Field* fd,const Card* cs) int evaluate_cardstatus(Field* fd,CardStatus* cs) { int value = 0; - value += cs->m_hp; - value += 2*cs->attack_power(); + value += cs->m_hp; + value += 2*cs->attack_power(); value += cs->protected_value(); for( auto ss : cs->m_card->m_skills) { value += evaluate_skill(fd,cs->m_card,&ss); @@ -3354,14 +3354,18 @@ Results evaluate_sim_result(Field* fd, bool single_turn_both) { unsigned enemy_brawl_score = evaluate_brawl_score(fd, 1); unsigned max_score = max_possible_score[(size_t)OptimizationMode::brawl_defense]; - return {0, 0, 1, (points_score_type)(max_score - enemy_brawl_score)}; + if(enemy_brawl_score> max_score) + std::cerr << "WARNING: enemy_brawl_score > max_possible_brawl_score" << std::endl; + return {0, 0, 1, (points_score_type)safe_minus(max_score , enemy_brawl_score)}; } case OptimizationMode::war: return {0,0,1, (points_score_type) 20}; case OptimizationMode::war_defense: { unsigned enemy_war_score = evaluate_war_score(fd, 1); unsigned max_score = max_possible_score[(size_t)OptimizationMode::war_defense]; - return {0, 0, 1, (points_score_type)(max_score - enemy_war_score)}; + if(enemy_war_score> max_score) + std::cerr << "WARNING: enemy_war_score > max_possible_war_score" << std::endl; + return {0, 0, 1, (points_score_type)safe_minus(max_score , enemy_war_score)}; } #ifndef NQUEST case OptimizationMode::quest: return {0, 0, 1, (points_score_type)(fd->quest.must_win ? 0 : quest_score)}; diff --git a/tyrant_optimize.cpp b/tyrant_optimize.cpp index 8e2b8608..db0c771f 100644 --- a/tyrant_optimize.cpp +++ b/tyrant_optimize.cpp @@ -178,6 +178,14 @@ void init() eval_iter=8; eval_turn=8; requirement.num_cards.clear(); + for(unsigned i(0); i < Skill::num_skills;++i){ + auto s = static_cast(i); + x_skill_scale[s]=1.0; + n_skill_scale[s]=1.0; + c_skill_scale[s]=1.0; + } + hp_scale = 1.0; + atk_scale = 1.0; #ifndef NQUEST //quest = new Quest(); //TODO Quest bugged in Android now here #endif @@ -2329,6 +2337,49 @@ DeckResults run(int argc, const char** argv) opt_do_reorder = true; argIndex += 1; } + else if (strncmp(argv[argIndex], "scale-opts:", 11) == 0) { + std::string climb_opts_str(argv[argIndex] + 11); + boost::tokenizer> climb_opts{climb_opts_str, boost::char_delimiters_separator{false, ",", ""}}; + for (const auto & opt : climb_opts) + { + const auto dot_pos = opt.find("."); + const auto slash_pos = opt.find("/"); + const bool has_value = (dot_pos != std::string::npos); + if(slash_pos == std::string::npos) + throw std::runtime_error("scale-opts:" + opt + " requires an argument"); + const std::string & opt_type = has_value ? opt.substr(0, dot_pos) : ""; + const std::string opt_name{has_value ? opt.substr(dot_pos + 1,slash_pos-dot_pos-1) : opt.substr(0,slash_pos)}; + const std::string opt_value{ opt.substr(slash_pos + 1) }; + if ((opt_name == "hp") ) + { + hp_scale = atof(opt_value.c_str()); + } + else if ((opt_name == "atk")) + { + atk_scale = atof(opt_value.c_str()); + } + else if (opt_name == "x") + { + x_skill_scale[skill_name_to_id(opt_type)] = atof(opt_value.c_str()); + } + else if (opt_name == "n") + { + n_skill_scale[skill_name_to_id(opt_type)] = atof(opt_value.c_str()); + } + else if (opt_name == "c") + { + c_skill_scale[skill_name_to_id(opt_type)] = atof(opt_value.c_str()); + } + else + { + std::cerr << "Error: Unknown scale option " << opt_name << " of " << opt_type; + if (has_value) + { std::cerr << " (value is: " << opt_value << ")"; } + std::cerr << std::endl; + exit(1); + } + } + } // climbing options else if (strncmp(argv[argIndex], "climb-opts:", 11) == 0) { diff --git a/tyrant_optimize.h b/tyrant_optimize.h index 70e47f00..4ffa326a 100644 --- a/tyrant_optimize.h +++ b/tyrant_optimize.h @@ -24,6 +24,7 @@ struct Requirement #else #define EXTERN extern #endif + namespace tuo { EXTERN Cards all_cards; EXTERN unsigned opt_num_threads; @@ -61,6 +62,11 @@ namespace tuo { EXTERN unsigned eval_iter; EXTERN unsigned eval_turn; EXTERN Requirement requirement; + EXTERN double hp_scale; + EXTERN double atk_scale; + EXTERN std::map x_skill_scale; + EXTERN std::map n_skill_scale; + EXTERN std::map c_skill_scale; #ifndef NQUEST EXTERN Quest quest; #endif diff --git a/xml.cpp b/xml.cpp index 401cb856..38014d2c 100644 --- a/xml.cpp +++ b/xml.cpp @@ -12,6 +12,7 @@ #include "cards.h" #include "deck.h" #include "tyrant.h" +#include "tyrant_optimize.h" //---------------------- $20 cards.xml parsing --------------------------------- // Sets: 1 enclave; 2 nexus; 3 blight; 4 purity; 5 homeworld; // 6 phobos; 7 phobos aftermath; 8 awakening @@ -152,6 +153,7 @@ bool parse_file(const std::string & filename, std::vector& buffer, xml_doc //------------------------------------------------------------------------------ void parse_card_node(Cards& all_cards, Card* card, xml_node<>* card_node) { + double eps = 1e-4; xml_node<>* id_node(card_node->first_node("id")); xml_node<>* card_id_node = card_node->first_node("card_id"); assert(id_node || card_id_node); @@ -171,8 +173,15 @@ void parse_card_node(Cards& all_cards, Card* card, xml_node<>* card_node) if (name_node) { card->m_name = name_node->value(); } if (level_node) { card->m_level = atoi(level_node->value()); } if (fusion_level_node) { card->m_fusion_level = atoi(fusion_level_node->value()); } - if (attack_node) { card->m_attack = atoi(attack_node->value()); } - if (health_node) { card->m_health = atoi(health_node->value()); } + if (attack_node) { card->m_attack = atoi(attack_node->value()); + if(abs(1-atk_scale)>eps) + card->m_attack = ceil(card->m_attack/(atk_scale)); +} + if (health_node) { card->m_health = atoi(health_node->value()); + if(abs(1-hp_scale)>eps) + card->m_health = ceil(card->m_health/(hp_scale)); + + } if (cost_node) { card->m_delay = atoi(cost_node->value()); } if (id_node) { @@ -314,6 +323,16 @@ void parse_card_node(Cards& all_cards, Card* card, xml_node<>* card_node) auto s2 = skill_target_skill(skill_node, "s2"); bool all = skill_node->first_attribute("all"); auto card_id = node_value(skill_node, "card_id", 0); + //scaling + if(abs(1-x_skill_scale[Skill::no_skill]*x_skill_scale[skill_id==Skill::enhance?s:skill_id])>eps) + x = ceil(x/(x_skill_scale[Skill::no_skill]*x_skill_scale[skill_id==Skill::enhance?s:skill_id])); + if(abs(1-n_skill_scale[Skill::no_skill]*n_skill_scale[skill_id])>eps) + n = ceil(n/(n_skill_scale[Skill::no_skill]*n_skill_scale[skill_id])); + if(abs(1-c_skill_scale[Skill::no_skill]*c_skill_scale[skill_id])>eps) + c = ceil(c/(c_skill_scale[Skill::no_skill]*c_skill_scale[skill_id])); + + + card->add_skill(trig, skill_id, x, y, n, c, s, s2, all, card_id); } all_cards.all_cards.push_back(card);