using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Runtime.Serialization.Formatters;
using System.Windows.Forms;
using Battlefield_Simulator_2019;

namespace battle
{
    public class classBattleUnit
    {
        #region "enumerated types"
        public enum enuUnitStage
        {
            idle,
            resting,
            showAllowedMoves,
            showSelectedPath,
            moving,
            _num_stages
        }

        public enum enuSearchMap
        {
            unreachable,
            enemy,
            ally,
            empty,
            _numSearchMap
        }

        #endregion

        #region "variables"
        static public Point[] udrUnGuardPOCs;
        static int intUniqueUnitIDNumber = 0;
        const int intUniqueUnitIDNumberStringSize = 5;

        public int MyID;

        public enuUnitStage myStage = enuUnitStage.idle;
        public classBattle.enuUnitTypes myType;
        public classBattle.enuUnitColors myClr;
        public classBattle.enuUnitRanks myRank;
        public Point myPosition = new Point();
        public int intMovementPoints;
        public int intMovementPoints_Max;
        public bool bolFullStop;
        public int intNumLoop = 0;

        public int intSize;
        public int intSize_Max;
        public string strMovePath = "";

        public classBattle.classMaxMin udrMeleeDamage = new classBattle.classMaxMin();
        public classBattle.classMaxMin udrRangeDamage = new classBattle.classMaxMin();
        public int intRange;
        public double dblMeleeDefense;
        public double dblRangeDefense;

        public Point udrDrawing_MyImageLoc = new Point();

        public classBattleUnit next;                        // Linked-list of units used in classbattlefield's unit_Q[] array for each color
        public classBattleUnit previous;

        public classBattleUnit terrain_next;                // linked-list of units on the terrain, used when one unit moves over another unit's square
        public classBattleUnit terrain_previous;

        public classBattleUnit unitIAmAttacking;

        public Point udrTargetLoc;

        public classBattleField battlefield;
        public classBattle.enuAttackTypes attackType;
        public Point udrAttackLoc = new Point();
        public classBattleField.classUnitStats myStats  = new classBattleField.classUnitStats();
        public bool bolDie;
        public int intTotalDamageFromHit;

        // open field defense variables
        public static bool bolBlueSideHasMoved = false;
        public static int intNumberBlueUnitsOnField = 0;
        public static int intCurrentTurn = 0;
        public int intTurnsSkipped = 0;
        
        #endregion

        #region "structures"
        public class classPathMap
        {
            public int intMovementCost;
            public int intStepsFromStart;
            public classBattleUnit unit;
            public classBattle.enuDirections direction;
            public bool fullStop;
            public bool seen;
        }

        public class classTargetRating
        {
            public classBattleUnit unit;
            public int intTargetValue;
        }


        #endregion

        #region "objects"
        public Bitmap myBitMap, myOriginalBitMap;
        public Bitmap imgTerrainBehindMe;
        public Point ptLoc;
        #endregion

        public classBattleUnit(classBattle.enuUnitTypes typeUnit,
                               classBattle.enuUnitColors color,
                               classBattle.enuUnitRanks rank)
        {
            MyID = intUniqueUnitIDNumber++;
            if (intUniqueUnitIDNumber.ToString().Length > intUniqueUnitIDNumberStringSize)
                intUniqueUnitIDNumber = 0;
                        
            myType = typeUnit;
            myClr = color;
            myRank = rank;
            setMaxMovement();
            intMovementPoints = intMovementPoints_Max;
            setMaxSize();
            intSize = intSize_Max;

            setMeleeDefense();
            setRangeDefense();
            setMeleeDamage();
            setRangeDamage();
        }

        public string myIDstring { get { return MyID.ToString().PadLeft(intUniqueUnitIDNumberStringSize, '0'); } }

        public void initPics()
        {
            setMyBitMap();
        }

        #region "day change resets"
        public void NewDay()
        {
            intMovementPoints = intMovementPoints_Max;
            bolFullStop = false;
            display();
            intTurnsSkipped = 0;

            myStage = enuUnitStage.idle;
        }

        public void setMyStats()
        {
            myStats.melee.defense = dblMeleeDefense;
            myStats.melee.offense = intSize * (udrMeleeDamage.Max - udrMeleeDamage.Min) / 2;

            myStats.range.defense = dblRangeDefense;
            myStats.range.offense = intSize * (udrRangeDamage.Max - udrRangeDamage.Min) / 2;
        }
        #endregion

        #region "display"
        public void setMyImage()
        {
            myBitMap = (Bitmap)myOriginalBitMap.Clone();
            using (Graphics g = Graphics.FromImage(myBitMap))
            {
                string strTextMovementPts = intMovementPoints.ToString() + "/" + intMovementPoints_Max.ToString();
                Bitmap bmpTextMovementPts = battlefield.cLibBattle.getFontBitMap(strTextMovementPts);
                Point ptMovementPts = new Point((int)(myBitMap.Width * .05), (int)(myBitMap.Height * .4));
                g.DrawImage(bmpTextMovementPts, ptMovementPts.X, ptMovementPts.Y, (int)(myBitMap.Width * .95), (int)(myBitMap.Height * .3));

                string strTextSize = intSize.ToString();
                Bitmap bmpTextSize = battlefield.cLibBattle.getFontBitMap(strTextSize);
                bmpTextSize.MakeTransparent();
                Point ptSize = new Point((int)(myBitMap.Width * .15), (int)(myBitMap.Height * .7));
                g.DrawImage(bmpTextSize, ptSize.X, ptSize.Y, (int)(myBitMap.Width * .8), (int)(myBitMap.Height * .3));
            }
        }
        public void shake()
        {
            int intGridMapOffset = (int)((double)battlefield.intMapGridSize * .1);
            if (intTotalDamageFromHit > 10)
            {
                int intPartialDamage = (int)(battlefield.rnd.NextDouble() * 10000) % (int)((double)intTotalDamageFromHit * .1);
                hit(intPartialDamage);
                intTotalDamageFromHit -= intPartialDamage;
            }
            else if (intTotalDamageFromHit > 2)
            {
                int intPartialDamage = intTotalDamageFromHit / 2;
                hit(intPartialDamage);
                intTotalDamageFromHit -= intPartialDamage;
            }
            else
            {
                hit(intTotalDamageFromHit);
                intTotalDamageFromHit = 0;
            }
            setMyImage();
            using (Graphics gMap = Graphics.FromImage(battlefield.picMap.Image))
            {
                Bitmap thisTerrain = new Bitmap(battlefield.cLibBattle.getTerrainImage(battlefield.terrain[myPosition.X, myPosition.Y].type, classBattle.enuTerrainImageSetting.normal), battlefield.intMapGridSize, battlefield.intMapGridSize);
                using (Graphics gTerrain = Graphics.FromImage(thisTerrain))
                {
                    int intX = (int)(battlefield.rnd.NextDouble() * intGridMapOffset * 2);
                    int intY = (int)(battlefield.rnd.NextDouble() * intGridMapOffset * 2);
                    gTerrain.DrawImage(myBitMap, intX, intY, myBitMap.Width, myBitMap.Height);
                }
                gMap.DrawImage(thisTerrain, new Point(battlefield.getGridMapObjectLeft(myPosition), battlefield.getGridMapObjectTop(myPosition)));
            }
            battlefield.picMap.Refresh();
        }

        public void hit(int intDamage)
        {
            intSize -= intDamage;
            if (intSize <= 0)
            {
                intSize = 0;
                bolDie = true;
            }
            setMyImage();
        }

        public void die()
        {
            erase();
            battlefield.killUnit(this);
            battlefield.terrain[myPosition.X, myPosition.Y].unit = null;
        }

        public void erase()
        {
            battlefield.displayMapLoc(myPosition, classBattle.enuTerrainImageSetting.normal);
            battlefield.picMap.Refresh();
        }

        public int getDamage(classBattle.classMaxMin Range, double dblDefense)
        {
            double dblRange = Range.Max - Range.Min;
            double dblRnd = battlefield.rnd.NextDouble();
            int intRetVal = (int)((Range.Min + dblRange * dblRnd)
                          * dblDefense
                          * ((double)intSize / (double)(intSize_Max))
                          * (double)intSize_Max)
                          + 1;
            return intRetVal;
        }

        public void display()
        { display(false); }
        public void display(bool bolForceRebuildImage)
        {
            if (bolDie)
                return;

            if (bolForceRebuildImage)
                setMyBitMap();

            int intGridMapOffset = (int)((double)battlefield.intMapGridSize * .1);

            setMyImage();

            ptLoc = new Point(battlefield.getGridMapObjectLeft(myPosition) + intGridMapOffset, battlefield.getGridMapObjectTop(myPosition) + intGridMapOffset);
            Size myImageSize = new Size(myBitMap.Width, myBitMap.Height);
            Rectangle recSaveArea = new Rectangle(ptLoc, myImageSize);

            imgTerrainBehindMe = new Bitmap(recSaveArea.Width, recSaveArea.Height);

            using (Graphics g = Graphics.FromImage(imgTerrainBehindMe))
            { 
                g.DrawImage(battlefield.bm_Map_Original, ptLoc.X, ptLoc.Y, recSaveArea.Width, recSaveArea.Height);
            }

            using (Graphics g = Graphics.FromImage(battlefield.picMap.Image))
            {
                g.DrawImage(myBitMap, ptLoc);
            }
        }

        #endregion

        #region "helper functions"

        classBattle.enuUnitColors otherClr() { return (classBattle.enuUnitColors)(((int)myClr + 1) % 2); }

        bool ClrIsSameAsMyClr(classBattle.enuUnitColors clr) { return (clr == myClr); }

        public bool moveOneStep(classBattle.enuDirections dir)
        {
            Point udrNewPos = battlefield.getNextPos(myPosition, dir);
            classBattle.enuTerrainTypes typeNewTerrain = battlefield.terrain[udrNewPos.X, udrNewPos.Y].type;
            int intMovementCost = battlefield.getMovementCost(typeNewTerrain);

            if (intMovementCost <= intMovementPoints
                && !bolFullStop)
            {
                Point udrOldPos = myPosition;
                intMovementPoints -= intMovementCost;
                battlefield.terrain[myPosition.X, myPosition.Y].unit = terrain_next;
                myPosition = udrNewPos;
                terrain_next = battlefield.terrain[myPosition.X, myPosition.Y].unit;
                battlefield.terrain[myPosition.X, myPosition.Y].unit = this;

                if (thereIsAnEnemyUnitNextToThisSquare(myPosition))
                    bolFullStop = true;

                setRangeForTerrain();

                display();
                battlefield.displayMapLoc(udrOldPos, classBattle.enuTerrainImageSetting.normal);
                battlefield.picMap.Refresh();
                return true;
            }
            return false;
        }

        public void setRangeForTerrain()
        { intRange = getRangeForTerrain(); }

        public int getRangeForTerrain()
        { return getRangeForTerrain(myPosition); }
        public int getRangeForTerrain(Point udrLoc)
        { return getRangeForTerrain(battlefield.terrain[udrLoc.X, udrLoc.Y].type); }
        public int getRangeForTerrain(classBattle.enuTerrainTypes terrainType)
        {
            int intRetval = getRangeForType();
            if (myType == classBattle.enuUnitTypes.artillery)

                switch (battlefield.terrain[myPosition.X, myPosition.Y].type)
                {
                    case classBattle.enuTerrainTypes.castle:
                        intRetval += 1;
                        break;

                    default:
                        break;
                }
            else
                intRetval = 1;
            return intRetval;
        }

        public bool thereIsAnEnemyUnitNextToThisSquare()
        { return thereIsAnEnemyUnitNextToThisSquare(myPosition, this); }
        public bool thereIsAnEnemyUnitNextToThisSquare(Point udrPos)
        { return thereIsAnEnemyUnitNextToThisSquare(udrPos, this); }
        public bool thereIsAnEnemyUnitNextToThisSquare(Point udrPos, classBattleUnit classIgnoreThisUnit)
        {
            Point udrAdjPos;
            for (classBattle.enuDirections dirCounter = 0; dirCounter < classBattle.enuDirections._num_directions; dirCounter++)
            {
                udrAdjPos = battlefield.getNextPos(udrPos, dirCounter);
                if (udrAdjPos.X >= 0 && udrAdjPos.X < battlefield.szMapSize.Width)
                    if (udrAdjPos.Y >= 0 && udrAdjPos.Y < battlefield.szMapSize.Height)
                        if (battlefield.terrain[udrAdjPos.X, udrAdjPos.Y].unit != null
                            && battlefield.terrain[udrAdjPos.X, udrAdjPos.Y].unit.myClr != myClr
                            && battlefield.terrain[udrAdjPos.X, udrAdjPos.Y].unit != classIgnoreThisUnit)
                            return true;
            }
            return false;
        }

        public int countFriendlyUnitsNextToThisSquare()
        { return countFriendlyUnitsNextToThisSquare(myPosition, this); }
        public int countFriendlyUnitsNextToThisSquare(Point udrPos)
        { return countFriendlyUnitsNextToThisSquare(udrPos, this); }
        public int countFriendlyUnitsNextToThisSquare(Point udrPos, classBattleUnit classIgnoreThisUnit)
        {
            Point udrAdjPos;
            int intRetVal = 0;
            for (classBattle.enuDirections dirCounter = 0; dirCounter < classBattle.enuDirections._num_directions; dirCounter++)
            {
                udrAdjPos = battlefield.getNextPos(udrPos, dirCounter);
                if (udrAdjPos.X >= 0 && udrAdjPos.X < battlefield.szMapSize.Width)
                    if (udrAdjPos.Y >= 0 && udrAdjPos.Y < battlefield.szMapSize.Height)
                        if (battlefield.terrain[udrAdjPos.X, udrAdjPos.Y].unit != null
                            && battlefield.terrain[udrAdjPos.X, udrAdjPos.Y].unit.myClr == myClr)
                            intRetVal++;
            }
            return intRetVal;
        }

        #endregion

        #region "AI search functions"
        public string getNextMovePath(Point udrTargetLoc)
        {
            bool[,] bolAvoidMap = new bool[battlefield.szMapSize.Width, battlefield.szMapSize.Height];
            int intMaxTrials = 10;
            string strOriginalPath = getShortestPath(myPosition, udrTargetLoc, false, false, bolAvoidMap);
            string strPath = strOriginalPath;

            for (int intTrialCounter = 0; intTrialCounter < intMaxTrials; intTrialCounter++)
            {
                strPath = getShortestPath(myPosition, udrTargetLoc, false, false, bolAvoidMap);
                Point udrEndSquare = getSquareAlongPathWhereIRunOutofMovementPoints(strPath);
                if (battlefield.terrain[udrEndSquare.X, udrEndSquare.Y].unit == null)
                    return strPath;
                bolAvoidMap[udrEndSquare.X, udrEndSquare.Y] = true;
            }

            Point udrThisPos = myPosition;
            Point udrNextPos = new Point();
            int intMovementPointsLeft = intMovementPoints;
            string strRetVal = "";
            string strPathTravelledSoFar = "";

            while (strOriginalPath.Length > 0)
            {
                string strDir = strOriginalPath.Substring(0, 2);
                strOriginalPath = strOriginalPath.Substring(2);
                classBattle.enuDirections dir = battlefield.getDirFromString(strDir);
                udrNextPos = battlefield.getNextPos(udrThisPos, dir);
                int intStepMovementCost = battlefield.getMovementCost(battlefield.terrain[udrNextPos.X, udrNextPos.Y].type);
                if (intStepMovementCost > intMovementPointsLeft)
                    return strRetVal;

                intMovementPointsLeft -= intStepMovementCost;
                udrThisPos = udrNextPos;
                strPathTravelledSoFar += dir.ToString();
                if (battlefield.terrain[udrThisPos.X, udrThisPos.Y].unit == null)
                    strRetVal = strPathTravelledSoFar;
            }

            return strRetVal;
        }

