[src=csharp]using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace TrafficLightControlledCrossroads
{
/// <summary>
/// Die Simulationslogik
/// </summary>
internal class Simulation
{
private readonly Road _northRoad;
private readonly Road _southRoad;
private readonly Road _eastRoad;
private readonly Road _westRoad;
private readonly TrafficLight _trafficLightNorthDirection;
private readonly TrafficLight _trafficLightSouthDirection;
private readonly TrafficLight _trafficLightWestDirection;
private readonly TrafficLight _trafficLightEastDirection;
private const int LastBrick = 41;
private const int TurnLeftBrick = 21;
private const int TurnRightBrick = 20;
private const int StopBrick = 19;
private const int InductionLoop = 9;
private const int InductionLoopOffSet = 5;
private const int FirstBrick = 0;
private readonly CrossRoadField _crossRoadField;
/// <summary>
/// Initialisiert eine neue Instanz von <see cref="Simulation"/> class.
/// </summary>
/// <param name="hwnd">Handle für das Controll auf dem gezeichnet werden soll</param>
public Simulation(IntPtr hwnd)
{
_crossRoadField = new CrossRoadField(hwnd);
_northRoad = _crossRoadField.NorthRoad;
_southRoad = _crossRoadField.SouthRoad;
_eastRoad = _crossRoadField.EastRoad;
_westRoad = _crossRoadField.WestRoad;
_trafficLightNorthDirection = _crossRoadField.TrafficLights.Find(x => x.Name == "NORTH");
_trafficLightSouthDirection = _crossRoadField.TrafficLights.Find(x => x.Name == "SOUTH");
_trafficLightWestDirection = _crossRoadField.TrafficLights.Find(x => x.Name == "WEST");
_trafficLightEastDirection = _crossRoadField.TrafficLights.Find(x => x.Name == "EAST");
_trafficLightNorthDirection.PropertyChanged += TrafficLightNorthDirection_PropertyChanged;
}
/// <summary>
/// behandelt den PropertyChanged-Event des TrafficLightNorthDirection-Controls.
/// </summary>
/// <param name="sender">Auslöser des Events</param>
/// <param name="e">The <see cref="EventArgs"/>Instanz, die die Daten des Event enthält</param>
private void TrafficLightNorthDirection_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
//Da alle Ampeln gleichzeitig Umschalten, reicht die Abfrage bei einer Ampel
if (
_trafficLightNorthDirection.TrafficLightStatus ==
TrafficLightStatus.Green || _trafficLightNorthDirection.TrafficLightStatus == TrafficLightStatus.Red)
{
_northRoad.TrafficVolumeExtensions = GetNewRandomTrafficVolume();
_southRoad.TrafficVolumeExtensions = GetNewRandomTrafficVolume();
_westRoad.TrafficVolumeExtensions = GetNewRandomTrafficVolume();
_eastRoad.TrafficVolumeExtensions = GetNewRandomTrafficVolume();
}
}
/// <summary>
/// Auswahl eines neuen zufälligen Verkehrsaufkommens.
/// </summary>
/// <returns>Eine neues Verkehrsaufkommen, ergänzt durch Ergänzungen zur Aufkommenswahrscheinlichkeit</returns>
private TrafficVolumeExtensions GetNewRandomTrafficVolume()
{
int temp = 0;
var boundaries = new List<int>();
var trafficVolumeExtensionsList = new List<TrafficVolumeExtensions>();
for (int i = 0; i < Enum.GetNames(typeof (TrafficVolume)).Length; i++)
{
var trafficVolumeExtensions = new TrafficVolumeExtensions((TrafficVolume) i);
boundaries.Add(temp + trafficVolumeExtensions.ProbabilityForThisTrafficVolumeSizeRange);
trafficVolumeExtensionsList.Add(trafficVolumeExtensions);
temp += trafficVolumeExtensions.ProbabilityForThisTrafficVolumeSizeRange;
}
int highestBoundery = temp;
int rnd = TlccRandom.GenerateRandomNumber(1, highestBoundery);
for (int i = 0; i < boundaries.Count; i++)
{
if (rnd <= boundaries)
{
return trafficVolumeExtensionsList;
}
}
return null;
}
/// <summary>
/// Ein Auto am Ende der Straße muß uns verlassen.
/// </summary>
/// <param name="brick">The brick.</param>
private void LeaveRoad(Brick brick)
{
brick.Car = null;
}
/// <summary>
/// Prüft die Ampel und ob der Gegenverkehr sich bewegt.
/// </summary>
/// <param name="brick">Der Aktuelle Brick.</param>
/// <param name="nextBrick">Der nächste Brick.</param>
/// <param name="overNextBrick">Der übernächste Brick.</param>
/// <param name="leftRoadTurnLeftBrick">Der brick auf der von links kommenden Spur, wo ein Linksabbiegerauto anhält.</param>
/// <param name="trafficLight">Die Ampel</param>
private void CheckVelocityAndTrafficLight(Brick brick, Brick nextBrick, Brick overNextBrick,
Brick leftRoadTurnLeftBrick,
TrafficLight trafficLight)
{
if (brick.Car != null)
{
if (brick.Car.Stopped)
{
if (trafficLight.TrafficLightStatus == TrafficLightStatus.Green && overNextBrick.Car == null &&
leftRoadTurnLeftBrick.Car == null)
{
brick.Car.Stopped = false;
GoStraightOn(brick, nextBrick, overNextBrick);
}
}
else
{
if (trafficLight.TrafficLightStatus == TrafficLightStatus.Green &&
(nextBrick.Car == null && leftRoadTurnLeftBrick.Car == null) &&
(overNextBrick.Car == null || !overNextBrick.Car.Stopped) ||
brick.Car.Destination == Destination.Right)
{
GoStraightOn(brick, nextBrick, overNextBrick);
}
else
{
brick.Car.Stopped = true;
}
}
}
}
/// <summary>
/// Turns the right.
/// </summary>
/// <param name="brick">Der Aktuelle Brick.</param>
/// <param name="nextBrick">Der nächste Brick.</param>
/// <param name="overNextBrick">Der übernächste Brick.</param>
/// <param name="rightBrick">Der nächste Brick beim Reechtsabbiegen </param>
private void TurnRight(Brick brick, Brick nextBrick, Brick overNextBrick, Brick rightBrick)
{
if (brick.Car != null)
{
if (brick.Car.Destination == Destination.Right)
{
if (rightBrick.Car == null)
{
brick.Car.Stopped = false;
rightBrick.Car = brick.Car;
brick.Car = null;
}
else
{
brick.Car.Stopped = true;
}
}
else
{
GoStraightOn(brick, nextBrick, overNextBrick);
}
}
}
/// <summary>
/// Prüft, ob eine gewisse Anzahl von Autos vor der Ampel stehen, so daß Priorität gewährt werden sollte.
/// Aber nur, wenn in den beiden kreuzenden Fahrspuren bis zur Grünphase nicht auch dieser Zustand
/// zu erwarten ist
/// </summary>
/// <param name="currentInductionBrick">The induction brick der aktuellen Fahrspur. Dort wo auf Stau geprüft wird.</param>
/// <param name="leftInductionBrick">The induction brick der von links kommenden Fahrspur.Dort wo auf Stau geprüft wird.</param>
/// <param name="leftExtraCheckPointBrick">Ein zusätzlicher Prüfstein für Verkehr auf der von links kommenden Fahrspur direkt vor dem off sett Brick</param>
/// <param name="leftOffSetBrick">Ein Prüfstein mit festem Versatz zum induction Brick auf der von links kommenden Fahrspur</param>
/// <param name="rightInductionBrickBrick">The induction brick der von rechts kommenden Fahrspur.Dort wo auf Stau geprüft wird.</param>
/// <param name="rightExtraCheckPointBrick">Ein zusätzlicher Prüfstein für Verkehr auf der von rechts kommenden Fahrspur direkt vor dem off sett Brick</param>
/// <param name="rightOffSetBrick">Ein Prüfstein mit festem Versatz zum induction Brick auf der von rechts kommenden Fahrspur</param>
/// <returns></returns>
private bool PriorityNeeded(Brick currentInductionBrick, Brick leftInductionBrick,
Brick leftExtraCheckPointBrick, Brick leftOffSetBrick, Brick rightInductionBrickBrick,
Brick rightExtraCheckPointBrick, Brick rightOffSetBrick)
{
// Ein stehendes Auto bedeutet Stau, im Gegensatz zu kein Auto oder in Bewegung
if (currentInductionBrick.Car != null && currentInductionBrick.Car.Stopped &&
(leftInductionBrick.Car == null || !leftInductionBrick.Car.Stopped) &&
(leftExtraCheckPointBrick.Car == null) &&
(leftOffSetBrick.Car == null) &&
(rightInductionBrickBrick.Car == null || !rightInductionBrickBrick.Car.Stopped) &&
(rightExtraCheckPointBrick.Car == null) &&
(rightOffSetBrick.Car == null)
)
{
return true;
}
return false;
}
/// <summary>
/// Prüft ob sich auf einem Stein ein Auto mit Linksabbiegerabsicht befindet.
/// </summary>
/// <param name="brick">Der aktuelle Stein</param>
/// <returns>Einen Wert, der angibt, ob der Wagen asl Linskabbieger markiert ist, oder nicht. </returns>
private bool MarkedForTurnLeft(Brick brick)
{
return (brick.Car != null && brick.Car.Destination == Destination.Left);
}
/// <summary>
/// Linksabbiegen
/// </summary>
/// <param name="brick">Der Aktuelle Stein</param>
/// <param name="leftBrick">Der Stein, auf den das Auto bein Linksabbiegen auf die andere Fahrspuhr begibt.</param>
/// <param name="contraflow">Die Gegenverkehrfahrspur</param>
private void TurnLeft(Brick brick, Brick leftBrick, Road contraflow) //old
{
if (contraflow.Bricks[TurnRightBrick].Car == null &&
(contraflow.Bricks[StopBrick].Car == null || contraflow.Bricks[StopBrick].Car.Stopped))
{
brick.Car.Destination = Destination.Straight;
brick.Car.Stopped = false;
leftBrick.Car = brick.Car;
brick.Car = null;
}
else
{
brick.Car.Stopped = true;
}
}
/// <summary>
/// Vorwärtsfahren
/// </summary>
/// <param name="brick">Der Aktuelle Stein</param>
/// <param name="nextBrick">Der nächste Stein der Fahrspur.</param>
/// <param name="overNextBrick">Der übernächste Stein der Fahrspur.</param>
private void GoStraightOn(Brick brick, Brick nextBrick, Brick overNextBrick)
{
if (brick.Car != null)
{
if (nextBrick.Car == null && (overNextBrick.Car == null || overNextBrick.Car.Stopped))
{
brick.Car.Stopped = false;
nextBrick.Car = brick.Car;
brick.Car = null;
}
else
{
brick.Car.Stopped = true;
}
}
}
/// <summary>
/// Entscheidet nach Zufall und Wahrscheinlichkeitsparameter, ob ein neues Auto erscheint.
/// </summary>
/// <param name="trafficVolumeExtensions">Erweiterung von de Aufzählung der Verkehrsaufkommen,
/// welches Informationen über Verkehrswahrscheinlichkeiten speichert</param>
/// <returns>Einen Wert, der angibt, ob ein neues Auto auf der Fahrspur erscheint, oder aber nicht.</returns>
private bool DoWeWantNewCar(TrafficVolumeExtensions trafficVolumeExtensions)
{
var rnd = TlccRandom.GenerateRandomNumber(1, 101);
return rnd < trafficVolumeExtensions.ProbabilityOfNewCar;
}
/// <summary>
/// Setzt ein neues Auto auf die Fahrspur.
/// </summary>
/// <param name="road">Die aktuelle Fahrspur</param>
private void NewCarToTheRoad(Road road)
{
if (road.Bricks[FirstBrick].Car == null &&
(road.Bricks[FirstBrick + 1].Car == null || road.Bricks[FirstBrick + 1].Car.Stopped) &&
DoWeWantNewCar(road.TrafficVolumeExtensions))
{
road.Bricks[FirstBrick].Car = new Car();
}
}
/// <summary>
/// Ein Simulationszyklus
/// </summary>
public void Simulate()
{
for (var i = LastBrick; i >= 0; i--)
{
switch (i)
{
#region Kommentar
//
#endregion
case LastBrick:
LeaveRoad(_northRoad.Bricks);
LeaveRoad(_southRoad.Bricks);
LeaveRoad(_westRoad.Bricks);
LeaveRoad(_eastRoad.Bricks);
break;
case (LastBrick - 1):
#region Kommentar
//Trick. Der 3.Parameter sollte eigentlich der übernächste Brick sein. Der liegt aber in diesem Fall außerhalb der Range, wird aber hier eh nicht benötigt, also bestücken wir
//ihn anders(mit dem aktuellen brick)
//Alternativ müßte man GoStraightOn extra überladen.
#endregion
GoStraightOn(_northRoad.Bricks, _northRoad.Bricks[i + 1], _northRoad.Bricks);
GoStraightOn(_southRoad.Bricks, _southRoad.Bricks[i + 1], _southRoad.Bricks);
GoStraightOn(_westRoad.Bricks, _westRoad.Bricks[i + 1], _westRoad.Bricks);
GoStraightOn(_eastRoad.Bricks, _eastRoad.Bricks[i + 1], _eastRoad.Bricks);
break;
case TurnLeftBrick:
#region Kommentar
//
#endregion
if (MarkedForTurnLeft(_northRoad.Bricks))
{
TurnLeft(_northRoad.Bricks, _westRoad.Bricks[TurnRightBrick], _southRoad);
}
else
{
GoStraightOn(_northRoad.Bricks, _northRoad.Bricks[i + 1], _northRoad.Bricks[i + 2]);
}
if (MarkedForTurnLeft(_southRoad.Bricks))
{
TurnLeft(_southRoad.Bricks, _eastRoad.Bricks[TurnRightBrick], _northRoad);
}
else
{
GoStraightOn(_southRoad.Bricks, _southRoad.Bricks[i + 1], _southRoad.Bricks[i + 2]);
}
if (MarkedForTurnLeft(_westRoad.Bricks))
{
TurnLeft(_westRoad.Bricks, _southRoad.Bricks[TurnRightBrick], _eastRoad);
}
else
{
GoStraightOn(_westRoad.Bricks, _westRoad.Bricks[i + 1], _westRoad.Bricks[i + 2]);
}
if (MarkedForTurnLeft(_eastRoad.Bricks))
{
TurnLeft(_eastRoad.Bricks, _northRoad.Bricks[TurnRightBrick], _westRoad);
}
else
{
GoStraightOn(_eastRoad.Bricks, _eastRoad.Bricks[i + 1], _eastRoad.Bricks[i + 2]);
}
break;
case TurnRightBrick:
#region Kommentar
//
#endregion
TurnRight(_northRoad.Bricks, _northRoad.Bricks[i + 1], _northRoad.Bricks[i + 2],
_eastRoad.Bricks[i + 2]);
TurnRight(_southRoad.Bricks, _southRoad.Bricks[i + 1], _southRoad.Bricks[i + 2],
_westRoad.Bricks[i + 2]);
TurnRight(_westRoad.Bricks, _westRoad.Bricks[i + 1], _westRoad.Bricks[i + 2],
_northRoad.Bricks[i + 2]);
TurnRight(_eastRoad.Bricks, _eastRoad.Bricks[i + 1], _eastRoad.Bricks[i + 2],
_southRoad.Bricks[i + 2]);
break;
case StopBrick:
#region Kommentar
//
#endregion
CheckVelocityAndTrafficLight(_northRoad.Bricks, _northRoad.Bricks[i + 1],
_northRoad.Bricks[i + 2], _eastRoad.Bricks[TurnLeftBrick], _trafficLightNorthDirection);
CheckVelocityAndTrafficLight(_southRoad.Bricks, _southRoad.Bricks[i + 1],
_southRoad.Bricks[i + 2], _westRoad.Bricks[TurnLeftBrick], _trafficLightSouthDirection);
CheckVelocityAndTrafficLight(_westRoad.Bricks, _westRoad.Bricks[i + 1],
_westRoad.Bricks[i + 2], _northRoad.Bricks[TurnLeftBrick], _trafficLightWestDirection);
CheckVelocityAndTrafficLight(_eastRoad.Bricks, _eastRoad.Bricks[i + 1],
_eastRoad.Bricks[i + 2], _southRoad.Bricks[TurnLeftBrick], _trafficLightEastDirection);
break;
case InductionLoop: //+222://( +222 = deaktiviert)
if (PriorityNeeded(_northRoad.Bricks, _westRoad.Bricks[InductionLoop],
_westRoad.Bricks[InductionLoop + InductionLoopOffSet - 1],
_westRoad.Bricks[InductionLoop + InductionLoopOffSet],
_eastRoad.Bricks[InductionLoop], _eastRoad.Bricks[InductionLoop + InductionLoopOffSet - 1],
_eastRoad.Bricks[InductionLoop + InductionLoopOffSet]) &&
_trafficLightNorthDirection.TrafficLightStatus == TrafficLightStatus.Red)
{
ForcePhaseChange();
}
GoStraightOn(_northRoad.Bricks, _northRoad.Bricks[i + 1], _northRoad.Bricks[i + 2]);
if (PriorityNeeded(_southRoad.Bricks, _eastRoad.Bricks[InductionLoop],
_eastRoad.Bricks[InductionLoop + InductionLoopOffSet - 1],
_eastRoad.Bricks[InductionLoop + InductionLoopOffSet],
_westRoad.Bricks[InductionLoop], _westRoad.Bricks[InductionLoop + InductionLoopOffSet - 1],
_westRoad.Bricks[InductionLoop + InductionLoopOffSet]) &&
_trafficLightSouthDirection.TrafficLightStatus == TrafficLightStatus.Red)
{
ForcePhaseChange();
}
GoStraightOn(_southRoad.Bricks, _southRoad.Bricks[i + 1], _southRoad.Bricks[i + 2]);
if (PriorityNeeded(_westRoad.Bricks, _southRoad.Bricks[InductionLoop],
_southRoad.Bricks[InductionLoop + InductionLoopOffSet - 1],
_southRoad.Bricks[InductionLoop + InductionLoopOffSet],
_northRoad.Bricks[InductionLoop], _northRoad.Bricks[InductionLoop + InductionLoopOffSet - 1],
_northRoad.Bricks[InductionLoop + InductionLoopOffSet]) &&
_trafficLightWestDirection.TrafficLightStatus == TrafficLightStatus.Red)
{
ForcePhaseChange();
}
GoStraightOn(_westRoad.Bricks, _westRoad.Bricks[i + 1], _westRoad.Bricks[i + 2]);
if (PriorityNeeded(_eastRoad.Bricks, _northRoad.Bricks[InductionLoop],
_northRoad.Bricks[InductionLoop + InductionLoopOffSet - 1],
_northRoad.Bricks[InductionLoop + InductionLoopOffSet],
_southRoad.Bricks[InductionLoop], _southRoad.Bricks[InductionLoop + InductionLoopOffSet - 1],
_southRoad.Bricks[InductionLoop + InductionLoopOffSet]) &&
_trafficLightEastDirection.TrafficLightStatus == TrafficLightStatus.Red)
{
ForcePhaseChange();
}
GoStraightOn(_eastRoad.Bricks, _eastRoad.Bricks[i + 1], _eastRoad.Bricks[i + 2]);
break;
case FirstBrick:
#region Kommentar
//
#endregion
GoStraightOn(_northRoad.Bricks, _northRoad.Bricks[i + 1], _northRoad.Bricks[i + 2]);
NewCarToTheRoad(_northRoad);
GoStraightOn(_southRoad.Bricks, _southRoad.Bricks[i + 1], _southRoad.Bricks[i + 2]);
NewCarToTheRoad(_southRoad);
GoStraightOn(_westRoad.Bricks, _westRoad.Bricks[i + 1], _westRoad.Bricks[i + 2]);
NewCarToTheRoad(_westRoad);
GoStraightOn(_eastRoad.Bricks, _eastRoad.Bricks[i + 1], _eastRoad.Bricks[i + 2]);
NewCarToTheRoad(_eastRoad);
# if DEBUG
//TODO: entfernen nach Testphase:
// Die Farbe der Autos "im Debug Modus" wird überschrieben. Jeweils mit dem Wert für
//alle Wagen aus der gleichen Richtung um das Abbiegeverhalten zum Testen sichtbar zu machen.
//
if (_northRoad.Bricks[FirstBrick].Car != null)
{
_northRoad.Bricks[FirstBrick].Car.Color = TlccColors.Blue;
}
if (_southRoad.Bricks[FirstBrick].Car != null)
{
_southRoad.Bricks[FirstBrick].Car.Color = TlccColors.Green;
}
if (_westRoad.Bricks[FirstBrick].Car != null)
{
_westRoad.Bricks[FirstBrick].Car.Color = TlccColors.Red;
}
if (_eastRoad.Bricks[FirstBrick].Car != null)
{
_eastRoad.Bricks[FirstBrick].Car.Color = TlccColors.Yellow;
}
#endif
break;
default:
#region Kommentar
//
#endregion
GoStraightOn(_northRoad.Bricks, _northRoad.Bricks[i + 1], _northRoad.Bricks[i + 2]);
GoStraightOn(_southRoad.Bricks, _southRoad.Bricks[i + 1], _southRoad.Bricks[i + 2]);
GoStraightOn(_westRoad.Bricks, _westRoad.Bricks[i + 1], _westRoad.Bricks[i + 2]);
GoStraightOn(_eastRoad.Bricks, _eastRoad.Bricks[i + 1], _eastRoad.Bricks[i + 2]);
break;
}
}
#region Kommentar
//
#endregion
_crossRoadField.DrawRoads();
_crossRoadField.DrawInterSection();
TriggerLights();
}
/// <summary>
/// Triggert die Ampeln
/// </summary>
private void TriggerLights()
{
foreach (var trafficLight in _crossRoadField.TrafficLights)
{
trafficLight.Tick();
}
}
/// <summary>
/// Forciert bei den Wechsel bei Rot, bzw. für Grün auf den kreuzenden Fahrspuren.
/// </summary>
private void ForcePhaseChange()
{
foreach (var trafficLight in _crossRoadField.TrafficLights)
{
switch (trafficLight.TrafficLightStatus)
{
case TrafficLightStatus.Green:
trafficLight.BeginStopPhase();
break;
case TrafficLightStatus.Red:
trafficLight.BeginGoPhase();
break;
}
}
}
}
}[/src]