public static void Turn( GameState gs )
        {
            /* Current strongest planet */
            IOrderedEnumerable<Planet> planetsByStrongest = gs.Planets.Mine.OrderByDescending( p => p.FuturedAvailableShips );
            Planet strongest = planetsByStrongest.Count() > 0 ? planetsByStrongest.First() : null;

            if (strongest != null)
            {
                int shipsRemain = strongest.FuturedAvailableShips;
                Debug.Assert( strongest.FuturedAvailableShips <= strongest.ShipCount );

                /* All planets that won't be ours when any fleet send from here would reach them */
                IOrderedEnumerable<Planet> weightedPlanets =
                    gs.Planets.FuturedPredicate( gs, strongest, x => x.Owner != Players.Singleton.Me ).
                    OrderByDescending( p => PolynomialDistanceWeight( p, strongest, new Polynomial( 0, 2, 0 ) ) );

                /* Go through what all the planets' ratings are predicted to be when a fleet would reach them */
                foreach (Planet futurePlanet in weightedPlanets)
                {
                    /* must send one more than the planet's shipcount, otherwise it doesn't change hands. */
                    if (futurePlanet.ShipCount < shipsRemain)
                    {
                        gs.Orders.Add(new Order(strongest, futurePlanet, futurePlanet.ShipCount + 1));
                        shipsRemain -= futurePlanet.ShipCount + 1;
                    }
                }
            }

            gs.Orders.Done();
        }
        private static bool EndStates( )
        {
            GameState gs = new GameState( TestStrings.GameStateEndState1, 0 );

            Debug.Assert( gs.EndState == false );
            Debug.Assert( gs.Winner == null );

            return true;
        }
        /* Dispatch to single planet (no futuring):
         * Bully: 95
         * Dual: 86
         * Prospector: 93
         * Rage: 96
         * Random: 100
         *
         * Dispatch to multiple planets (no futuring):
         * Bully: 100
         * Dual: 98
         * Prospector: 100
         * Rage: 70
         * Random: 100
         */
        public static void Turn(GameState gs)
        {
            /* Current strongest planet - this should really be futured for the time it will take the ships to get there, but we don't yet know where they're coming from.
             * So for now, we work on most desirable now (may not be desirable in future if a massive enemy fleet is en route).
             * This is different to the problem of the desired planet's shipcount increasing, which we can know once we've decided which one it is (below). */
            /* OH HAI. Desirability is NOT based on current ship count, but how many ships we will have to throw to take it.
             * The planet with the lowest ship count might take a load of ships to take, if it's far away and so a lot have to be thrown across the map, to account for its growth in the meantime.
             * TODO: we need to run this algorithm (futured closet-first ship throwing) for all planets, then at the end the most desirable is the most growth we get for the fewest ships we'd actually need to send */
            /* TODO: need to make sure that we still get the "auto defense" from us targeting our own planets with just enough ships when they're unable to defend themselves. Not sure how to do this yet */
            IOrderedEnumerable<Planet> desirablePlanets =
                gs.Planets.NotMine.
                Where(p => !gs.Fleets.Where(f => f.DestinationPlanet == p).Any()).
                OrderByDescending(p => Weight(p));

            foreach (Planet desired in desirablePlanets)
            {
                /* GameState turning *must* render our orders into the mix too */
                int shipsSent = 0;
                IList<Order> potentialOrders = new List<Order>();

                IOrderedEnumerable<Planet> closetPlanets =
                    gs.Planets.Mine.OrderBy( p => p.DistanceTo( desired ) );

                foreach (Planet closePlanet in closetPlanets)
                {
                    Planet futureDesired = gs.Futures[closePlanet.DistanceTo( desired )].Planets[desired.Id];

                    if (futureDesired.Owner == Players.Singleton.Me) break;

                    /* must send one more than the planet's shipcount, otherwise it doesn't change hands. */
                    int shipsNeeded = futureDesired.ShipCount + 1;

                    int shipsToSend = Math.Min(
                        shipsNeeded - shipsSent,
                        closePlanet.FuturedAvailableShips - gs.Orders.Where(o => o.SourcePlanet == closePlanet).Select(o => o.ShipCount).Sum() //TODO: nice method in gs to account for this?
                    );

                    /* FuturedAvailableShips will return 0 if we're under attack and will need every last ship to defend. */
                    if (shipsToSend > 0)
                    {
                        potentialOrders.Add(new Order(closePlanet, desired, shipsToSend));
                        shipsSent += shipsToSend;
                        Debug.Assert(shipsToSend <= shipsNeeded);
                    }

                    if (shipsSent == shipsNeeded)
                    {
                        /* Only issue order if we mustered enough ships to take the planet. */
                        gs.Orders.AddRange(potentialOrders);
                        break;
                    }
                }
            }

            gs.Orders.Done();
        }