        public Point getSquareAlongPathWhereIRunOutofMovementPoints(string strPath)
        { return getSquareAlongPathWhereIRunOutofMovementPoints(strPath, myPosition, intMovementPoints); }
        public Point getSquareAlongPathWhereIRunOutofMovementPoints(string strPath, Point udrStartLoc, int intMovementPointsLeft)
        {
            Point udrThisPos = udrStartLoc;
            Point udrNextPos = new Point();
            while (strPath.Length > 0)
            {
                string strDir = strPath.Substring(0, 2);
                strPath = strPath.Substring(2);
                classBattle.enuDirections dir = battlefield.getDirFromString(strDir);
                udrNextPos = battlefield.getNextPos(udrThisPos, dir);
                int intStepMovementCost = battlefield.getMovementCost(battlefield.terrain[udrNextPos.X, udrNextPos.Y].type);
                if (intStepMovementCost > intMovementPointsLeft)
                    return udrThisPos;
                intMovementPointsLeft -= intStepMovementCost;
                udrThisPos = udrNextPos;
            }
            return udrThisPos;
        }


        public string getShortestPath(Point udrStartLoc, Point udrTargetLoc)
        { return getShortestPath(udrStartLoc, udrTargetLoc, false); }
        public string getShortestPath(Point udrStartLoc, Point udrTargetLoc, bool bolIgnoreMovementCost)
        {
            bool[,] bolAvoidMap = new bool[battlefield.szMapSize.Width, battlefield.szMapSize.Height];
            return getShortestPath(udrStartLoc, udrTargetLoc, bolIgnoreMovementCost, false, bolAvoidMap);
        }
        public string getShortestPath(Point udrStartLoc, Point udrTargetLoc, bool bolIgnoreMovementCost, bool bolIgnoreEnemyUnits, bool[,] bolAvoidMap)
        {
            /// breadth first search
            /// starts from udrTargetLoc and expands outwards using a Q with ranked insertion (least intMovementCost at the front)
            /// then quits search and builds a string path return variable when udrStartLoc has been found
            ///                                             or returns an empty string when udrStartLoc is not found
            int intInfinity = (int)Math.Pow(10, 5);

            classPathMap[,] udrPathMap = new classPathMap[battlefield.szMapSize.Width, battlefield.szMapSize.Height];
            for (int intX = 0; intX < battlefield.szMapSize.Width; intX++)
                for (int intY = 0; intY < battlefield.szMapSize.Height; intY++)
                {
                    udrPathMap[intX, intY] = new classPathMap();
                    udrPathMap[intX, intY].direction = classBattle.enuDirections._num_directions;
                    udrPathMap[intX, intY].intMovementCost = intInfinity;
                    udrPathMap[intX, intY].unit = battlefield.terrain[intX, intY].unit;
                }

            classShortestPathQelement SPeleQ = null;

            classShortestPathQelement firstQele = new classShortestPathQelement(0, udrTargetLoc, classBattle.enuDirections._num_directions);
            enQShortestPathElement(ref SPeleQ, ref firstQele);

            udrPathMap[firstQele.pos.X, firstQele.pos.Y].intMovementCost = 0;

            classShortestPathQelement thisQEle = deQShortestPathElement(ref SPeleQ);

            while (thisQEle != null
                  && !(thisQEle.pos.X == udrStartLoc.X && thisQEle.pos.Y == udrStartLoc.Y))
            {
                string strDir = "";
                for (classBattle.enuDirections dirCounter = 0; dirCounter < classBattle.enuDirections._num_directions; dirCounter++)
                {
                    Point udrNextPos = battlefield.getNextPos(thisQEle.pos, dirCounter);
                    if (udrNextPos.X >= 0 && udrNextPos.Y >= 0 && udrNextPos.X < battlefield.szMapSize.Width && udrNextPos.Y < battlefield.szMapSize.Height)
                    {
                        if (!battlefield.impassableTerrain(battlefield.terrain[udrNextPos.X, udrNextPos.Y].type)
                            && !bolAvoidMap[udrNextPos.X, udrNextPos.Y])
                            if (bolIgnoreEnemyUnits
                                ||
                                (udrPathMap[udrNextPos.X, udrNextPos.Y].unit == null
                                   ||
                                  (udrPathMap[udrNextPos.X, udrNextPos.Y].unit != null
                                   && udrPathMap[udrNextPos.X, udrNextPos.Y].unit.myClr == myClr)))
                            {
                                int intNewMovementCost = thisQEle.intMovementCost + battlefield.getMovementCost(udrNextPos);
                                if (intNewMovementCost < udrPathMap[udrNextPos.X, udrNextPos.Y].intMovementCost)
                                    strDir += dirCounter.ToString();
                            }
                    }
                }
                if (strDir.Length > 4)
                    for (int intShuffler = 0; intShuffler < 10; intShuffler++)
                        shuffle(ref strDir, 2, ref battlefield.rnd);

                while (strDir.Length > 0)
                {
                    string strThisDir = strDir.Substring(0, 2);
                    strDir = strDir.Substring(2);
                    int intMovementCost_new = intInfinity;

                    classBattle.enuDirections dir_new = dir_new = battlefield.getDirFromString(strThisDir);
                    Point udrPos_new = battlefield.getNextPos(thisQEle.pos, dir_new);
                    intMovementCost_new = thisQEle.intMovementCost + battlefield.getMovementCost(udrPos_new);
                    if (intMovementCost_new < udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost || bolIgnoreMovementCost)
                    {
                        udrPathMap[udrPos_new.X, udrPos_new.Y].direction = battlefield.getOppositedirection(dir_new);
                        udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost = intMovementCost_new;
                        udrPathMap[udrPos_new.X, udrPos_new.Y].unit = battlefield.terrain[udrPos_new.X, udrPos_new.Y].unit;

                        udrPathMap[udrPos_new.X, udrPos_new.Y].fullStop = !bolIgnoreEnemyUnits && thereIsAnEnemyUnitNextToThisSquare(udrPos_new, battlefield.terrain[udrTargetLoc.X, udrTargetLoc.Y].unit);

                        if (!udrPathMap[udrPos_new.X, udrPos_new.Y].fullStop)
                        {
                            classShortestPathQelement NewQele = new classShortestPathQelement(udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost, udrPos_new, udrPathMap[udrPos_new.X, udrPos_new.Y].direction);
                            enQShortestPathElement(ref SPeleQ, ref NewQele);
                        }
                    }
                }
                thisQEle = deQShortestPathElement(ref SPeleQ);
            }
            // spit it out
            string retval = "";
            Point thisPos = udrStartLoc;
            if (udrPathMap[thisPos.X, thisPos.Y].direction != classBattle.enuDirections._num_directions)

                while (!(thisPos.X == udrTargetLoc.X && thisPos.Y == udrTargetLoc.Y))
                {
                    retval += udrPathMap[thisPos.X, thisPos.Y].direction;
                    thisPos = battlefield.getNextPos(thisPos, udrPathMap[thisPos.X, thisPos.Y].direction);
                }
            return retval;
        }

        public void shuffle(ref string strInput, int intSizeOfItem, ref Random rndGenerator)
        {
            int intCutChrLeft = 0;
            int intCutChrRight = 0;
            int intNumItems = strInput.Length/ intSizeOfItem;
              if (intNumItems <= 1)
                return;

           while (Math.Abs(intCutChrLeft - intCutChrRight) < 2)
            {
                intCutChrLeft = (int)(rndGenerator.NextDouble() * intNumItems);
                intCutChrRight =(int)( rndGenerator.NextDouble() * intNumItems);
            }
  
            if (intCutChrLeft > intCutChrRight)
            {
                int intTemp = intCutChrLeft;
                intCutChrLeft = intCutChrRight;
                intCutChrRight = intTemp;
            }


    //    transpose A B C -> C B A
            string strA = strInput.Substring(0, intCutChrLeft * intSizeOfItem );
            string strB = strInput.Substring(strA.Length , intSizeOfItem * (intCutChrRight - intCutChrLeft));
            string strC = strInput.Substring(intCutChrRight  * intSizeOfItem );

            strInput = strC + strB + strA;

    //End Sub
        }


        public bool CanTravelBetweenLocsInLessThanNSteps(Point udrStartLoc, Point udrTargetLoc, bool[,] bolAvoidMap, int intMaxSteps)
        {
            /// uses breadth first search to find a shortest-path between udrStartLoc and udrTargetLoc
            /// returns TRUE iff it finds a path shorter than the limit expressed in input parameter intMaxStep
            /// is bound by the bolAvoidMap, not to step on those squares indicated in this boolean array (mapsize)
            int intInfinity = (int)Math.Pow(10, 5);

            classPathMap[,] udrPathMap = new classPathMap[battlefield.szMapSize.Width, battlefield.szMapSize.Height];
            for (int intX = 0; intX < battlefield.szMapSize.Width; intX++)
                for (int intY = 0; intY < battlefield.szMapSize.Height; intY++)
                {
                    udrPathMap[intX, intY].direction = classBattle.enuDirections._num_directions;
                    udrPathMap[intX, intY].intMovementCost = intInfinity;
                    udrPathMap[intX, intY].unit = battlefield.terrain[intX, intY].unit;
                }

            classShortestPathQelement SPEleQ = null;

            classShortestPathQelement firstQele = new classShortestPathQelement(0, udrTargetLoc, classBattle.enuDirections._num_directions);
            enQShortestPathElement(ref SPEleQ, ref firstQele);

            udrPathMap[firstQele.pos.X, firstQele.pos.Y].intMovementCost = 0;

            classShortestPathQelement thisQEle = deQShortestPathElement(ref SPEleQ);

            while (thisQEle != null)
            {
                string strDir = "";
                if (thisQEle.intMovementCost > intMaxSteps)
                    return false;
                int intNewMovementCost = thisQEle.intMovementCost + 1;
                for (classBattle.enuDirections dirCounter = 0; dirCounter < classBattle.enuDirections._num_directions; dirCounter++)
                {
                    Point udrNextPos = battlefield.getNextPos(thisQEle.pos, dirCounter);
                    if (udrNextPos.X == udrStartLoc.X
                        && udrNextPos.Y == udrStartLoc.Y)
                        return (intNewMovementCost < intMaxSteps);
                    if (udrNextPos.X >= 0 && udrNextPos.Y >= 0 && udrNextPos.X < battlefield.szMapSize.Width && udrNextPos.Y < battlefield.szMapSize.Height)
                    {
                        if (!bolAvoidMap[udrNextPos.X, udrNextPos.Y])
                        {
                            if (intNewMovementCost < udrPathMap[udrNextPos.X, udrNextPos.Y].intMovementCost)
                                strDir += dirCounter.ToString();
                        }
                    }
                }
                while (strDir.Length > 0)
                {
                    string strThisDir = strDir.Substring(0, 2);
                    strDir = strDir.Substring(2);
                    int intMovementCost_new = intInfinity;

                    classBattle.enuDirections dir_new = dir_new = battlefield.getDirFromString(strThisDir);
                    Point udrPos_new = battlefield.getNextPos(thisQEle.pos, dir_new);
                    intMovementCost_new = thisQEle.intMovementCost + 1;

                    if (udrPos_new.X == udrStartLoc.X && udrPos_new.Y == udrStartLoc.Y)
                        return (intMovementCost_new < intMaxSteps);

                    if (intMovementCost_new < udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost)
                    {
                        udrPathMap[udrPos_new.X, udrPos_new.Y].direction = battlefield.getOppositedirection(dir_new);
                        udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost = intMovementCost_new;
                        udrPathMap[udrPos_new.X, udrPos_new.Y].unit = battlefield.terrain[udrPos_new.X, udrPos_new.Y].unit;


                        classShortestPathQelement NewQele = new classShortestPathQelement(udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost, udrPos_new, udrPathMap[udrPos_new.X, udrPos_new.Y].direction);
                        enQShortestPathElement(ref SPEleQ, ref NewQele);
                    }
                }
                thisQEle = deQShortestPathElement(ref SPEleQ);
            }
            return false;
        }

        public int getTravelTimeToLocInTurns(Point udrEndLoc)
        { return getTravelTimeToLocInTurns(myPosition, udrEndLoc); }
        public int getTravelTimeToLocInTurns(Point udrStartLoc, Point udrEndLoc)
        {
            int intRetVal = 0;
            string strPath = getShortestPath(udrStartLoc, udrEndLoc);
            int intMPts = 0;
            int intCostToMove = 0;
            classBattle.enuDirections dir = classBattle.enuDirections.N_;
            string strDir = "";
            Point udrPos = udrStartLoc;
            while (strPath.Length > 0)
            {
                strDir = strPath.Substring(0, 2);
                strPath = strPath.Substring(2);

                dir = battlefield.getDirFromString(strDir);
                udrPos = battlefield.getNextPos(udrPos, dir);
                intCostToMove = battlefield.getMovementCost(battlefield.terrain[udrPos.X, udrPos.Y].type);
                if (intCostToMove > intMPts)
                {
                    intRetVal++;
                    intMPts = intMovementPoints_Max;
                }
                intMPts -= intCostToMove;
            }
            return intRetVal;
        }

        public string getShortestPathToNearestEnemyUnit()
        { return getShortestPathToNearestEnemyUnit(myPosition); }
        public string getShortestPathToNearestEnemyUnit(Point udrLoc)
        { return getShortestPathToNearestEnemyUnit(udrLoc, battlefield.getBolDefaultAvoidMap()); }
        public string getShortestPathToNearestEnemyUnit(Point udrLoc, bool[,] bolAvoidMap)
        {
            classBattleField.classAIShortestPathToEnemy[] udrSP = getShortestPathToAllEnemyUnits(udrLoc, bolAvoidMap);
            if (udrSP.Length > 0)
            {
                battlefield.reorderByPathLengthAIShortestPathToEnemyArray(ref udrSP);
                for (int intPathCounter = udrSP.Length - 1; intPathCounter >= 0; intPathCounter--)
                {
                    if (udrSP[intPathCounter].path.Length > 0)
                        return udrSP[intPathCounter].path;
                }
                return "";
            }
            else
                return "";
        }

