public IReadOnlyList <Command> Act(GameState gameState)
        {
            /* Detailed strategy:
             *
             * 1. If there are mineral deposits near a base and not being fully mined, supply is not maxed, the base is not currently building anything, and minerals are available, build a worker.
             * 2. If minerals and supply are available, and there is a Barracks or equivalent not building a basic military unit, start building one.
             * 3. If supply is maxed out, build a Supply Depot or equivalent.
             * 4. If minerals are available, build a Barracks or equivalent.
             *
             * No expansion. Once you hit the threshold of military units in existence, attack-move your opponent's base.
             *
             * Implement for Terran only initially (no Creep/Pylon placement concerns).
             *
             * Implement for maps with only two starting locations, so we don't scout.
             */
            var commands = new List <Command>();

            var controlledUnits = gameState.RawUnits.Where(u => u.Alliance == Alliance.Self).ToList();

            TerranBuilding commandCenter    = null;
            var            workers          = new List <TerranUnit>();
            var            soldiers         = new List <TerranUnit>();
            var            soldierProducers = new List <TerranBuilding>();

            if (sleep > 0)
            {
                sleep -= 1;
                return(commands);
            }

            foreach (var unit in gameState.Units)
            {
                if (unit is TerranBuilding terranBuilding)
                {
                    if (terranBuilding.TerranBuildingType == TerranBuildingType.CommandCenter ||
                        terranBuilding.TerranBuildingType == TerranBuildingType.OrbitalCommand ||
                        terranBuilding.TerranBuildingType == TerranBuildingType.PlanetaryFortress)
                    {
                        commandCenter = terranBuilding;
                    }
                    else if (terranBuilding.TerranBuildingType == TerranBuildingType.Barracks)
                    {
                        soldierProducers.Add(terranBuilding);
                    }
                }
                else if (unit is TerranUnit terranUnit)
                {
                    if (terranUnit.TerranUnitType == TerranUnitType.SCV)
                    {
                        workers.Add(terranUnit);
                    }
                    else if (terranUnit.TerranUnitType == TerranUnitType.Marine)
                    {
                        soldiers.Add(terranUnit);
                    }
                }
            }

            Deposit closestDeposit  = gameState.MapData.Deposits.OrderBy(d => commandCenter.GetDistance(d.Center)).First();
            var     mineralDeposits = closestDeposit.Resources.Where(u => u.IsMineralDeposit).ToList();



            // First update, ignore the default worker orders, which are to mass on the center mineral deposit
            // (this ends up causing problems since we have to keep track of who is harvesting what ourselves)
            if (first)
            {
                foreach (var worker in workers)
                {
                    worker.Raw.Orders.Clear();
                }

                workersByMineralDeposit = mineralDeposits.ToDictionary(m => m.Raw.Tag, m => new List <ulong>());
            }

            if (commandCenter == null)
            {
                // Accept death as inevitable.
                return(new List <Command>());

                // TODO: Surrender?
            }

            // Each possible behavior is implemented as a function that adds a command to the list
            // if the situation is appropriate. We will then execute whichever command was added first.
            BuildWorker(gameState, commandCenter, commands);
            BuildMarine(gameState, soldierProducers, commands);
            BuildSupplyDepot(gameState, workers, soldierProducers, commands);
            BuildBarracks(gameState, workers, commands);

            commands = commands.Take(1).ToList();

            // If we tell a worker to build something, make sure we don't think he's harvesting
            if (commands.Count == 1)
            {
                sleep = 1;
                RemoveWorkerFromHarvestAssignments(commands[0].Unit);
            }

            // No matter what else happens, we can always attack, and we should always set idle workers to harvest minerals
            Attack(gameState, commandCenter, soldiers, commands);
            SetIdleWorkerToHarvest(gameState, workers, mineralDeposits, commands);

            if (first)
            {
                first = false;

                // Make sure workers don't automatically harvest minerals, since we're managing assignments ourselves
                commands.Add(commandCenter.RallyWorkers(commandCenter.Raw.Pos.X, commandCenter.Raw.Pos.Y));
            }

            return(commands);
        }
        private void Attack(GameState gameState, TerranBuilding commandCenter, List <TerranUnit> soldiers, List <Command> commands)
        {
            // Initially, await X idle soldiers and send them toward the enemy's starting location.
            // Once they're there and have no further orders, send them to attack any sighted enemy unit/structure.
            // Once we run out of those, send them to scout every resource deposit until we find more.
            var enemyStartLocation = gameState.MapData.Raw.StartLocations.OrderByDescending(point => commandCenter.GetDistance(point)).First();

            var idleSoldiers = soldiers.Where(s => s.Raw.Orders.Count == 0).ToList();

            if (!soldiers.Any(s => s.GetDistance(enemyStartLocation) < 5f) ||
                gameState.EnemyUnits.Any(e => e.GetDistance(enemyStartLocation) < 10f))
            {
                if (idleSoldiers.Count >= AttackThreshold)
                {
                    foreach (var soldier in idleSoldiers)
                    {
                        commands.Add(soldier.AttackMove(enemyStartLocation.X, enemyStartLocation.Y));
                    }
                }

                return;
            }

            if (gameState.EnemyUnits.Count > 0)
            {
                foreach (var soldier in idleSoldiers)
                {
                    commands.Add(soldier.AttackMove(gameState.EnemyUnits[0].X, gameState.EnemyUnits[0].Y));
                }

                return;
            }

            var unscoutedLocations = gameState.MapData.Deposits.Select(d => d.Center).ToList();

            foreach (var location in unscoutedLocations)
            {
                if (soldiers.Any(s => s.GetDistance(location) < 5f ||
                                 s.Raw.Orders.Any(o => o.TargetWorldSpacePos.GetDistance(location) < 5f)))
                {
                    continue;
                }

                if (idleSoldiers.Count == 0)
                {
                    break;
                }

                commands.Add(idleSoldiers[0].AttackMove(location));
                idleSoldiers.RemoveAt(0);
            }
        }