예제 #4
0
 public Fleet(GameState gs,
     Player owner,
     int shipCount,
     int sourcePlanet,
     int destinationPlanet,
     int totalTripLength,
     int turnsRemaining)
 {
     m_Owner = owner;
     m_ShipCount = shipCount;
     m_SourcePlanet = gs.Planets[sourcePlanet];
     m_DestinationPlanet = gs.Planets[destinationPlanet];
     m_TotalTripLength = totalTripLength;
     m_TurnsRemaining = turnsRemaining;
 }
        /* Turn entry point */
        public static void Turn(GameState gs)
        {
            // (1) If we currently have a fleet in flight, just do nothing.
            if (gs.Fleets.Mine.Any())
            {
                return;
            }

            // (2) Find my strongest planet.
            Planet source = null;
            double sourceScore = Double.MinValue;
            foreach (Planet p in gs.Planets.Mine)
            {
                double score = (double)p.ShipCount;
                if (score > sourceScore)
                {
                    sourceScore = score;
                    source = p;
                }
            }

            // (3) Find the weakest enemy or neutral planet.
            Planet dest = null;
            double destScore = Double.MinValue;
            foreach (Planet p in gs.Planets.Neutral.Concat(gs.Planets.Yours))
            {
                double score = 1.0 / (1 + p.ShipCount);
                if (score > destScore)
                {
                    destScore = score;
                    dest = p;
                }
            }

            // (4) Send half the ships from my strongest planet to the weakest
            // planet that I do not own.
            if (source != null && dest != null)
            {
                int numShips = source.ShipCount / 2;

                gs.Orders.Add(new Order(source, dest, numShips));
            }

            gs.Orders.Done();
        }
예제 #6
0
 public bool IsAlive( GameState pw )
 {
     return pw.Planets.Any(x => x.Owner == this) || pw.Fleets.Any(x => x.Owner == this);
 }
        private void RenderGameState( GameState gs )
        {
            /* Geometry */
            List<GeometryGroup> planetsGeoms = new List<GeometryGroup>
            {
                new GeometryGroup(), new GeometryGroup(  ), new GeometryGroup(  )
            };

            gs.Planets.ForEach( p => planetsGeoms[ p.Owner.Id ].Children.Add( new PlanetRender( p ).Geometry ) );

            /* Rendering */
            List<GeometryDrawing> planetsDrawers = new List<GeometryDrawing>
            {
                new GeometryDrawing( ), new GeometryDrawing( ), new GeometryDrawing( )
            };

            planetsGeoms.ForEach( pg => planetsDrawers[ planetsGeoms.IndexOf( pg ) ].Geometry = pg );

            planetsDrawers[ Players.Neutral.Id ].Brush = new SolidColorBrush( Color.FromArgb( 255, 128, 128, 128 ) );
            planetsDrawers[ Players.Me.Id      ].Brush = new SolidColorBrush( Color.FromArgb( 255,   0, 255,   0 ) );
            planetsDrawers[ Players.You.Id     ].Brush = new SolidColorBrush( Color.FromArgb( 255, 255,   0,   0 ) );

            /* Geometry */
            List<GeometryGroup> fleetsGeoms = new List<GeometryGroup>
            {
                new GeometryGroup(), new GeometryGroup(  ), new GeometryGroup(  )
            };

            gs.Fleets.ForEach(f => fleetsGeoms[f.Owner.Id].Children.Add(new FleetRender(f, checkBoxLines.IsChecked).Geometry));

            /* Rendering */
            List<GeometryDrawing> fleetsDrawers = new List<GeometryDrawing>
            {
                new GeometryDrawing( ), new GeometryDrawing( ), new GeometryDrawing( )
            };

            fleetsGeoms.ForEach(fg => fleetsDrawers[fleetsGeoms.IndexOf(fg)].Geometry = fg);

            fleetsDrawers[Players.Me.Id ].Brush = new SolidColorBrush(Color.FromArgb(255, 0, 255, 0));
            fleetsDrawers[Players.Me.Id ].Pen = new Pen(new SolidColorBrush(Color.FromArgb(128, 0, 255, 0)), 0.05);
            fleetsDrawers[Players.You.Id].Brush = new SolidColorBrush(Color.FromArgb(255, 255, 0, 0));
            fleetsDrawers[Players.You.Id].Pen = new Pen( new SolidColorBrush(Color.FromArgb(128, 255, 0, 0)), 0.05);

            DrawingGroup udg = new DrawingGroup(  );

            planetsDrawers.ForEach( udg.Children.Add );
            fleetsDrawers.ForEach( udg.Children.Add );

            m_CanvasUniverse.Background = new DrawingBrush(udg);
        }