        public classBattleField.classAIShortestPathToEnemy[] getShortestPathToAllEnemyUnits()
        { return getShortestPathToAllEnemyUnits(myPosition, battlefield.getBolDefaultAvoidMap()); }
        public classBattleField.classAIShortestPathToEnemy[] getShortestPathToAllEnemyUnits(Point udrStartLoc, bool[,] bolAvoidMap)
        {
            /// finds the shortest path to all enemy units
            /// is bound by bolAvoidMap, not to step on squares in boolean array set to true
            /// does not take movement cost into consideration but counts squares, number of steps NOT travel cost
            int intInfinity = (int)Math.Pow(10, 5);

            classPathMap[,] udrPathMap = new classPathMap[battlefield.szMapSize.Width, battlefield.szMapSize.Height];
            for (int intCounterXCounter =0; intCounterXCounter < battlefield.szMapSize.Width; intCounterXCounter ++)
            for (int intCounterYCounter =0; intCounterYCounter < battlefield.szMapSize.Height; intCounterYCounter ++)
                udrPathMap[intCounterXCounter, intCounterYCounter] = new classPathMap();

            for (int intX = 0; intX < battlefield.szMapSize.Width; intX++)
                for (int intY = 0; intY < battlefield.szMapSize.Height; intY++)
                {
                    udrPathMap[intX, intY].direction = classBattle.enuDirections._num_directions;
                    udrPathMap[intX, intY].intMovementCost = intInfinity;
                    udrPathMap[intX, intY].unit = battlefield.terrain[intX, intY].unit;
                }

            classShortestPathQelement SPEleQ = null;

            classShortestPathQelement firstQele = new classShortestPathQelement(0, udrStartLoc, classBattle.enuDirections._num_directions);
            enQShortestPathElement(ref SPEleQ, ref firstQele);

            udrPathMap[firstQele.pos.X, firstQele.pos.Y].intMovementCost = 0;

            classShortestPathQelement thisQEle = deQShortestPathElement(ref SPEleQ);

            int intNumberEnemy = battlefield.CountUnitsInQ(battlefield.Unit_Q[(int)otherClr()]);
            int intNumberEnemyFound = 0;
            while (thisQEle != null
                  && intNumberEnemyFound < intNumberEnemy)
            {
                string strDir = "";
                for (classBattle.enuDirections dirCounter = 0; dirCounter < classBattle.enuDirections._num_directions; dirCounter++)
                {
                    Point udrNextPos = battlefield.getNextPos(thisQEle.pos, dirCounter);
                    if (udrNextPos.X >= 0 && udrNextPos.Y >= 0 && udrNextPos.X < battlefield.szMapSize.Width && udrNextPos.Y < battlefield.szMapSize.Height)
                    {
                        int intMovementCost_new = thisQEle.intMovementCost + battlefield.getMovementCost(udrNextPos);
                        if (intMovementCost_new < udrPathMap[udrNextPos.X, udrNextPos.Y].intMovementCost
                            && !bolAvoidMap[udrNextPos.X, udrNextPos.Y])
                        {
                            strDir += dirCounter.ToString();
                        }
                    }
                }

                if (udrPathMap[thisQEle.pos.X, thisQEle.pos.Y].unit != null
                          && !ClrIsSameAsMyClr(udrPathMap[thisQEle.pos.X, thisQEle.pos.Y].unit.myClr))
                    intNumberEnemyFound++;

                while (strDir.Length > 0)
                {
                    string strThisDir = strDir.Substring(0, 2);
                    strDir = strDir.Substring(2);
                    classBattle.enuDirections dir_new = dir_new = battlefield.getDirFromString(strThisDir);
                    Point udrPos_new = battlefield.getNextPos(thisQEle.pos, dir_new);
                    if (udrPos_new.X >= 0 && udrPos_new.X < battlefield.szMapSize.Width
                        &&
                        udrPos_new.Y >= 0 && udrPos_new.Y < battlefield.szMapSize.Height)
                    {
                        int intMovementCost_new = thisQEle.intMovementCost + battlefield.getMovementCost(udrPos_new);


                        if (intMovementCost_new < udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost
                            && !bolAvoidMap[udrPos_new.X, udrPos_new.Y])
                        {
                            udrPathMap[udrPos_new.X, udrPos_new.Y].direction = battlefield.getOppositedirection(dir_new);
                            udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost = intMovementCost_new;
                            udrPathMap[udrPos_new.X, udrPos_new.Y].unit = battlefield.terrain[udrPos_new.X, udrPos_new.Y].unit;

                            classShortestPathQelement NewQele = new classShortestPathQelement(udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost, udrPos_new, udrPathMap[udrPos_new.X, udrPos_new.Y].direction);
                            enQShortestPathElement(ref SPEleQ, ref NewQele);
                        }
                    }
                }
                thisQEle = deQShortestPathElement(ref SPEleQ);
            }
            // spit it out
            classBattleField.classAIShortestPathToEnemy[] retval = new classBattleField.classAIShortestPathToEnemy[0];
            classBattleUnit thisEnemyUnit = battlefield.Unit_Q[(int)otherClr()];
            while (thisEnemyUnit != null)
            {
                Point thisPos = thisEnemyUnit.myPosition;

                if (udrPathMap[thisPos.X, thisPos.Y].direction != classBattle.enuDirections._num_directions)
                {
                    Array.Resize<classBattleField.classAIShortestPathToEnemy>(ref retval, retval.Length + 1);
                    for (int intCounter = 0; intCounter < retval.Length; intCounter++)
                        retval[intCounter] = new classBattleField.classAIShortestPathToEnemy();
                    retval[retval.Length - 1].unit = thisEnemyUnit;
                    retval[retval.Length - 1].path = "";
                    retval[retval.Length - 1].intTotalMovementCost = 0;
                    while (!(thisPos.X == udrStartLoc.X && thisPos.Y == udrStartLoc.Y))
                    {
                        retval[retval.Length - 1].path = battlefield.getOppositedirection(udrPathMap[thisPos.X, thisPos.Y].direction) + retval[retval.Length - 1].path;
                        thisPos = battlefield.getNextPos(thisPos, udrPathMap[thisPos.X, thisPos.Y].direction);
                        retval[retval.Length - 1].intTotalMovementCost += battlefield.getMovementCost(thisPos);
                    }
                }
                thisEnemyUnit = thisEnemyUnit.next;
            }
            return retval;
        }

        public int getMovementCostAlongTravelPath(string strPath)
        { return getMovementCostAlongTravelPath(strPath, myPosition); }
        public int getMovementCostAlongTravelPath(string strPath, Point udrStartLoc)
        {
            int intRetval = 0;
            Point thisPos = udrStartLoc;
            while (strPath.Length > 0)
            {
                string strDir = strPath.Substring(0, 2);
                strPath = strPath.Substring(2);
                thisPos = battlefield.getNextPos(thisPos, battlefield.getDirFromString(strDir));
                intRetval += battlefield.getMovementCost(thisPos);
            }
            return intRetval;
        }

        public enuSearchMap[,] searchMap()
        {
            // sets up a boolean array for the subsequent call to the working function below
            bool[,] bolAvoidMapLoc = new bool[battlefield.szMapSize.Width, battlefield.szMapSize.Height];
            for (int intX = 0; intX < battlefield.szMapSize.Width; intX++)
                for (int intY = 0; intY < battlefield.szMapSize.Height; intY++)
                {
                    if (battlefield.getMovementCost(battlefield.cLibBattle.getPos(intX, intY)) > intMovementPoints_Max)
                        bolAvoidMapLoc[intX, intY] = true;
                }
            return searchMap(myPosition, bolAvoidMapLoc);
        }

        public enuSearchMap[,] searchMap(Point udrLoc, bool[,] bolAvoidMapLoc)
        {
            /// returns 2d array describing map in terms of : ally, enemy, open OR unreachable
            enuSearchMap[,] retVal = new enuSearchMap[battlefield.szMapSize.Width, battlefield.szMapSize.Height];
            int intInfinity = (int)Math.Pow(10, 5);
            Point udrRetVal = new Point();
            classPathMap[,] udrPathMap = new classPathMap[battlefield.szMapSize.Width, battlefield.szMapSize.Height];
            for (int intX = 0; intX < battlefield.szMapSize.Width; intX++)
                for (int intY = 0; intY < battlefield.szMapSize.Height; intY++)
                {
                    udrPathMap[intX, intY] = new classPathMap();
                    udrPathMap[intX, intY].intMovementCost = intInfinity;
                    if (battlefield.terrain[intX, intY].unit != null
                        && battlefield.terrain[intX, intY].unit.myClr != myClr)
                        retVal[intX, intY] = enuSearchMap.enemy;
                }

            bool bolCannotMove = true;
            for (classBattle.enuDirections dirCounter = 0; dirCounter < classBattle.enuDirections._num_directions; dirCounter++)
            {
                Point udrNextPos = battlefield.getNextPos(myPosition, dirCounter);
                if (udrNextPos.X < battlefield.szMapSize.Width && udrNextPos.X >= 0
                    && udrNextPos.Y < battlefield.szMapSize.Height && udrNextPos.Y >= 0)
                {
                    if (!bolAvoidMapLoc[udrNextPos.X, udrNextPos.Y])
                    {
                        bolCannotMove = false;
                        break;
                    }
                }
            }
            if (bolCannotMove)
                return retVal;

            classShortestPathQelement SPEleQ = null;

            classShortestPathQelement firstQele = new classShortestPathQelement(0, myPosition, classBattle.enuDirections._num_directions);
            enQShortestPathElement(ref SPEleQ, ref firstQele);
            udrPathMap[myPosition.X, myPosition.Y].intMovementCost = 0;
            classShortestPathQelement thisQEle = deQShortestPathElement(ref SPEleQ);

            while (thisQEle != null)
            {
                string strDir = "";

                classBattle.classTerrain thisTerrain = battlefield.terrain[thisQEle.pos.X, thisQEle.pos.Y];

                if (thisTerrain.unit != null)
                    if (thisTerrain.unit.myClr != myClr)
                        retVal[thisQEle.pos.X, thisQEle.pos.Y] = enuSearchMap.enemy;
                    else
                        retVal[thisQEle.pos.X, thisQEle.pos.Y] = enuSearchMap.ally;
                else
                    retVal[thisQEle.pos.X, thisQEle.pos.Y] = enuSearchMap.empty;


                for (classBattle.enuDirections dirCounter = 0; dirCounter < classBattle.enuDirections._num_directions; dirCounter++)
                {
                    Point udrNextPos = battlefield.getNextPos(thisQEle.pos, dirCounter);
                    if (udrNextPos.X >= 0 && udrNextPos.Y >= 0 && udrNextPos.X < battlefield.szMapSize.Width && udrNextPos.Y < battlefield.szMapSize.Height)
                    {
                        int intMovementCost_new_TestDir = thisQEle.intMovementCost + battlefield.getMovementCost(udrNextPos);
                        if (intMovementCost_new_TestDir < udrPathMap[udrNextPos.X, udrNextPos.Y].intMovementCost
                            && (battlefield.terrain[udrNextPos.X, udrNextPos.Y].unit == null
                                 ||
                                (battlefield.terrain[udrNextPos.X, udrNextPos.Y].unit != null
                                 && battlefield.terrain[udrNextPos.X, udrNextPos.Y].unit.myClr == myClr
                                )
                               )
                            && !bolAvoidMapLoc[udrNextPos.X, udrNextPos.Y])
                            strDir += dirCounter.ToString();
                    }
                }

                while (strDir.Length > 0)
                {
                    string strThisDir = strDir.Substring(0, 2);
                    strDir = strDir.Substring(2);
                    classBattle.enuDirections dir_new = battlefield.getDirFromString(strThisDir);
                    Point udrPos_new = battlefield.getNextPos(thisQEle.pos, dir_new);
                    int intMovementCost_new = thisQEle.intMovementCost + battlefield.getMovementCost(udrPos_new);


                    if (!bolAvoidMapLoc[udrPos_new.X, udrPos_new.Y])
                    {
                        udrPathMap[udrPos_new.X, udrPos_new.Y].direction = battlefield.getOppositedirection(dir_new);
                        udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost = intMovementCost_new;
                        udrPathMap[udrPos_new.X, udrPos_new.Y].unit = battlefield.terrain[udrPos_new.X, udrPos_new.Y].unit;
                        udrPathMap[udrPos_new.X, udrPos_new.Y].fullStop = thereIsAnEnemyUnitNextToThisSquare(udrPos_new, battlefield.terrain[udrTargetLoc.X, udrTargetLoc.Y].unit);

                        classShortestPathQelement NewQele = new classShortestPathQelement(udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost, udrPos_new, udrPathMap[udrPos_new.X, udrPos_new.Y].direction);
                        enQShortestPathElement(ref SPEleQ, ref NewQele);
                    }
                }
                thisQEle = deQShortestPathElement(ref SPEleQ);
            }

            return retVal;
        }

        bool CanReachAnAttackLocation(enuSearchMap[,] udrSM)
        {
            /// given the results of searchMap() (above) this function scans this SM for enemy units
            /// then it gets that enemy unit's target map (locations it can strike from where it currently is) given MY RANGE (this instance of battleUnit)
            /// then scans the resultant attackMap[,] empty spaces where this unit can move, occupy and attack
            /// returns TRUE or FALSE
            for (int intX = 0; intX < battlefield.szMapSize.Width; intX++)
                for (int intY = 0; intY < battlefield.szMapSize.Height; intY++)
                {
                    if (udrSM[intX, intY] == enuSearchMap.enemy)
                    {
                        bool[,] bolAttackMap = battlefield.terrain[intX, intY].unit.getAttackMapFromLoc(battlefield.cLibBattle.getPos(intX, intY), getRangeForTerrain());

                        for (int intAX = 0; intAX < battlefield.szMapSize.Width; intAX++)
                            for (int intAY = 0; intAY < battlefield.szMapSize.Height; intAY++)
                                if (bolAttackMap[intAX, intAY])
                                    if (udrSM[intAX, intAY] == enuSearchMap.empty)
                                        return true;
                    }
                }
            return false;
        }
        /******************************************************************************************************************************************/
        public Point getNearestOpenFieldMapLocation(ref classBattleField.classOpenFieldDefenseInfo udrOFDInfo)
        {
            return myPosition;
        }
        /******************************************************************************************************************************************/
        



        /******************************************************************************************************************************************/
        Point[] getPOCsNextToLoc(classBattleField.classPOCSearchInfo udrPOC)
        { return getPOCsNextToLoc(udrPOC, myPosition); }
        Point[] getPOCsNextToLoc(classBattleField.classPOCSearchInfo udrPOC, Point udrLoc)
        {
            Point[] udrRetVal = new Point[0];
            Point udrNextPos;
            for (classBattle.enuDirections dirCounter = 0; dirCounter < classBattle.enuDirections._num_directions; dirCounter++)
            {
                udrNextPos = battlefield.getNextPos(udrLoc, dirCounter);
                if (battlefield.ptOnMap(udrNextPos))
                    if (udrPOC.POCMap[udrNextPos.X, udrNextPos.Y] > 0)
                    {
                        Array.Resize<Point>(ref udrRetVal, udrRetVal.Length + 1);
                        udrRetVal[udrRetVal.Length - 1] = udrNextPos;
                    }
            }
            return udrRetVal;
        }

        public Point getNearestDefensibleLocation(ref classBattleField.classPOCSearchInfo udrPOC)
        {
            bool bolNoValidPOCLocs = true;
            for (int intPOCLocCounter = 0; intPOCLocCounter < udrPOC.POCLocs.Length; intPOCLocCounter++)
                if (udrPOC.POCLocs[intPOCLocCounter].flag)
                {
                    bolNoValidPOCLocs = false;
                    break;
                }

            bool bolIAmArtilleryUnderMeleeAttack = false;
            if (myType == classBattle.enuUnitTypes.artillery)
            {
                if (thereIsAnEnemyUnitNextToThisSquare(myPosition)) // protect artillery from melee attacks
                {
                    bolIAmArtilleryUnderMeleeAttack = true;
                }
                else
                {
                    if (CanIAttackFromThisPos(myPosition, getRangeForTerrain()))
                        return myPosition;
                }
            }
            else if (udrPOC.POCMap[myPosition.X, myPosition.Y] == 0)
            {
                if (bolNoValidPOCLocs)
                {
                    int intMovementCostToNearestPOC = 0;
                    string strPathToNearestPOC = "";
                    Point udrNearestPOC = getNearestPOCDefenseSquare(udrPOC, myPosition, ref strPathToNearestPOC, ref intMovementCostToNearestPOC);
                    if (intMovementCostToNearestPOC > intMovementPoints_Max)
                        return udrNearestPOC;
                    else
                        return myPosition;
                }
            }
            bool[,] bolAvoidMap = new bool[battlefield.szMapSize.Width, battlefield.szMapSize.Height];
            for (int intX = 0; intX < battlefield.szMapSize.Width; intX++)
                for (int intY = 0; intY < battlefield.szMapSize.Height; intY++)
                    bolAvoidMap[intX, intY] = udrPOC.bolAvoidMap[intX, intY] ? true : false;
            if (bolIAmArtilleryUnderMeleeAttack)
                bolAvoidMap[myPosition.X, myPosition.Y] = true;
            return getNearestDefensibleLocation(ref udrPOC, bolAvoidMap);
        }

