public RCT2RideData GenerateWoodenRollerCoaster()
        {
            RideData.RCT2RideData coaster = new RideData.RCT2RideData();

            //Track Type
            coaster.TrackType          = new RideData.RCT2RideCode();
            coaster.TrackType.RideType = RideData.RCT2RideCode.RCT2TrackName.WoodenRollerCoaster6Seater;

            do
            {
                //Track Data
                coaster.TrackData = GenerateWoodenRollerCoasterTrack();
            } while (coaster.TrackData == null);

            //Ride Features
            coaster.RideFeatures = new RideData.RCT2RideFeatures();
            coaster.RideFeatures.Populate(coaster.TrackData);

            //Operating Mode
            coaster.OperatingMode = RideData.RCT2RideData.RCT2OperatingModes.ContinuousCircuit;

            //Colour Scheme
            coaster.ColourScheme            = new RideData.RCT2VehicleColourScheme();
            coaster.ColourScheme.ColourMode = RideData.RCT2VehicleColourScheme.RCT2VehicleColourMode.AllSameColour;
            List <RideData.RCT2VehicleColourScheme.RCT2Colour> bodyColours       = new List <RideData.RCT2VehicleColourScheme.RCT2Colour>();
            List <RideData.RCT2VehicleColourScheme.RCT2Colour> trimColours       = new List <RideData.RCT2VehicleColourScheme.RCT2Colour>();
            List <RideData.RCT2VehicleColourScheme.RCT2Colour> additionalColours = new List <RideData.RCT2VehicleColourScheme.RCT2Colour>();
            Random random       = new Random();
            Array  colourValues = Enum.GetValues(typeof(RideData.RCT2VehicleColourScheme.RCT2Colour));

            for (int i = 0; i < 32; i++)
            {
                bodyColours.Add((RideData.RCT2VehicleColourScheme.RCT2Colour)colourValues.GetValue(random.Next(colourValues.Length)));
                trimColours.Add((RideData.RCT2VehicleColourScheme.RCT2Colour)colourValues.GetValue(random.Next(colourValues.Length)));
                additionalColours.Add((RideData.RCT2VehicleColourScheme.RCT2Colour)colourValues.GetValue(random.Next(colourValues.Length)));
            }

            coaster.ColourScheme.BodyColours       = bodyColours.ToArray();
            coaster.ColourScheme.TrimColours       = trimColours.ToArray();
            coaster.ColourScheme.AdditionalColours = additionalColours.ToArray();

            //Entrance Style
            coaster.EntranceStyle = RideData.RCT2RideData.RCT2EntranceStyle.Plain;

            //Air Time In Seconds
            coaster.TrackData.PopulateRideStatistics();
            coaster.AirTimeInSeconds = coaster.TrackData.AirTimeInSeconds;

            //Departure Flags
            coaster.DepartureFlags = new RideData.RCT2DepartureControlFlags();
            coaster.DepartureFlags.UseMinimumTime  = true;
            coaster.DepartureFlags.WaitForFullLoad = true;

            //Number of Trains
            coaster.NumberOfTrains = 1;

            //Number of Cars per Train
            coaster.NumberOfCarsPerTrain = 2;

            //Min Wait Time in Seconds
            coaster.MinWaitTimeInSeconds = 10;

            //Max Wait Time in Seconds
            coaster.MaxWaitTimeInSeconds = 60;

            //Speed of Powered Launch/Number of Go Kart Laps/Max number of people in Maze
            coaster.SpeedOfPoweredLaunch  = 0;
            coaster.NumberOfGoKartLaps    = 0;
            coaster.MaxNumberOfPeopleMaze = 0;

            //Max Speed of Ride
            coaster.MaxSpeedOfRide = coaster.TrackData.MaxSpeed;

            //Average Speed of Ride
            coaster.AverageSpeedOfRide = coaster.TrackData.AverageSpeed;

            //Ride length in metres
            coaster.RideLengthInMetres = coaster.TrackData.CalculateRideLengthInMeters();

            //Pos G Force
            coaster.PosGForce = coaster.TrackData.MaxPositiveG;

            //Neg G Force
            coaster.NegGForce = coaster.TrackData.MaxNegativeG;

            //Lat G Force
            coaster.LatGForce = coaster.TrackData.MaxLateralG;

            //Number of Inversions
            coaster.NumberOfInversions = coaster.TrackData.NumOfInversions;

            //Number of Drops
            coaster.NumberOfDrops = coaster.TrackData.NumOfDrops;

            //Highest Drop
            coaster.HighestDrop = coaster.TrackData.HighestDrop;

            //Excitement Times Ten
            coaster.ExcitementTimesTen = coaster.TrackData.Excitement * 10;

            //Intensity Times Ten
            coaster.IntensityTimesTen = coaster.TrackData.Intensity * 10;

            //Nausea Times Ten
            coaster.NauseaTimesTen = coaster.TrackData.Nausea * 10;

            //Main Track Colour
            coaster.TrackMainColour     = (RideData.RCT2VehicleColourScheme.RCT2Colour)colourValues.GetValue(random.Next(colourValues.Length));
            coaster.TrackMainColourAlt1 = (RideData.RCT2VehicleColourScheme.RCT2Colour)colourValues.GetValue(random.Next(colourValues.Length));
            coaster.TrackMainColourAlt2 = (RideData.RCT2VehicleColourScheme.RCT2Colour)colourValues.GetValue(random.Next(colourValues.Length));
            coaster.TrackMainColourAlt3 = (RideData.RCT2VehicleColourScheme.RCT2Colour)colourValues.GetValue(random.Next(colourValues.Length));

            //Additional Track Colour
            coaster.TrackAdditionalColour     = (RideData.RCT2VehicleColourScheme.RCT2Colour)colourValues.GetValue(random.Next(colourValues.Length));
            coaster.TrackAdditionalColourAlt1 = (RideData.RCT2VehicleColourScheme.RCT2Colour)colourValues.GetValue(random.Next(colourValues.Length));
            coaster.TrackAdditionalColourAlt2 = (RideData.RCT2VehicleColourScheme.RCT2Colour)colourValues.GetValue(random.Next(colourValues.Length));
            coaster.TrackAdditionalColourAlt3 = (RideData.RCT2VehicleColourScheme.RCT2Colour)colourValues.GetValue(random.Next(colourValues.Length));

            //Support Track Colour
            coaster.TrackSupportColour     = (RideData.RCT2VehicleColourScheme.RCT2Colour)colourValues.GetValue(random.Next(colourValues.Length));
            coaster.TrackSupportColourAlt1 = (RideData.RCT2VehicleColourScheme.RCT2Colour)colourValues.GetValue(random.Next(colourValues.Length));
            coaster.TrackSupportColourAlt2 = (RideData.RCT2VehicleColourScheme.RCT2Colour)colourValues.GetValue(random.Next(colourValues.Length));
            coaster.TrackSupportColourAlt3 = (RideData.RCT2VehicleColourScheme.RCT2Colour)colourValues.GetValue(random.Next(colourValues.Length));

            //Is Six Flag Design
            coaster.IsSixFlagsDesign = false;

            //DAT File Header
            //We scum this in the TD6 Parser so it's not needed to be filled yet
            //TODO
            coaster.DatFile = new RideData.DATFileHeader();

            //DAT File Checksum
            coaster.DatChecksum = coaster.DatFile.CalculateChecksum(RideData.RCT2RideCode.RideNameVehicleMap[coaster.TrackType.RideType]);

            //Required Map Space
            coaster.RequiredMapSpace = coaster.TrackData.CalculateRequiredMapSpace();

            //Lift Chain Speed
            coaster.LiftChainSpeed = 5;

            //Number of Circuits
            coaster.NumberOfCircuits = 1;

            //Check Validity
            RCT2TrackData.InvalidityCode invalidityResult = coaster.TrackData.CheckValidity();
            if (invalidityResult != RCT2TrackData.InvalidityCode.Valid)
            {
                Console.WriteLine("Failed Validity Check: " + invalidityResult.ToString());
                return(null);
            }

            return(coaster);
        }
        private RCT2TrackData GenerateWoodenRollerCoasterTrack()
        {
            RCT2TrackData trackData = new RCT2TrackData();

            trackData.TrackData = new List <RCT2TrackPiece>();
            Random random = new Random();

            //Begin Station
            trackData.TrackData.Add(new RideData.RCT2TrackPiece()
            {
                TrackElement = RideData.RCT2TrackElements.RCT2TrackElement.BeginStation,
                Qualifier    = new RideData.RCT2Qualifier()
                {
                    IsChainLift             = false,
                    TrackColourSchemeNumber = 0,
                    TrackRotation           = RideData.RCT2Qualifier.RCT2QualifierRotation.Zero,
                    AtTerminalStation       = false,
                    StationNumber           = 0
                }
            });

            //End Station
            trackData.TrackData.Add(new RideData.RCT2TrackPiece()
            {
                TrackElement = RideData.RCT2TrackElements.RCT2TrackElement.EndStation,
                Qualifier    = new RideData.RCT2Qualifier()
                {
                    IsChainLift             = false,
                    TrackColourSchemeNumber = 0,
                    TrackRotation           = RideData.RCT2Qualifier.RCT2QualifierRotation.Zero,
                    AtTerminalStation       = false,
                    StationNumber           = 0
                }
            });

            //TODO: Marking valid track pieces as invalid
            //      The prior connection check is failing

            for (int i = 2; i < length; i++)
            {
                List <RCT2TrackElements.RCT2TrackElement> candidates = RCT2TrackElements.FindValidSuccessors(whitelistedTracks, trackData.TrackData[i - 1].TrackElement);
                bool reselect = false;

                do
                {
                    //If we have no candidates left
                    if (candidates.Count <= 0)
                    {
                        return(null);
                        //if (steppedBack)
                        //{
                        //    return null;
                        //}

                        //if (i < 3)
                        //{
                        //    throw new Exception("ERROR: Unable to create Coaster - Index stepped back too far");
                        //}
                        ////Console.WriteLine("ERROR: No Valid Track Pieces Found, Stepping back and starting again");
                        //trackData.TrackData.Remove(trackData.TrackData.Last());
                        //i -= 2;
                        //steppedBack = true;


                        //TODO - Make this a better solution, right now it's a hack to make it work
                        //break;
                    }

                    //Select our successor and remove it from the potential pool
                    RCT2TrackElements.RCT2TrackElement successor = candidates[random.Next(candidates.Count)];
                    candidates.Remove(successor);
                    RCT2TrackElementProperty property = RCT2TrackElements.TrackElementPropertyMap[successor];

                    //Console.WriteLine($"\tAttempting Track Piece {successor.ToString()}");

                    RCT2Qualifier qualifier;

                    //Create our qualifier bit
                    if (property.Displacement.Y > 0)
                    {
                        //TODO: Check if it should be a chain
                        //      Perform a lookup to see if previous track was chain lift
                        //      Or if our current velocity would be negative/0
                        //      If not possible, do a lookup to see if previous X tracks contained a decline, if not we need one

                        bool chainLift = trackData.TrackData[i - 1].Qualifier.IsChainLift;

                        //If our current velocity would be negative or zero, we need a chain lift


                        qualifier = new RCT2Qualifier()
                        {
                            IsChainLift             = true,
                            TrackColourSchemeNumber = 0,
                            TrackRotation           = RideData.RCT2Qualifier.RCT2QualifierRotation.Zero,
                            AtTerminalStation       = false,
                            StationNumber           = 0
                        };
                    }
                    else
                    {
                        qualifier = new RCT2Qualifier()
                        {
                            IsChainLift             = false,
                            TrackColourSchemeNumber = 0,
                            TrackRotation           = RideData.RCT2Qualifier.RCT2QualifierRotation.Zero,
                            AtTerminalStation       = false,
                            StationNumber           = 0
                        };
                    }

                    //Add to track
                    trackData.TrackData.Add(new RCT2TrackPiece()
                    {
                        TrackElement = successor, Qualifier = qualifier
                    });

                    //If it's invalid
                    RCT2TrackData.InvalidityCode invalidityCode = trackData.CheckValidity();
                    if (invalidityCode != RCT2TrackData.InvalidityCode.Valid)
                    {
                        //Remove it and try again
                        reselect = true;
                        trackData.TrackData.Remove(trackData.TrackData.Last());
                        //Console.WriteLine($"\tInvalid Selection, Code: {invalidityCode.ToString()}");
                    }
                    else
                    {
                        reselect = false;
                    }
                } while (reselect);

                //Console.WriteLine($"{trackData.TrackData.Last().TrackElement.ToString()} Selected!");
            }

            //for (int i = 0; i < trackData.TrackData.Count(); i++)
            //{
            //    Console.WriteLine("\t" + trackData.TrackData[i].TrackElement.ToString());
            //}

            return(trackData);
        }
        private List <RCT2RideData> Crossover(RCT2RideData parent1, RCT2RideData parent2)
        {
            List <RCT2RideData> children = new List <RCT2RideData>();
            int  crossoverPoint          = length;
            int  redoCount = 0;
            bool redo      = false;

            RCT2TrackData.InvalidityCode parent1Invalidity = parent1.TrackData.CheckValidity();
            RCT2TrackData.InvalidityCode parent2Invalidity = parent2.TrackData.CheckValidity();

            //Create crossover point
            if (random.NextDouble() <= crossoverRate)
            {
                crossoverPoint = random.Next(length);
            }

            do
            {
                if (redoCount >= crossoverAttempts)
                {
                    crossoverPoint = length;
                }

                //Add first halves to each child
                RCT2TrackData child1Track = new RCT2TrackData();
                RCT2TrackData child2Track = new RCT2TrackData();
                for (int i = 0; i < crossoverPoint; i++)
                {
                    child1Track.TrackData.Add(parent1.TrackData.TrackData[i]);
                    child2Track.TrackData.Add(parent2.TrackData.TrackData[i]);
                }

                //Add second halves to each child
                for (int i = crossoverPoint; i < parent2.TrackData.TrackData.Count(); i++)
                {
                    child1Track.TrackData.Add(parent2.TrackData.TrackData[i]);
                }
                for (int i = crossoverPoint; i < parent1.TrackData.TrackData.Count(); i++)
                {
                    child2Track.TrackData.Add(parent1.TrackData.TrackData[i]);
                }

                RCT2RideData child1 = new RCT2RideData(parent1);
                RCT2RideData child2 = new RCT2RideData(parent2);
                child1.TrackData = child1Track;
                child2.TrackData = child2Track;

                //If the created children are invalid, keep trying
                //Wont cause an infinite loop as we will eventually crossover at point 0
                //Which acts as if we never crossed over at all
                RCT2TrackData.InvalidityCode child1Invalidity = child1.TrackData.CheckValidity();
                RCT2TrackData.InvalidityCode child2Invalidity = child2.TrackData.CheckValidity();
                if (child1Invalidity != RCT2TrackData.InvalidityCode.Valid ||
                    child2Invalidity != RCT2TrackData.InvalidityCode.Valid)
                {
                    redo = true;
                    redoCount++;
                    crossoverPoint = random.Next(length);
                }
                else
                {
                    redo = false;
                    children.Add(child1);
                    children.Add(child2);
                    if (crossoverPoint != length)
                    {
                        successfulCrossovers++;
                    }
                }
            } while (redo);

            return(children);
        }