
(********************************************************************)
(*                                                                  *)
(*  dnafight.sd7  Bacterial dna fight programming game              *)
(*  Copyright (C) 1985  Markus Stumptner                            *)
(*                                                                  *)
(*  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 the Free Software Foundation; either version 2 of  *)
(*  the License, or (at your option) any later version.             *)
(*                                                                  *)
(*  This program is distributed in the hope that it will be useful, *)
(*  but WITHOUT ANY WARRANTY; without even the implied warranty of  *)
(*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   *)
(*  GNU General Public License for more details.                    *)
(*                                                                  *)
(*  You should have received a copy of the GNU General Public       *)
(*  License along with this program; if not, write to the           *)
(*  Free Software Foundation, Inc., 51 Franklin Street,             *)
(*  Fifth Floor, Boston, MA  02110-1301, USA.                       *)
(*                                                                  *)
(********************************************************************)


(* WHITE V3.1 *)


const proc: dna (WHITE) is func

  local
    var direction: movDir is HERE;
    var direction: maxDir is HERE;
    var direction: killDir is HERE;
    var power: maxFood is 0;
    var power: maxKill is 0;
    var float: initSplitSize is 0.0;
    var float: splitSize is 0.0;
    var directSet: dirSet is directSet.EMPTY_SET;


    const func float: meanFood is func
      result
        var float: result is 0.0;
      local
        var direction: actdir is HERE;
        var power: sum is 0;
        var integer: anz is 1;

      begin
        anz := 1;
        sum := 0;
        for actdir range HERE to SE do
          if view(actdir) <> EDGE then
            sum +:= food(actdir);
            incr(anz);
          end if;
        end for;
        result := flt(sum) / flt(anz);
      end func; (* meanFood *)


    const func boolean: noEnemy is func
      result
        var boolean: result is FALSE;
      local
        const colorSet: ACTSET is {CLEAR, EDGE, WHITE};

      begin
        result := (view(N)  in ACTSET) and (view(S)  in ACTSET) and
                  (view(W)  in ACTSET) and (view(E)  in ACTSET) and
                  (view(NW) in ACTSET) and (view(SW) in ACTSET) and
                  (view(NE) in ACTSET) and (view(SE) in ACTSET);
      end func; (* noEnemy *)


  begin (* dna (WHITE) *)
    maxDir := HERE;
    killDir := HERE;
    maxFood := 0;
    maxKill := 0;
    dirSet := directSet.EMPTY_SET;
    initSplitSize := 0.25 * flt(foodReserve) + 4.5;
    splitSize := 0.153 * flt(foodReserve) + 4.7;
    for movDir range HERE to E do
      if (view(movDir) = CLEAR or movDir = HERE) and
          food(movDir) >= maxFood then
        if food(movDir) = maxFood then
          incl(dirSet, movDir);
        else
          dirSet := {movDir};
        end if;
        maxFood := food(movDir);
        maxDir := movDir;
      end if;
    end for;
    for movDir range N to E do
      if not view(movDir) in {CLEAR, EDGE, WHITE} and
          strength(movDir) <= strength(HERE) then
        maxKill := strength(movDir);
        killDir := movDir;
      end if;
    end for;
    if (max(maxFood, maxKill) <= shrinkSize(strength(HERE)) or
        flt(strength(HERE)) > initSplitSize and maxFood = foodReserve and
        noEnemy) and
       (card(dirSet) > 1 or
        dirSet <> {HERE} and dirSet <> directSet.EMPTY_SET) and
        strength(HERE) > 1 then
      maxDir := ranDir(dirSet - {HERE});
      split(maxDir,min(strength(HERE) div 2 + ord(odd(strength(HERE))),
                       food(HERE)),
                   min(strength(HERE) div 2, food(maxDir)))
    else
      if (maxKill > maxFood or
          maxKill >= shrinkSize(strength(HERE))) and
          killDir <> HERE then
        kill(killDir);
      else
        if noEnemy and meanFood < 0.33 * flt(foodReserve) then
          eat(ranDir(dirSet - {HERE}), shrinkSize(strength(HERE)));
        else
          maxDir := ranDir(dirSet - {HERE});
          eat(maxDir, min(maxFood, strength(HERE)));
        end if;
      end if;
    end if;
  end func; (* dna (WHITE) *)