        public Point getNearestDefensibleLocation(ref classBattleField.classPOCSearchInfo udrPOC, bool[,] bolAvoidMap)
        {
            int intInfinity = (int)Math.Pow(10, 5);
            classPathMap[,] udrPathMap = new classPathMap[battlefield.szMapSize.Width, battlefield.szMapSize.Height];

            for (int intX = 0; intX < battlefield.szMapSize.Width; intX++)
                for (int intY = 0; intY < battlefield.szMapSize.Height; intY++)
                {
                    udrPathMap[intX, intY].intMovementCost = intInfinity;
                    if (battlefield.getMovementCost(battlefield.cLibBattle.getPos(intX, intY)) > intMovementPoints_Max)
                        bolAvoidMap[intX, intY] = true;
                }

           if (udrUnGuardPOCs.Length > 0)
            {
                if (myType != classBattle.enuUnitTypes.artillery)
                {
                    Point[] udrPOCNextToLoc = getPOCsNextToLoc(udrPOC);
                    bool bolICanLeaveMyPost = true;
                    for (int intPOCCounter = 0; intPOCCounter < udrPOCNextToLoc.Length; intPOCCounter++)
                    {
                        if (countFriendlyUnitsNextToThisSquare(udrPOCNextToLoc[intPOCCounter]) <= 1)
                            bolICanLeaveMyPost = false;
                    }

                    if (bolICanLeaveMyPost)
                    {
                        {  // there are more than 1 friendly guarded this POC
                            // this unit can move to unguarded POC
                            for (int intUnGuardedPOCCounter = 0; intUnGuardedPOCCounter < udrUnGuardPOCs.Length; intUnGuardedPOCCounter++)
                            {
                                string strPathToUnguardedPOC = getShortestPath(myPosition, udrUnGuardPOCs[intUnGuardedPOCCounter]);
                                if (strPathToUnguardedPOC.Length > 0)
                                {
                                    // cut off last step before stepping onto POC 
                                    string strLastStep = strPathToUnguardedPOC.Substring(strPathToUnguardedPOC.Length - 2);
                                    strPathToUnguardedPOC = strPathToUnguardedPOC.Substring(0, strPathToUnguardedPOC.Length - 2);

                                    int intMovementCostToUnguardedPOC = getMovementCostAlongTravelPath(strPathToUnguardedPOC);
                                    if (intMovementCostToUnguardedPOC < intMovementPoints)
                                    {
                                        // remove unguarded POC from list
                                        Point udrRetVal = battlefield.getNextPos(udrUnGuardPOCs[intUnGuardedPOCCounter], battlefield.getOppositedirection(battlefield.getDirFromString(strLastStep)));
                                        udrUnGuardPOCs[intUnGuardedPOCCounter] = udrUnGuardPOCs[udrUnGuardPOCs.Length - 1];
                                        Array.Resize<Point>(ref udrUnGuardPOCs, udrUnGuardPOCs.Length - 1);

                                        return udrRetVal;
                                    }
                                }
                                else
                                    return myPosition;
                            }
                        }
                    }
                }
            }
            else
            {
                if (!CanIAttackFromThisPos(myPosition, intRange) || bolAvoidMap[myPosition.X, myPosition.Y] )
                {
                    Point udrNearestAttackPos = getNearestAttackLocation(bolAvoidMap);
                    if (udrPOC.POCMap[udrNearestAttackPos.X, udrNearestAttackPos.Y] == 0)
                    {
                        string strPathToNearestAttackPos = getShortestPath(myPosition, udrNearestAttackPos);
                        if (strPathToNearestAttackPos.Length > 0)
                        {
                            int intCostToMoveToNearestAttackPos = getMovementCostAlongTravelPath(strPathToNearestAttackPos);
                            if (intCostToMoveToNearestAttackPos < intMovementPoints)
                                return udrNearestAttackPos;
                        }
                    }
                }
                
                if ( !CanIAttackAPOCFromThisPos(udrPOC, myPosition, intRange, true))
                {
                    int intMovementCostToNearestPOC = 0;
                    string strPathToNearestPOC = "";
                    Point udrNearestPOC = getNearestPOCDefenseSquare(udrPOC, myPosition, ref strPathToNearestPOC, ref intMovementCostToNearestPOC);
                    if (intMovementCostToNearestPOC < intMovementPoints_Max)
                        return udrNearestPOC;
                    else
                        return myPosition;
                }
                else
                    return myPosition;
            }



            bool bolCannotMove = true;
            for (classBattle.enuDirections dirCounter = 0; dirCounter < classBattle.enuDirections._num_directions; dirCounter++)
            {
                Point udrNextPos = battlefield.getNextPos(myPosition, dirCounter);
                if (udrNextPos.X < battlefield.szMapSize.Width && udrNextPos.X >= 0
                    && udrNextPos.Y < battlefield.szMapSize.Height && udrNextPos.Y >= 0)
                {
                    if (!bolAvoidMap[udrNextPos.X, udrNextPos.Y])
                    {
                        bolCannotMove = false;
                        break;
                    }
                }
            }

            if (bolCannotMove)
                return myPosition;

            enuSearchMap[,] udrSM = searchMap(myPosition, bolAvoidMap);

            classShortestPathQelement SPEleQ = null;
            classBattleField.classAIShortestPathToEnemy[] udrOptions = new classBattleField.classAIShortestPathToEnemy[0];

            classShortestPathQelement firstQele = new classShortestPathQelement(0, myPosition, classBattle.enuDirections._num_directions);
            enQShortestPathElement(ref SPEleQ, ref firstQele);
            udrPathMap[myPosition.X, myPosition.Y].intMovementCost = 0;
            classShortestPathQelement thisQEle = deQShortestPathElement(ref SPEleQ);

            while (thisQEle != null)
            {
                string strDir = "";
                for (classBattle.enuDirections dirCounter = 0; dirCounter < classBattle.enuDirections._num_directions; dirCounter++)
                {
                    Point udrNextPos = battlefield.getNextPos(thisQEle.pos, dirCounter);
                    if (udrNextPos.X >= 0 && udrNextPos.Y >= 0 && udrNextPos.X < battlefield.szMapSize.Width && udrNextPos.Y < battlefield.szMapSize.Height)
                    {
                        int intMovementCost_new_TestDir = thisQEle.intMovementCost + battlefield.getMovementCost(udrNextPos);
                        if (udrPathMap[udrNextPos.X, udrNextPos.Y].intMovementCost > intMovementCost_new_TestDir
                            && (battlefield.terrain[udrNextPos.X, udrNextPos.Y].unit == null
                                 ||
                                (battlefield.terrain[udrNextPos.X, udrNextPos.Y].unit != null
                                 && battlefield.terrain[udrNextPos.X, udrNextPos.Y].unit.myClr == myClr
                                )
                               )
                            && !bolAvoidMap[udrNextPos.X, udrNextPos.Y])
                            strDir += dirCounter.ToString();
                    }
                }

                bool bolICanMoveFromHere = false;
                while (strDir.Length > 0)
                {
                    string strThisDir = strDir.Substring(0, 2);
                    strDir = strDir.Substring(2);

                    classBattle.enuDirections dir_new = battlefield.getDirFromString(strThisDir);
                    Point udrPos_new = battlefield.getNextPos(thisQEle.pos, dir_new);
                    int intMovementCost_new = thisQEle.intMovementCost + battlefield.getMovementCost(udrPos_new);

                    if (!bolAvoidMap[udrPos_new.X, udrPos_new.Y])
                    {
                        udrPathMap[udrPos_new.X, udrPos_new.Y].direction = battlefield.getOppositedirection(dir_new);
                        udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost = intMovementCost_new;
                        udrPathMap[udrPos_new.X, udrPos_new.Y].unit = battlefield.terrain[udrPos_new.X, udrPos_new.Y].unit;
                        udrPathMap[udrPos_new.X, udrPos_new.Y].fullStop = thereIsAnEnemyUnitNextToThisSquare(udrPos_new, battlefield.terrain[udrPos_new.X, udrPos_new.Y].unit);

                        if (battlefield.terrain[udrPos_new.X, udrPos_new.Y].unit == null)
                        {
                            if (udrPOC.POCMap[udrPos_new.X, udrPos_new.Y] == 0)
                                if (CanIAttackAPOCFromThisPos(udrPOC, udrPos_new, intRange, true)
                                    || (myType == classBattle.enuUnitTypes.artillery
                                        && CanIAttackFromThisPos(udrPos_new, getRangeForTerrain(udrPos_new))))
                                {
                                    Array.Resize<classBattleField.classAIShortestPathToEnemy>(ref udrOptions, udrOptions.Length + 1);
                                    udrOptions[udrOptions.Length - 1].unit = battlefield.terrain[udrAttackLoc.X, udrAttackLoc.Y].unit;
                                    udrOptions[udrOptions.Length - 1].udrLoc = udrPos_new;
                                    udrOptions[udrOptions.Length - 1].flag = false;
                                    udrOptions[udrOptions.Length - 1].path = "";

                                    udrOptions[udrOptions.Length - 1].rating = 1
                                                                               + (udrPOC.POCMap[udrPos_new.X, udrPos_new.Y] == 0 ? (myType == classBattle.enuUnitTypes.artillery ? 2 : 1) : 0)
                                                                               + CountPOCsICanAttackFromThisPos(udrPOC, udrPos_new, getRangeForTerrain(udrPos_new), true) * 2
                                                                               + CountUnitsIAttackFromThisPos(udrPos_new, getRangeForTerrain(udrPos_new)) * 2;
                                }
                        }

                        if (!udrPathMap[udrPos_new.X, udrPos_new.Y].fullStop)
                        {
                            bolICanMoveFromHere = true;
                            classShortestPathQelement NewQele = new classShortestPathQelement(udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost, udrPos_new, udrPathMap[udrPos_new.X, udrPos_new.Y].direction);
                            enQShortestPathElement(ref SPEleQ, ref NewQele);
                        }
                    }
                }
                if (!bolICanMoveFromHere)
                {
                    bolAvoidMap[thisQEle.pos.X, thisQEle.pos.Y] = true;
                    if (udrOptions.Length == 0)
                    {
                        if (thisQEle.pos.X == myPosition.X && thisQEle.pos.Y == myPosition.Y)
                            return myPosition;
                        else
                            return getNearestDefensibleLocation(ref udrPOC, bolAvoidMap);
                    }
                }
                thisQEle = deQShortestPathElement(ref SPEleQ);
            }

        measureMovementPoints:
            if (udrOptions.Length == 0)
                return myPosition;
            for (int intOptionCounter = 0; intOptionCounter < udrOptions.Length; intOptionCounter++)
            {
                Point thisPos = udrOptions[intOptionCounter].udrLoc;
                udrOptions[intOptionCounter].path = "";
                if (udrPathMap[thisPos.X, thisPos.Y].direction != classBattle.enuDirections._num_directions)

                    while (!(thisPos.X == myPosition.X && thisPos.Y == myPosition.Y))
                    {
                        udrOptions[intOptionCounter].path = battlefield.getOppositedirection(udrPathMap[thisPos.X, thisPos.Y].direction).ToString() + udrOptions[intOptionCounter].path;
                        thisPos = battlefield.getNextPos(thisPos, udrPathMap[thisPos.X, thisPos.Y].direction);
                    }
            }
            // reorder by Rating
            battlefield.reorderByPathLengthAIShortestPathToEnemyArray_byRating(ref udrOptions);

            // keep best rating
            int intIndexLastBestRating = udrOptions[0].rating;
            for (int intOptionCounter = 1; intOptionCounter < udrOptions.Length; intOptionCounter++)
                if (udrOptions[intOptionCounter].rating < udrOptions[0].rating)
                {
                    intIndexLastBestRating = intOptionCounter;
                    break;
                }

            Array.Resize<classBattleField.classAIShortestPathToEnemy>(ref udrOptions, intIndexLastBestRating);

            // reorder by length and pick the nearest one
            battlefield.reorderByPathLengthAIShortestPathToEnemyArray(ref udrOptions);

            // traverse path until out of movement points
            Point udrPos = myPosition;
            Point udrNextPathPos = new Point();
            int intBestChoice = 0;
            if (myType == classBattle.enuUnitTypes.artillery)
            { // find one that is a range of 2 or more
                for (int intOptionCounter = 0; intOptionCounter < udrOptions.Length; intOptionCounter++)
                {
                    int intDistance = getDistanceBetweenSquares(udrOptions[intOptionCounter].udrLoc, udrOptions[intOptionCounter].udrLoc);
                    if (intDistance > 1)
                    {
                        intBestChoice = intOptionCounter;
                        break;
                    }
                }
            }

            string strPathCopy = udrOptions[intBestChoice].path;
            int intMyMovementPoints = intMovementPoints;
            while (udrOptions[intBestChoice].path.Length > 0)
            {
                string strDir = udrOptions[intBestChoice].path.Substring(0, 2);
                udrOptions[intBestChoice].path = udrOptions[intBestChoice].path.Substring(2);
                classBattle.enuDirections dir_new = battlefield.getDirFromString(strDir);
                udrNextPathPos = battlefield.getNextPos(udrPos, dir_new);
                int intMovementCost = battlefield.getMovementCost(udrNextPathPos);

                intMyMovementPoints -= intMovementCost;
                if (intMyMovementPoints < 0)
                { // will have to stop here
                    if (!(udrPos.X == myPosition.X && udrPos.Y == myPosition.Y)
                        && battlefield.terrain[udrPos.X, udrPos.Y].unit != null)
                        goto Failed;
                    else
                        return udrPos;
                }
                udrPos = udrNextPathPos;
            }

            if (battlefield.terrain[udrPos.X, udrPos.Y].unit == null)
                return udrPos;
        Failed:
            bolAvoidMap[udrPos.X, udrPos.Y] = true;
            return getNearestDefensibleLocation(ref udrPOC, bolAvoidMap);
        }

        /******************************************************************************************************************************************/
        public bool ThereIsASafeEmptySquareNextToLoc(classBattleField.classPOCSearchInfo udrPOC, Point udrLoc, ref Point udrSafeLoc)
        {
            Point udrNextPos;
            for (classBattle.enuDirections dirCounter = 0; dirCounter < classBattle.enuDirections._num_directions; dirCounter++)
            {
                udrNextPos = battlefield.getNextPos(udrLoc, dirCounter);
                if (battlefield.ptOnMap(udrNextPos))
                {
                    if (udrPOC.POCMap[udrNextPos.X, udrNextPos.Y] == 0
                        && battlefield.terrain[udrNextPos.X, udrNextPos.Y].unit == null)
                    {
                        udrSafeLoc = udrNextPos;
                        return true;
                    }
                }
            }
            return false;
        }
        public Point getNearestPOCDefenseSquare(classBattleField.classPOCSearchInfo udrPOC, ref string strPath, ref int intMovementCost)
        { return getNearestPOCDefenseSquare(udrPOC, myPosition, ref strPath, ref intMovementCost); }
        public Point getNearestPOCDefenseSquare(classBattleField.classPOCSearchInfo udrPOC, Point udrStartLoc, ref string strPath, ref int intMovementCost)
        {
            Point udrRetVal = myPosition;
            strPath = "";
            intMovementCost = 100000;

            string strPath_Temp = "";
            int intMovementCost_Temp = 0;
            for (int intPOCCounter = 0; intPOCCounter < udrPOC.POCLocs.Length; intPOCCounter++)
            {
                if (udrPOC.POCLocs[intPOCCounter].flag)
                {
                    Point udrSafeLoc = new Point();
                    if (getDistanceBetweenSquares(myPosition, udrPOC.POCLocs[intPOCCounter].pt) > 1)
                    {
                        if (ThereIsASafeEmptySquareNextToLoc(udrPOC, udrPOC.POCLocs[intPOCCounter].pt, ref udrSafeLoc))
                        {
                            strPath_Temp = getShortestPath(udrStartLoc, udrSafeLoc);
                            intMovementCost_Temp = getMovementCostAlongTravelPath(strPath_Temp, udrStartLoc);
                            if (intMovementCost_Temp < intMovementCost)
                            {
                                intMovementCost = intMovementCost_Temp;
                                strPath = strPath_Temp;
                                udrRetVal = udrSafeLoc;
                            }
                        }
                    }
                    else
                    { // i am already defending a POC
                        strPath = "";
                        udrRetVal = myPosition;
                        return udrRetVal;
                    }
                }
            }
            return udrRetVal;
        }

