(**************************************************************************)
(*                             W A R N I N G                              *)
(*                                                                        *)
(*  This Robot does not work correctly. Fixing it is left as an exercise. *)
(**************************************************************************)

  PROCEDURE Hugger;
  {
   Author: David Malmberg

   Strategy:  Start off by going to the middle of the battlefield
              (if possible).  Then Scan for Obstructions and
              move to an Obstruction and "hide" beside it by "hugging"
              its walls.  While "protected" by the Obstruction, blast
              away at ememies. If no enemies can be found, move to
              another Obstruction (it there is one) and blast away
              from it.  RaiseShield when moving still and lower them
              when standing still and being "protected" by the
              Obstruction.

              This Robot has been designed to utilize Fuel (if it
              is available) to power its Shield.  It has also been
              designed to take advantage of Obstructions.
  }

  VAR { Hugger "Global" variables }

    Angle, { Scanning angle }
    StartAngle, { Begining angle for "sizing up" Obstruction }
    LowAngle, { Lowest angle for "Arc" of Obstruction }
    HighAngle, { Highest angle for "Arc" of Obstruction }
    Start, { Starting angle for scanning for enemies }
    Finish, { Last angle for scanning for enemies }
    Range, { Range/Distance to foe }
    Sweep, { "Sweep count" -- when = 18, Robot has scanned 360 degrees }
    Delta          : Integer; { Scanning arc }


    PROCEDURE GOTO(X, Y : Integer);
      { Go to location X,Y on playing field. }
    VAR Heading    : Integer;
    BEGIN
    { WARNING:  If the point X,Y is inside an Obstruction then }
    { executing this routine will cause the Robot to commit }
    { suicide by repeatedly running into the wall of the Obstruction. }

      { Find the heading we need to get to the desired spot. }
      Heading := Angle_To(x, y);

      { Keep traveling at top speed until we are within 150 meters }
      WHILE (distance(loc_x, loc_y, x, y) > 150) DO drive(Heading, 100);

      { Cut speed, and creep the rest of the way. }
      WHILE (distance(loc_x, loc_y, x, y) > 20) DO drive(Heading, 20);

      { Stop driving, should coast to a stop. }
      drive(Heading, 0); {I.E., Stop}
    END; {GoTo(X,Y)}


    PROCEDURE Ramble(X, Y : Integer);
      { Move to X, Y (if possible) on the playing field }
      { by avoiding Obstructions - if any.              }
    VAR Heading, Tries, Dist : Integer;
    BEGIN
      Tries := 0;
      Heading := Angle_To(X, Y);
      Drive(Heading, 50); {Start off toward X,Y}
      Dist := Scan(Heading, 5);
      REPEAT
        IF ObjectScanned = Obstruction
          THEN BEGIN
            REPEAT
              Heading := Heading + 10;
              Dist := Scan(Heading, 5);
            UNTIL ObjectScanned <> Obstruction;
            Drive(Heading, 50); {Minimum speed to turn freely}
          END;
        Heading := Angle_To(X, Y);
        Dist := Scan(Heading, 5);
        Tries := Tries + 1;
      UNTIL (ObjectScanned <> Obstruction) OR (Tries > 20);
      IF (ObjectScanned <> Obstruction) THEN GOTO(X,Y);
    END; {Ramble}


    PROCEDURE Aim(VAR Ang : Integer; VAR Arc : Integer);
{
 Improve aim by doing a binary search of the target area.
 I.E., divide the target area in two equal pieces and redefine
 the target area to be the piece where the foe is found.
 If the foe is not found, expand the search area to the
 maximum arc of plus or minus 10 degrees.
}
    BEGIN
      IF ObjectScanned = Enemy
        THEN BEGIN
          Arc := Arc DIV 2; { Divide search area in two. }
          IF scan(Ang-Arc, Arc) <> 0 { Check piece "below" target angle. }
            THEN Ang := Ang-Arc { If foe found, redefine target angle. }
            ELSE IF scan(Ang+Arc, Arc) <> 0 { Check piece "above" target angle. }
             THEN Ang := Ang+Arc { If foe found, redefine target angle. }
             ELSE Arc := 10;
          { Foe not found in either piece, expand search area to maximum arc. }
        END
        ELSE Arc := 10;
    END; {Aim}


PROCEDURE FindArc;
{ Find the "Arc" of the Obstruction -- if any }
VAR Dist : Integer;
BEGIN
  Sweep := 0;
  REPEAT
    Sweep := Sweep + 1;
    Start := Start + 20;
    Dist := Scan(Start, 10)
  UNTIL (ObjectScanned = Obstruction) OR (Sweep > 18);
  IF Sweep <= 18 THEN
    BEGIN
      {Now find "highest" angle of "Arc" of the Obstruction}
      HighAngle := Start - 5;
      REPEAT
        HighAngle := HighAngle + 5;
        Dist := Scan(HighAngle,0);
      UNTIL ObjectScanned <> Obstruction;
      {Now find "Lowest" angle of "Arc" of the Obstruction}
      LowAngle := Start + 5;
      REPEAT
        LowAngle := LowAngle - 5;
        Dist := Scan(LowAngle,0);
      UNTIL ObjectScanned <> Obstruction; {lowest angle might be negative}
    END
    ELSE {Sweep > 18 -- No Obstruction found}
    BEGIN
      LowAngle := 0; {Set to zero if no Obstruction found}
      HighAngle := 0;
    END;
END; { FindArc }


PROCEDURE GoToObstruction;
 { Go to the Obstruction and "hug" its walls }
 VAR Heading, Dist : Integer;
  BEGIN {GoToObstruction}
    RaiseShield; {Need protection when moving in open territory}
    Heading := (HighAngle + LowAngle) DIV 2; {"middle" of Obstruction}
    REPEAT
      Drive(Heading, 100);
      Dist := Scan(Heading,0);
    UNTIL (Dist < 2) AND (ObjectScanned = Obstruction); {"Hug" the wall}
    StartAngle := Heading;
    FindArc; {New LowAngle and HighAngle calculated}
    Start := HighAngle - 360; {"Arc" for scanning for enemies}
    Finish := LowAngle;
    LowerShield; {Obstruction will "protect" robot}
  END; {GoToObstruction}


PROCEDURE Blast_Em;
 {Scan for enemies and blast 'em}
  BEGIN {Blast_Em}
    Sweep := 0;
    Angle := Start + 10;
    REPEAT
      Delta := 10; { Start with widest scanning arc. }
      Range := scan(Angle, Delta);
      WHILE (Range > 40) AND (Range < 700) AND (ObjectScanned = Enemy)
        DO { Must be far enough away to avoid self-damage. }
        BEGIN
          Sweep := 0; {Reset Sweep counter}
          Aim(Angle, Delta); { Improve aim. }
          IF ObjectScanned = Enemy
            THEN cannon(Angle, Range); { Fire!! }
          Range := scan(Angle, Delta); { Is foe still in sights? }
        END;
      Angle := Angle+20; { Look in adjacent target area. }
      IF Angle >= Finish THEN
        BEGIN
          Angle := Start + 10;
          Sweep := Sweep + 1;
        END;
    UNTIL Sweep > 10; {10 unsuccessful scans of whole area}
  END; {Blast_Em}


  BEGIN {Hugger Main}
    RaiseShield;
    Angle := 0;
    Ramble(500, 500); { Move to center of field -- if possible. }
    REPEAT { Until Dead or Winner }
      FindArc; {Find Obstruction}
      GoToObstruction; {"Hide" beside Obstruction}
      Blast_Em; {Scan and Blast enemies}
    UNTIL Dead OR Winner;
  END; {Hugger Main}

