Complete.Org: Mailing Lists: Archives: freeciv-dev: January 2002:
[Freeciv-Dev] Re: Cleaning up find_a_direction. (PR#1132)
Home

[Freeciv-Dev] Re: Cleaning up find_a_direction. (PR#1132)

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
To: Gregory Berkolaiko <gberkolaiko@xxxxxxxxxxx>
Cc: freeciv-dev@xxxxxxxxxxx, bugs@xxxxxxxxxxxxxxxxxxx
Subject: [Freeciv-Dev] Re: Cleaning up find_a_direction. (PR#1132)
From: Raimar Falke <hawk@xxxxxxxxxxxxxxxxxxxxxxx>
Date: Sun, 6 Jan 2002 18:02:21 +0100
Reply-to: rf13@xxxxxxxxxxxxxxxxxxxxxx

On Thu, Dec 13, 2001 at 10:19:20AM -0800, Gregory Berkolaiko wrote:
> This is extensive cleanup of find_a_direction function from gotohand.c
> A lot of variable renaming (from a,b,c to more meaningful names),
> commenting, putting braces in ifs.
> 

> The only significant change in the fabric of the code is trying to make
> triremes safer at sea.  The previous implementation didn't work at all,
> now it works if warmap is generated in the right way (it isn't, but
> that's will be fixed in future patches).  Even if warmap is "wrong", the
> trireme is saved if there is a coast nearby.

Can I ask you to seperate this?

> This patch is highly recommended (if I can recommend my own patch) as now
> it is actually possible to understand what find_a_direction is doing.
> 
> Tested, savegames differ from about 1500BC (due to trireme use, I guess),
> visually AI behaves normally (that is "stupid as usual").
> 
> Best,
> G.
> 
> __________________________________________________
> Do You Yahoo!?
> Everything you'll ever need on one web page
> from News and Sport to Email and Music Charts
> http://uk.my.yahoo.com
Content-Description: find_dir_cleanup.diff
> ? rfile2
> ? rfile1
> ? saves
> ? results
> Index: server/gotohand.c
> ===================================================================
> RCS file: /home/freeciv/CVS/freeciv/server/gotohand.c,v
> retrieving revision 1.126
> diff -u -r1.126 gotohand.c
> --- server/gotohand.c 2001/12/09 14:08:26     1.126
> +++ server/gotohand.c 2001/12/13 17:59:23
> @@ -866,139 +866,214 @@
>  Returns a direction as used in DIR_DX[] and DIR_DY[] arrays, or -1 if none 
> could be
>  found.
>  
> -This function does not check for loops, which we currently rely on
> +Notes on the implementation: 
> +1. d[8] contains "goodness" of the directions.  Bigger number means safer
> +direction.  It takes into account: how well the unit will be defended at 
> +the next tile, how many possible attackers there are around it, whether it 
> +is likely to sink there (for triremes).
> +2. This function does not check for loops, which we currently rely on
>  find_the_shortest_path() to make sure there are none of. If the warmap did
>  contain a loop repeated calls of this function may result in the unit going
>  in cycles forever.
> +3. It doesn't check for ZOC as it has been done in find_the_shortest_path
> +(which is called every turn).
>  **************************************************************************/
>  static int find_a_direction(struct unit *punit,
>                           enum goto_move_restriction restriction,
>                           const int dest_x, const int dest_y)
>  {
> -  int k, d[8], n, a, best = 0, d0, d1, h0, h1, u, c;
> -  struct tile *ptile, *adjtile;
> -  int nearland;
> +  int k, d[8], best = 0;

Rename k to dir(ection).

> +  int defence_multiplier, tmp;
> +  int defence_of_unit, defence_of_ally, hp_of_unit, hp_of_ally, num_of_units;
> +  int base_move_cost;
> +  struct tile *ptile;
>    struct city *pcity;
>    struct unit *passenger;
>    struct player *pplayer = unit_owner(punit);
> +  int afraid_of_sinking = (unit_flag(punit, F_TRIREME) 
> +                        && !player_owns_active_wonder(pplayer, 
> B_LIGHTHOUSE));
> +  /* if the destination is one step away, look around first or just go 
> there? */
> +  int do_full_check = afraid_of_sinking; 
>  
>    if (map_get_terrain(punit->x, punit->y) == T_OCEAN)
>      passenger = other_passengers(punit);
>    else passenger = NULL;
>  
>    /* If we can get to the destination rigth away there is nothing to be 
> gained
> -     from going round in little circles to move across desirable squares */
> -  adjc_dir_iterate(punit->x, punit->y, x, y, dir) {
> -    if (warmap.vector[punit->x][punit->y] & (1 << dir)
> -     && !(restriction == GOTO_MOVE_CARDINAL_ONLY
> -          && !DIR_IS_CARDINAL(dir))) {
> -      if (x == dest_x && y == dest_y)
> +   * from going round in little circles to move across desirable squares */
> +  /* Actually there are things to gain, in AI case, like the safety checks 
> -- GB */
> +  if (!do_full_check) {

> +    adjc_dir_iterate(punit->x, punit->y, x, y, dir) {
> +      if ((x == dest_x && y == dest_y)
> +       && warmap.vector[punit->x][punit->y] & (1 << dir)
> +       && !(restriction == GOTO_MOVE_CARDINAL_ONLY
> +            && !DIR_IS_CARDINAL(dir))) {
>       return dir;

Can this be expressed in terms of is_tiles_adjacent and
get_direction_for_step?

> -    }
> -  } adjc_dir_iterate_end;
> -
> +      }
> +    } adjc_dir_iterate_end;
> +  }
> +  
>    memset(d, 0, sizeof(d));
>  
>    adjc_dir_iterate(punit->x, punit->y, x, y, k) {
> -    if ((restriction == GOTO_MOVE_CARDINAL_ONLY) && !DIR_IS_CARDINAL(k))

> +    /* is it an allowed direction?  is it marked on the warmap? */

Full sentences please with the first word capitalized.

> +    if (!(warmap.vector[punit->x][punit->y]&(1<<k))
> +     || ((restriction == GOTO_MOVE_CARDINAL_ONLY) && !DIR_IS_CARDINAL(k))) {
> +      /* make sure we don't select it later */
> +      d[k] = -1;
>        continue;
> +    }
>  
> -    if (!(warmap.vector[punit->x][punit->y]&(1<<k))) d[k] = 0;
> -    else {
> -      if (is_ground_unit(punit))
> -        c = map_get_tile(punit->x, punit->y)->move_cost[k];
> -      else c = 3;
> -      if (unit_flag(punit, F_IGTER) && c) c = 1;
> -      if (passenger) {
> -     freelog(LOG_DEBUG, "%d@(%d,%d) evaluating (%d,%d)[%d/%d]",
> -             punit->id, punit->x, punit->y, x, y, c, punit->moves_left);
> +    /* determine the cost of the proposed move */
> +    if (is_ground_unit(punit))

> +      /* assuming the move is valid, but what if unit is trying to board? -- 
> GB*/

Is this a "I don't know what the code does" question? Or more a "if it
is a ground_unit than it is trying to board"?

> +      base_move_cost = map_get_tile(punit->x, punit->y)->move_cost[k];
> +    else 
> +      base_move_cost = SINGLE_MOVE;

Add extra {}.

> +    if (unit_flag(punit, F_IGTER) && base_move_cost >= MOVE_COST_ROAD) 
> +      base_move_cost = MOVE_COST_ROAD;
> +
> +    freelog(LOG_DEBUG, "%d@(%d,%d) evaluating (%d,%d)[%d/%d]",
> +         punit->id, punit->x, punit->y, x, y, base_move_cost, 
> punit->moves_left);
> +
> +    /* find everybody's defence stats */
> +    ptile = map_get_tile(x, y);
> +    defence_of_unit = get_simple_defense_power(punit->type, x, y);
> +    pcity = map_get_city(x, y);
> +    defence_multiplier = 2;
> +    if (pcity) { /* this code block inspired by David Pfitzner -- Syela */
> +      if (city_got_citywalls(pcity)) defence_multiplier += 2;
> +      if (city_got_building(pcity, B_SDI)) defence_multiplier++;
> +      if (city_got_building(pcity, B_SAM)) defence_multiplier++;
> +      if (city_got_building(pcity, B_COASTAL)) defence_multiplier++;
> +    }
> +    defence_of_unit = (defence_of_unit * defence_multiplier) / 2;

> +    hp_of_unit = punit->hp;
> +    /* find the best friendly defensive unit at the target tile */
> +    hp_of_ally = 0; 

Please seperate such sections by an empty line. Maybe even some fancy
comment style like:

/********* find the best friendly defensive unit at the target tile 
************/

> +    defence_of_ally = 0; 

> +    num_of_units = 1;
> +    unit_list_iterate(ptile->units, aunit) {
> +      if (!pplayers_allied(unit_owner(aunit), unit_owner(punit))) {
> +     /* MINIMUM priority */

> +     defence_of_ally = -1;

What means -1? What 0?

> +      } else {
> +     num_of_units++;
> +     tmp = (get_simple_defense_power(aunit->type, x, y) * 
> defence_multiplier) / 2;
> +     if (tmp * aunit->hp > defence_of_ally * hp_of_ally) { 
> +       defence_of_ally = tmp; 
> +       hp_of_ally = aunit->hp; 
> +     }
>        }
> -      ptile = map_get_tile(x, y);
> -      d0 = get_simple_defense_power(punit->type, x, y);
> -      pcity = map_get_city(x, y);
> -      n = 2;
> -      if (pcity) { /* this code block inspired by David Pfitzner -- Syela */
> -        if (city_got_citywalls(pcity)) n += 2;
> -        if (city_got_building(pcity, B_SDI)) n++;
> -        if (city_got_building(pcity, B_SAM)) n++;
> -        if (city_got_building(pcity, B_COASTAL)) n++;
> +    } unit_list_iterate_end;
> +
> +    {
> +      /* calculate some clever weights basing on defence stats */
> +      int rating_of_unit = defence_of_unit * hp_of_unit;
> +      int rating_of_ally = defence_of_ally * hp_of_ally;
> +      if (num_of_units == 1) {
> +     d[k] = rating_of_unit;
> +      } else if (pcity || ptile->special&S_FORTRESS) {
> +     d[k] = MAX(rating_of_unit, rating_of_ally);
> +      } else if (rating_of_unit <= rating_of_ally) {
> +     d[k] = rating_of_ally * (num_of_units - 1) / num_of_units;
> +      } else { 
> +     d[k] = MIN(rating_of_unit * num_of_units, 
> +                rating_of_unit * rating_of_unit * (num_of_units - 1) / 
> +                MAX(num_of_units, (rating_of_ally * num_of_units)));
>        }
> -      d0 = (d0 * n) / 2;
> -      h0 = punit->hp; h1 = 0; d1 = 0; u = 1;
> -      unit_list_iterate(ptile->units, aunit)
> -     if (!pplayers_allied(unit_owner(aunit), unit_owner(punit)))
> -       d1 = -1;              /* MINIMUM priority */
> -        else {
> -          u++;
> -          a = get_simple_defense_power(aunit->type, x, y) * n / 2;
> -          if (a * aunit->hp > d1 * h1) { d1 = a; h1 = aunit->hp; }
> -        }
> -      unit_list_iterate_end;
> -      if (u == 1) d[k] = d0 * h0;
> -      else if (pcity || ptile->special&S_FORTRESS)
> -        d[k] = MAX(d0 * h0, d1 * h1);
> -      else if ((d0 * h0) <= (d1 * h1)) d[k] = (d1 * h1) * (u - 1) / u;
> -      else d[k] = MIN(d0 * h0 * u, d0 * h0 * d0 * h0 * (u - 1) / MAX(u, (d1 
> * h1 * u)));
> -      if (d0 > d1) d1 = d0;
> -
> -      if (ptile->special&S_ROAD) d[k] += 10; /* in case we change directions 
> */
> -      if (ptile->special&S_RAILROAD) d[k] += 10; /* next turn, roads are 
> nice */
> -
> -      nearland = 0;
> -      if (!pplayer->ai.control && !map_get_known(x, y, pplayer)) nearland++;
> -      adjc_iterate(x, y, tmp_x, tmp_y) {
> -     adjtile = map_get_tile(tmp_x, tmp_y);
> -        if (adjtile->terrain != T_OCEAN) nearland++;
> -        if (!((adjtile->known)&(1u<<punit->owner))) {
> -          if (punit->moves_left <= c) d[k] -= (d[k]/16); /* Avoid the 
> unknown */
> -          else d[k]++; /* nice but not important */
> -        } else { /* NOTE: Not being omniscient here!! -- Syela */
> -          unit_list_iterate(adjtile->units, aunit) /* lookin for trouble */
> -            if (pplayers_at_war(unit_owner(aunit), unit_owner(punit))
> -             && (a = get_attack_power(aunit))) {
> -              if (punit->moves_left < c + SINGLE_MOVE) { /* can't fight */
> -                if (passenger && !is_ground_unit(aunit)) d[k] = -99;
> -                else d[k] -= d1 * (aunit->hp * a * a / (a * a + d1 * d1));
> -              }
> -            }
> -          unit_list_iterate_end;
> -        } /* end this-tile-is-seen else */
> -      } adjc_iterate_end;
> - 
> -      if (unit_flag(punit, F_TRIREME) && !nearland) {
> -        if (punit->moves_left < 6) d[k] = -1; /* Tired of Kaput!! -- Syela */
> -        else if (punit->moves_left == 6) {
> -       adjc_dir_iterate(x, y, tmp_x, tmp_y, n) {
> -         if ((warmap.vector[x][y] & (1 << n))) {
> -           if (is_coastline(tmp_x, tmp_y))
> -             nearland++;
> +    }
> +    
> +    /* in case we change directions next turn, roads are nice */
> +    if ((ptile->special&S_ROAD) || (ptile->special&S_RAILROAD)) 
> +      d[k] += 10; 
> +    
> +    defence_of_ally = MAX(defence_of_unit, defence_of_ally);
> +    /* what is around the tile we are about to step to? */
> +    adjc_iterate(x, y, tmp_x, tmp_y) {
> +      struct tile *adjtile = map_get_tile(tmp_x, tmp_y);

> +      if (!((adjtile->known)&(1u<<punit->owner))) {

Isn't there a function which does this?

> +     if (punit->moves_left <= base_move_cost) {
> +       /* Avoid the unknown */

> +       d[k] -= (d[k]/16);

Why 16?

> +     } else { 
> +       /* nice but not important */
> +       d[k]++;
> +     }
> +      } else {
> +     /* NOTE: Not being omniscient here!! -- Syela */
> +     /* lookin for trouble */
> +     int attack_of_enemy;
> +     unit_list_iterate(adjtile->units, aunit)
> +       if (pplayers_at_war(unit_owner(aunit), unit_owner(punit))
> +           && (attack_of_enemy = get_attack_power(aunit))) {
> +         if (punit->moves_left < base_move_cost + SINGLE_MOVE) { 
> +           /* can't fight */
> +           if (passenger && !is_ground_unit(aunit)) { 

> +             d[k] = -99;

Why -99?

        Raimar

-- 
 email: rf13@xxxxxxxxxxxxxxxxx
  "With a PC, I always felt limited by the software available.
   On Unix, I am limited by my knowledge."
    -- Peter J. Schoenster <pschon@xxxxxxxxxxxxxxxxx>


[Prev in Thread] Current Thread [Next in Thread]