        public Point getNearestAttackLocation(bool[,] bolAvoidMapLoc)
        {
            if (CanIAttackFromThisPos(myPosition, getRangeForTerrain(myPosition)))
            {
                if (myType == classBattle.enuUnitTypes.artillery)
                {
                    int intDistance = getDistanceBetweenSquares(myPosition, udrAttackLoc);
                    if (intDistance > 1)
                        return myPosition;
                }
                else
                    return myPosition;
            }
            classShortestPathQelement MyNewQele;
            int intInfinity = (int)Math.Pow(10, 5);
            classPathMap[,] udrPathMap = new classPathMap[battlefield.szMapSize.Width, battlefield.szMapSize.Height];
            for (int intPathCounterX = 0; intPathCounterX < battlefield.szMapSize.Width; intPathCounterX ++)
            {
                for(int intPathCounterY = 0; intPathCounterY < battlefield.szMapSize.Height; intPathCounterY++)
                {
                    udrPathMap[intPathCounterX, intPathCounterY] = new classPathMap();
                }
            }

            for (int intX = 0; intX < battlefield.szMapSize.Width; intX++)
                for (int intY = 0; intY < battlefield.szMapSize.Height; intY++)
                {
                    udrPathMap[intX, intY].intMovementCost = intInfinity;
                    if (battlefield.getMovementCost(battlefield.cLibBattle.getPos(intX, intY)) > intMovementPoints_Max)
                        bolAvoidMapLoc[intX, intY] = true;
                }

            bool bolCannotMove = true;
            for (classBattle.enuDirections dirCounter = 0; dirCounter < classBattle.enuDirections._num_directions; dirCounter++)
            {
                Point udrNextPos = battlefield.getNextPos(myPosition, dirCounter);
                if (udrNextPos.X < battlefield.szMapSize.Width && udrNextPos.X >= 0
                    && udrNextPos.Y < battlefield.szMapSize.Height && udrNextPos.Y >= 0)
                {
                    if (!bolAvoidMapLoc[udrNextPos.X, udrNextPos.Y])
                    {
                        bolCannotMove = false;
                        break;
                    }
                }
            }
            if (bolCannotMove)
                return myPosition;

            enuSearchMap[,] udrSM = searchMap(myPosition, bolAvoidMapLoc);


            if (!CanReachAnAttackLocation(udrSM))
                return myPosition;

            classShortestPathQelement SPEleQ = null;
            classBattleField.classAIShortestPathToEnemy[] udrOptions = new classBattleField.classAIShortestPathToEnemy[0];

            classShortestPathQelement firstQele = new classShortestPathQelement(0, myPosition, classBattle.enuDirections._num_directions);
            enQShortestPathElement(ref SPEleQ, ref firstQele);
            udrPathMap[myPosition.X, myPosition.Y].intMovementCost = 0;
            classShortestPathQelement thisQEle = deQShortestPathElement(ref SPEleQ);

            while (thisQEle != null)
            {
                string strDir = "";
               
                for (classBattle.enuDirections dirCounter = 0; dirCounter < classBattle.enuDirections._num_directions; dirCounter++)
                {
                    Point udrNextPos = battlefield.getNextPos(thisQEle.pos, dirCounter);
                    if (udrNextPos.X >= 0 && udrNextPos.Y >= 0 && udrNextPos.X < battlefield.szMapSize.Width && udrNextPos.Y < battlefield.szMapSize.Height)
                    {
                        int intMovementCost_new_TestDir = thisQEle.intMovementCost + battlefield.getMovementCost(udrNextPos);
                        if (udrPathMap[udrNextPos.X, udrNextPos.Y].intMovementCost > intMovementCost_new_TestDir
                            && (battlefield.terrain[udrNextPos.X, udrNextPos.Y].unit == null
                                 ||
                                (battlefield.terrain[udrNextPos.X, udrNextPos.Y].unit != null
                                 && battlefield.terrain[udrNextPos.X, udrNextPos.Y].unit.myClr == myClr
                                )
                               )
                            && !bolAvoidMapLoc[udrNextPos.X, udrNextPos.Y])
                            strDir += dirCounter.ToString();
                    }
                }


                bool bolICanMoveFromHere = false;
                while (strDir.Length > 0)
                {
                    string strThisDir = strDir.Substring(0, 2);
                    strDir = strDir.Substring(2);

                    classBattle.enuDirections dir_new = battlefield.getDirFromString(strThisDir);
                    Point udrPos_new = battlefield.getNextPos(thisQEle.pos, dir_new);
                    int intMovementCost_new = thisQEle.intMovementCost + battlefield.getMovementCost(udrPos_new);

                    if (!bolAvoidMapLoc[udrPos_new.X, udrPos_new.Y])
                    {
                        udrPathMap[udrPos_new.X, udrPos_new.Y].direction = battlefield.getOppositedirection(dir_new);
                        udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost = intMovementCost_new;
                        udrPathMap[udrPos_new.X, udrPos_new.Y].unit = battlefield.terrain[udrPos_new.X, udrPos_new.Y].unit;
                        udrPathMap[udrPos_new.X, udrPos_new.Y].fullStop = thereIsAnEnemyUnitNextToThisSquare(udrPos_new, battlefield.terrain[udrPos_new.X, udrPos_new.Y].unit);

                        if (battlefield.terrain[udrPos_new.X, udrPos_new.Y].unit == null
                            && CanIAttackFromThisPos(udrPos_new, getRangeForTerrain(udrPos_new)))
                        {
                            if (intRange == 1
                                ||
                                  (myType == classBattle.enuUnitTypes.artillery
                                   && getDistanceBetweenSquares(udrPos_new, udrTargetLoc) > 1)
                                )
                            {
                                Array.Resize<classBattleField.classAIShortestPathToEnemy>(ref udrOptions, udrOptions.Length + 1);
                                udrOptions[udrOptions.Length - 1] = new classBattleField.classAIShortestPathToEnemy();
                                udrOptions[udrOptions.Length - 1].unit = battlefield.terrain[udrAttackLoc.X, udrAttackLoc.Y].unit;
                                udrOptions[udrOptions.Length - 1].udrLoc = udrPos_new;
                                udrOptions[udrOptions.Length - 1].flag = false;
                                udrOptions[udrOptions.Length - 1].path = "";
                            }
                        }
                        if (!udrPathMap[udrPos_new.X, udrPos_new.Y].fullStop)
                        {
                            bolICanMoveFromHere = true;
                            MyNewQele = new classShortestPathQelement(udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost, udrPos_new, udrPathMap[udrPos_new.X, udrPos_new.Y].direction);
                            enQShortestPathElement(ref SPEleQ, ref MyNewQele);
                        }
                    }
                }
                //if (!bolICanMoveFromHere)
                //{
                //    bolAvoidMapLoc[thisQEle.pos.X, thisQEle.pos.Y] = true;
                //    if (udrOptions.Length == 0)
                //        return getNearestAttackLocation(bolAvoidMapLoc);
                //}
                thisQEle = deQShortestPathElement(ref SPEleQ);
            }

        measureMovementPoints:
            if (udrOptions.Length > 0)
            {

                for (int intOptionCounter = 0; intOptionCounter < udrOptions.Length; intOptionCounter++)
                {
                    Point thisPos = udrOptions[intOptionCounter].udrLoc;
                    udrOptions[intOptionCounter].path = "";
                    if (udrPathMap[thisPos.X, thisPos.Y].direction != classBattle.enuDirections._num_directions)

                        while (!(thisPos.X == myPosition.X && thisPos.Y == myPosition.Y))
                        {
                            udrOptions[intOptionCounter].path = battlefield.getOppositedirection(udrPathMap[thisPos.X, thisPos.Y].direction).ToString() + udrOptions[intOptionCounter].path;
                            thisPos = battlefield.getNextPos(thisPos, udrPathMap[thisPos.X, thisPos.Y].direction);
                        }
                }

                battlefield.reorderByPathLengthAIShortestPathToEnemyArray(ref udrOptions);
                // now the shortest one is in front

                // traverse path until out of movement points
                Point udrPos = myPosition;
                Point udrNextPathPos = new Point();
                int intBestChoice = udrOptions.Length - 1;
                if (myType == classBattle.enuUnitTypes.artillery)
                { // find one that is a range of 2 or more
                    for (int intOptionCounter = udrOptions.Length - 1; intOptionCounter >= 0; intOptionCounter--)
                    {
                        int intDistance = getDistanceBetweenSquares(udrOptions[intOptionCounter].unit.myPosition, udrOptions[intOptionCounter].udrLoc);
                        if (intDistance > 1)
                        {
                            intBestChoice = intOptionCounter;
                            break;
                        }
                    }
                }

                string strPathCopy = udrOptions[intBestChoice].path;
                int intMyMovementPoints = intMovementPoints;
                while (udrOptions[intBestChoice].path.Length > 0)
                {
                    string strDir = udrOptions[intBestChoice].path.Substring(0, 2);
                    udrOptions[intBestChoice].path = udrOptions[intBestChoice].path.Substring(2);
                    classBattle.enuDirections dir_new = battlefield.getDirFromString(strDir);
                    udrNextPathPos = battlefield.getNextPos(udrPos, dir_new);
                    int intMovementCost = battlefield.getMovementCost(udrNextPathPos);

                    intMyMovementPoints -= intMovementCost;
                    if (intMyMovementPoints < 0)
                    { // will have to stop here
                        if (!(udrPos.X == myPosition.X && udrPos.Y == myPosition.Y)
                            && battlefield.terrain[udrPos.X, udrPos.Y].unit != null)
                            goto Failed;
                        else
                            return udrPos;
                    }
                    udrPos = udrNextPathPos;
                }

                if (battlefield.terrain[udrPos.X, udrPos.Y].unit == null)
                    return udrPos;

            Failed:
                bolAvoidMapLoc[udrPos.X, udrPos.Y] = true;
                return getNearestAttackLocation(bolAvoidMapLoc);
            }
            else
                return myPosition;
        }

        public void RankPOCs(ref classBattleField.classPOCSearchInfo udrPOC)
        {
            /// assigns values to POCs from higher to lower as each is found
            /// when all units have found all POCs and ranked them the POCs with the highest 'hits'
            /// are the ones which need to be defended first, as they are the ones which the enemy finds(reaches) first

            int intInfinity = (int)Math.Pow(10, 5);

            if (udrPOC.POCMap[myPosition.X, myPosition.Y] >= 0)
            { // I am standing on a POC
                if (thereIsAnEnemyUnitNextToThisSquare()) // I am blocked by the enemy
                    return;
            }


            bool[,] bolAvoidMap = battlefield.getBolDefaultAvoidMap();

            classPathMap[,] udrPathMap = new classPathMap[battlefield.szMapSize.Width, battlefield.szMapSize.Height];
            for (int intX = 0; intX < battlefield.szMapSize.Width; intX++)
                for (int intY = 0; intY < battlefield.szMapSize.Height; intY++)
                {
                    udrPathMap[intX, intY].direction = classBattle.enuDirections._num_directions;
                    udrPathMap[intX, intY].intMovementCost = intInfinity;
                    udrPathMap[intX, intY].unit = battlefield.terrain[intX, intY].unit;
                }

            classShortestPathQelement SPEleQ = null;

            classShortestPathQelement firstQele = new classShortestPathQelement(0, myPosition, classBattle.enuDirections._num_directions);
            enQShortestPathElement(ref SPEleQ, ref firstQele);

            udrPathMap[firstQele.pos.X, firstQele.pos.Y].intMovementCost = 0;

            classShortestPathQelement thisQEle = deQShortestPathElement(ref SPEleQ);

            int intNumberOfPOCsLeftToFound = udrPOC.shrNumFound;

            while (thisQEle != null)
            {
                string strDir = "";
                for (classBattle.enuDirections dirCounter = 0; dirCounter < classBattle.enuDirections._num_directions; dirCounter++)
                {
                    Point udrNextPos = battlefield.getNextPos(thisQEle.pos, dirCounter);
                    if (udrNextPos.X >= 0 && udrNextPos.Y >= 0 && udrNextPos.X < battlefield.szMapSize.Width && udrNextPos.Y < battlefield.szMapSize.Height)
                    {
                        int intMovementCost_new = thisQEle.intMovementCost + 1;
                        if (intMovementCost_new < udrPathMap[udrNextPos.X, udrNextPos.Y].intMovementCost
                            && udrPOC.POCMap[udrNextPos.X, udrNextPos.Y] <= 0)
                        {
                            strDir += dirCounter.ToString();
                        }
                    }
                }

                if (udrPOC.POCMap[thisQEle.pos.X, thisQEle.pos.Y] > 0)
                {
                    /// this is a POC add to its rank-value according to the order in which it was found
                    udrPOC.POCMap[thisQEle.pos.X, thisQEle.pos.Y] += (short)intNumberOfPOCsLeftToFound--;
                    //if (intNumberOfPOCsLeftToFound == 0)
                    //    return;
                }
                else
                {
                    /// do not continue past a POC
                    /// 

                    udrPOC.POCMap[thisQEle.pos.X, thisQEle.pos.Y]--;
                    /// this tells the defending side that the square on the POCMap with negative numbers
                    /// are outside the safe-zone, positive numbers are ranked POCs and 
                    /// zeroes are safe square where the enemy can't reach them.


                    while (strDir.Length > 0)
                    {
                        string strThisDir = strDir.Substring(0, 2);
                        strDir = strDir.Substring(2);
                        classBattle.enuDirections dir_new = dir_new = battlefield.getDirFromString(strThisDir);
                        Point udrPos_new = battlefield.getNextPos(thisQEle.pos, dir_new);
                        int intMovementCost_new = thisQEle.intMovementCost + battlefield.getMovementCost(udrPos_new);

                        if (intMovementCost_new < udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost
                            && !bolAvoidMap[udrPos_new.X, udrPos_new.Y]
                            && udrPOC.POCMap[udrPos_new.X, udrPos_new.Y] == 0)
                        {
                            udrPathMap[udrPos_new.X, udrPos_new.Y].direction = battlefield.getOppositedirection(dir_new);
                            udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost = intMovementCost_new;
                            udrPathMap[udrPos_new.X, udrPos_new.Y].unit = battlefield.terrain[udrPos_new.X, udrPos_new.Y].unit;

                            classShortestPathQelement NewQele = new classShortestPathQelement(udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost, udrPos_new, udrPathMap[udrPos_new.X, udrPos_new.Y].direction);
                            enQShortestPathElement(ref SPEleQ, ref NewQele);
                        }
                    }
                }
                thisQEle = deQShortestPathElement(ref SPEleQ);
            }

       }

