Feature #1521 ยป 0100-ai-default-Remove-trailing-spaces.patch
ai/default/aiguard.h | ||
---|---|---|
/**********************************************************************
|
||
/***********************************************************************
|
||
Freeciv - Copyright (C) 2002 - The Freeciv Project
|
||
This program is free software; you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License as published by
|
ai/default/daiair.c | ||
---|---|---|
/* Cost of our unit */
|
||
unit_cost = unit_build_shield_cost_base(punit);
|
||
/* This is to say "wait, ill unit will get better!" */
|
||
unit_cost = unit_cost * unit_type_get(punit)->hp / punit->hp;
|
||
unit_cost = unit_cost * unit_type_get(punit)->hp / punit->hp;
|
||
/* Determine cost of enemy units */
|
||
victim_cost = stack_cost(punit, pdefender);
|
||
... | ... | |
profit = kill_desire(victim_cost, unit_attack, unit_cost, victim_defense, 1)
|
||
- SHIELD_WEIGHTING + 2 * TRADE_WEIGHTING;
|
||
if (profit > 0) {
|
||
profit = military_amortize(unit_owner(punit),
|
||
profit = military_amortize(unit_owner(punit),
|
||
game_city_by_number(punit->homecity),
|
||
profit, sortie_time, balanced_cost);
|
||
log_debug("%s at (%d, %d) is a worthy target with profit " ADV_WANT_PRINTF,
|
||
... | ... | |
continue;
|
||
}
|
||
if (has_handicap(pplayer, H_FOG)
|
||
if (has_handicap(pplayer, H_FOG)
|
||
&& !map_is_known_and_seen(ptile, pplayer, V_MAIN)) {
|
||
/* The tile is fogged */
|
||
continue;
|
||
... | ... | |
}
|
||
} else {
|
||
try to attack something
|
||
}
|
||
}
|
||
TODO: Distant target selection, support for fuel > 2
|
||
**********************************************************************/
|
||
void dai_manage_airunit(struct ai_type *ait, struct player *pplayer,
|
||
... | ... | |
if (find_something_to_bomb(ait, nmap, punit, &path, &dst_tile) > 0) {
|
||
/* Found target, coordinates are in punit's goto_dest.
|
||
* TODO: separate attacking into a function, check for the best
|
||
* TODO: separate attacking into a function, check for the best
|
||
* tile to attack from */
|
||
fc_assert_ret(path != NULL && dst_tile != NULL);
|
||
if (!adv_follow_path(punit, path, dst_tile)) {
|
||
... | ... | |
}
|
||
pf_path_destroy(path);
|
||
} else {
|
||
log_debug("%s cannot find anything to kill and is staying put",
|
||
log_debug("%s cannot find anything to kill and is staying put",
|
||
unit_rule_name(punit));
|
||
def_ai_unit_data(punit, ait)->done = TRUE;
|
||
unit_activity_handling(punit, ACTIVITY_IDLE, ACTION_NONE);
|
ai/default/daidata.c | ||
---|---|---|
/* We are tracking a unit if punit->server.ai->cur_pos is not NULL. If we
|
||
* are not tracking, start tracking by setting cur_pos. If we are,
|
||
* fill prev_pos with previous cur_pos. This way we get the
|
||
* fill prev_pos with previous cur_pos. This way we get the
|
||
* necessary coordinates to calculate a probable trajectory. */
|
||
players_iterate_alive(aplayer) {
|
||
if (aplayer == pplayer) {
|
||
... | ... | |
****************************************************************************/
|
||
void dai_adjust_policies(struct ai_type *ait, struct player *pplayer)
|
||
{
|
||
bool needs_back_rearrange = FALSE;
|
||
bool needs_back_rearrange = FALSE;
|
||
struct adv_data *adv;
|
||
adv = adv_data_get(pplayer, NULL);
|
ai/default/daidiplomat.c | ||
---|---|---|
* previously used one. This is important for diplomacy. - Per */
|
||
#define DIPLO_DEFENSE_WANT 3000
|
||
static bool is_city_surrounded_by_our_spies(struct player *pplayer,
|
||
static bool is_city_surrounded_by_our_spies(struct player *pplayer,
|
||
struct city *pcity);
|
||
static void find_city_to_diplomat(struct player *pplayer, struct unit *punit,
|
||
... | ... | |
struct unit_type *ut = best_role_unit(pcity, UTYF_DIPLOMAT);
|
||
if (ut) {
|
||
log_base(LOG_DIPLOMAT_BUILD,
|
||
log_base(LOG_DIPLOMAT_BUILD,
|
||
"A defensive diplomat will be built in city %s.",
|
||
city_name_get(pcity));
|
||
choice->want = 16000; /* diplomat more important than soldiers */
|
||
... | ... | |
return;
|
||
}
|
||
want = military_amortize(pplayer, pcity, want, time_to_dest,
|
||
want = military_amortize(pplayer, pcity, want, time_to_dest,
|
||
utype_build_shield_cost(pcity, NULL, ut));
|
||
if (!player_has_embassy(pplayer, city_owner(acity))
|
||
... | ... | |
if (aplayer == pplayer || is_barbarian(aplayer)
|
||
|| (pplayers_allied(pplayer, aplayer) && has_embassy)) {
|
||
continue;
|
||
continue;
|
||
}
|
||
incite_cost = city_incite_cost(pplayer, acity);
|
||
... | ... | |
struct city *ctarget = NULL;
|
||
struct city *pcity = tile_city(unit_tile(punit));
|
||
if (pcity
|
||
if (pcity
|
||
&& count_diplomats_on_tile(pcity->tile) == 1
|
||
&& def_ai_city_data(pcity, ait)->urgency > 0) {
|
||
/* Danger and we are only diplomat present - stay. */
|
||
... | ... | |
Will try to bribe a ship on the coast as well as land stuff.
|
||
******************************************************************************/
|
||
static bool dai_diplomat_bribe_nearby(struct ai_type *ait,
|
||
struct player *pplayer,
|
||
struct player *pplayer,
|
||
struct unit *punit, struct pf_map *pfm)
|
||
{
|
||
int gold_avail, expenses;
|
||
... | ... | |
bribee_tile = mapstep(nmap, pos.tile, DIR_REVERSE(pos.dir_to_here));
|
||
path = pf_map_path(pfm, bribee_tile);
|
||
if (!path || !adv_unit_execute_path(punit, path)
|
||
if (!path || !adv_unit_execute_path(punit, path)
|
||
|| punit->moves_left <= 0) {
|
||
pf_path_destroy(path);
|
||
return FALSE;
|
||
... | ... | |
if (count_diplomats_on_tile(unit_tile(punit)) == 1
|
||
&& (city_data->diplomat_threat
|
||
|| city_data->urgency > 0)) {
|
||
UNIT_LOG(LOG_DIPLOMAT, punit, "stays to protect %s (urg %d)",
|
||
UNIT_LOG(LOG_DIPLOMAT, punit, "stays to protect %s (urg %d)",
|
||
city_name_get(pcity), city_data->urgency);
|
||
dai_unit_new_task(ait, punit, AIUNIT_NONE, NULL); /* abort mission */
|
||
def_ai_unit_data(punit, ait)->done = TRUE;
|
||
... | ... | |
}
|
||
dai_unit_new_task(ait, punit, task, ctarget->tile);
|
||
fc_assert(punit->moves_left > 0 && ctarget
|
||
fc_assert(punit->moves_left > 0 && ctarget
|
||
&& unit_data->task != AIUNIT_NONE);
|
||
}
|
||
ai/default/daidomestic.c | ||
---|---|---|
return;
|
||
}
|
||
if (pcity == wonder_city
|
||
if (pcity == wonder_city
|
||
|| wonder_city == NULL
|
||
|| city_data->distance_to_wonder_city <= 0
|
||
|| !city_production_gets_caravan_shields(&wonder_city->production)
|
||
... | ... | |
fc_assert_ret(VUT_IMPROVEMENT == wonder_city->production.kind);
|
||
want /= MAX(dist, 1);
|
||
CITY_LOG(LOG_DEBUG, pcity, "want %s to help wonder in %s with " ADV_WANT_PRINTF,
|
||
CITY_LOG(LOG_DEBUG, pcity, "want %s to help wonder in %s with " ADV_WANT_PRINTF,
|
||
utype_rule_name(unit_type),
|
||
city_name_get(wonder_city),
|
||
want);
|
||
... | ... | |
/***********************************************************************//**
|
||
Calculate walking distances to wonder city from nearby cities.
|
||
***************************************************************************/
|
||
void dai_wonder_city_distance(struct ai_type *ait, struct player *pplayer,
|
||
void dai_wonder_city_distance(struct ai_type *ait, struct player *pplayer,
|
||
struct adv_data *adv)
|
||
{
|
||
struct pf_map *pfm;
|
ai/default/daidomestic.h | ||
---|---|---|
struct player *pplayer,
|
||
struct city *pcity);
|
||
void dai_wonder_city_distance(struct ai_type *ait, struct player *pplayer,
|
||
void dai_wonder_city_distance(struct ai_type *ait, struct player *pplayer,
|
||
struct adv_data *adv);
|
||
#endif /* FC__DAIDOMESTIC_H */
|
ai/default/daieffects.c | ||
---|---|---|
specialists who provide at least HAPPY_COST luxury, being the number of
|
||
luxuries needed to make one citizen content or happy.
|
||
The AI assumes that for any specialist that provides HAPPY_COST luxury,
|
||
if we can get that luxury from some other source it allows the specialist
|
||
The AI assumes that for any specialist that provides HAPPY_COST luxury,
|
||
if we can get that luxury from some other source it allows the specialist
|
||
to become a worker. The benefits from an extra worker are weighed against
|
||
the losses from acquiring the two extra luxury.
|
||
... | ... | |
int factor = 2;
|
||
/* Try to build wonders to offset empire size unhappiness */
|
||
if (city_list_size(pplayer->cities)
|
||
if (city_list_size(pplayer->cities)
|
||
> get_player_bonus(pplayer, EFT_EMPIRE_SIZE_BASE)) {
|
||
if (get_player_bonus(pplayer, EFT_EMPIRE_SIZE_BASE) > 0) {
|
||
int step_bonus = get_player_bonus(pplayer, EFT_EMPIRE_SIZE_STEP);
|
||
factor += city_list_size(pplayer->cities)
|
||
factor += city_list_size(pplayer->cities)
|
||
/ MAX(step_bonus, 1);
|
||
}
|
||
factor += 2;
|
||
... | ... | |
}
|
||
break;
|
||
case EFT_AIRLIFT:
|
||
/* FIXME: We need some smart algorithm here. The below is
|
||
/* FIXME: We need some smart algorithm here. The below is
|
||
* totally braindead. */
|
||
v += c + MIN(adv->stats.units.airliftable, 13);
|
||
break;
|
||
... | ... | |
/* The idea being that if we have a full granary, we have an
|
||
* automatic surplus of our granary excess in addition to anything
|
||
* collected by city workers. */
|
||
extra_food += pcity->food_stock -
|
||
extra_food += pcity->food_stock -
|
||
city_granary_size(city_size_get(pcity) - 1);
|
||
}
|
||
ai/default/daihand.c | ||
---|---|---|
/*************************************************************************//**
|
||
Set tax/science/luxury rates.
|
||
TODO: Add general support for luxuries: select the luxury rate at which
|
||
all cities are content and the trade output (minus what is consumed by
|
||
luxuries) is maximal. For this we need some more information from the
|
||
city management code.
|
||
TODO: Add general support for luxuries: select the luxury rate at which
|
||
all cities are content and the trade output (minus what is consumed by
|
||
luxuries) is maximal. For this we need some more information from
|
||
the city management code.
|
||
TODO: Audit the use of pplayer->ai.maxbuycost in the code elsewhere,
|
||
then add support for it here.
|
||
... | ... | |
/* === Luxury === */
|
||
/* Should (and can) we celebrate? */
|
||
/* TODO: In the future, we should check if we should
|
||
* celebrate for other reasons than growth. Currently
|
||
/* TODO: In the future, we should check if we should
|
||
* celebrate for other reasons than growth. Currently
|
||
* this is ignored. Maybe we need ruleset AI hints. */
|
||
/* TODO: Allow celebrate individual cities? No modpacks use this yet. */
|
||
if (get_player_bonus(pplayer, EFT_RAPTURE_GROW) > 0
|
||
... | ... | |
want += 25 * game.info.turn;
|
||
}
|
||
plr_data->tech_want[adv->goal.govt.req] += want;
|
||
TECH_LOG(ait, LOG_DEBUG, pplayer, advance_by_number(adv->goal.govt.req),
|
||
TECH_LOG(ait, LOG_DEBUG, pplayer, advance_by_number(adv->goal.govt.req),
|
||
"dai_manage_government() + %d for %s",
|
||
want,
|
||
government_rule_name(adv->goal.govt.gov));
|
||
... | ... | |
dai_manage_cities(ait, pplayer);
|
||
TIMING_LOG(AIT_CITIES, TIMER_STOP);
|
||
TIMING_LOG(AIT_TECH, TIMER_START);
|
||
dai_manage_tech(ait, pplayer);
|
||
dai_manage_tech(ait, pplayer);
|
||
TIMING_LOG(AIT_TECH, TIMER_STOP);
|
||
dai_manage_spaceship(pplayer);
|
||
ai/default/daihunter.c | ||
---|---|---|
We don't need a hunter in this city if we already have one. Return
|
||
existing hunter if any.
|
||
**************************************************************************/
|
||
static struct unit *dai_hunter_find(struct player *pplayer,
|
||
static struct unit *dai_hunter_find(struct player *pplayer,
|
||
struct city *pcity)
|
||
{
|
||
unit_list_iterate(pcity->units_supported, punit) {
|
||
... | ... | |
}
|
||
/* FIXME: We need to store some data that can tell us if
|
||
* enemy transports are protected by anti-missile technology.
|
||
* enemy transports are protected by anti-missile technology.
|
||
* In this case, want nuclear much more! */
|
||
desire = (ut->hp
|
||
* MIN(ut->attack_strength, 30) /* nuke fix */
|
||
... | ... | |
}
|
||
UNIT_LOG(LOGLEVEL_HUNT, punit, "hunting %s %s[%d](%d,%d) "
|
||
"with want %d, dist1 %d, dist2 %d",
|
||
"with want %d, dist1 %d, dist2 %d",
|
||
nation_rule_name(nation_of_unit(target)),
|
||
unit_rule_name(target),
|
||
unit_rule_name(target),
|
||
target->id,
|
||
TILE_XY(target_tile),
|
||
stackthreat,
|
ai/default/dailog.h | ||
---|---|---|
/* utility */
|
||
#include "log.h"
|
||
#include "support.h"
|
||
|
||
/* Change these and remake to watch logs from a specific
|
||
/* Change these and remake to watch logs from a specific
|
||
part of the AI code. */
|
||
#define LOGLEVEL_TECH LOG_DEBUG
|
||
ai/default/daimilitary.c | ||
---|---|---|
This algorithm is very strange. But I created it by nesting up
|
||
Syela's convoluted if ... else logic, and it seems to work. -- Per
|
||
**************************************************************************/
|
||
static void dai_reevaluate_building(struct city *pcity, adv_want *value,
|
||
unsigned int urgency, unsigned int danger,
|
||
static void dai_reevaluate_building(struct city *pcity, adv_want *value,
|
||
unsigned int urgency, unsigned int danger,
|
||
int defense)
|
||
{
|
||
if (*value == 0 || danger <= 0) {
|
||
... | ... | |
}
|
||
/* Not bothering to s/!vuln/!pdef/ here for the time being. -- Syela
|
||
* (this is noted elsewhere as terrible bug making warships yoyoing)
|
||
* as the warships will go to enemy cities hoping that the enemy builds
|
||
* (this is noted elsewhere as terrible bug making warships yoyoing)
|
||
* as the warships will go to enemy cities hoping that the enemy builds
|
||
* something for them to kill. */
|
||
if (vuln == 0
|
||
&& (utype_class(punittype)->adv.land_move == MOVE_NONE
|
||
... | ... | |
/* Benefit from fighting the target */
|
||
adv_want benefit;
|
||
/* Defender of the target city/tile */
|
||
struct unit *pdef;
|
||
struct unit *pdef;
|
||
const struct unit_type *def_type;
|
||
struct player *def_owner;
|
||
int def_vet; /* Is the defender veteran? */
|
||
... | ... | |
process_attacker_want(ait, pcity, benefit, def_type, def_owner,
|
||
def_vet, ptile,
|
||
best_choice, NULL, NULL, NULL);
|
||
} else {
|
||
} else {
|
||
/* Attract a boat to our city or retain the one that's already here */
|
||
fc_assert_ret_val(unit_class_get(myunit)->adv.sea_move != MOVE_FULL, choice);
|
||
best_choice->need_boat = TRUE;
|
||
... | ... | |
Before building a military unit, AI builds a barracks/port/airport
|
||
NB: It is assumed this function isn't called in an emergency
|
||
situation, when we need a defender _now_.
|
||
|
||
TODO: something more sophisticated, like estimating future demand
|
||
for military units, considering Sun Tzu instead.
|
||
**************************************************************************/
|
||
static void adjust_ai_unit_choice(struct city *pcity,
|
||
static void adjust_ai_unit_choice(struct city *pcity,
|
||
struct adv_choice *choice)
|
||
{
|
||
Impr_type_id id;
|
||
... | ... | |
bool allow_gold_upkeep;
|
||
urgency = assess_danger(ait, nmap, pcity, ul_cb);
|
||
/* Changing to quadratic to stop AI from building piles
|
||
/* Changing to quadratic to stop AI from building piles
|
||
* of small units -- Syela */
|
||
/* It has to be AFTER assess_danger() thanks to wallvalue. */
|
||
our_def = assess_defense_quadratic(ait, pcity);
|
||
our_def = assess_defense_quadratic(ait, pcity);
|
||
dai_choose_diplomat_defensive(ait, pplayer, pcity, choice, our_def);
|
||
... | ... | |
}
|
||
} /* Ok, don't need to defend */
|
||
if (pcity->surplus[O_SHIELD] <= 0
|
||
if (pcity->surplus[O_SHIELD] <= 0
|
||
|| pcity->feel[CITIZEN_UNHAPPY][FEELING_FINAL] > pcity->feel[CITIZEN_UNHAPPY][FEELING_EFFECT]
|
||
|| pcity->id == ai->wonder_city) {
|
||
/* Things we consider below are not life-saving so we don't want to
|
||
/* Things we consider below are not life-saving so we don't want to
|
||
* build them if our populace doesn't feel like it */
|
||
return choice;
|
||
}
|
ai/default/daiparadrop.c | ||
---|---|---|
if (!map_is_known(ptile, pplayer)) {
|
||
continue;
|
||
}
|
||
|
||
acity = tile_city(ptile);
|
||
if (acity && city_owner(acity) == unit_owner(punit)
|
||
&& unit_list_size(ptile->units) == 0) {
|
||
... | ... | |
}
|
||
}
|
||
} square_iterate_end;
|
||
|
||
if (best_tile != NULL) {
|
||
acity = tile_city(best_tile);
|
||
UNIT_LOG(LOGLEVEL_PARATROOPER, punit,
|
||
UNIT_LOG(LOGLEVEL_PARATROOPER, punit,
|
||
"Choose to jump in order to protect allied city %s (%d %d). "
|
||
"Benefit: %d",
|
||
city_name_get(acity), TILE_XY(best_tile), best);
|
||
... | ... | |
}
|
||
}
|
||
} square_iterate_end;
|
||
|
||
if (best_tile != NULL) {
|
||
acity = tile_city(best_tile);
|
||
UNIT_LOG(LOGLEVEL_PARATROOPER, punit,
|
||
UNIT_LOG(LOGLEVEL_PARATROOPER, punit,
|
||
"Choose to jump into enemy city %s (%d %d). Benefit: %d",
|
||
city_name_get(acity), TILE_XY(best_tile), best);
|
||
return best_tile;
|
||
... | ... | |
NULL);
|
||
val += pterrain->defense_bonus / 10;
|
||
val -= punit->hp * 100;
|
||
|
||
if (val > best) {
|
||
best = val;
|
||
best_tile = ptile;
|
||
... | ... | |
if (punit->moves_left == 0) {
|
||
return;
|
||
}
|
||
|
||
if (pcity && unit_list_size(unit_tile(punit)->units) == 1) {
|
||
UNIT_LOG(LOGLEVEL_PARATROOPER, punit, "Defending the city.");
|
||
return;
|
||
... | ... | |
struct civ_map *nmap = &(wld.map);
|
||
profit += u_type->defense_strength
|
||
+ u_type->move_rate
|
||
+ u_type->move_rate
|
||
+ u_type->attack_strength;
|
||
square_iterate(nmap, ptile_city, range, ptile) {
|
ai/default/daisettler.c | ||
---|---|---|
/* utility */
|
||
#include "mem.h"
|
||
#include "log.h"
|
||
#include "support.h"
|
||
#include "support.h"
|
||
#include "timing.h"
|
||
/* common */
|
||
... | ... | |
/* COMMENTS */
|
||
/*
|
||
/*
|
||
This code tries hard to do the right thing, including looking
|
||
into the future (wrt to government), and also doing this in a
|
||
modpack friendly manner. However, there are some pieces missing.
|
||
A tighter integration into the city management code would
|
||
A tighter integration into the city management code would
|
||
give more optimal city placements, since existing cities could
|
||
move their workers around to give a new city better placement.
|
||
Occasionally you will see cities being placed sub-optimally
|
||
... | ... | |
/* Percentage bonus to city locations near an ocean. */
|
||
#define NAVAL_EMPHASIS 20
|
||
/* Modifier for defense bonus that is applied to city location want.
|
||
/* Modifier for defense bonus that is applied to city location want.
|
||
* This is % of defense % to increase want by. */
|
||
#define DEFENSE_EMPHASIS 20
|
||
... | ... | |
+ (result->best_other.tdc != NULL
|
||
? result->best_other.tdc->sum : 0);
|
||
} else if (result->best_other.tdc != NULL) {
|
||
/* Baseline is best extra tile only. This is why making new cities
|
||
/* Baseline is best extra tile only. This is why making new cities
|
||
* is so darn good. */
|
||
result->total = result->best_other.tdc->sum;
|
||
} else {
|
||
... | ... | |
/* FIXME: Maybe penalty for using an existing boat is too high?
|
||
* We shouldn't make the penalty for building a new boat too high though.
|
||
* Building a new boat is like a war against a weaker enemy --
|
||
* Building a new boat is like a war against a weaker enemy --
|
||
* good for the economy. (c) Bush family */
|
||
cr2 = settler_map_iterate(ait, ¶meter, punit,
|
||
unit_build_shield_cost_base(ferry));
|
||
... | ... | |
if (result && result->result > best_impr) {
|
||
UNIT_LOG(LOG_DEBUG, punit, "city want " ADV_WANT_PRINTF, result->result);
|
||
if (tile_city(result->tile)) {
|
||
UNIT_LOG(LOG_DEBUG, punit, "immigrates to %s (%d, %d)",
|
||
UNIT_LOG(LOG_DEBUG, punit, "immigrates to %s (%d, %d)",
|
||
city_name_get(tile_city(result->tile)),
|
||
TILE_XY(result->tile));
|
||
} else {
|
||
UNIT_LOG(LOG_DEBUG, punit, "makes city at (%d, %d)",
|
||
UNIT_LOG(LOG_DEBUG, punit, "makes city at (%d, %d)",
|
||
TILE_XY(result->tile));
|
||
if (punit->server.debug) {
|
||
print_cityresult(pplayer, result);
|
ai/default/daitech.c | ||
---|---|---|
struct ai_tech_choice {
|
||
Tech_type_id choice; /* The id of the most needed tech */
|
||
adv_want want; /* Want of the most needed tech */
|
||
adv_want current_want; /* Want of the tech which is currently researched
|
||
adv_want current_want; /* Want of the tech which is currently researched
|
||
* or is our current goal */
|
||
};
|
||
... | ... | |
4. A tech isn't a requirement of itself.
|
||
**************************************************************************/
|
||
static void dai_select_tech(struct ai_type *ait,
|
||
struct player *pplayer,
|
||
struct player *pplayer,
|
||
struct ai_tech_choice *choice,
|
||
struct ai_tech_choice *goal)
|
||
{
|
||
... | ... | |
&& (penalty + research->bulbs_researched
|
||
<= research_total_bulbs_required(research, research->researching,
|
||
FALSE))) {
|
||
TECH_LOG(ait, LOG_DEBUG, pplayer, advance_by_number(choice.choice),
|
||
"new research, was %s, penalty was %d",
|
||
TECH_LOG(ait, LOG_DEBUG, pplayer, advance_by_number(choice.choice),
|
||
"new research, was %s, penalty was %d",
|
||
research_advance_rule_name(research, research->researching),
|
||
penalty);
|
||
choose_tech(research, choice.choice);
|