Пример #1
0
        /// <summary>
        /// Get the ending of road state
        /// </summary>
        /// <param name="roadState">Road state</param>
        /// <param name="timeState">Time state</param>
        /// <returns>Ending of road</returns>
        RoadEnding GetEndingOfRoad(List<CarState> roadState, CollideTimeState timeState)
        {
            RoadEnding ending = new RoadEnding();

            CollideTimeState aState = this.GetCollideTimeState(roadState, timeState.Time, timeState.CarAIndex);
            CollideTimeState bState = this.GetCollideTimeState(roadState, timeState.Time, timeState.CarBIndex);

            CollideTimeState maxState = null;
            bool isAStateBetter = true;

            if (this.CompareNegativeAsInfinity(aState.Time - timeState.Time, bState.Time - timeState.Time) > 0) // aState is better
            {
                maxState = aState;
                isAStateBetter = true;
            }
            else
            {
                maxState = bState;
                isAStateBetter = false;
            }

            // t > 0, should recursive call to solve
            // t = 0, it's going to crash
            // t < 0, cheers!
            if (maxState.Time - timeState.Time > 0)
            {
                if (isAStateBetter && timeState.CarAIndex >= 0)
                {
                    roadState[timeState.CarAIndex].ChangeLane();
                }
                else if(timeState.CarBIndex >= 0)
                {
                    roadState[timeState.CarBIndex].ChangeLane();
                }

                // Recursive call
                ending = this.GetEndingOfRoad(
                    roadState,
                    maxState
                );
            }
            else if (maxState.Time - timeState.Time == 0)
            {
                // BAD END
                ending.CanSafeDriveForever = false;
                ending.TimeBeforeCollide = timeState.Time;
            }
            else
            {
                // GOOD END
                ending.CanSafeDriveForever = true;
                ending.TimeBeforeCollide = -1;
            }

            return ending;
        }
Пример #2
0
        /// <summary>
        /// Get the max time before collide
        /// </summary>
        /// <param name="roadState">Road state</param>
        /// <param name="time">Time passed</param>
        /// <param name="carIndexChangingLane">Index of car that changing lane</param>
        /// <returns>Time state</returns>
        CollideTimeState GetCollideTimeState(List<CarState> roadState, double time, Int32 carIndexChangingLane)
        {
            CollideTimeState maxTimeState = new CollideTimeState(time, -1, -1);
            double?[] minTimeBeforeCollide = new double?[2];
            Int32[][] carIndex = new Int32[2][];
            carIndex[0] = new Int32[2];
            carIndex[1] = new Int32[2];

            // If index not in road, treat as bad end
            // But if index < 0, that means do-not-change-lane-of-any-car
            // Currently this only happend at the begainning of process
            if (carIndexChangingLane < roadState.Count)
            {
                // Try change lane
                if (carIndexChangingLane >= 0)
                {
                    roadState[carIndexChangingLane].ChangeLane();
                }

                List<List<CarState>> carsOnLanes = new List<List<CarState>>(2)
                {
                    (from car in roadState
                     where car.Lane == CarState.LaneSide.Left
                     orderby car.PositionAt(time)
                     select car)
                    .ToList(),

                    (from car in roadState
                     where car.Lane == CarState.LaneSide.Right
                     orderby car.PositionAt(time)
                     select car)
                    .ToList()
                };

                for (int i = 0; i < carsOnLanes.Count; i++)
                {
                    for (int j = 0; j < carsOnLanes[i].Count; j++)
                    {
                        if (j == carsOnLanes[i].Count - 1) // The last car
                        {
                            minTimeBeforeCollide[i] = (minTimeBeforeCollide[i] < 0 || !minTimeBeforeCollide[i].HasValue) ?
                                -1 :
                                minTimeBeforeCollide[i];
                        }
                        else
                        {
                            if (carsOnLanes[i][j].Speed > carsOnLanes[i][j + 1].Speed)
                            {
                                double distance = carsOnLanes[i][j + 1].PositionAt(time) > carsOnLanes[i][j].PositionAt(time) + carsOnLanes[i][j].Length ?
                                                    carsOnLanes[i][j + 1].PositionAt(time) - (carsOnLanes[i][j].PositionAt(time) + carsOnLanes[i][j].Length)
                                                    : 0;
                                double timeBeforeCollide = distance / (carsOnLanes[i][j].Speed - carsOnLanes[i][j + 1].Speed);

                                if (minTimeBeforeCollide[i].HasValue)
                                {
                                    // Only store the minimum collide time
                                    if (this.CompareNegativeAsInfinity(timeBeforeCollide, minTimeBeforeCollide[i].Value) < 0)
                                    {
                                        minTimeBeforeCollide[i] = timeBeforeCollide;
                                        carIndex[i][0] = carsOnLanes[i][j].ID;
                                        carIndex[i][1] = carsOnLanes[i][j + 1].ID;
                                    }
                                }
                                else
                                {
                                    minTimeBeforeCollide[i] = timeBeforeCollide;
                                    carIndex[i][0] = carsOnLanes[i][j].ID;
                                    carIndex[i][1] = carsOnLanes[i][j + 1].ID;
                                }
                            }
                            else
                            {
                                double distance = carsOnLanes[i][j + 1].PositionAt(time) - (carsOnLanes[i][j].PositionAt(time) + carsOnLanes[i][j].Length);

                                if (distance >= 0)
                                {
                                    minTimeBeforeCollide[i] = (minTimeBeforeCollide[i] < 0 || !minTimeBeforeCollide[i].HasValue) ?
                                        -1
                                        : minTimeBeforeCollide[i];
                                }
                                else
                                {
                                    minTimeBeforeCollide[i] = 0;
                                }
                            }
                        }
                    }
                }

                // Change back
                if (carIndexChangingLane >= 0)
                {
                    roadState[carIndexChangingLane].ChangeLane();
                }
            }

            bool leftLaneIsMoreDangerous = false;
            bool atLeastOneLaneIsDangerous = false;

            if (minTimeBeforeCollide[0].HasValue
                && minTimeBeforeCollide[1].HasValue)
            {
                atLeastOneLaneIsDangerous = true;

                if (this.CompareNegativeAsInfinity(minTimeBeforeCollide[0].Value, minTimeBeforeCollide[1].Value) < 0)
                {
                    leftLaneIsMoreDangerous = true;
                }
                else
                {
                    leftLaneIsMoreDangerous = false;
                }
            }
            else if(minTimeBeforeCollide[0].HasValue || minTimeBeforeCollide[1].HasValue)
            {
                atLeastOneLaneIsDangerous = true;

                if (minTimeBeforeCollide[0].HasValue)
                {
                    leftLaneIsMoreDangerous = true;
                }
                else
                {
                    leftLaneIsMoreDangerous = false;
                }
            }

            if (atLeastOneLaneIsDangerous)
            {
                double minTime = 0;

                if (leftLaneIsMoreDangerous)
                {
                    minTime = minTimeBeforeCollide[0].Value;
                    maxTimeState.CarAIndex = carIndex[0][0];
                    maxTimeState.CarBIndex = carIndex[0][1];
                }
                else
                {
                    minTime = minTimeBeforeCollide[1].Value;
                    maxTimeState.CarAIndex = carIndex[1][0];
                    maxTimeState.CarBIndex = carIndex[1][1];
                }

                if (minTime < 0)
                {
                    maxTimeState.Time += -1;
                }
                else
                {
                    maxTimeState.Time += minTime;
                }
            }

            return maxTimeState;
        }