        public int getDistanceBetweenSquares(Point udrLocA, Point udrLocB)
        {
            int intInfinity = (int)Math.Pow(10, 5);

            classPathMap[,] udrPathMap = new classPathMap[battlefield.szMapSize.Width, battlefield.szMapSize.Height];
            for (int intX = 0; intX < battlefield.szMapSize.Width; intX++)
                for (int intY = 0; intY < battlefield.szMapSize.Height; intY++)
                {
                    udrPathMap[intX, intY] = new classPathMap();
                    udrPathMap[intX, intY].intMovementCost = intInfinity;
                }

            classRangeMapElement RMeleQ = null;

            classRangeMapElement firstQele = new classRangeMapElement(0, udrLocA, classBattle.enuDirections._num_directions);
            enQRangeMapElement(ref RMeleQ, ref firstQele);

            udrPathMap[firstQele.pos.X, firstQele.pos.Y].intMovementCost = 0;

            classRangeMapElement thisQEle = deQRangeMapElement(ref RMeleQ);

            while (thisQEle != null)
            {
                string strDir = "";
                for (classBattle.enuDirections dirCounter = 0; dirCounter < classBattle.enuDirections._num_directions; dirCounter++)
                {
                    Point udrNextPos = battlefield.getNextPos(thisQEle.pos, dirCounter);
                    if (udrNextPos.X >= 0 && udrNextPos.Y >= 0 && udrNextPos.X < battlefield.szMapSize.Width && udrNextPos.Y < battlefield.szMapSize.Height)
                    {
                        int intNewMovementCost = thisQEle.intDistanceFromStart + 1;

                        if (udrPathMap[udrNextPos.X, udrNextPos.Y].intMovementCost > intNewMovementCost)
                        {
                            if (intNewMovementCost < udrPathMap[udrNextPos.X, udrNextPos.Y].intMovementCost)
                                strDir += dirCounter.ToString();
                        }
                    }
                }

                while (strDir.Length > 0)
                {
                    string strThisDir = strDir.Substring(0, 2);
                    strDir = strDir.Substring(2);

                    classBattle.enuDirections dir_new = battlefield.getDirFromString(strThisDir);
                    Point udrPos_new = battlefield.getNextPos(thisQEle.pos, dir_new);

                    int intMovementCost_new = thisQEle.intDistanceFromStart + 1;

                    if (udrPos_new.X == udrLocB.X &&
                        udrPos_new.Y == udrLocB.Y)
                        return intMovementCost_new;

                    udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost = intMovementCost_new;
                    classRangeMapElement NewQele = new classRangeMapElement(udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost, udrPos_new, udrPathMap[udrPos_new.X, udrPos_new.Y].direction);
                    enQRangeMapElement(ref RMeleQ, ref NewQele);
                }
                thisQEle = deQRangeMapElement(ref RMeleQ);
            }
            return intInfinity;
        }

        public bool[,] getAttackMapFromLoc(Point udrLoc, int intMyRange)
        {
            int intInfinity = (int)Math.Pow(10, 5);
            bool[,] bolRetVal = new bool[battlefield.szMapSize.Width, battlefield.szMapSize.Height];
            Point udrRetVal = new Point();

            classPathMap[,] udrPathMap = new classPathMap[battlefield.szMapSize.Width, battlefield.szMapSize.Height];
            for (int intX = 0; intX < battlefield.szMapSize.Width; intX++)
                for (int intY = 0; intY < battlefield.szMapSize.Height; intY++)
                {
                    udrPathMap[intX, intY] = new classPathMap();
                    udrPathMap[intX, intY].direction = classBattle.enuDirections._num_directions;
                    udrPathMap[intX, intY].intMovementCost = intInfinity;
                    udrPathMap[intX, intY].unit = battlefield.terrain[intX, intY].unit;
                    bolRetVal[intX, intY] = false;
                }

            classRangeMapElement RMeleQ = null;

            classRangeMapElement firstQele = new classRangeMapElement(0, udrLoc, classBattle.enuDirections._num_directions);
            enQRangeMapElement(ref RMeleQ, ref firstQele);

            udrPathMap[firstQele.pos.X, firstQele.pos.Y].intMovementCost = 0;

            classRangeMapElement thisQEle = deQRangeMapElement(ref RMeleQ);

            while (thisQEle != null)
            {
                string strDir = "";
                for (classBattle.enuDirections dirCounter = 0; dirCounter < classBattle.enuDirections._num_directions; dirCounter++)
                {
                    Point udrNextPos = battlefield.getNextPos(thisQEle.pos, dirCounter);
                    if (udrNextPos.X >= 0 && udrNextPos.Y >= 0 && udrNextPos.X < battlefield.szMapSize.Width && udrNextPos.Y < battlefield.szMapSize.Height)
                    {
                        int intNewMovementCost = thisQEle.intDistanceFromStart + 1;

                        if (udrPathMap[udrNextPos.X, udrNextPos.Y].intMovementCost > intNewMovementCost)
                        {
                            if (intNewMovementCost < udrPathMap[udrNextPos.X, udrNextPos.Y].intMovementCost)
                                strDir += dirCounter.ToString();
                        }
                    }
                }

                while (strDir.Length > 0)
                {
                    string strThisDir = strDir.Substring(0, 2);
                    strDir = strDir.Substring(2);
                    int intMovementCost_new = intInfinity;


                    classBattle.enuDirections dir_new = battlefield.getDirFromString(strThisDir);
                    Point udrPos_new = battlefield.getNextPos(thisQEle.pos, dir_new);

                    intMovementCost_new = thisQEle.intDistanceFromStart + 1;
                    bolRetVal[udrPos_new.X, udrPos_new.Y] = (intMovementCost_new <= intMyRange);

                    if (intMovementCost_new <= intMyRange)
                    {
                        udrPathMap[udrPos_new.X, udrPos_new.Y].direction = battlefield.getOppositedirection(dir_new);
                        udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost = intMovementCost_new;
                        udrPathMap[udrPos_new.X, udrPos_new.Y].unit = battlefield.terrain[udrPos_new.X, udrPos_new.Y].unit;
                        udrPathMap[udrPos_new.X, udrPos_new.Y].fullStop = thereIsAnEnemyUnitNextToThisSquare(udrPos_new);

                        classRangeMapElement NewQele = new classRangeMapElement(udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost, udrPos_new, udrPathMap[udrPos_new.X, udrPos_new.Y].direction);
                        enQRangeMapElement(ref RMeleQ, ref NewQele);
                    }
                }
                thisQEle = deQRangeMapElement(ref RMeleQ);
            }
            return bolRetVal;
        }

        public void attack()
        {
            if (getDistanceBetweenSquares(myPosition, unitIAmAttacking.myPosition) > 1)
                attackType = classBattle.enuAttackTypes.barrage;
            else
            {
                if (myType == classBattle.enuUnitTypes.cavalry)
                {
                    if (intMovementPoints > classBattleField.intCostCharge)
                    {
                        if (intSize > unitIAmAttacking.intSize && unitIAmAttacking.myType != classBattle.enuUnitTypes.cavalry  )

                            attackType = classBattle.enuAttackTypes.charge;
                        else
                            attackType = classBattle.enuAttackTypes.normal;
                    }
                    else
                        attackType = classBattle.enuAttackTypes.normal;
                }
                else
                    attackType = classBattle.enuAttackTypes.normal;
            }

            attack(udrAttackLoc, attackType);
        }
        public void attack(Point udrLocAttack, classBattle.enuAttackTypes typeAttack)
        {
            unitIAmAttacking = battlefield.terrain[udrLocAttack.X, udrLocAttack.Y].unit;

            if (unitIAmAttacking != null)
            {
                int intDamage = 0;
                int intReturnDamage = 0;
                switch (typeAttack)
                {
                    case classBattle.enuAttackTypes.barrage:
                        intMovementPoints -= classBattleField.intCostAttack;
                        // done in the classBarrage
                        break;

                    case classBattle.enuAttackTypes.normal:
                        intMovementPoints -= classBattleField.intCostAttack;
                        intDamage = getDamage(udrMeleeDamage, unitIAmAttacking.dblMeleeDefense);
                        unitIAmAttacking.intTotalDamageFromHit = intDamage;

                        intReturnDamage = getDamage(unitIAmAttacking.udrMeleeDamage, dblMeleeDefense);
                        intTotalDamageFromHit = intReturnDamage;
                        break;

                    case classBattle.enuAttackTypes.charge:
                        intMovementPoints -= classBattleField.intCostCharge;
                        double dblChargeFactor = 4;
                        if (intSize < unitIAmAttacking.intSize)
                            dblChargeFactor = 1 / dblChargeFactor;
                        intDamage = (int)((double)getDamage(udrMeleeDamage, unitIAmAttacking.dblMeleeDefense) * dblChargeFactor);
                        unitIAmAttacking.intTotalDamageFromHit = intDamage;

                        intReturnDamage = (int)((double)getDamage(unitIAmAttacking.udrMeleeDamage, dblMeleeDefense) / dblChargeFactor);
                        intTotalDamageFromHit = intReturnDamage;
                        break;
                }
                display();
            }
        }

        public int CountUnitsIAttackFromThisPos(Point udrLoc, int intMyRange)
        {
            int intInfinity = (int)Math.Pow(10, 5);
            classPathMap[,] udrMapSeen = new classPathMap[battlefield.szMapSize.Width, battlefield.szMapSize.Height];

            attackType = classBattle.enuAttackTypes._numAttackTypes;

            classRangeMapElement RMeleQ = null;

            classRangeMapElement firstQele = new classRangeMapElement(0, udrLoc, classBattle.enuDirections._num_directions);
            enQRangeMapElement(ref RMeleQ, ref firstQele);
            udrMapSeen[firstQele.pos.X, firstQele.pos.Y].seen = true;

            classRangeMapElement thisQEle = deQRangeMapElement(ref RMeleQ);

            Point[] udrAttackLocArray = new Point[0];

            while (thisQEle != null)
            {
                string strDir = "";
                int intMovementCost_new = thisQEle.intDistanceFromStart + 1;
                for (classBattle.enuDirections dirCounter = 0; dirCounter < classBattle.enuDirections._num_directions; dirCounter++)
                {
                    Point udrNextPos = battlefield.getNextPos(thisQEle.pos, dirCounter);
                    if (udrNextPos.X >= 0
                        && udrNextPos.Y >= 0
                        && udrNextPos.X < battlefield.szMapSize.Width
                        && udrNextPos.Y < battlefield.szMapSize.Height
                        && !udrMapSeen[udrNextPos.X, udrNextPos.Y].seen)
                    {
                        if (battlefield.terrain[udrNextPos.X, udrNextPos.Y].unit != null
                             && battlefield.terrain[udrNextPos.X, udrNextPos.Y].unit.myClr != myClr)
                        {
                            if (udrMapSeen[thisQEle.pos.X, thisQEle.pos.Y].intMovementCost + 1 > 1)
                                attackType = classBattle.enuAttackTypes.barrage;
                            else
                                attackType = classBattle.enuAttackTypes.normal;

                            Array.Resize<Point>(ref udrAttackLocArray, udrAttackLocArray.Length + 1);
                            udrAttackLocArray[udrAttackLocArray.Length - 1] = udrNextPos;

                        }
                        strDir += dirCounter.ToString();
                    }
                }

                while (strDir.Length > 0)
                {
                    string strThisDir = strDir.Substring(0, 2);
                    strDir = strDir.Substring(2);

                    classBattle.enuDirections dir_new = battlefield.getDirFromString(strThisDir);
                    Point udrPos_new = battlefield.getNextPos(thisQEle.pos, dir_new);
                    intMovementCost_new = udrMapSeen[thisQEle.pos.X, thisQEle.pos.Y].intMovementCost + 1;
                    if (intMovementCost_new < intMyRange && !udrMapSeen[udrPos_new.X, udrPos_new.Y].seen)
                    {
                        udrMapSeen[udrPos_new.X, udrPos_new.Y].intMovementCost = intMovementCost_new;
                        udrMapSeen[udrPos_new.X, udrPos_new.Y].seen = true;
                        classRangeMapElement NewQele = new classRangeMapElement(intMovementCost_new, udrPos_new, dir_new);
                        enQRangeMapElement(ref RMeleQ, ref NewQele);
                    }
                }
                thisQEle = deQRangeMapElement(ref RMeleQ);
            }

            return udrAttackLocArray.Length;
        }

        public bool CanIAttackFromThisPos(Point udrLoc, int intMyRange)
        {
            int intInfinity = (int)Math.Pow(10, 5);
            Point udrRetVal = new Point();
            classPathMap[,] udrMapSeen = new classPathMap[battlefield.szMapSize.Width, battlefield.szMapSize.Height];
            for (int intXCounter =0; intXCounter < battlefield.szMapSize.Width; intXCounter++)
            {
                for (int intYCounter =0; intYCounter < battlefield.szMapSize.Height; intYCounter++)
                {
                    udrMapSeen[intXCounter, intYCounter] = new classPathMap();
                }
            }

            attackType = classBattle.enuAttackTypes._numAttackTypes;

            classRangeMapElement RMeleQ = null;

            classRangeMapElement firstQele = new classRangeMapElement(0, udrLoc, classBattle.enuDirections._num_directions);
            enQRangeMapElement(ref RMeleQ, ref firstQele);
            udrMapSeen[firstQele.pos.X, firstQele.pos.Y].seen = true;

            classRangeMapElement thisQEle = deQRangeMapElement(ref RMeleQ);

            Point[] udrAttackLocArray = new Point[0];

            while (thisQEle != null)
            {
                string strDir = "";
                int intMovementCost_new = thisQEle.intDistanceFromStart + 1;
                for (classBattle.enuDirections dirCounter = 0; dirCounter < classBattle.enuDirections._num_directions; dirCounter++)
                {
                    Point udrNextPos = battlefield.getNextPos(thisQEle.pos, dirCounter);
                    if (udrNextPos.X >= 0
                        && udrNextPos.Y >= 0
                        && udrNextPos.X < battlefield.szMapSize.Width
                        && udrNextPos.Y < battlefield.szMapSize.Height
                        && !udrMapSeen[udrNextPos.X, udrNextPos.Y].seen)
                    {
                        if (battlefield.terrain[udrNextPos.X, udrNextPos.Y].unit != null
                             && battlefield.terrain[udrNextPos.X, udrNextPos.Y].unit.myClr != myClr)
                        {

                            Array.Resize<Point>(ref udrAttackLocArray, udrAttackLocArray.Length + 1);
                            udrAttackLocArray[udrAttackLocArray.Length - 1] = udrNextPos;

                        }
                        strDir += dirCounter.ToString();
                    }
                }

                while (strDir.Length > 0)
                {
                    string strThisDir = strDir.Substring(0, 2);
                    strDir = strDir.Substring(2);

                    classBattle.enuDirections dir_new = battlefield.getDirFromString(strThisDir);
                    Point udrPos_new = battlefield.getNextPos(thisQEle.pos, dir_new);
                    intMovementCost_new = udrMapSeen[thisQEle.pos.X, thisQEle.pos.Y].intMovementCost + 1;
                    if (intMovementCost_new < intMyRange && !udrMapSeen[udrPos_new.X, udrPos_new.Y].seen)
                    {
                        udrMapSeen[udrPos_new.X, udrPos_new.Y].intMovementCost = intMovementCost_new;
                        udrMapSeen[udrPos_new.X, udrPos_new.Y].seen = true;
                        classRangeMapElement NewQele = new classRangeMapElement(intMovementCost_new, udrPos_new, dir_new);
                        enQRangeMapElement(ref RMeleQ, ref NewQele);
                    }
                }
                thisQEle = deQRangeMapElement(ref RMeleQ);
            }
            if (udrAttackLocArray.Length > 0)
            {
                // pick the best target for AI unit to attack
                if (myRank > classBattle.enuUnitRanks.lieutenant)

                    udrAttackLoc = bestTargetLocationFromPossibleArray(udrAttackLocArray);
                else
                {
                    int intIndex = (int)(battlefield.rnd.NextDouble() * udrAttackLocArray.Length);
                    udrAttackLoc = udrAttackLocArray[intIndex];
                }
                unitIAmAttacking = battlefield.terrain[udrAttackLoc.X, udrAttackLoc.Y].unit;
                return true;
            }
            else
                return false;
        }

        bool validPOCAtThisLoc(classBattleField.classPOCSearchInfo udrPOC, Point udrLoc)
        {
            for (int intLocCounter = 0; intLocCounter < udrPOC.POCLocs.Length; intLocCounter++)
            {
                if (udrPOC.POCLocs[intLocCounter].pt.X == udrLoc.X && udrPOC.POCLocs[intLocCounter].pt.Y == udrLoc.Y)
                    return udrPOC.POCLocs[intLocCounter].flag;
            }
            return false;
        }

