public static void placePieces(Boolean is_loaded, String loaded_file)
        {
            if (!is_loaded)
            {
                Tuple<Int16,Int16> castleCoords = GameBoard.getPlayerCastle();
                Int16 j = castleCoords.Item1;
                Int16 i = castleCoords.Item2;

                //Logger.log(@"Placing player pieces in random positions.");
                if (i - 1 >= 0)
                {
                    if (GameBoard.overlay[i - 1, j] != '@')
                    {
                        Tuple<Int16, Int16> coords = Tuple.Create((short)(i-1),(short)j);
                        PlayerCharacter character = new PlayerCharacter('1', coords.Item1, coords.Item2, 10, 1, 1);
                        FlameBadge.player_units.Add(character);
                        GameBoard.update(character, coords.Item1, coords.Item2);
                        Logger.log(String.Format(@"Placed {0} at {1}, {2} with health {3}, level {4}, and dpsMod {5}", character.id.ToString(), coords.Item1, coords.Item2, 10, 1, 1));
                    }
                }
                if (i + 1 < GameBoard.overlay.GetLength(0))
                {
                    if (GameBoard.overlay[i + 1, j] != '@')
                    {
                        Tuple<Int16, Int16> coords = Tuple.Create((short)(i+1),(short)j);
                        PlayerCharacter character = new PlayerCharacter('2', coords.Item1, coords.Item2, 10, 1, 1);
                        FlameBadge.player_units.Add(character);
                        GameBoard.update(character, coords.Item1, coords.Item2);
                        Logger.log(String.Format(@"Placed {0} at {1}, {2} with health {3}, level {4}, and dpsMod {5}", character.id.ToString(), coords.Item1, coords.Item2, 10, 1, 1));
                    }
                }
                if (j - 1 >= 0)
                {
                    if (GameBoard.overlay[i, j - 1] != '@')
                    {
                        Tuple<Int16, Int16> coords = Tuple.Create((short)(i),(short)(j-1));
                        PlayerCharacter character = new PlayerCharacter('3', coords.Item1, coords.Item2, 10, 1, 1);
                        FlameBadge.player_units.Add(character);
                        GameBoard.update(character, coords.Item1, coords.Item2);
                        Logger.log(String.Format(@"Placed {0} at {1}, {2} with health {3}, level {4}, and dpsMod {5}", character.id.ToString(), coords.Item1, coords.Item2, 10, 1, 1));
                    }
                }
                if (j + 1 < GameBoard.overlay.GetLength(1))
                {
                    if (GameBoard.overlay[i, j + 1] != '@')
                    {
                        Tuple<Int16, Int16> coords = Tuple.Create((short)(i),(short)(j+1));
                        PlayerCharacter character = new PlayerCharacter('4', coords.Item1, coords.Item2, 10, 1, 1);
                        FlameBadge.player_units.Add(character);
                        GameBoard.update(character, coords.Item1, coords.Item2);
                        Logger.log(String.Format(@"Placed {0} at {1}, {2} with health {3}, level {4}, and dpsMod {5}", character.id.ToString(), coords.Item1, coords.Item2, 10, 1, 1));
                    }
                }

                //diagonals
                if (i - 1 >= 0 && j + 1 < GameBoard.overlay.GetLength(1))
                {
                    if (GameBoard.overlay[i - 1, j + 1] != '@')
                    {
                        Tuple<Int16, Int16> coords = Tuple.Create((short)(i-1),(short)(j+1));
                        PlayerCharacter character = new PlayerCharacter('5', coords.Item1, coords.Item2, 10, 1, 1);
                        FlameBadge.player_units.Add(character);
                        GameBoard.update(character, coords.Item1, coords.Item2);
                        Logger.log(String.Format(@"Placed {0} at {1}, {2} with health {3}, level {4}, and dpsMod {5}", character.id.ToString(), coords.Item1, coords.Item2, 10, 1, 1));
                    }
                }
                if (i + 1 < GameBoard.overlay.GetLength(0) && j - 1 >= 0)
                {
                    if (GameBoard.overlay[i + 1, j - 1] != '@')
                    {
                        Tuple<Int16, Int16> coords = Tuple.Create((short)(i+1),(short)(j-1));
                        PlayerCharacter character = new PlayerCharacter('6', coords.Item1, coords.Item2, 10, 1, 1);
                        FlameBadge.player_units.Add(character);
                        GameBoard.update(character, coords.Item1, coords.Item2);
                        Logger.log(String.Format(@"Placed {0} at {1}, {2} with health {3}, level {4}, and dpsMod {5}", character.id.ToString(), coords.Item1, coords.Item2, 10, 1, 1));
                    }
                }
                if (i - 1 >= 0 && j - 1 >= 0)
                {
                    if (GameBoard.overlay[i - 1, j - 1] != '@')
                    {
                        Tuple<Int16, Int16> coords = Tuple.Create((short)(i-1),(short)(j-1));
                        PlayerCharacter character = new PlayerCharacter('7', coords.Item1, coords.Item2, 10, 1, 1);
                        FlameBadge.player_units.Add(character);
                        GameBoard.update(character, coords.Item1, coords.Item2);
                        Logger.log(String.Format(@"Placed {0} at {1}, {2} with health {3}, level {4}, and dpsMod {5}", character.id.ToString(), coords.Item1, coords.Item2, 10, 1, 1));
                    }
                }
                if (i + 1 < GameBoard.overlay.GetLength(0) && j + 1 < GameBoard.overlay.GetLength(1))
                {
                    if (GameBoard.overlay[i + 1, j + 1] != '@')
                    {
                        Tuple<Int16, Int16> coords = Tuple.Create((short)(i + 1), (short)(j+1));
                        PlayerCharacter character = new PlayerCharacter('8', coords.Item1, coords.Item2, 10, 1, 1);
                        FlameBadge.player_units.Add(character);
                        GameBoard.update(character, coords.Item1, coords.Item2);
                        Logger.log(String.Format(@"Placed {0} at {1}, {2} with health {3}, level {4}, and dpsMod {5}", character.id.ToString(), coords.Item1, coords.Item2, 10, 1, 1));
                    }

                }
            }
            else
            {
                Logger.log(@"Placing player pieces according to loaded save file.");
                try
                {
                    using (StreamReader sr = new StreamReader(loaded_file))
                    {
                        while (sr.Peek() > -1)
                        {
                            String line = sr.ReadLine();
                            if (line.StartsWith("Player"))
                            {
                                for (int i = 0; i < Convert.ToInt16(line.Split()[1]); i++)
                                {
                                    String[] unit_info = sr.ReadLine().Split();
                                    PlayerCharacter character = new PlayerCharacter(Convert.ToChar(unit_info[0]), Convert.ToInt16(unit_info[1]), Convert.ToInt16(unit_info[2]), Convert.ToInt32(unit_info[3]), Convert.ToInt32(unit_info[4]), Convert.ToInt32(unit_info[5]));
                                    FlameBadge.player_units.Add(character);
                                    GameBoard.update(character, Convert.ToInt16(unit_info[1]), Convert.ToInt16(unit_info[2]));
                                    Logger.log(String.Format(@"Placed {0} at {1}, {2} with health {3}, level {4}, and dpsMod {5}", character.id.ToString(), Convert.ToInt16(unit_info[1]), Convert.ToInt16(unit_info[2]), Convert.ToInt32(unit_info[3]), Convert.ToInt32(unit_info[4]), Convert.ToInt32(unit_info[5])));
                                }
                            }
                        }

                    }
                }
                catch (Exception)
                {
                    Logger.log("Could not load player pieces from save file. Quitting...", "error");
                    Environment.Exit(1);
                }

            }
        }
        private int calculateNextMoveHeuristic(EnemyCharacter c, List<Character> units, List<Character> enemyUnits, int numLevels, Boolean cpuTurn)
        {
            if (numLevels == 0) return 0;

            List<Character> futureUnits = new List<Character>();
            int averageHeuristic = 0;

            // move each of the units tentatively
            foreach (Character unit in units)
            {
                if (unit == c) continue;
                // get all possible moves for the cpu unit
                List<Tuple<int, int>> moves = unit.getPossibleMoves();
                int bestMoveHeuristic = -999999;
                Character best = null;

                foreach (Tuple<int, int> move in moves)
                {
                    int heuristic = 0;

                    Character potentialUnit = null;
                    if (cpuTurn)
                    {
                        // create a new character so that we don't override the original
                        potentialUnit = new EnemyCharacter(unit.id, (short)move.Item1, (short)move.Item2, unit.health, unit.level, unit.dpsMod);
                        heuristic += canAttackBaseAttacker(potentialUnit, enemyUnits, cpuBasePos);
                        heuristic += canDamageOpponentBase(potentialUnit, playerBasePos);
                        heuristic += isGuardingBase(potentialUnit, cpuBasePos);
                        heuristic += isTravellingToBase(potentialUnit, unit.xPos, unit.yPos, playerBasePos, true);
                        heuristic += isTravellingToBase(potentialUnit, unit.xPos, unit.yPos, cpuBasePos, false);
                    }
                    else
                    {
                        // create a new character so that we don't override the original
                        potentialUnit = new PlayerCharacter(unit.id, (short)move.Item1, (short)move.Item2, unit.health, unit.level, unit.dpsMod);
                        heuristic += canAttackBaseAttacker(potentialUnit, enemyUnits, playerBasePos);
                        heuristic += canDamageOpponentBase(potentialUnit, cpuBasePos);
                        heuristic += isGuardingBase(potentialUnit, playerBasePos);
                        heuristic += isTravellingToBase(potentialUnit, unit.xPos, unit.yPos, cpuBasePos, true);
                        heuristic += isTravellingToBase(potentialUnit, unit.xPos, unit.yPos, playerBasePos, false);
                    }

                    heuristic += isFleeingFromOverwhelmingForce(potentialUnit, enemyUnits, units, unit.xPos, unit.yPos);
                    heuristic += canAttackOpponent(potentialUnit, enemyUnits);
                    heuristic += isMovingToInterceptOpponent(potentialUnit, enemyUnits, unit.xPos, unit.yPos);

                    // get the best move for that unit
                    if (heuristic > bestMoveHeuristic)
                    {
                        bestMoveHeuristic = heuristic;
                        best = potentialUnit;
                    }
                    else if (heuristic == bestMoveHeuristic)
                    {
                        // if the values are equal, flip a coin to see which to choose
                        Random r = new Random();
                        if (r.Next(0, 2) == 0)
                            best = potentialUnit;
                    }
                }
                averageHeuristic += bestMoveHeuristic;
                futureUnits.Add(best);
            }
            averageHeuristic = averageHeuristic / units.Count();

            if (cpuTurn)
            {
                List<Tuple<int, int>> moves = c.getPossibleMoves();
                int bestMoveHeuristic = -999999;

                foreach (Tuple<int, int> move in moves)
                {
                    int heuristic = 0;

                    Character potentialUnit = null;

                    // create a new character so that we don't override the original
                    potentialUnit = new EnemyCharacter(c.id, (short)move.Item1, (short)move.Item2, c.health, c.level, c.dpsMod);
                    heuristic += canAttackBaseAttacker(potentialUnit, enemyUnits, cpuBasePos);
                    heuristic += canDamageOpponentBase(potentialUnit, playerBasePos);
                    heuristic += isGuardingBase(potentialUnit, cpuBasePos);
                    heuristic += isTravellingToBase(potentialUnit, c.xPos, c.yPos, playerBasePos, true);
                    heuristic += isTravellingToBase(potentialUnit, c.xPos, c.yPos, cpuBasePos, false);
                    heuristic += isFleeingFromOverwhelmingForce(potentialUnit, enemyUnits, units, c.xPos, c.yPos);
                    heuristic += canAttackOpponent(potentialUnit, enemyUnits);
                    heuristic += isMovingToInterceptOpponent(potentialUnit, enemyUnits, c.xPos, c.yPos);

                    int negHeuristic = calculateNextMoveHeuristic(c, enemyUnits, futureUnits, numLevels - 1, !cpuTurn);

                    // subtract the heuristic points gained by the enemy
                    heuristic -= negHeuristic;

                    // get the best move for that unit
                    if (heuristic > bestMoveHeuristic)
                    {
                        bestMoveHeuristic = heuristic;
                    }
                }
                return bestMoveHeuristic;
            }
            else
            {
                // if this was the tentative player turn, go down the next level and return the heuristic
                int negHeuristic = calculateNextMoveHeuristic(c, enemyUnits, futureUnits, numLevels - 1, !cpuTurn);
                averageHeuristic -= negHeuristic;
                return averageHeuristic;
            }
        }