← Back to team overview

widelands-dev team mailing list archive

Re: [Merge] lp:~widelands-dev/widelands/ai_persistent_data into lp:widelands

 

my turn now, see my comments to your comments...

Diff comments:

> 
> === modified file 'src/ai/defaultai.cc'
> --- src/ai/defaultai.cc	2015-08-28 19:09:59 +0000
> +++ src/ai/defaultai.cc	2015-10-05 17:29:41 +0000
> @@ -690,8 +733,98 @@
>  	taskDue[ScheduleTasks::kUnbuildableFCheck] = 1000;
>  	taskDue[ScheduleTasks::kWareReview] = 15 * 60 * 1000;
>  	taskDue[ScheduleTasks::kPrintStats] = 30 * 60 * 1000;
> -	taskDue[ScheduleTasks::kCountMilitaryVacant] = 10 * 60 * 1000;
> +	taskDue[ScheduleTasks::kCountMilitaryVacant] = 1 * 60 * 1000;
>  	taskDue[ScheduleTasks::kCheckEnemySites] = 10 * 60 * 1000;
> +
> +	// Here the AI persistent data either exists - then they are read
> +	// or does not exist, then they are created and saved
> +	const int16_t persistent_data_exists_ = player_->get_ai_data_int16(kPersistentData);
> +
> +	// 0 implies no saved data exits yet
> +	if (persistent_data_exists_ == 0) {
> +		player_->set_ai_data(static_cast<int16_t>(1), kPersistentData);
> +
> +		// these random values to make some small differences between players
> +		// they are immediately saved
> +		// these values are never changed
> +		ai_personality_military_loneliness_ = std::rand() % 5 * 30 - 60;
> +		player_->set_ai_data(ai_personality_military_loneliness_, kMilitLoneliness);
> +
> +		ai_personality_attack_margin_ = std::max(std::rand() % 20 - 5, 0);
> +		player_->set_ai_data(ai_personality_attack_margin_, kAttackMargin);
> +
> +		ai_personality_wood_difference_ = std::rand() % 40 - 20;
> +		player_->set_ai_data(ai_personality_wood_difference_, kWoodDiff);
> +
> +		ai_productionsites_ratio_ = std::rand() % 5 + 7;
> +		player_->set_ai_data(ai_productionsites_ratio_, kProdRatio);
> +
> +		ai_personality_early_militarysites = std::rand() % 20 + 20;
> +		player_->set_ai_data(ai_personality_early_militarysites, kEarlyMilitary);
> +
> +	} else {
> +		log (" %d: restoring saved AI data...\n", player_number());
> +
> +
> +		// Restoring data and doing some basic check
> +		ai_personality_military_loneliness_ = player_->get_ai_data_int16(kMilitLoneliness);
> +		if (ai_personality_military_loneliness_ < -60 || ai_personality_military_loneliness_ > 60) {
> +			log(" %d: unexpected value for ai_personality_military_loneliness_: %d\n",
> +			player_number(), ai_personality_military_loneliness_);
> +		}
> +
> +		ai_personality_attack_margin_ = player_->get_ai_data_uint32(kAttackMargin);
> +		if (ai_personality_attack_margin_ > 15) {
> +			log(" %d: unexpected value for ai_personality_attack_margin_: %d\n",
> +			player_number(), ai_personality_attack_margin_);
> +		}
> +
> +		ai_personality_wood_difference_ = player_->get_ai_data_int32(kWoodDiff);
> +		if (ai_personality_wood_difference_ < -20 || ai_personality_wood_difference_ > 19) {
> +			log(" %d: unexpected value for ai_personality_wood_difference_: %d\n",
> +			player_number(), ai_personality_wood_difference_);
> +		}
> +
> +		ai_productionsites_ratio_ = player_->get_ai_data_uint32(kProdRatio);
> +		if (ai_productionsites_ratio_< 5 || ai_productionsites_ratio_ > 15) {
> +			log(" %d: unexpected value for ai_productionsites_ratio_: %d\n",
> +			player_number(), ai_productionsites_ratio_);
> +		}
> +
> +		ai_personality_early_militarysites = player_->get_ai_data_uint32(kEarlyMilitary);
> +		if (ai_personality_early_militarysites< 20 || ai_personality_early_militarysites > 40) {
> +			log(" %d: unexpected value for ai_personality_early_msites: %d\n",
> +			player_number(), ai_personality_early_militarysites);
> +		}
> +

well if we have arrays m_ai_data_uint32[], m_ai_data_int32[] and m_ai_data_uint16[] I dont know how to make template function that would return value from array based on template data type....

I know template functions only in 'passively', so this one would look like this:

template <typename type> type get_ai_data(uint32_t position) {
//here based on type it would pick proper array - I dont know how to do it
return m_ai_data_???????[position];
}

Or can I pass type (int32_t, uint32_t ...) as an argument to the function, like:

get_ai_data(uint32_t position, type) {
if (type == int32_t) {
return m_ai_data_int32[position]
} else if (type == uint32_t) {
return m_ai_data_uint32[position]
} else ....
.....
....
}

this would do the trick...

> +		// Now some runtime values that are generated and saved during course of game
> +		last_attack_time_ = player_->get_ai_data_uint32(kLastAttack);
> +
> +		last_attacked_player_ = static_cast<uint16_t>(player_->get_ai_data_int16(kAttacker));
> +		if (last_attacked_player_ > 8) {
> +			log(" %d: unexpected value for last_attacked_player_: %d\n",
> +			player_number(), ai_personality_attack_margin_);
> +		}
> +
> +		colony_scan_area_ = player_->get_ai_data_uint32(kColonyScan);
> +		if (colony_scan_area_ > 50) {
> +			log(" %d: unexpected value for colony_scan_area_: %d\n",
> +			player_number(), colony_scan_area_);
> +		}
> +
> +		trees_around_cutters_ = player_->get_ai_data_uint32(kTreesAround);
> +
> +		least_military_score_ = player_->get_ai_data_int32(kLeastMilit);
> +		if (least_military_score_< 0 || least_military_score_ > 1000) {
> +			log(" %d: unexpected value for least_military_score_: %d\n",
> +			player_number(), least_military_score_);
> +		}
> +		target_military_score_ = player_->get_ai_data_int32(kTargetMilit);
> +		if (target_military_score_< least_military_score_ || target_military_score_ > 1000) {
> +			log(" %d: unexpected value for target_military_score_: %d\n",
> +			player_number(), target_military_score_);
> +		}
> +	}
>  }
>  
>  /**
> @@ -3531,61 +3577,97 @@
>  		return true;
>  	}
>  
> -	// doing nothing when failed count is too low
> -	if (site.no_resources_count < 4) {
> +	// to avoid problems with uint underflow, we discourage considerations below
> +	if (gametime < 10 * 60 * 1000) {
>  		return false;
>  	}
>  
> -	// dismantling when the failed count is too high
> -	if (site.no_resources_count > 12) {
> -		flags_to_be_removed.push_back(site.site->base_flag().get_position());
> -		if (connected_to_wh) {
> -			game().send_player_dismantle(*site.site);
> -		} else {
> -			game().send_player_bulldoze(*site.site);
> -		}
> -		site.bo->construction_decision_time_ = gametime;
> -		return true;
> -	}
> -
> -	// is output needed (compare stocked materials vs target values)
> -	check_building_necessity(*site.bo);
> -
> -	// if we have enough of mined materials on stock - do not upgrade (yet)
> -	if (site.bo->output_needed_ == ExtendedBool::kFalse) {
> +	// if mine is working, doing nothing
> +	if (site.no_resources_since_ > gametime - 5 * 60 * 1000) {
>  		return false;
>  	}
>  
>  	// Check whether building is enhanceable. If yes consider an upgrade.
>  	const BuildingIndex enhancement = site.site->descr().enhancement();
> -
> -	// if no enhancement is possible
> -	if (enhancement == INVALID_INDEX) {
> -		// will be destroyed when no_resource_count will overflow
> +	bool has_upgrade = false;
> +	if (enhancement != INVALID_INDEX) {
> +		if (player_->is_building_type_allowed(enhancement)) {
> +			has_upgrade = true;
> +		}
> +	}
> +
> +	// every type of mine has minimal number of mines that are to be preserved
> +	// (we will not dismantle even if there are no mineable resources left for this level of mine
> +	// and output is not needed)
> +	bool forcing_upgrade = false;
> +	const uint16_t minimal_mines_count = (site.bo->built_mat_producer_)?2:1;
> +	if (has_upgrade &&
> +		mines_per_type[site.bo->mines_].total_count() <= minimal_mines_count) {
> +		forcing_upgrade = true;
> +	}
> +
> +
> +	// dismantling a mine
> +	if (!has_upgrade) { // if no upgrade, now
> +		flags_to_be_removed.push_back(site.site->base_flag().get_position());
> +		if (connected_to_wh) {
> +			game().send_player_dismantle(*site.site);
> +		} else {
> +			game().send_player_bulldoze(*site.site);
> +		}
> +		site.bo->construction_decision_time_ = gametime;
> +		return true;
> +	// if having an upgrade, after half hour
> +	} else if (site.no_resources_since_ < gametime - 30 * 60 * 1000 && !forcing_upgrade) {
> +		flags_to_be_removed.push_back(site.site->base_flag().get_position());
> +		if (connected_to_wh) {
> +			game().send_player_dismantle(*site.site);
> +		} else {
> +			game().send_player_bulldoze(*site.site);
> +		}
> +		site.bo->construction_decision_time_ = gametime;
> +		return true;
> +	}
> +
> +	// if we are here, a mine is upgradeable
> +
> +	// if we don't need the output, and we have other buildings of the same type, the function returns
> +	// and building will be dismantled later.
> +	check_building_necessity(*site.bo, PerfEvaluation::kForDismantle, gametime);
> +	if (site.bo->max_needed_preciousness_ == 0 && !forcing_upgrade) {
>  		return false;
>  	}
>  
> +	// again similarly, no upgrading if not connected, other parts of AI will dismantle it,
> +	// or connect to a warehouse
>  	if (!connected_to_wh) {
> -		// no enhancement possible
> +		return false;
> +	}
> +
> +	// don't upgrade now if other mines of the same type are right now in construction
> +	if (mines_per_type[site.bo->mines_].in_construction > 0) {
>  		return false;
>  	}
>  
>  	bool changed = false;
> -	if (player_->is_building_type_allowed(enhancement)) {
> -		// first exclude possibility there are enhancements in construction or unoccupied_
> -		const BuildingDescr& bld = *tribe_->get_building_descr(enhancement);
> -		BuildingObserver& en_bo = get_building_observer(bld.name().c_str());
> -
> -		// if it is too soon for enhancement and making sure there are no unoccupied mines
> -		if (gametime - en_bo.construction_decision_time_ >= kBuildingMinInterval &&
> -		    en_bo.unoccupied_ + en_bo.cnt_under_construction_ == 0) {
> -
> -			// now verify that there are enough workers
> -			if (site.site->has_workers(enhancement, game())) {  // enhancing
> -				game().send_player_enhance_building(*site.site, enhancement);
> -				en_bo.construction_decision_time_ = gametime;
> -				changed = true;
> -			}
> +
> +	// first exclude possibility there are enhancements in construction or unoccupied_count_
> +	const BuildingDescr& bld = *tribe_->get_building_descr(enhancement);
> +	BuildingObserver& en_bo = get_building_observer(bld.name().c_str());
> +
> +	// if it is too soon for enhancement
> +	if (gametime - en_bo.construction_decision_time_ >= kBuildingMinInterval) {
> +		// now verify that there are enough workers
> +		if (site.site->has_workers(enhancement, game())) {  // enhancing

Now I am not sure what you mean. When we consider upgrade we allways check if we have workers for target building. So I presume that this will guarantee that newly upgraded building will have enough workers.
Of course I can imagine some corner cases, f.e. two buidlings needed the same workers being built/upgraded in the same time..

> +			game().send_player_enhance_building(*site.site, enhancement);
> +			if (site.bo->max_needed_preciousness_ == 0) {
> +				assert (mines_per_type[site.bo->mines_].total_count() <= minimal_mines_count);
> +			}
> +			if (mines_per_type[site.bo->mines_].total_count() > minimal_mines_count) {
> +				assert(site.bo->max_needed_preciousness_ > 0);
> +			}
> +			en_bo.construction_decision_time_ = gametime;
> +			changed = true;
>  		}
>  	}
>  


-- 
https://code.launchpad.net/~widelands-dev/widelands/ai_persistent_data/+merge/271853
Your team Widelands Developers is subscribed to branch lp:~widelands-dev/widelands/ai_persistent_data.


References