        int CountPOCsICanAttackFromThisPos(classBattleField.classPOCSearchInfo udrPOC, Point udrLoc, int intMyRange, bool bolOnlyValidPOCs)
        {
            int intInfinity = (int)Math.Pow(10, 5);
            //Point udrRetVal = new Point();
            classPathMap[,] udrMapSeen = new classPathMap[battlefield.szMapSize.Width, battlefield.szMapSize.Height];

            attackType = classBattle.enuAttackTypes._numAttackTypes;

            classRangeMapElement RMeleQ = null;

            classRangeMapElement firstQele = new classRangeMapElement(0, udrLoc, classBattle.enuDirections._num_directions);
            enQRangeMapElement(ref RMeleQ, ref firstQele);
            udrMapSeen[firstQele.pos.X, firstQele.pos.Y].seen = true;

            classRangeMapElement thisQEle = deQRangeMapElement(ref RMeleQ);

            Point[] udrAttackLocArray = new Point[0];

            while (thisQEle != null)
            {
                string strDir = "";
                int intMovementCost_new = thisQEle.intDistanceFromStart + 1;
                for (classBattle.enuDirections dirCounter = 0; dirCounter < classBattle.enuDirections._num_directions; dirCounter++)
                {
                    Point udrNextPos = battlefield.getNextPos(thisQEle.pos, dirCounter);
                    if (udrNextPos.X >= 0
                        && udrNextPos.Y >= 0
                        && udrNextPos.X < battlefield.szMapSize.Width
                        && udrNextPos.Y < battlefield.szMapSize.Height
                        && !udrMapSeen[udrNextPos.X, udrNextPos.Y].seen)
                    {
                        if (udrPOC.POCMap[udrNextPos.X, udrNextPos.Y] > 0
                            && ((validPOCAtThisLoc(udrPOC, udrNextPos) && bolOnlyValidPOCs)
                                 || !bolOnlyValidPOCs
                               )
                            )
                        {
                            if (udrMapSeen[thisQEle.pos.X, thisQEle.pos.Y].intMovementCost + 1 > 1)
                                attackType = classBattle.enuAttackTypes.barrage;
                            else
                                attackType = classBattle.enuAttackTypes.normal;

                            Array.Resize<Point>(ref udrAttackLocArray, udrAttackLocArray.Length + 1);
                            udrAttackLocArray[udrAttackLocArray.Length - 1] = udrNextPos;
                        }
                        strDir += dirCounter.ToString();
                    }
                }

                while (strDir.Length > 0)
                {
                    string strThisDir = strDir.Substring(0, 2);
                    strDir = strDir.Substring(2);

                    classBattle.enuDirections dir_new = battlefield.getDirFromString(strThisDir);
                    Point udrPos_new = battlefield.getNextPos(thisQEle.pos, dir_new);
                    intMovementCost_new = udrMapSeen[thisQEle.pos.X, thisQEle.pos.Y].intMovementCost + 1;
                    if (intMovementCost_new < intMyRange && !udrMapSeen[udrPos_new.X, udrPos_new.Y].seen)
                    {
                        udrMapSeen[udrPos_new.X, udrPos_new.Y].intMovementCost = intMovementCost_new;
                        udrMapSeen[udrPos_new.X, udrPos_new.Y].seen = true;
                        classRangeMapElement NewQele = new classRangeMapElement(intMovementCost_new, udrPos_new, dir_new);
                        enQRangeMapElement(ref RMeleQ, ref NewQele);
                    }
                }
                thisQEle = deQRangeMapElement(ref RMeleQ);
            }
            return udrAttackLocArray.Length;
        }

        public bool CanIAttackAPOCFromThisPos(classBattleField.classPOCSearchInfo udrPOC, Point udrLoc, int intMyRange, bool bolOnlyValidPOCs)
        {
            int intInfinity = (int)Math.Pow(10, 5);
            Point udrRetVal = new Point();
            classPathMap[,] udrMapSeen = new classPathMap[battlefield.szMapSize.Width, battlefield.szMapSize.Height];

            attackType = classBattle.enuAttackTypes._numAttackTypes;

            classRangeMapElement RMeleQ = null;

            classRangeMapElement firstQele = new classRangeMapElement(0, udrLoc, classBattle.enuDirections._num_directions);
            enQRangeMapElement(ref RMeleQ, ref firstQele);
            udrMapSeen[firstQele.pos.X, firstQele.pos.Y].seen = true;

            classRangeMapElement thisQEle = deQRangeMapElement(ref RMeleQ);

            Point[] udrAttackLocArray = new Point[0];

            while (thisQEle != null)
            {
                string strDir = "";
                int intMovementCost_new = thisQEle.intDistanceFromStart + 1;
                for (classBattle.enuDirections dirCounter = 0; dirCounter < classBattle.enuDirections._num_directions; dirCounter++)
                {
                    Point udrNextPos = battlefield.getNextPos(thisQEle.pos, dirCounter);
                    if (udrNextPos.X >= 0
                        && udrNextPos.Y >= 0
                        && udrNextPos.X < battlefield.szMapSize.Width
                        && udrNextPos.Y < battlefield.szMapSize.Height
                        && !udrMapSeen[udrNextPos.X, udrNextPos.Y].seen)
                    {
                        if (udrPOC.POCMap[udrNextPos.X, udrNextPos.Y] > 0
                            && ((validPOCAtThisLoc(udrPOC, udrNextPos) && bolOnlyValidPOCs)
                                 || !bolOnlyValidPOCs
                               )
                            )
                        {
                            if (udrMapSeen[thisQEle.pos.X, thisQEle.pos.Y].intMovementCost + 1 > 1)
                                attackType = classBattle.enuAttackTypes.barrage;
                            else
                                attackType = classBattle.enuAttackTypes.normal;

                            Array.Resize<Point>(ref udrAttackLocArray, udrAttackLocArray.Length + 1);
                            udrAttackLocArray[udrAttackLocArray.Length - 1] = udrNextPos;
                        }
                        strDir += dirCounter.ToString();
                    }
                }

                while (strDir.Length > 0)
                {
                    string strThisDir = strDir.Substring(0, 2);
                    strDir = strDir.Substring(2);

                    classBattle.enuDirections dir_new = battlefield.getDirFromString(strThisDir);
                    Point udrPos_new = battlefield.getNextPos(thisQEle.pos, dir_new);
                    intMovementCost_new = udrMapSeen[thisQEle.pos.X, thisQEle.pos.Y].intMovementCost + 1;
                    if (intMovementCost_new < intMyRange && !udrMapSeen[udrPos_new.X, udrPos_new.Y].seen)
                    {
                        udrMapSeen[udrPos_new.X, udrPos_new.Y].intMovementCost = intMovementCost_new;
                        udrMapSeen[udrPos_new.X, udrPos_new.Y].seen = true;
                        classRangeMapElement NewQele = new classRangeMapElement(intMovementCost_new, udrPos_new, dir_new);
                        enQRangeMapElement(ref RMeleQ, ref NewQele);
                    }
                }
                thisQEle = deQRangeMapElement(ref RMeleQ);
            }
            if (udrAttackLocArray.Length > 0)
            {
                // pick the best target for AI unit to attack
                if (myRank > classBattle.enuUnitRanks.lieutenant)
                    udrAttackLoc = bestTargetLocationFromPossibleArray(udrAttackLocArray);
                else
                {
                    int intIndex = (int)(battlefield.rnd.NextDouble() * udrAttackLocArray.Length);
                    udrAttackLoc = udrAttackLocArray[intIndex];
                }

                return true;
            }
            else
                return false;
        }

        Point bestTargetLocationFromPossibleArray(Point[] udrTargetArray)
        {
            setMyStats();
            int intRangeRating = 100;
            int intThreatRating = 10;
            int intUnitTypeRating = 50;

            classTargetRating[] udrTargetRating = new classTargetRating[udrTargetArray.Length];
            int intBestRating = 0;
            int intBestIndex = 0;
            for (int intTargetCounter = 0; intTargetCounter < udrTargetArray.Length; intTargetCounter++)
            {
                udrTargetRating[intTargetCounter] = new classTargetRating();
                udrTargetRating[intTargetCounter].unit = battlefield.terrain[udrTargetArray[intTargetCounter].X, udrTargetArray[intTargetCounter].Y].unit;
                udrTargetRating[intTargetCounter].intTargetValue = 0;
                if (udrTargetRating[intTargetCounter].unit != null)
                {
                    udrTargetRating[intTargetCounter].unit.setMyStats();
                    int intDistance = getDistanceBetweenSquares(udrTargetRating[intTargetCounter].unit.myPosition, myPosition);
                    if (intDistance > 1)
                    {
                        udrTargetRating[intTargetCounter].intTargetValue += intRangeRating;
                        udrTargetRating[intTargetCounter].intTargetValue += udrTargetRating[intTargetCounter].unit.intSize;
                    }
                    else
                    {
                        udrTargetRating[intTargetCounter].intTargetValue += (int)(myStats.melee.offense - udrTargetRating[intTargetCounter].unit.myStats.melee.offense);
                    }
                    udrTargetRating[intTargetCounter].intTargetValue += (int)(udrTargetRating[intTargetCounter].unit.myRank - myRank) * intThreatRating;
                    udrTargetRating[intTargetCounter].intTargetValue += (int)(udrTargetRating[intTargetCounter].unit.myType) * intUnitTypeRating;
                }
                if (udrTargetRating[intTargetCounter].intTargetValue > intBestRating)
                {
                    intBestRating = udrTargetRating[intTargetCounter].intTargetValue;
                    intBestIndex = intTargetCounter;
                }
            }
            if (udrTargetRating[intBestIndex].unit != null)
                return udrTargetRating[intBestIndex].unit.myPosition;
            else
                return myPosition;
        }

        public bool[,] getReachableMap(Point udrMapSquare)
        {
            bool[,] bolRetVal = new bool[battlefield.szMapSize.Width, battlefield.szMapSize.Height];

            Point udrPos = myPosition;
            string strPath = getShortestPath(myPosition, udrMapSquare);
            if (strPath.Length > 0)
                do
                {
                    string strThisDir = strPath.Substring(0, 2);
                    strPath = strPath.Substring(2);
                    classBattle.enuDirections dir = battlefield.getDirFromString(strThisDir);
                    bolRetVal[udrPos.X, udrPos.Y] = true;
                    udrPos = battlefield.getNextPos(udrPos, dir);
                } while (strPath.Length > 0);
            bolRetVal[udrMapSquare.X, udrMapSquare.Y] = true;
            return bolRetVal;
        }

        public int getNumMoveSquaresAroundLoc(Point udrLoc)
        { return battlefield.getNumMoveSquaresAroundLoc(udrLoc); }

        public int getNumPlacesICanMoveDisregardingEnemy(Point udrStartLoc, bool[,] bolAvoidMap)
        {
            int intRetVal = 0;
            int intInfinity = (int)Math.Pow(10, 5);
            classPathMap[,] udrPathMap = new classPathMap[battlefield.szMapSize.Width, battlefield.szMapSize.Height];

            for (int intX = 0; intX < battlefield.szMapSize.Width; intX++)
                for (int intY = 0; intY < battlefield.szMapSize.Height; intY++)
                {
                    udrPathMap[intX, intY].direction = classBattle.enuDirections._num_directions;
                    udrPathMap[intX, intY].intMovementCost = intInfinity;
                    udrPathMap[intX, intY].unit = battlefield.terrain[intX, intY].unit;
                }

            classShortestPathQelement SPeleQ = null;

            classShortestPathQelement firstQele = new classShortestPathQelement(0, udrStartLoc, classBattle.enuDirections._num_directions);
            enQShortestPathElement(ref SPeleQ, ref firstQele);

            udrPathMap[firstQele.pos.X, firstQele.pos.Y].intMovementCost = 0;

            classShortestPathQelement thisQEle = deQShortestPathElement(ref SPeleQ);

            while (thisQEle != null)
            {
                string strDir = "";
                int intNewMovementCost = thisQEle.intMovementCost + 1;

                for (classBattle.enuDirections dirCounter = 0; dirCounter < classBattle.enuDirections._num_directions; dirCounter++)
                {
                    Point udrNextPos = battlefield.getNextPos(thisQEle.pos, dirCounter);
                    if (udrNextPos.X >= 0 && udrNextPos.Y >= 0 && udrNextPos.X < battlefield.szMapSize.Width && udrNextPos.Y < battlefield.szMapSize.Height)
                    {
                        if (!bolAvoidMap[udrNextPos.X, udrNextPos.Y])
                        {
                            if (intNewMovementCost < udrPathMap[udrNextPos.X, udrNextPos.Y].intMovementCost)
                                strDir += dirCounter.ToString();
                        }
                    }
                }

                while (strDir.Length > 0)
                {
                    string strThisDir = strDir.Substring(0, 2);
                    strDir = strDir.Substring(2);

                    classBattle.enuDirections dir_new = battlefield.getDirFromString(strThisDir);
                    Point udrPos_new = battlefield.getNextPos(thisQEle.pos, dir_new);

                    if (intNewMovementCost < udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost)
                    {
                        udrPathMap[udrPos_new.X, udrPos_new.Y].direction = battlefield.getOppositedirection(dir_new);
                        udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost = intNewMovementCost;
                        udrPathMap[udrPos_new.X, udrPos_new.Y].unit = battlefield.terrain[udrPos_new.X, udrPos_new.Y].unit;
                        udrPathMap[udrPos_new.X, udrPos_new.Y].fullStop = thereIsAnEnemyUnitNextToThisSquare(udrPos_new);
                        intRetVal++;
                        if (!udrPathMap[udrPos_new.X, udrPos_new.Y].fullStop && udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost < intMovementPoints)
                        {
                            classShortestPathQelement NewQele = new classShortestPathQelement(udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost, udrPos_new, udrPathMap[udrPos_new.X, udrPos_new.Y].direction);
                            enQShortestPathElement(ref SPeleQ, ref NewQele);
                        }
                    }
                }
                thisQEle = deQShortestPathElement(ref SPeleQ);
            }

            return intRetVal;
        }

        public bool[,] getAllowedMovesMap()
        {
            int intInfinity = (int)Math.Pow(10, 5);
            bool[,] bolRetVal = new bool[battlefield.szMapSize.Width, battlefield.szMapSize.Height];

            classPathMap[,] udrPathMap = new classPathMap[battlefield.szMapSize.Width, battlefield.szMapSize.Height];
            for (int intX = 0; intX < battlefield.szMapSize.Width; intX++)
                for (int intY = 0; intY < battlefield.szMapSize.Height; intY++)
                {
                    udrPathMap[intX, intY] = new classPathMap();
                    udrPathMap[intX, intY].direction = classBattle.enuDirections._num_directions;
                    udrPathMap[intX, intY].intMovementCost = intInfinity;
                    udrPathMap[intX, intY].unit = battlefield.terrain[intX, intY].unit;
                    bolRetVal[intX, intY] = false;
                }

            classShortestPathQelement SPeleQ = null;

            classShortestPathQelement firstQele = new classShortestPathQelement(0, myPosition, classBattle.enuDirections._num_directions);
            enQShortestPathElement(ref SPeleQ, ref firstQele);

            udrPathMap[firstQele.pos.X, firstQele.pos.Y].intMovementCost = 0;

            classShortestPathQelement thisQEle = deQShortestPathElement(ref SPeleQ);

            while (thisQEle != null)
            {
                string strDir = "";
                for (classBattle.enuDirections dirCounter = 0; dirCounter < classBattle.enuDirections._num_directions; dirCounter++)
                {
                    Point udrNextPos = battlefield.getNextPos(thisQEle.pos, dirCounter);
                    if (udrNextPos.X >= 0 && udrNextPos.Y >= 0 && udrNextPos.X < battlefield.szMapSize.Width && udrNextPos.Y < battlefield.szMapSize.Height)
                    {
                        if (udrPathMap[udrNextPos.X, udrNextPos.Y].unit == null
                            ||
                           (udrPathMap[udrNextPos.X, udrNextPos.Y].unit != null
                             && udrPathMap[udrNextPos.X, udrNextPos.Y].unit.myClr == myClr))
                        {
                            int intNewMovementCost = thisQEle.intMovementCost + battlefield.getMovementCost(udrNextPos);
                            if (intNewMovementCost < udrPathMap[udrNextPos.X, udrNextPos.Y].intMovementCost)
                                strDir += dirCounter.ToString();
                        }
                    }
                }

                while (strDir.Length > 0)
                {
                    string strThisDir = strDir.Substring(0, 2);
                    strDir = strDir.Substring(2);
                    int intMovementCost_new = intInfinity;

                    classBattle.enuDirections dir_new = battlefield.getDirFromString(strThisDir);
                    Point udrPos_new = battlefield.getNextPos(thisQEle.pos, dir_new);
                    intMovementCost_new = thisQEle.intMovementCost + battlefield.getMovementCost(udrPos_new);

                    if (intMovementCost_new < udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost)
                    {
                        udrPathMap[udrPos_new.X, udrPos_new.Y].direction = battlefield.getOppositedirection(dir_new);
                        udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost = intMovementCost_new;
                        udrPathMap[udrPos_new.X, udrPos_new.Y].unit = battlefield.terrain[udrPos_new.X, udrPos_new.Y].unit;
                        udrPathMap[udrPos_new.X, udrPos_new.Y].fullStop = thereIsAnEnemyUnitNextToThisSquare(udrPos_new);
                        bolRetVal[udrPos_new.X, udrPos_new.Y] = (udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost < intMovementPoints
                                                                  && battlefield.terrain[udrPos_new.X, udrPos_new.Y].unit == null);
                        if (!udrPathMap[udrPos_new.X, udrPos_new.Y].fullStop && udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost < intMovementPoints)
                        {
                            classShortestPathQelement NewQele = new classShortestPathQelement(udrPathMap[udrPos_new.X, udrPos_new.Y].intMovementCost, udrPos_new, udrPathMap[udrPos_new.X, udrPos_new.Y].direction);
                            enQShortestPathElement(ref SPeleQ, ref NewQele);
                        }
                    }
                }
                thisQEle = deQShortestPathElement(ref SPeleQ);
            }
            return bolRetVal;
        }
        #endregion