예제 #8
0
        public static void Main( string[] args )
        {
            switch( args.Length )
            {
                case 1:
                    if( args[0] == "/tcpio")
                    {
                        ObjectFactory.Get<Settings>( ).TcpIo = true;
                    }
                    break;
            }

            int c;
            string line = "";
            string message = "";
            ISourceSink source = ObjectFactory.Get<ISourceSink>();
            int turn = 0;

            Loggers.CurrentLevel = Loggers.LogLevel.Info;

            while( ( c = source.Source(  ) ) > 0)
            {
                switch (c)
                {
                    case '\r':
                        /* Swallow */
                        break;

                    case '\n':
                        if (line == "go")
                        {
                            GameState gs = new GameState(message, turn++);

                            if( !ObjectFactory.Get<PlanetGeometryCache>(  ).Initialised )
                            {
                                ObjectFactory.Get<PlanetGeometryCache>(  ).Initialise( gs.Planets.Count );
                            }

                            /* We get given winning states at the end of games, where there's nothing for us to do.
                             * To avoid potentially embarrassing problems with the logic infinite-looping, don't call it */
                            if (gs.EndState)
                            {
                                s_Logger.Error( String.Format( "{0} Wins! ", gs.Winner ) );
                                gs.Orders.Done(  );
                                break;
                            }

                            DateTime start = DateTime.Now;
                            Strategy4.Turn(gs);
                            DateTime end = DateTime.Now;

                            s_Logger.Info( String.Format( "Turn {0} took {1}ms", turn, (end - start).TotalMilliseconds ) );

                            message = "";
                        }
                        else
                        {
                            message += line + "\n";
                        }
                        line = "";
                        break;

                    default:
                        line += (char)c;
                        break;
                }
            }

            AppDomain.CurrentDomain.DomainUnload += (x, y) => Loggers.DisposeAll();
        }
        /* The fleet overpowers the forces on the planet, thus the planet's owner changes. */
        private static bool TestOneFleetOverpower()
        {
            GameState gs = new GameState(TestStrings.GameStateOneFleetOverpower, 0 ),
                      gs22,
                      gs23;

            Planet planet0, planet1, planet2;
            Fleet myFleet;

            Debug.Assert(gs.Planets.Count == 3);

            planet2 = gs.Planets.Single(x => x.Id == 2);
            Debug.Assert(planet2.Owner == Players.Singleton.Neutral);
            Debug.Assert(planet2.ShipCount == 40);
            Debug.Assert(planet2.GrowthRate == 4);
            Debug.Assert(planet2.X == 10);
            Debug.Assert(planet2.Y == 10);

            planet0 = gs.Planets.Single(x => x.Id == 0);
            Debug.Assert(planet0.Owner == Players.Singleton.Me);
            Debug.Assert(planet0.ShipCount == 100);
            Debug.Assert(planet0.GrowthRate == 5);
            Debug.Assert(planet0.X == 2);
            Debug.Assert(planet0.Y == 3);

            planet1 = gs.Planets.Single(x => x.Id == 1);
            Debug.Assert(planet1.Owner == Players.Singleton.You);
            Debug.Assert(planet1.ShipCount == 100);
            Debug.Assert(planet1.GrowthRate == 5);
            Debug.Assert(planet1.X == 17);
            Debug.Assert(planet1.Y == 18);

            Debug.Assert(gs.Fleets.Count == 1);
            myFleet = gs.Fleets.Mine.Single();
            Debug.Assert(myFleet.Owner == Players.Singleton.Me);
            Debug.Assert(myFleet.ShipCount == 300);
            Debug.Assert(myFleet.SourcePlanet == planet0);
            Debug.Assert(myFleet.DestinationPlanet == planet1);
            Debug.Assert(myFleet.TotalTripLength == 22);
            Debug.Assert(myFleet.TurnsRemaining == 22);

            gs22 = gs.Futures[ 22 ];

            Debug.Assert(gs22.Planets.Count == 3);

            planet2 = gs22.Planets.Single(x => x.Id == 2);
            Debug.Assert(planet2.Owner == Players.Singleton.Neutral);
            Debug.Assert(planet2.ShipCount == 40);
            Debug.Assert(planet2.GrowthRate == 4);
            Debug.Assert(planet2.X == 10);
            Debug.Assert(planet2.Y == 10);

            planet0 = gs22.Planets.Single(x => x.Id == 0);
            Debug.Assert(planet0.Owner == Players.Singleton.Me);
            Debug.Assert(planet0.ShipCount == 210);
            Debug.Assert(planet0.GrowthRate == 5);
            Debug.Assert(planet0.X == 2);
            Debug.Assert(planet0.Y == 3);

            planet1 = gs22.Planets.Single(x => x.Id == 1);
            Debug.Assert(planet1.Owner == Players.Singleton.Me);
            Debug.Assert(planet1.ShipCount == 90);
            Debug.Assert(planet1.GrowthRate == 5);
            Debug.Assert(planet1.X == 17);
            Debug.Assert(planet1.Y == 18);

            Debug.Assert(gs22.Fleets.Count == 0);

            gs23 = gs.Futures[ 23 ];

            Debug.Assert(gs23.Planets.Count == 3);

            planet2 = gs23.Planets.Single(x => x.Id == 2);
            Debug.Assert(planet2.Owner == Players.Singleton.Neutral);
            Debug.Assert(planet2.ShipCount == 40);
            Debug.Assert(planet2.GrowthRate == 4);
            Debug.Assert(planet2.X == 10);
            Debug.Assert(planet2.Y == 10);

            planet0 = gs23.Planets.Single(x => x.Id == 0);
            Debug.Assert(planet0.Owner == Players.Singleton.Me);
            Debug.Assert(planet0.ShipCount == 215);
            Debug.Assert(planet0.GrowthRate == 5);
            Debug.Assert(planet0.X == 2);
            Debug.Assert(planet0.Y == 3);

            planet1 = gs23.Planets.Single(x => x.Id == 1);
            Debug.Assert(planet1.Owner == Players.Singleton.Me);
            Debug.Assert(planet1.ShipCount == 95);
            Debug.Assert(planet1.GrowthRate == 5);
            Debug.Assert(planet1.X == 17);
            Debug.Assert(planet1.Y == 18);

            Debug.Assert(gs23.Fleets.Count == 0);

            Debug.Assert( gs23.EndState == true );
            Debug.Assert( gs23.Winner == Players.Singleton.Me );

            return true;
        }
        private static bool TestNoFleets()
        {
            GameState gs = new GameState( TestStrings.GameStateNoFleets, 0 ),
                      gs1,
                      gs5,
                      gs1_4;

            Planet neutralPlanet, myPlanet, yourPlanet;

            Debug.Assert( gs.Planets.Count == 3 );

            Debug.Assert( gs.Planets.Neutral.Count( ) == 1 );
            neutralPlanet = gs.Planets.Neutral.Single( );
            Debug.Assert( neutralPlanet.ShipCount == 40 );
            Debug.Assert( neutralPlanet.GrowthRate == 4 );
            Debug.Assert( neutralPlanet.X == 10 );
            Debug.Assert( neutralPlanet.Y == 10 );

            Debug.Assert( gs.Planets.Mine.Count( ) == 1 );
            myPlanet = gs.Planets.Mine.Single( );
            Debug.Assert( myPlanet.ShipCount == 100 );
            Debug.Assert( myPlanet.GrowthRate == 5 );
            Debug.Assert( myPlanet.X == 2 );
            Debug.Assert( myPlanet.Y == 3 );

            Debug.Assert( gs.Planets.Yours.Count( ) == 1 );
            yourPlanet = gs.Planets.Yours.Single( );
            Debug.Assert( yourPlanet.ShipCount == 100 );
            Debug.Assert( yourPlanet.GrowthRate == 5 );
            Debug.Assert( yourPlanet.X == 17 );
            Debug.Assert( yourPlanet.Y == 18 );

            Debug.Assert( gs.Fleets.Count == 0 );

            gs1 = gs.Futures[ 1 ];

            Debug.Assert( gs1.Planets.Count == 3 );

            Debug.Assert( gs1.Planets.Neutral.Count( ) == 1 );
            neutralPlanet = gs1.Planets.Neutral.Single( );
            Debug.Assert( neutralPlanet.ShipCount == 40 );
            Debug.Assert( neutralPlanet.GrowthRate == 4 );
            Debug.Assert( neutralPlanet.X == 10 );
            Debug.Assert( neutralPlanet.Y == 10 );

            Debug.Assert( gs1.Planets.Mine.Count( ) == 1 );
            myPlanet = gs1.Planets.Mine.Single( );
            Debug.Assert( myPlanet.ShipCount == 105 );
            Debug.Assert( myPlanet.GrowthRate == 5 );
            Debug.Assert( myPlanet.X == 2 );
            Debug.Assert( myPlanet.Y == 3 );

            Debug.Assert( gs1.Planets.Yours.Count( ) == 1 );
            yourPlanet = gs1.Planets.Yours.Single( );
            Debug.Assert( yourPlanet.ShipCount == 105 );
            Debug.Assert( yourPlanet.GrowthRate == 5 );
            Debug.Assert( yourPlanet.X == 17 );
            Debug.Assert( yourPlanet.Y == 18 );

            Debug.Assert( gs1.Fleets.Count == 0 );

            gs5 = gs.Futures[ 5 ];

            Debug.Assert( gs5.Planets.Count == 3 );

            Debug.Assert( gs5.Planets.Neutral.Count( ) == 1 );
            neutralPlanet = gs5.Planets.Neutral.Single( );
            Debug.Assert( neutralPlanet.ShipCount == 40 );
            Debug.Assert( neutralPlanet.GrowthRate == 4 );
            Debug.Assert( neutralPlanet.X == 10 );
            Debug.Assert( neutralPlanet.Y == 10 );

            Debug.Assert( gs5.Planets.Mine.Count( ) == 1 );
            myPlanet = gs5.Planets.Mine.Single( );
            Debug.Assert( myPlanet.ShipCount == 125 );
            Debug.Assert( myPlanet.GrowthRate == 5 );
            Debug.Assert( myPlanet.X == 2 );
            Debug.Assert( myPlanet.Y == 3 );

            Debug.Assert( gs5.Planets.Yours.Count( ) == 1 );
            yourPlanet = gs5.Planets.Yours.Single( );
            Debug.Assert( yourPlanet.ShipCount == 125 );
            Debug.Assert( yourPlanet.GrowthRate == 5 );
            Debug.Assert( yourPlanet.X == 17 );
            Debug.Assert( yourPlanet.Y == 18 );

            Debug.Assert( gs5.Fleets.Count == 0 );

            Debug.Assert(gs5.EndState == false);
            Debug.Assert(gs5.Winner == null);

            gs1_4 = gs1.Futures[ 4 ];

            Debug.Assert( gs1_4.Planets.Count == 3 );

            Debug.Assert( gs1_4.Planets.Neutral.Count( ) == 1 );
            neutralPlanet = gs1_4.Planets.Neutral.Single( );
            Debug.Assert( neutralPlanet.ShipCount == 40 );
            Debug.Assert( neutralPlanet.GrowthRate == 4 );
            Debug.Assert( neutralPlanet.X == 10 );
            Debug.Assert( neutralPlanet.Y == 10 );

            Debug.Assert( gs1_4.Planets.Mine.Count( ) == 1 );
            myPlanet = gs1_4.Planets.Mine.Single( );
            Debug.Assert( myPlanet.ShipCount == 125 );
            Debug.Assert( myPlanet.GrowthRate == 5 );
            Debug.Assert( myPlanet.X == 2 );
            Debug.Assert( myPlanet.Y == 3 );

            Debug.Assert( gs1_4.Planets.Yours.Count( ) == 1 );
            yourPlanet = gs1_4.Planets.Yours.Single( );
            Debug.Assert( yourPlanet.ShipCount == 125 );
            Debug.Assert( yourPlanet.GrowthRate == 5 );
            Debug.Assert( yourPlanet.X == 17 );
            Debug.Assert( yourPlanet.Y == 18 );

            Debug.Assert( gs1_4.Fleets.Count == 0 );

            Debug.Assert( gs1_4.EndState == false );
            Debug.Assert( gs1_4.Winner == null );

            return true;
        }
        /* The fleet is not sufficient to overpower the forces on the planet.
         * This test also does more general stuff like composition of futures and proper movement. */
        private static bool TestOneFleetInsufficient()
        {
            GameState gs = new GameState(TestStrings.GameStateOneFleetInsufficient, 0 ),
                      gs1,
                      gs22,
                      gs1_4;

            Planet neutralPlanet, myPlanet, yourPlanet;
            Fleet myFleet;

            Debug.Assert(gs.Planets.Count == 3);

            Debug.Assert(gs.Planets.Neutral.Count() == 1);
            neutralPlanet = gs.Planets.Neutral.Single();
            Debug.Assert(neutralPlanet.ShipCount == 40);
            Debug.Assert(neutralPlanet.GrowthRate == 4);
            Debug.Assert(neutralPlanet.X == 10);
            Debug.Assert(neutralPlanet.Y == 10);

            Debug.Assert(gs.Planets.Mine.Count() == 1);
            myPlanet = gs.Planets.Mine.Single();
            Debug.Assert(myPlanet.ShipCount == 100);
            Debug.Assert(myPlanet.GrowthRate == 5);
            Debug.Assert(myPlanet.X == 2);
            Debug.Assert(myPlanet.Y == 3);

            Debug.Assert(gs.Planets.Yours.Count() == 1);
            yourPlanet = gs.Planets.Yours.Single();
            Debug.Assert(yourPlanet.ShipCount == 100);
            Debug.Assert(yourPlanet.GrowthRate == 5);
            Debug.Assert(yourPlanet.X == 17);
            Debug.Assert(yourPlanet.Y == 18);

            Debug.Assert(gs.Fleets.Count == 1);
            myFleet = gs.Fleets.Mine.Single( );
            Debug.Assert( myFleet.Owner == Players.Singleton.Me );
            Debug.Assert( myFleet.ShipCount == 50 );
            Debug.Assert( myFleet.SourcePlanet == myPlanet );
            Debug.Assert( myFleet.DestinationPlanet == yourPlanet );
            Debug.Assert( myFleet.TotalTripLength == 22 );
            Debug.Assert( myFleet.TurnsRemaining == 22 );

            gs1 = gs.Futures[ 1 ];

            Debug.Assert(gs1.Planets.Count == 3);

            Debug.Assert(gs1.Planets.Neutral.Count() == 1);
            neutralPlanet = gs1.Planets.Neutral.Single();
            Debug.Assert(neutralPlanet.ShipCount == 40);
            Debug.Assert(neutralPlanet.GrowthRate == 4);
            Debug.Assert(neutralPlanet.X == 10);
            Debug.Assert(neutralPlanet.Y == 10);

            Debug.Assert(gs1.Planets.Mine.Count() == 1);
            myPlanet = gs1.Planets.Mine.Single();
            Debug.Assert(myPlanet.ShipCount == 105);
            Debug.Assert(myPlanet.GrowthRate == 5);
            Debug.Assert(myPlanet.X == 2);
            Debug.Assert(myPlanet.Y == 3);

            Debug.Assert(gs1.Planets.Yours.Count() == 1);
            yourPlanet = gs1.Planets.Yours.Single();
            Debug.Assert(yourPlanet.ShipCount == 105);
            Debug.Assert(yourPlanet.GrowthRate == 5);
            Debug.Assert(yourPlanet.X == 17);
            Debug.Assert(yourPlanet.Y == 18);

            Debug.Assert(gs1.Fleets.Count == 1);
            myFleet = gs1.Fleets.Mine.Single();
            Debug.Assert(myFleet.Owner == Players.Singleton.Me);
            Debug.Assert(myFleet.ShipCount == 50);
            Debug.Assert(myFleet.SourcePlanet == myPlanet);
            Debug.Assert(myFleet.DestinationPlanet == yourPlanet);
            Debug.Assert(myFleet.TotalTripLength == 22);
            Debug.Assert(myFleet.TurnsRemaining == 21);

            gs22 = gs.Futures[ 22 ];

            Debug.Assert(gs22.Planets.Count == 3);

            Debug.Assert(gs22.Planets.Neutral.Count() == 1);
            neutralPlanet = gs22.Planets.Neutral.Single();
            Debug.Assert(neutralPlanet.ShipCount == 40);
            Debug.Assert(neutralPlanet.GrowthRate == 4);
            Debug.Assert(neutralPlanet.X == 10);
            Debug.Assert(neutralPlanet.Y == 10);

            Debug.Assert(gs22.Planets.Mine.Count() == 1);
            myPlanet = gs22.Planets.Mine.Single();
            Debug.Assert(myPlanet.ShipCount == 210);
            Debug.Assert(myPlanet.GrowthRate == 5);
            Debug.Assert(myPlanet.X == 2);
            Debug.Assert(myPlanet.Y == 3);

            Debug.Assert(gs22.Planets.Yours.Count() == 1);
            yourPlanet = gs22.Planets.Yours.Single();
            Debug.Assert(yourPlanet.ShipCount == 160);
            Debug.Assert(yourPlanet.GrowthRate == 5);
            Debug.Assert(yourPlanet.X == 17);
            Debug.Assert(yourPlanet.Y == 18);

            Debug.Assert(gs22.Fleets.Count == 0);

            Debug.Assert(gs22.EndState == false);
            Debug.Assert(gs22.Winner == null);

            gs1_4 = gs1.Futures[ 4 ];

            Debug.Assert(gs1_4.Planets.Count == 3);

            Debug.Assert(gs1_4.Planets.Neutral.Count() == 1);
            neutralPlanet = gs1_4.Planets.Neutral.Single();
            Debug.Assert(neutralPlanet.ShipCount == 40);
            Debug.Assert(neutralPlanet.GrowthRate == 4);
            Debug.Assert(neutralPlanet.X == 10);
            Debug.Assert(neutralPlanet.Y == 10);

            Debug.Assert(gs1_4.Planets.Mine.Count() == 1);
            myPlanet = gs1_4.Planets.Mine.Single();
            Debug.Assert(myPlanet.ShipCount == 125);
            Debug.Assert(myPlanet.GrowthRate == 5);
            Debug.Assert(myPlanet.X == 2);
            Debug.Assert(myPlanet.Y == 3);

            Debug.Assert(gs1_4.Planets.Yours.Count() == 1);
            yourPlanet = gs1_4.Planets.Yours.Single();
            Debug.Assert(yourPlanet.ShipCount == 125);
            Debug.Assert(yourPlanet.GrowthRate == 5);
            Debug.Assert(yourPlanet.X == 17);
            Debug.Assert(yourPlanet.Y == 18);

            Debug.Assert(gs1_4.Fleets.Count == 1);
            myFleet = gs1_4.Fleets.Mine.Single();
            Debug.Assert(myFleet.Owner == Players.Singleton.Me);
            Debug.Assert(myFleet.ShipCount == 50);
            Debug.Assert(myFleet.SourcePlanet == myPlanet);
            Debug.Assert(myFleet.DestinationPlanet == yourPlanet);
            Debug.Assert(myFleet.TotalTripLength == 22);
            Debug.Assert(myFleet.TurnsRemaining == 17);

            return true;
        }
        public static void Turn( GameState gs )
        {
            IOrderedEnumerable<Planet> desirablePlanets;

            /* STAGE 1 */

            /* Current strongest planet */
            IOrderedEnumerable<Planet> strongestPlanets = gs.Planets.Mine.OrderByDescending( p => p.FuturedAvailableShips );
            Set<Planet> attackedPlanets = new Set<Planet>();

            foreach( Planet strongestPlanet in strongestPlanets )
            {
                int shipsRemain = strongestPlanet.FuturedAvailableShips;
                Debug.Assert( strongestPlanet.FuturedAvailableShips <= strongestPlanet.ShipCount );

                /* All planets that won't be ours when any fleet send from here would reach them */
                desirablePlanets =
                    gs.Planets.FuturedPredicate( gs, strongestPlanet, x => x.Owner != Players.Singleton.Me ).
                    OrderByDescending( p => PolynomialDistanceWeight( p, strongestPlanet, new Polynomial( 0, 2, 0 ) ) );

                /* Go through what all the planets' ratings are predicted to be when a fleet would reach them */
                foreach (Planet futurePlanet in desirablePlanets)
                {
                    /* Don't attack any planets that we're currently attacking, or will attack this turn.
                     * The will-attack-this-turn seems fair enough, as we always send sufficient fleets.
                     * The currently-attacking is a bit of a hack to avoid the strongest-getting-closer problem, and should be solved by strat 4 */
                    if (attackedPlanets.Contains(futurePlanet)) continue;
                    if (gs.Fleets.Mine.Where(f => f.DestinationPlanet == futurePlanet).Any()) continue;

                    /* must send one more than the planet's shipcount, otherwise it doesn't change hands. */
                    if (futurePlanet.ShipCount < shipsRemain)
                    {
                        gs.Orders.Add(new Order(strongestPlanet, futurePlanet, futurePlanet.ShipCount + 1));
                        attackedPlanets.Add(futurePlanet);

                        shipsRemain -= futurePlanet.ShipCount + 1;
                    }
                }
            }

            /* STAGE 2 */
            desirablePlanets =
                gs.Planets.Where( p => p.Owner != Players.Singleton.Me ).
                Where( p => !gs.Orders.Where( o => o.DestinationPlanet == p ).Any() ).
                OrderByDescending( p => NoDistanceWeight( p ) );

            foreach (Planet desirablePlanet in desirablePlanets)
            {
                int shipsNeeded = desirablePlanet.ShipCount + 1; //FIXME needs futuring
                IList<Order> potentialOrders = new List<Order>();

                IOrderedEnumerable<Planet> closetPlanets =
                    gs.Planets.Mine.OrderBy(p => p.DistanceTo(desirablePlanet));

                foreach (Planet closePlanet in closetPlanets)
                {
                    int shipsToSend = Math.Min(
                        shipsNeeded,
                        closePlanet.FuturedAvailableShips - gs.Orders.Where(o => o.SourcePlanet == closePlanet).Select(o => o.ShipCount).Sum() //TODO: nice method in gs to account for this?
                    );

                    /* FuturedAvailableShips will return 0 if we're under attack and will need every last ship to defend. */
                    if (shipsToSend > 0)
                    {
                        potentialOrders.Add(new Order(closePlanet, desirablePlanet, shipsToSend));
                        shipsNeeded -= shipsToSend;
                        Debug.Assert(shipsNeeded >= 0);
                    }

                    if (shipsNeeded == 0)
                    {
                        /* Only issue order if we mustered enough ships to take the planet. */
                        gs.Orders.AddRange( potentialOrders );
                        break;
                    }
                }
            }

            /* ATTACK! */

            gs.Orders.Done();
        }