private HexPointFlow[] GetFlowByCorner(HexPointCorner corner)
 {
     switch (corner.Corner)
     {
         //     0
         //     ^
         //     |
         //    (X) <= corner
         //    / \
         //   v   v
         //  1     2
         //  |  T  |
         case HexCorner.North:
             return new HexPointFlow[]
                        {
                            new HexPointFlow
                                {
                                    Corner = new HexPointCorner
                                                 {
                                                     Point = corner.Point.Neighbor(HexDirection.NorthWest), 
                                                     Corner = HexCorner.NorthEast
                                                 }, 
                                    Flow = MapCell.FlowDirectionType.North
                                }, // 0
                            new HexPointFlow 
                                { 
                                    Corner = new HexPointCorner
                                                 {
                                                     Point = corner.Point.Neighbor(HexDirection.NorthWest),
                                                     Corner = HexCorner.South
                                                 }, 
                                    Flow = MapCell.FlowDirectionType.SouthWest 
                                }, // 1
                            new HexPointFlow
                                {
                                    Corner = new HexPointCorner
                                                 {
                                                     Point = corner.Point.Neighbor(HexDirection.NorthEast), 
                                                     Corner = HexCorner.South
                                                 }, 
                                    Flow = MapCell.FlowDirectionType.SouthEast
                                } // 2
                        };
         //      |
         //      +       +
         //     / 0     1
         //    /   ^   ^
         //   /     \ /
         //  +      (X) <= corner
         //  |   T   |
         //  |       v
         //  |       2
         case HexCorner.NorthEast:
             return new HexPointFlow[]
                        {
                            new HexPointFlow 
                                {
                                    Corner = new HexPointCorner
                                                 {
                                                     Point = corner.Point.Neighbor(HexDirection.NorthEast),
                                                     Corner = HexCorner.SouthWest
                                                 }, 
                                    Flow = MapCell.FlowDirectionType.NorthWest 
                                }, // 0
                            new HexPointFlow 
                            {
                                    Corner = new HexPointCorner
                                                 {
                                                     Point = corner.Point.Neighbor(HexDirection.NorthEast),
                                                     Corner = HexCorner.SouthEast
                                                 }, 
                                    Flow = MapCell.FlowDirectionType.SouthWest 
                            }, // 1
                            new HexPointFlow 
                            {
                                    Corner = new HexPointCorner
                                                 {
                                                     Point = corner.Point,
                                                     Corner = HexCorner.SouthEast
                                                 }, 
                                    Flow = MapCell.FlowDirectionType.South 
                            } // 2
                        };
         //  |       0   
         //  |       ^
         //  |   T   |
         //  +      (X) <= corner
         //   \     / \
         //    \   v   v 
         //     \ 2     1 
         //      +       +
         case HexCorner.SouthEast:
             return new HexPointFlow[]
                        {
                            new HexPointFlow 
                            {
                                    Corner = new HexPointCorner
                                                 {
                                                     Point = corner.Point,
                                                     Corner = HexCorner.NorthEast
                                                 }, 
                                    Flow = MapCell.FlowDirectionType.North 
                            }, // 0
                            new HexPointFlow 
                            {
                                    Corner = new HexPointCorner
                                                 {
                                                     Point = corner.Point.Neighbor(HexDirection.East),
                                                     Corner = HexCorner.South
                                                 }, 
                                    Flow = MapCell.FlowDirectionType.NorthWest 
                            }, // 1
                            new HexPointFlow 
                            {
                                    Corner = new HexPointCorner
                                                 {
                                                     Point = corner.Point,
                                                     Corner = HexCorner.South
                                                 }, 
                                    Flow = MapCell.FlowDirectionType.SouthWest 
                            } // 2
                        };
         //  |   T   |
         //  +       +
         //   2     0
         //    ^   ^ 
         //     \ /  
         //     (X) <= corner
         //      |
         //      v
         //      1
         case HexCorner.South:
             return new HexPointFlow[]
                        {
                            new HexPointFlow 
                            {
                                    Corner = new HexPointCorner
                                                 {
                                                     Point = corner.Point,
                                                     Corner = HexCorner.SouthEast
                                                 }, 
                                    Flow = MapCell.FlowDirectionType.NorthEast 
                            }, // 0
                            new HexPointFlow 
                            {
                                    Corner = new HexPointCorner
                                                 {
                                                     Point = corner.Point.Neighbor(HexDirection.SouthWest),
                                                     Corner = HexCorner.SouthEast
                                                 }, 
                                    Flow = MapCell.FlowDirectionType.South 
                            }, // 1
                            new HexPointFlow 
                            {
                                    Corner = new HexPointCorner
                                                 {
                                                     Point = corner.Point,
                                                     Corner = HexCorner.SouthWest
                                                 }, 
                                    Flow = MapCell.FlowDirectionType.NorthWest 
                            } // 2
                        };
         //  |       0   
         //  |       ^
         //  |       |    T
         //  +      (X) <= corner
         //   \     / \
         //    \   v   v 
         //     \ 2     1 
         //      +       +
         case HexCorner.SouthWest:
             return new HexPointFlow[]
                        {
                            new HexPointFlow 
                            {
                                    Corner = new HexPointCorner
                                                 {
                                                     Point = corner.Point.Neighbor(HexDirection.West),
                                                     Corner = HexCorner.NorthEast
                                                 }, 
                                    Flow = MapCell.FlowDirectionType.North 
                            }, // 0
                            new HexPointFlow 
                            {
                                    Corner = new HexPointCorner
                                                 {
                                                     Point = corner.Point,
                                                     Corner = HexCorner.South
                                                 }, 
                                    Flow = MapCell.FlowDirectionType.SouthEast 
                            }, // 1
                            new HexPointFlow 
                            {
                                    Corner = new HexPointCorner
                                                 {
                                                     Point = corner.Point.Neighbor(HexDirection.West),
                                                     Corner = HexCorner.South
                                                 }, 
                                    Flow = MapCell.FlowDirectionType.SouthWest 
                            } // 2
                        };
         //      |
         //      +       +
         //     / 0     1
         //    /   ^   ^
         //   /     \ /
         //  +      (X) <= corner
         //  |       |    T
         //  |       v
         //  |       2
         case HexCorner.NorthWest:
             return new HexPointFlow[]
                        {
                            new HexPointFlow 
                            {
                                    Corner = new HexPointCorner
                                                 {
                                                     Point = corner.Point.Neighbor(HexDirection.NorthWest),
                                                     Corner = HexCorner.SouthWest
                                                 }, 
                                    Flow = MapCell.FlowDirectionType.NorthWest 
                            }, // 0
                            new HexPointFlow 
                            {
                                    Corner = new HexPointCorner
                                                 {
                                                     Point = corner.Point.Neighbor(HexDirection.NorthWest),
                                                     Corner = HexCorner.SouthEast
                                                 }, 
                                    Flow = MapCell.FlowDirectionType.NorthEast 
                            }, // 1
                            new HexPointFlow 
                            {
                                    Corner = new HexPointCorner
                                                 {
                                                     Point = corner.Point.Neighbor(HexDirection.West),
                                                     Corner = HexCorner.SouthEast
                                                 }, 
                                    Flow = MapCell.FlowDirectionType.South 
                            } // 2
                        };
         default:
             throw new Exception();
     }
 }
        public void Create(GameStartupSettings settings)
        {
            Random rnd = new Random();

            log.DebugFormat("Create( {0} )", settings);
            HeightMap heightmap = CreateHeightMap(settings);

            float seaLevel = heightmap.FindHeightLevel(settings.OceanRatio * 1.5f, 0.05f); // <-- Values from settings
            float shoreLevel = heightmap.FindHeightLevel(settings.OceanRatio, 0.05f); // <-- Values from settings
            float hillLevel = heightmap.FindHeightLevel(0.1f, 0.01f); // <-- Values from settings
            float mountainLevel = heightmap.FindHeightLevel(settings.PeakRatio, 0.01f); // <-- Values from settings

            OnProgress(new ProgressNotificationEventArgs(string.Format("Min: {0}, Sea: {1}, shoreLevel: {2}, mountain: {3}, max: {4}", heightmap.Minimum, seaLevel, shoreLevel, mountainLevel, heightmap.Maximum), 1f, 0.1f));

            Init(settings.Width, settings.Height);

            // assign coords
            for (int i = 0; i < settings.Width; ++i)
            {
                for (int j = 0; j < settings.Height; ++j)
                {
                    this[i, j].Height = heightmap[i, j];
                }
            }

            Terrain ocean = Provider.Instance.Terrains["Ocean"];
            Terrain shore = Provider.Instance.Terrains["Shore"]; // Shore
            Terrain coast = Provider.Instance.Terrains["Coast"];
            Terrain grassland = Provider.Instance.Terrains["Grassland"];

            Feature hills = Provider.Instance.Features["Hills"];
            Feature mountains = Provider.Instance.Features["Mountains"];

            // settle ground plains (ocean, grassland, mountain)
            RangeConversion<float, Terrain> conv = new RangeConversion<float, Terrain>(grassland);

            conv.AddMapping(heightmap.Minimum, seaLevel, ocean);
            conv.AddMapping(seaLevel, shoreLevel, shore);
            conv.AddMapping(shoreLevel, hillLevel, grassland);
            //conv.AddMapping(hillLevel, mountainLevel, hill);
            //conv.AddMapping(mountainLevel, heightmap.Maximum, mountain);

            for (int i = 0; i < settings.Width; ++i)
            {
                for (int j = 0; j < settings.Height; ++j)
                {
                    this[i, j].Terrain = conv.Find(heightmap[i, j]);

                    if(hillLevel <= heightmap[i,j] && heightmap[i,j] < mountainLevel)
                        this[i, j].Features.Add(hills);
                    else if(mountainLevel <= heightmap[i,j])
                        this[i, j].Features.Add(mountains);
                }
            }

            OnProgress(new ProgressNotificationEventArgs("Basic Terrain Assignment", 1f, 0.2f));

            // find coasts
            for (int i = 0; i < settings.Width; ++i)
            {
                for (int j = 0; j < settings.Height; ++j)
                {
                    if (this[i, j].IsOcean)
                    {
                        if (ShouldBeCoast(i, j))
                            this[i, j].Terrain = coast;
                    }
                }
            }

            OnProgress(new ProgressNotificationEventArgs("Find Coasts: " + GetArea(a => a.IsOcean).Count + " ocean tiles, " + GetArea(a => a.IsLand).Count + " land tiles", 1f, 0.3f));

            // find river tiles
            List<MapCell> hillsOrMountains = GetArea(a => a.IsSpring);

            int currentRiverId = 0;

            int numOfRivers = Math.Min(hillsOrMountains.Count, settings.NumOfRivers);
            Array corners = Enum.GetValues(typeof(HexCorner));
            while( currentRiverId < numOfRivers)
            {
                MapCell spring = hillsOrMountains.PickRandom();

                HexCorner randomCorner = (HexCorner)corners.GetValue(rnd.Next(corners.Length));

                HexPointCorner hxc = new HexPointCorner { Corner = randomCorner, Point = spring.Point };
                HexPointFlow[] flows = GetFlowByCorner(hxc);

                River currentriver = new River(string.Format("River{0}", currentRiverId));
                Rivers.Add(currentriver);
                DoRiver(flows[rnd.Next(3)], hxc, currentriver, 0);

                currentRiverId++;
            }

            OnProgress(new ProgressNotificationEventArgs("Add Rivers: " + GetArea(a => a.IsRiver).Count + " tiles", 1f, 0.3f));
        }
        private void DoRiver(HexPointFlow hexPointFlow, HexPointCorner hxc, River river, int iteration)
        {
            if (river.Points.Count > 50 || iteration > 100) // paranoia
                return;

            if (!IsValid(hxc.Point))
                return;

            if( !river.Points.Select( a => a.Point).Contains(hxc.Point) )
                river.Points.Add(new FlowPoint( hxc.Point, hexPointFlow.Flow));

            this[hxc.Point].SetRiver(hexPointFlow.Flow);

            if (this[hxc.Point].IsOcean)
                return;

            List<HexPointFlow> flows = new List<HexPointFlow>(GetFlowByCorner(hxc));

            // remove not valid and current flow (resp. reverse flow)
            for (int i = 2; i > -1; i-- )
            {
                if (!IsValid(flows[i].Corner.Point) || Reverse(flows[i].Flow) == hexPointFlow.Flow || flows[i].Flow == hexPointFlow.Flow)
                    flows.RemoveAt(i);
            }

            if (flows.Count == 0)
                return;

            if( flows.Count == 1) 
            {
                DoRiver( new HexPointFlow { Corner = flows[0].Corner, Flow = flows[0].Flow }, flows[0].Corner, river, iteration + 1);
                return;
            }

            float height1 = GetHeightAtCorner( flows[0].Corner.Point.X, flows[0].Corner.Point.Y, flows[0].Corner.Corner);
            float height2 = GetHeightAtCorner( flows[1].Corner.Point.X, flows[1].Corner.Point.Y, flows[1].Corner.Corner);

            if(height1 < height2)
                DoRiver(new HexPointFlow { Corner = flows[0].Corner, Flow = flows[0].Flow }, flows[0].Corner, river, iteration + 1);
            else
                DoRiver(new HexPointFlow { Corner = flows[1].Corner, Flow = flows[1].Flow }, flows[1].Corner, river, iteration + 1);
        }