        #region "Q functions"


        public void enQShortestPathElement(ref classShortestPathQelement SPele_thisQ, ref classShortestPathQelement SPEleNew)
        {
            if (SPEleNew == null)
                return;

            if (SPele_thisQ == null)
            {
                SPele_thisQ = SPEleNew;
                SPEleNew.next = null;
                SPEleNew.previous = null;
            }
            else
            {  // rank by movement cost -> cheapest at the front
                if (SPele_thisQ.intMovementCost > SPEleNew.intMovementCost)
                {
                    SPEleNew.next = SPele_thisQ;
                    SPele_thisQ.previous = SPEleNew;

                    SPEleNew.previous = null;
                    SPele_thisQ = SPEleNew;
                }
                else
                {
                    classShortestPathQelement thisElement = SPele_thisQ;
                    while (thisElement.next != null && thisElement.next.intMovementCost < SPEleNew.intMovementCost)
                        thisElement = thisElement.next;

                    SPEleNew.next = thisElement.next;
                    if (SPEleNew.next != null)
                        SPEleNew.next.previous = SPEleNew;

                    thisElement.next = SPEleNew;
                    SPEleNew.previous = thisElement;
                }
            }
        }

        public classShortestPathQelement deQShortestPathElement(ref classShortestPathQelement SPele_thisQ)
        {
            classShortestPathQelement eleRetVal = SPele_thisQ;
            if (SPele_thisQ != null)
            {
                SPele_thisQ = SPele_thisQ.next;

                if (SPele_thisQ != null)
                    SPele_thisQ.previous = null;
                eleRetVal.next = null;
            }
            return eleRetVal;
        }

        public void enQRangeMapElement(ref classRangeMapElement RMele_thisQ, ref classRangeMapElement RMEleNew)
        {
            if (RMEleNew == null)
                return;

            if (RMele_thisQ == null)
            {
                RMele_thisQ = RMEleNew;
                RMEleNew.next = null;
                RMEleNew.previous = null;
            }
            else
            {
                if (RMele_thisQ.intDistanceFromStart > RMEleNew.intDistanceFromStart)
                {
                    RMEleNew.next = RMele_thisQ;
                    RMele_thisQ.previous = RMEleNew;

                    RMEleNew.previous = null;
                    RMele_thisQ = RMEleNew;
                }
                else
                {
                    classRangeMapElement thisElement = RMele_thisQ;
                    while (thisElement.next != null && thisElement.next.intDistanceFromStart < RMEleNew.intDistanceFromStart)
                        thisElement = thisElement.next;

                    RMEleNew.next = thisElement.next;
                    if (RMEleNew.next != null)
                        RMEleNew.next.previous = RMEleNew;

                    thisElement.next = RMEleNew;
                    RMEleNew.previous = thisElement;
                }
            }
        }

        public classRangeMapElement deQRangeMapElement(ref classRangeMapElement RMele_thisQ)
        {
            classRangeMapElement eleRetVal = RMele_thisQ;
            if (RMele_thisQ != null)
            {
                RMele_thisQ = RMele_thisQ.next;

                if (RMele_thisQ != null)
                    RMele_thisQ.previous = null;
                eleRetVal.next = null;
            }
            return eleRetVal;

        }
        #endregion

        #region "initial setup"

        void setRangeDamage()
        {
            double dblAverageDamage = 1.00;
            double dblRankFactor = 1.0;
            switch (myRank)
            {
                case classBattle.enuUnitRanks.lieutenant:
                    dblRankFactor = 0.8;
                    break;

                case classBattle.enuUnitRanks.captain:
                    dblRankFactor = 0.9;
                    break;

                case classBattle.enuUnitRanks.major:
                    dblRankFactor = 1.0;
                    break;

                case classBattle.enuUnitRanks.colonel:
                    dblRankFactor = 1.1;
                    break;

                case classBattle.enuUnitRanks.general:
                    dblRankFactor = 1.2;
                    break;

                case classBattle.enuUnitRanks.field_marshall:
                    dblRankFactor = 1.3;
                    break;
            }

            double dblRangeDamageFactor = 100;
            switch (myType)
            {
                case classBattle.enuUnitTypes.artillery:
                    dblRangeDamageFactor = 0.60;
                    break;

                case classBattle.enuUnitTypes.infantry:
                    dblRangeDamageFactor = 1.0;
                    break;

                case classBattle.enuUnitTypes.cavalry:
                    dblRangeDamageFactor = 1.0;
                    break;
            }
            intRange = getRangeForType();
            dblAverageDamage = (dblRangeDamageFactor * dblRankFactor);
            double dblRange = dblAverageDamage * .1;
            udrRangeDamage.Min = (dblAverageDamage - dblRange);
            udrRangeDamage.Max = (dblAverageDamage + dblRange);
        }

        int getRangeForType()
        {
            switch (myType)
            {
                case classBattle.enuUnitTypes.artillery:
                    switch (myRank)
                    {
                        //case classBattle.enuUnitRanks.lieutenant:
                        //    return 2;

                        //case classBattle.enuUnitRanks.captain:
                        //    return 3;

                        //case classBattle.enuUnitRanks.colonel:
                        //    return 3;

                        //case classBattle.enuUnitRanks.major:
                        //    return 4;

                        //case classBattle.enuUnitRanks.general:
                        //    return 4;

                        //case classBattle.enuUnitRanks.field_marshall:
                        //    return 5;

                        default:
                            return 2;
                    }
                    break;

                default:
                    return 1;
            }
        }

        void setMeleeDamage()
        {
            double dblAverageDamage = 1.00;
            double dblRankFactor = 1.0;
            switch (myRank)
            {
                case classBattle.enuUnitRanks.lieutenant:
                    dblRankFactor = 0.8;
                    break;

                case classBattle.enuUnitRanks.captain:
                    dblRankFactor = 0.9;
                    break;

                case classBattle.enuUnitRanks.major:
                    dblRankFactor = 1.0;
                    break;

                case classBattle.enuUnitRanks.colonel:
                    dblRankFactor = 1.1;
                    break;

                case classBattle.enuUnitRanks.general:
                    dblRankFactor = 1.2;
                    break;

                case classBattle.enuUnitRanks.field_marshall:
                    dblRankFactor = 1.3;
                    break;
            }

            double dblMeleDamageTypeFactor = 1.00;
            switch (myType)
            {
                case classBattle.enuUnitTypes.artillery:
                    dblMeleDamageTypeFactor = .50;
                    break;

                case classBattle.enuUnitTypes.infantry:
                    dblMeleDamageTypeFactor = .75;
                    break;

                case classBattle.enuUnitTypes.cavalry:
                    dblMeleDamageTypeFactor = 1.00;
                    break;
            }

            dblAverageDamage = (dblMeleDamageTypeFactor * dblRankFactor);
            double dblRange = dblAverageDamage * .1;
            
            udrMeleeDamage.Min = (dblAverageDamage - dblRange);
            udrMeleeDamage.Max = (dblAverageDamage + dblRange);
        }

        void setMeleeDefense()
        {
            double dblRankFactor = 1.0;
            switch (myRank)
            {
                case classBattle.enuUnitRanks.lieutenant:
                    dblRankFactor = 1.0;
                    break;

                case classBattle.enuUnitRanks.captain:
                    dblRankFactor = 0.95;
                    break;

                case classBattle.enuUnitRanks.major:
                    dblRankFactor = 0.8;
                    break;

                case classBattle.enuUnitRanks.colonel:
                    dblRankFactor = 0.85;
                    break;

                case classBattle.enuUnitRanks.general:
                    dblRankFactor = 0.8;
                    break;

                case classBattle.enuUnitRanks.field_marshall:
                    dblRankFactor = 0.75;
                    break;
            }

            double dblTypeUnitFactor = .100;
            switch (myType)
            {
                case classBattle.enuUnitTypes.artillery:
                    dblTypeUnitFactor = 0.10;
                    break;

                case classBattle.enuUnitTypes.infantry:
                    dblTypeUnitFactor = .0850;
                    break;

                case classBattle.enuUnitTypes.cavalry:
                    dblTypeUnitFactor = .0750;
                    break;
            }

            dblMeleeDefense = (dblTypeUnitFactor * dblRankFactor);
        }

        void setRangeDefense()
        {
            double dblRankFactor = 1.0;
            switch (myRank)
            {
                case classBattle.enuUnitRanks.lieutenant:
                    dblRankFactor = 1.0;
                    break;

                case classBattle.enuUnitRanks.captain:
                    dblRankFactor = 0.95;
                    break;

                case classBattle.enuUnitRanks.major:
                    dblRankFactor = 0.9;
                    break;

                case classBattle.enuUnitRanks.colonel:
                    dblRankFactor = 0.85;
                    break;

                case classBattle.enuUnitRanks.general:
                    dblRankFactor = 0.8;
                    break;

                case classBattle.enuUnitRanks.field_marshall:
                    dblRankFactor = 0.75;
                    break;
            }

            double dblUnitTypeFactor = 1.00;
            switch (myType)
            {
                case classBattle.enuUnitTypes.artillery:
                    dblUnitTypeFactor = .050;
                    break;

                case classBattle.enuUnitTypes.infantry:
                    dblUnitTypeFactor = 0.10;
                    break;

                case classBattle.enuUnitTypes.cavalry:
                    dblUnitTypeFactor = 0.075;
                    break;
            }

            dblRangeDefense = (dblUnitTypeFactor * dblRankFactor);
        }


        void setMaxSize()
        {
            switch (myType)
            {
                case classBattle.enuUnitTypes.artillery:
                    intSize_Max = 250;
                    break;

                case classBattle.enuUnitTypes.infantry:
                    intSize_Max = 500;
                    break;

                case classBattle.enuUnitTypes.cavalry:
                    intSize_Max = 250;
                    break;
            }
        }

        void setMaxMovement()
        {
            double dblRankFactor = 1.0;
            double dblMovementPoints = 100;
            switch (myType)
            {
                case classBattle.enuUnitTypes.artillery:
                    dblMovementPoints = 65;
                    break;

                case classBattle.enuUnitTypes.infantry:
                    dblMovementPoints = 90;
                    break;

                case classBattle.enuUnitTypes.cavalry:
                    dblMovementPoints = 125;
                    break;
            }

            intMovementPoints_Max = (int)(dblMovementPoints * dblRankFactor);
        }

        void setMyBitMap()
        {
            myBitMap = new Bitmap(getTypeImage(), (int)((double)battlefield.intMapGridSize * 0.8), (int)((double)battlefield.intMapGridSize * 0.8));
            using (Graphics grUnit = Graphics.FromImage(myBitMap))
            {
                int intRankImageSize = (int)(myBitMap.Width * .4);
                Bitmap myRankBM = new Bitmap(getRankImage(), intRankImageSize, intRankImageSize);
                //myRankBM.MakeTransparent();
                grUnit.DrawImage(myRankBM, new Point((int)(myBitMap.Width - intRankImageSize), (int)(0)));
            }

            myOriginalBitMap = new Bitmap(myBitMap);
        }

        Image getTypeImage()
        {
            switch (myType)
            {
                case classBattle.enuUnitTypes.cavalry:
                    if (myClr == classBattle.enuUnitColors.blue)
                        return Battlefield_Simulator_2019.Resources.Blue_Cavalry;
                    else
                        return Battlefield_Simulator_2019.Resources.Red_Cavalry;


                case classBattle.enuUnitTypes.artillery:
                    if (myClr == classBattle.enuUnitColors.blue)
                        return Battlefield_Simulator_2019.Resources.Blue_Artillery;
                    else
                        return Battlefield_Simulator_2019.Resources.Red_Artillery;

                case classBattle.enuUnitTypes.infantry:
                    if (myClr == classBattle.enuUnitColors.blue)
                        return Battlefield_Simulator_2019.Resources.Blue_Infantry;
                    else
                        return Battlefield_Simulator_2019.Resources.Red_Infantry;

                default:
                    if (myClr == classBattle.enuUnitColors.blue)
                        return Battlefield_Simulator_2019.Resources.Blue_Infantry;
                    else
                        return Battlefield_Simulator_2019.Resources.Red_Infantry;
            }
        }

        Image getRankImage()
        {
            switch (myRank)
            {
                case classBattle.enuUnitRanks.lieutenant:
                    return Battlefield_Simulator_2019.Resources.rank_lieutenant;


                case classBattle.enuUnitRanks.captain:
                    return Battlefield_Simulator_2019.Resources.rank_captain;


                case classBattle.enuUnitRanks.major:
                    return Battlefield_Simulator_2019.Resources.rank_major;


                case classBattle.enuUnitRanks.colonel:
                    return Battlefield_Simulator_2019.Resources.rank_colonel;


                case classBattle.enuUnitRanks.general:
                    return Battlefield_Simulator_2019.Resources.rank_general;


                case classBattle.enuUnitRanks.field_marshall:
                    return Battlefield_Simulator_2019.Resources.rank_field_marshall;

                default:
                    return Battlefield_Simulator_2019.Resources.rank_lieutenant;

            }
        }

        #endregion
    }

    public class classRangeMapElement
    {
        public classRangeMapElement next;
        public classRangeMapElement previous;
        public int intDistanceFromStart;
        public Point pos;
        public classBattle.enuDirections direction;
        public classBattleUnit unit;

        public classRangeMapElement(int intDistanceFromStart_local,
                                    Point pos_local,
                                    classBattle.enuDirections direction_local)
        {
            pos = pos_local;
            direction = direction_local;
            intDistanceFromStart = intDistanceFromStart_local;
            next = null;
            previous = null;
            unit = null;
        }
    }

    public class classShortestPathQelement
    {
        public classShortestPathQelement next;
        public classShortestPathQelement previous;
        public int intMovementCost;
        public Point pos;
        public classBattle.enuDirections direction;
        public classBattleUnit unit;
        public bool flag;

        public classShortestPathQelement(int intMovementCost_local,
                                         Point pos_local,
                                         classBattle.enuDirections direction_local)
        {
            pos = pos_local;
            direction = direction_local;
            intMovementCost = intMovementCost_local;
            next = null;
            previous = null;
            unit = null;
        }
    }
}