• Hallo liebe Userinnen und User,

    nach bereits längeren Planungen und Vorbereitungen sind wir nun von vBulletin auf Xenforo umgestiegen. Die Umstellung musste leider aufgrund der Serverprobleme der letzten Tage notgedrungen vorverlegt werden. Das neue Forum ist soweit voll funktionsfähig, allerdings sind noch nicht alle der gewohnten Funktionen vorhanden. Nach Möglichkeit werden wir sie in den nächsten Wochen nachrüsten. Dafür sollte es nun einige der Probleme lösen, die wir in den letzten Tagen, Wochen und Monaten hatten. Auch der Server ist nun potenter als bei unserem alten Hoster, wodurch wir nun langfristig den Tank mit Bytes vollgetankt haben.

    Anfangs mag die neue Boardsoftware etwas ungewohnt sein, aber man findet sich recht schnell ein. Wir wissen, dass ihr alle Gewohnheitstiere seid, aber gebt dem neuen Board eine Chance.
    Sollte etwas der neuen oder auch gewohnten Funktionen unklar sein, könnt ihr den "Wo issn da der Button zu"-Thread im Feedback nutzen. Bugs meldet ihr bitte im Bugtracker, es wird sicher welche geben die uns noch nicht aufgefallen sind. Ich werde das dann versuchen, halbwegs im Startbeitrag übersichtlich zu halten, was an Arbeit noch aussteht.

    Neu ist, dass die Boardsoftware deutlich besser für Mobiltelefone und diverse Endgeräte geeignet ist und nun auch im mobilen Style alle Funktionen verfügbar sind. Am Desktop findet ihr oben rechts sowohl den Umschalter zwischen hellem und dunklem Style. Am Handy ist der Hell-/Dunkelschalter am Ende der Seite. Damit sollte zukünftig jeder sein Board so konfigurieren können, wie es ihm am liebsten ist.


    Die restlichen Funktionen sollten eigentlich soweit wie gewohnt funktionieren. Einfach mal ein wenig damit spielen oder bei Unklarheiten im Thread nachfragen. Viel Spaß im ngb 2.0.

Programmierwettbewerb: Ampelschaltung

Larius

OutOfOrder

Registriert
12 Juli 2013
Beiträge
5.792
Aufgabe:
Ampelschaltung an einer Kreuzung mit 4 Straßen

Skizze:
viewer.php



Die Aufabe wird in mehrere Schwierigkeits-Grade geteilt, wie weit jeder Programmieren möchte ist jedem selber überlassen.
Der Ausprogrammierte Grad ist bei der Abgabe anzugeben.

Schwierigkeits-Level:

  1. alle 4 Ampeln schalten in regelmäßigen Abständen lt. normalen Verkehrsregeln
  2. Die Ampel verhält sich wie eine "offizielle" Ampel (unterschiedliches Timing für die einzelnen Phasen)
  3. Eine oder mehrere Ampel-Lampen können kaputt gehen, je nach Defekt wird "irgendwie" darauf reagiert (seid Kreativ) es darf nur kein Unfall passieren können.
  4. Autos fahren in regelmäßigen Abständen über die Kreuzung und fahren jeweils nur gerade aus.
  5. Autos fahren in regelmäßigen Abständen über die Kreuzung und biegen ab und an rechts ab.
  6. Autos fahren in regelmäßigen Abständen über die Kreuzung und biegen rechts und links ab.
  7. Autos fahren in zufälligen Abständen und zufälligen Fluss-raten über die Kreuzung, die Ampeln reagieren darauf und schalten unterschiedlich lange Grün-Phasen
  8. Kollisionserkennung, 2 Autos dürfen keinen "Unfall" bauen und biegen nur ab, insofern genug Platz frei ist. Bis zu diesem Schwierigkeit-Grad dürfen sich Autos auch überlappen.

Randbedingungen:
  • Programmiersprache kann frei gewählt werden.
  • Ob Graphisch oder nur Konsole ist jedem selber überlassen insofern das Schema zu erkennen ist.
  • Insofern Graphisch dann maximal 2D ohne Verwendung von DirectX, OpenGL (die Graphische-Ausarbeitung soll nicht Teil der Aufgabe sein.)
  • Eingereicht wird im Thread der Quellcode in Quellcode-Tags offen für jeden lesbar.
  • Code ist daher gut (in Deutsch) zu kommentieren.
  • Zusätzlich wird eine Compilierte .exe zum Download angeboten, bei Implementierung in Javascript, PHP etc. ein aufrufbarer Weblink, bei Java die .jar und evtl. eine .bat / sh dazu.
  • Die Anwendung muss nicht zwingend Multiplattform-Fähig sein.

Bewertung:

Eine "Einfache" und "Simple" Bewertung ist aufgrund der Bandbreite der möglichen Implementierungen nicht möglich. Daher konzentrieren wir uns auf "weichere" Kriterien.


  • Welche Umsetzung überzeugt einfach nach "Bauchgefühl" und warum / Was gefällt euch besonders gut? Besonders Kreativ?, Besonders klein (64kb ;D) ...
  • Bei der Bewertung darf der Schwierigkeits-Grad keinen Einfluss nehmen.
  • Gefundene Programmier-Fehler (Logik-Fehler usw..) geben Punkte Abzug und sollten aufgezeigt werden.
  • Probleme und Fragen bei der Umsetzung sind jedoch nicht negativ zu bewerten.

Allgemein geht es natürlich darum, etwas zu lernen. Das heißt es wäre schön wenn Zwischenstände im Thread gepostet werden und durch Mitspieler schon einmal kommentiert werden.

Bei Problemen und Fragen - das Problem nach Möglichkeit zum eigenen Quellcode zusätzlich verallgemeinert beschreiben um Antworten auch von Sprachen-Fremden Entwicklern zu erhalten.

Zeit bis zur finalen Abgabe sind 2 Monate.

Lasst die Spiele beginnen :coffee: :beer:

Anmerkung: Ein Danke geht dafür an drfuture welcher das Ganze ausgearbeitet hat :D
 

KaPiTN

♪♪♫ wild at heart ♪♫♫♪

Registriert
14 Juli 2013
Beiträge
29.138
1)Zeitrahmen?
2)Wenn man den Code direkt postet, kann ein Zwerg auf dem Schultern eines Riesen der Größte sein.
 

KaPiTN

♪♪♫ wild at heart ♪♫♫♪

Registriert
14 Juli 2013
Beiträge
29.138
@MSX:

Danke. Jetzt habe ich es entdeckt. Ich hatte nach einem Datum gesucht.
 

sharpy35

Neu angemeldet

Registriert
13 Apr. 2015
Beiträge
210
Und wo und wie gibt man ab?

EDIT: sorry die Bedingungen nich richtig gelesen.
 
Zuletzt bearbeitet:

Larius

OutOfOrder

Registriert
12 Juli 2013
Beiträge
5.792
  • Thread Starter Thread Starter
  • #6
Einen Vorschlag zur Güte: Was ist, wenn man den Code per PN an mich verschickt und ich veröffentliche es dann, nachdem die Abgabefrist abgelaufen ist?
 

drfuture

Zeitreisender
Teammitglied

Registriert
14 Juli 2013
Beiträge
8.728
Ort
in der Zukunft
Nun ja - da es ja nichts zu "gewinnen" gibt - und insofern jemand Abschreibt, man das denke ich schon sieht... finde ich das mit dem Veröffentlichen weniger Problematisch.
Die Idee dahinter war das man eben auch während den 2 Monaten den Thread lebendig hält und die Fortschritte durchaus schon kommentieren könnte.

Ist ja kein "klassischer" Wettbewerb.

Auch verteilt sich dann das lesen des Codes für alle ein wenig - und nicht 20 Programme sobald die Frist zu Ende ist.
 

epiphora

aus Plastik
Veteran

Registriert
14 Juli 2013
Beiträge
3.894
Ort
DE-CIX
Meine Simulation wird mit Javascript realisiert und als HTML dargestellt.

Das Besondere dabei ist:

Die Ampelschaltung und die Verarbeitung der Autos funktionieren unabhängig voneinander. Die Prototypen haben quasi keine geteilten Variablen und kommunizieren lediglich durch den DOM. Die Ampelschaltung weist den Ampeln also Zustände zu. Die Autos reagieren dann auf diese Zustände. Sie überprüfen, ob die Ampel grün ist und ob sie als Linksabbieger freie Fahrt haben.

Ich hab folgende Schwierigkeits-Level berücksichtigt:

[X] alle 4 Ampeln schalten in regelmäßigen Abständen lt. normalen Verkehrsregeln
[X] Die Ampel verhält sich wie eine "offizielle" Ampel (unterschiedliches Timing für die einzelnen Phasen)
[_] Eine oder mehrere Ampel-Lampen können kaputt gehen, je nach Defekt wird "irgendwie" darauf reagiert (seid Kreativ) es darf nur kein Unfall passieren können.
[X] Autos fahren in regelmäßigen Abständen über die Kreuzung und fahren jeweils nur gerade aus.
[X] Autos fahren in regelmäßigen Abständen über die Kreuzung und biegen ab und an rechts ab.
[X] Autos fahren in regelmäßigen Abständen über die Kreuzung und biegen rechts und links ab.
[_] Autos fahren in zufälligen Abständen und zufälligen Fluss-raten über die Kreuzung, die Ampeln reagieren darauf und schalten unterschiedlich lange Grün-Phasen
[_] Kollisionserkennung, 2 Autos dürfen keinen "Unfall" bauen und biegen nur ab, insofern genug Platz frei ist. Bis zu diesem Schwierigkeit-Grad dürfen sich Autos auch überlappen.

[src=html5]<div id="sim">

<!-- Darstellung der Straßen -->
<div class="vertical street">
<div class="stop top"></div>
<div class="stop bottom"></div>
</div>
<div class="horizontal street">
<div class="stop left"></div>
<div class="stop right"></div>
</div>
<div class="street crossing"></div>
<div class="t t1 top">
<div class="r"></div>
<div class="y"></div>
<div class="g"></div>
</div>

<!-- Darstellung der Ampeln-->
<div class="t t2 left">
<div class="r"></div>
<div class="y"></div>
<div class="g"></div>
</div>
<div class="t t2 right">
<div class="r"></div>
<div class="y"></div>
<div class="g"></div>
</div>
<div class="t t1 bottom">
<div class="r"></div>
<div class="y"></div>
<div class="g"></div>
</div>

<!-- Darstellung der Warteschlangen von Autos -->
<ol class="queue bottom"></ol>
<ol class="queue right"></ol>
<ol class="queue left"></ol>
<ol class="queue top"></ol>
</div>

<!-- Darstellung der Steuerelemente -->
<div id="controls">
<div>
<label for="car_speed">Auto-Geschwindigkeit:</label>
<input type="range" min="0" max="1" value="0.2" step="0.01" id="car_speed" />
</div>
<div>
<label for="t_speed">Ampel-Geschwindigkeit:</label>
<input type="range" min="0.1" max="20" value="1" step="0.01" id="t_speed" />
</div>
</div>[/src]

[src=javascript]NodeList.prototype.forEach = Array.prototype.forEach;

/*
------------------------------------------------------------------------------------------------------------------------
Die Farben der Ampeln werden als Konstanten definiert, um Fehler bei der Abfrage der Farben schneller zu erkennen.
*/
var RED = 'RED', GREEN = 'GREEN', YELLOW = 'YELLOW', REDYELLOW = 'REDYELLOW';

/*
------------------------------------------------------------------------------------------------------------------------
Diese Funktion kann zufällige Farben generieren, die hinterher den neu erzeugten Autos zugewiesen werden.
Quelle: http://stackoverflow.com/questions/1484506/random-color-generator-in-javascript
*/
var random_color = function(){
return '#' + (Math.random()*0xFFFFFF<<0).toString(16);
}

/*
------------------------------------------------------------------------------------------------------------------------
Beim Abarbeiten der Auto-Warteschlangen muss manchmal geprüft werden, wie der Gegenverkehr aussieht. Dafür kann über
die Attribute dieses Objekts iteriert werden.
*/
var opposites = {
left: 'right',
right: 'left',
top: 'bottom',
bottom: 'top'
};

/*
------------------------------------------------------------------------------------------------------------------------
Der Prototyp für eine Ampel
*/
var TrafficLightSet = function(qs){
/*
qs: Wird beim Erzeugen zugewiesen und erhält als String den Namen einer CSS-Klasse.
*/
this.qs = qs;

/*
set: Beim Aufruf dieser Methode werden alle Ampeln, die diesen Zustand anzeigen sollen (also Elemente mit der CSS-Klasse "qs")
auf eine bestimmte Farbe geschaltet. Das geschieht über die Zuweisung eines data-Attributs. Die Farbe wird hinterher
vom Stylesheet entsprechend dargestellt.
*/
this.set = function(color){
document.querySelectorAll(this.qs).forEach(function(elem){
elem.dataset.is = color;
});
};
};

/*
------------------------------------------------------------------------------------------------------------------------
Der Prototyp für eine Ampelschaltung
*/
var Circuit = function(){
/*
Im Konstruktur werden 2 Ampelgruppen angelegt, denen jeweils der Name einer CSS-Klasse bekannt ist, die
hinterher für die Darstellung der Ampeln und ihrer Zustände dient.
*/
var t1 = new TrafficLightSet('.t1');
var t2 = new TrafficLightSet('.t2');

/*
states: Die Steuerung der Ampeln erfolgt bei mir ganz einfach über die Definition von 8 Zuständen, die jeweils alle
Informationen darüber enthalten, welche Ampel was anzeigen soll. Jeder Zustand enthält eine Angabe, wie lange er
aktiv sein soll und welche Ampelgruppe welchen Zustand anzeigen soll.
*/
this.states = [
{
time: 7,
assign: [
{ dest: t1, state: RED },
{ dest: t2, state: GREEN }
]
},
{
time: 3,
assign: [
{ dest: t1, state: RED },
{ dest: t2, state: YELLOW }
]
},
{
time: 1,
assign: [
{ dest: t1, state: RED },
{ dest: t2, state: RED }
]
},
{
time: 3,
assign: [
{ dest: t1, state: REDYELLOW },
{ dest: t2, state: RED }
]
},
{
time: 7,
assign: [
{ dest: t1, state: GREEN },
{ dest: t2, state: RED }
]
},
{
time: 3,
assign: [
{ dest: t1, state: YELLOW },
{ dest: t2, state: RED }
]
},
{
time: 1,
assign: [
{ dest: t1, state: RED },
{ dest: t2, state: RED }
]
},
{
time: 3,
assign: [
{ dest: t1, state: RED },
{ dest: t2, state: REDYELLOW }
]
}
];

/*
current_state: Welcher Zustand ist gerade aktiv?
*/
this.current_state = 0;

/*
next: Hier wird der Zustand der Ampelgruppen geändert:
Es wird der aktuelle Zustand ermittelt und jeder Ampelgruppe wird ihr jeweils aktueller Zustand zugewiesen.
Anschließend wird ein Timer gesetzt, der den nächsten Zustand vorbereitet und die Methode ruft sich selbst
wieder auf. Der Timer wird dabei auf den Wert gesetzt, den der Zustand haben soll und durch die Eingabe des
Benutzers geteilt, sodass man festlegen kann, wie schnell das Schalten der Ampeln ablaufen soll.
*/
this.next = function(){
var state = this.states[this.current_state];
state.assign.forEach(function(s){
s.dest.set(s.state);
});
setTimeout(function(c){
c.current_state = (c.current_state + 1) % c.states.length;
c.next();
}, state.time * 500 / parseFloat(document.getElementById('t_speed').value), this);
}
};

/*
------------------------------------------------------------------------------------------------------------------------
Eine Funtion, die beim Aufruf ein neues Auto erstellen kann und gleichzeitig die vorhandenen Warteschlangen abarbeitet.
*/
var process_cars = function(time){
/*
Es soll nicht bei jedem Aufruf ein neues Auto erstellt werden, sondern zufällig, im Schnitt bei jedem 2. Aufruf.
Es wird ebenfalls zufällig entschieden, in welche Richtung das Auto fahren soll und welcher Warteschlange es
hinzugefügt wird. Dadurch soll ein realistischer Verkehr simuliert werden.

Richtung | Wahrscheinlichkeit
----------+-------------------
Links | 25%
Rechts | 25%
Geradeaus | 25%

Warteschlange | Wahrscheinlichkeit
--------------+-------------------
Oben | 15%
Unten | 15%
Links | 35%
Rechts | 35%

Anschließend wird ein neues HTML-Element erzeugt, das ein Auto repräsentiert. Ihm wird die Richtung und eine zufällige
Farbe zugewiesen und es wird in einer der Warteschlangen angehängt, die ebenfalls durch CSS visualisiert werden.
*/
if(Math.random() < 0.5){
var dir_r = Math.random();
var queue_r = Math.random();
var direction = dir_r < 0.25 ? 'left' : dir_r < 0.5 ? 'right' : 'straight';
var queue = queue_r < 0.15 ? 'top' : queue_r < 0.3 ? 'bottom' : queue_r < 0.65 ? 'left' : 'right';


var car = document.createElement('li');
car.className = 'car';
car.dataset.direction = direction;
car.style.background = random_color();
document.querySelector('.queue.' + queue).appendChild(car);
}

/*
Etwas später wird dann ermittelt, welche der Autos gerade fahren können.
Dafür werden alle Warteschlangen überprüft und der jeweilige Gegenverkehr ermittelt.
Dann wird ermittelt, ob die gerade überprüfte Warteschlange ein Auto enthält, ob der Gegenverkehr ein Auto enthält,
in welche Richtung das Auto abbiegen möchte, in welche Richtung das gegenüberliegende Auto abbiegen möchte und welche
Farbe die Ampel gerade zeigt.
Falls die Warteschlange ein Auto enthält und die Ampel gerade grün ist, werden weitere Prüfungen vorgenommen:
Wenn das Auto geradeaus fahren oder rechts abbiegen möchte, wird es sofort verareitet.
Falls das Auto links abbiegen möchte, wird überprüft, ob kein Gegenverkehr da ist oder ob der Gegenverkehr ebenfalls
links abbiegen möchte. Wenn ja, wird das Auto verarbeitet und der Gegenverkehr, falls existent, ebenfalls.
Ein Auto wird abgearbeitet, indem es einfach aus dem DOM gelöscht wird.
*/
setTimeout(function(){
for(var look_at in opposites){
var look_at_opposite = opposites[look_at];

var car = document.querySelector('.queue.' + look_at + ' .car:first-child');
var opposite_car = document.querySelector('.queue.' + look_at_opposite + ' .car:first-child');
var direction = car ? car.dataset.direction : null;
var opposite_direction = opposite_car ? opposite_car.dataset.direction : null;

var color = document.querySelector('.t.' + look_at).dataset.is;

if(car && color == GREEN){
if(direction == 'straight' || direction == 'right'){
car.parentNode.removeChild(car);
}
else if(direction == 'left' && (opposite_direction == null || opposite_direction == 'left')){
car.parentNode.removeChild(car);
if(opposite_car){
opposite_car.parentNode.removeChild(opposite_car);
}
return;
}
}
};
}, time);
};

/*
------------------------------------------------------------------------------------------------------------------------
Hier wird die Simulation initialisiert:
Die Ampeln werden das erste mal geschaltet und es wird auf Änderungen beim Slider für die Auto-Geschwindigkeit reagiert.
*/
window.addEventListener('load', function(){
(new Circuit()).next();

var car_speed = document.getElementById('car_speed');
var car_timer = (1 / (parseFloat(car_speed.value) + 0.01)) * 100;
var car_interval = setInterval(process_cars, car_timer, car_timer);

car_speed.addEventListener('change', function(){
car_timer = (1 / (parseFloat(this.value) + 0.01)) * 100;
clearInterval(car_interval);
car_interval = setInterval(process_cars, car_timer);
});

});[/src]
[src=css]@-webkit-keyframes signal {
0% { opacity: 0; }
10% { opacity: 1; }
90% { opacity: 1; }
100% { opacity: 0; }
}
@-moz-keyframes signal {
0% { opacity: 0; }
10% { opacity: 1; }
90% { opacity: 1; }
100% { opacity: 0; }
}
@-o-keyframes signal {
0% { opacity: 0; }
10% { opacity: 1; }
90% { opacity: 1; }
100% { opacity: 0; }
}
@keyframes signal {
0% { opacity: 0; }
10% { opacity: 1; }
90% { opacity: 1; }
100% { opacity: 0; }
}

body {
background: #666;
font-family: arial;
}
ol, li {
list-style-type: none;
margin: 0;
padding: 0;
}
#sim .t {
position: absolute;
border: 1px solid #000;
width: 28px;
height: 76px;
border-radius: 3px;
background: #444444;
box-shadow: inset 0 2px 2px rgba(255, 255, 255, 0.25), inset 0 -2px 2px rgba(0, 0, 0, 0.1);
}
#sim .t:after {
content: '';
display: block;
background: #333;
box-shadow: inset 0 5px 3px 1px rgba(255, 255, 255, 0.5);
position: absolute;
top: 38px;
left: 0;
right: 0;
margin: auto;
width: 4px;
height: 100px;
z-index: -1;
}
#sim .t.top {
margin: auto;
margin-bottom: 201px;
bottom: 50%;
left: 0;
right: 200px;
}
#sim .t.left {
margin: auto;
left: 50%;
margin-left: -174px;
top: 0;
bottom: 0;
}
#sim .t.right {
margin: auto;
right: 50%;
margin-right: -174px;
top: -400px;
bottom: 0;
}
#sim .t.bottom {
margin: auto;
margin-top: 120px;
top: 50%;
left: 200px;
right: 0;
}
#sim .r,
#sim .y,
#sim .g {
width: 20px;
height: 20px;
margin: 3px;
border-radius: 50px;
border: 1px solid #000;
box-shadow: inset 0 5px 5px rgba(255, 255, 255, 0.05), inset 0 -5px 5px rgba(0, 0, 0, 0.67), 0 -1px 0 #000, 0 -2px 0 #777;
}
#sim .r {
background: #290001;
}
#sim .y {
background: #2d1f00;
}
#sim .g {
background: #333833;
}
#sim .t[data-is="RED"] .r,
#sim .t[data-is="REDYELLOW"] .r {
background: #ffbbbb;
box-shadow: inset 0 0 10px 4px #ff0000, 0 0 5px 3px rgba(255, 0, 0, 0.67), 0 -1px 0 #800, 0 -2px 0 #777;
border: 1px solid #cc0000;
}
#sim .t[data-is="YELLOW"] .y,
#sim .t[data-is="REDYELLOW"] .y{
background: #ffeabf;
box-shadow: inset 0 0 10px 4px #ffd300, 0 0 5px 3px rgba(255, 209, 0, 0.67), 0 -1px 0 #887300, 0 -2px 0 #777;
border: 1px solid #cca900;
}
#sim .t[data-is="GREEN"] .g {
background: #bbffbb;
box-shadow: inset 0 0 10px 4px #00ff3a, 0 0 5px 3px rgba(0, 255, 36, 0.67), 0 -1px 0 #00881b, 0 -2px 0 #777;
border: 1px solid #00cc48;
}

#sim .street {
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
margin: auto;
background: #888;
box-shadow: 0 0 40px rgba(0, 0, 0, 0.2);
overflow: hidden;
z-index: -2;
}
#sim .street.horizontal {
height: 200px;
}
#sim .street.vertical {
width: 200px;
}
#sim .street:before {
display: block;
content: '';
width: 100%;
height: 100%;
border: 4px dashed #fff;
margin: -4px;
position: relative;
}
#sim .street.horizontal:before {
height: 50%;
top: -2px;
}
#sim .street.vertical:before {
width: 50%;
left: -2px;
}
#sim .stop {
position: absolute;
width: 20px;
height: 20px;
background: #fff;
}
#sim .stop.left {
top: 50%;
right: 50%;
margin-right: 200px;
height: 50%;
margin-top: -2px;
}
#sim .stop.right {
top: 0;
left: 50%;
margin-left: 200px;
height: 50%;
margin-top: 2px;
}
#sim .stop.top {
width: 50%;
bottom: 50%;
margin-bottom: 200px;
margin-left: 2px;
}
#sim .stop.bottom {
top: 50%;
margin-top: 200px;
width: 50%;
left: 50%;
margin-left: -2px;
}
#sim .crossing {
width: 200px;
height: 400px;
box-shadow: none;
overflow: visible;
}
#sim .crossing:before {
background: inherit;
width: 400px;
height: 200px;
margin-top: 100px;
margin-left: -100px;
border: none;
}
#sim .queue {
position: absolute;
width: 100px;
height: 100px;
padding: 20px;
overflow: hidden;
box-sizing: border-box;
z-index: -1;
}
#sim .queue.bottom {
top: 50%;
left: 50%;
padding-top: 220px;
height: 50%;
}
#sim .queue.right {
margin-top: -100px;
top: 50%;
left: 50%;
padding-left: 230px;
width: 50%;
white-space: nowrap;
}
#sim .queue.left {
top: 50%;
margin-right: 50%;
right: 220px;
width: 50%;
height: 100px;
}
#sim .queue.top {
bottom: 50%;
margin-bottom: 200px;
height: 50%;
left: 50%;
margin-left: -100px;
transform: rotate(180deg);
}
#sim .car {
width: 60px;
height: 60px;
background: blue;
border-radius: 10px;
color: #fff;
position: relative;
box-shadow: 0 3px 12px rgba(0, 0, 0, 0.25);
}
#sim .bottom .car,
#sim .top .car {
height: 120px;
margin: 20px 0;
}
#sim .right .car,
#sim .left .car{
width: 120px;
margin: 0 10px;
margin-bottom: 40px;
display: inline-block;
}
#sim .left .car {
float: right;
}
#sim .top .car {
transform: rotate(-180deg);
position: relative;
}

#sim .bottom .car[data-direction="left"]:before,
#sim .bottom .car[data-direction="left"]:after,
#sim .bottom .car[data-direction="right"]:before,
#sim .bottom .car[data-direction="right"]:after,
#sim .top .car[data-direction="left"]:before,
#sim .top .car[data-direction="left"]:after,
#sim .top .car[data-direction="right"]:before,
#sim .top .car[data-direction="right"]:after,
#sim .left .car[data-direction="left"]:before,
#sim .left .car[data-direction="left"]:after,
#sim .left .car[data-direction="right"]:before,
#sim .left .car[data-direction="right"]:after,
#sim .right .car[data-direction="left"]:before,
#sim .right .car[data-direction="left"]:after,
#sim .right .car[data-direction="right"]:before,
#sim .right .car[data-direction="right"]:after{
position: absolute;
content: '';
display: block;
background: #fff;
box-shadow: 0 0 10px 4px rgb(255, 165, 0), inset 0 0 2px 1px rgb(255, 126, 0);
-webkit-animation: signal 1s infinite;
-moz-animation: signal 1s infinite;
-o-animation: signal 1s infinite;
animation: signal 1s infinite;
}
#sim .left .car[data-direction="left"]:before,
#sim .left .car[data-direction="left"]:after,
#sim .left .car[data-direction="right"]:before,
#sim .left .car[data-direction="right"]:after,
#sim .right .car[data-direction="left"]:before,
#sim .right .car[data-direction="left"]:after,
#sim .right .car[data-direction="right"]:before,
#sim .right .car[data-direction="right"]:after{
width: 10px;
height: 5px;
}
#sim .left .car:before,
#sim .right .car:before {
left: 5%;
}
#sim .left .car:after,
#sim .right .car:after {
right: 5%;
}
#sim .left .car[data-direction="left"]:before,
#sim .left .car[data-direction="left"]:after {
bottom: 100%;
}
#sim .left .car[data-direction="right"]:before,
#sim .left .car[data-direction="right"]:after {
top: 100%;
}


#sim .right .car[data-direction="left"]:before,
#sim .right .car[data-direction="left"]:after {
top: 100%;
border-radius: 0 0 5px 5px;
}
#sim .right .car[data-direction="right"]:before,
#sim .right .car[data-direction="right"]:after {
bottom: 100%;
border-radius: 5px 5px 0 0;
}


#sim .bottom .car[data-direction="left"]:before,
#sim .bottom .car[data-direction="left"]:after,
#sim .bottom .car[data-direction="right"]:before,
#sim .bottom .car[data-direction="right"]:after,
#sim .top .car[data-direction="left"]:before,
#sim .top .car[data-direction="left"]:after,
#sim .top .car[data-direction="right"]:before,
#sim .top .car[data-direction="right"]:after{
width: 5px;
height: 10px;
}
#sim .bottom .car:before,
#sim .top .car:before {
top: 5%;
}
#sim .bottom .car:after,
#sim .top .car:after {
bottom: 5%;
}
#sim .bottom .car[data-direction="left"]:before,
#sim .bottom .car[data-direction="left"]:after {
right: 100%;
}
#sim .bottom .car[data-direction="right"]:before,
#sim .bottom .car[data-direction="right"]:after {
left: 100%;
}

#sim .top .car[data-direction="left"]:before,
#sim .top .car[data-direction="left"]:after {
left: 100%;
}
#sim .top .car[data-direction="right"]:before,
#sim .top .car[data-direction="right"]:after {
right: 100%;
}

#controls {
color: #fff;
}
#controls > div {
margin-bottom: 0.5em;
overflow: hidden;
}
#controls label {
width: 200px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
display: inline-block;
float: left;
padding: 5px;
text-align: right;
}[/src]

Und hier gibt's die Demo: https://fiddle.jshell.net/v5Lfn5mr/show/light/
 

sharpy35

Neu angemeldet

Registriert
13 Apr. 2015
Beiträge
210
nicht schlecht :D du hattest wohl viel zeit, dass du jetzt schon fertig bist? ^^
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.561
Ich versuche das ganze gerade in C zu realisieren, ist aber gar nicht mal so einfach oder ich denke zu kompliziert. Jedenfalls eine schöne Aufgabe!
Weiß noch nicht ob ich fertig werde, aber ist ja noch ellen lang Zeit bis zur Abgabe - selbst wenn ich daran scheitern sollte würde ich allerdings den Code veröffentlichen.. damit man sein Pro und Kontro loswerden kann, geht ja hierbei ums lernen nehme ich mal ganz stark an.
Muß ich noch jede Menge.

Wie gesagt, die Aufgabe ist doch anspruchsvoller als vermutet. :T
 

KaPiTN

♪♪♫ wild at heart ♪♫♫♪

Registriert
14 Juli 2013
Beiträge
29.138
Ich hatte nicht vor mitzumachen. Erwische mich aber immer wieder, daß ich in freien Minuten über Teilaspekte nachdenke.:confused:
 

Asseon

Draic Kin

Registriert
14 Juli 2013
Beiträge
10.353
Ort
Arcadia
werd mal sehen wenn ich genug zeit finde werd ich das in nim bauen.

ich sollte dazu sagen, dass das mein erstes Projekt in nim wird :D
 

Timon3

Team ModMii

Registriert
17 Juli 2013
Beiträge
499
Ich werde mich wohl auch mal bei Zeiten an eine C#-Umsetzung machen, sobald ich meine aktuellen Projekte durch hab.
 

drfuture

Zeitreisender
Teammitglied

Registriert
14 Juli 2013
Beiträge
8.728
Ort
in der Zukunft
Kreativ wäre zwar auch eine Umsetzung in PHP als Consolen-Anwendung... aber mein Ziel wäre es das ganze in vb.net umzusetzen...

in vb6 hätte ich einen Teil davon noch irgendwo rumfliegen ^^ - das könnte ich wenn ich es finde noch als Bonus veröffentlichen - das dürfte ~10 Jahre alt sein *fg*
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.561
@drfuture:
Bei 10 Jahre altem Code, zeig mal ob du was dazu gelernt hast - der Vergleich wäre gut :)

PS: Ich bin gerade zu faul zu programmieren, ich muss erstmal mindestens eine Nacht darüber schlafen über was mein if-statement hinaus ging an dem ich als letztes geschraubt habe :D
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.561
Auch mal ein wenig produktives zu dem Thema:

Hier meine Version 0.1 der Ampelschaltung.

Implementiert sind:
[X] alle 4 Ampeln schalten in regelmäßigen Abständen lt. normalen Verkehrsregeln
[X] Die Ampel verhält sich wie eine "offizielle" Ampel (unterschiedliches Timing für die einzelnen Phasen)
[_] Eine oder mehrere Ampel-Lampen können kaputt gehen, je nach Defekt wird "irgendwie" darauf reagiert (seid Kreativ) es darf nur kein Unfall passieren können.
[X] Autos fahren in regelmäßigen Abständen über die Kreuzung und fahren jeweils nur gerade aus.
[_] Autos fahren in regelmäßigen Abständen über die Kreuzung und biegen ab und an rechts ab.
[_] Autos fahren in regelmäßigen Abständen über die Kreuzung und biegen rechts und links ab.
[_] Autos fahren in zufälligen Abständen und zufälligen Fluss-raten über die Kreuzung, die Ampeln reagieren darauf und schalten unterschiedlich lange Grün-Phasen
[_] Kollisionserkennung, 2 Autos dürfen keinen "Unfall" bauen und biegen nur ab, insofern genug Platz frei ist. Bis zu diesem Schwierigkeit-Grad dürfen sich Autos auch überlappen.


Da ich ohne grafisches Interface gearbeitet habe und die Ausgabe nur in eine Konsole geht ist der Verkehr nur als simple Zahl ausgedrückt.
Auch die Anzahl der Fahrzeuge die, ohne es richtig zu timen, passieren können ist unreal hoch. Liegt aber an der Berechnung weil sich sonst der Verkehr stauen und selbst bei geringem Zufallswert der Autos für die Ampeln zuviel Verkehr aufkommen würde.

Kompiliert werden kann mit g++:
Linux:
"g++ ampelschaltung.c -w -o ampel" (wenn die Quelldatei als Ampelschaltung.c gespeichert wird)

Windows:
"g++ ampelschaltung.c -w -o ampel.exe" (wenn die Quelldatei als Ampelschaltung.c gespeichert wird)

[src=c]/*
*
* Ampelschaltung v0.1 by theSplit @ 23.04.15
* for the new gulli board coding competition
*
*/

// C-Header Datei Import
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

// Funktions Deklaration
void schliesseSchaltung();
void ampelStatus(unsigned int ampelIndex);

void erstelleAmpel(unsigned int richtung);
void verbindeAmpel(unsigned int ampelIndex1, unsigned int ampelIndex2);


// Definition der Ampelzustände
enum ampelZustand {
AUSGESCHALTET = 0,
GRUEN = 1,
GELB = 2,
ROT = 3,
DEFEKT_GRUEN = -1,
DEFEKT_GELB = -2,
DEFEKT_ROT = -3,
DEFEKT = -4
};

// Ampel Phasen-Dauer Definition, sollten durch 500 teilbar sein, Angabe in Sekunden
// aufgrund der Berechnunsschrittgröße
enum ampelZeiten {
PHASE_GRUEN = 6000,
PHASE_GELB = 2500,
PHASE_ROT = 7000,
PHASE_ROT_ZUSATZ = 1500 // Die Extra Zeit die eine Ampel nach einer aktiven Rotphase warten soll bevor die Straße freigegeben wird
};

// Definition der Himmelsrichtungen für Erstellung, nur Orientierungsangabe
enum ampelRichtung {
NORD = 0,
OST = 1,
SUED = 2,
WEST = 3
};

// Ampel Definition
typedef struct ampel {
int phase = 3;
int vorgaengerPhase = 3;
unsigned int index = 0;
unsigned int gruenPhase = 0;
unsigned int gelbPhase = 0;
unsigned int rotPhase = 0;
unsigned int warteZeit = 0;
unsigned int warteZeitLimit = 0;
unsigned int prioritaet = 0;
unsigned int richtung = 0;
int autosInWarteschlange = 0;
unsigned int inBetriebnahmen = 0;
struct ampel* partnerAmpel;
};

// Variablen Deklaration
static unsigned int ampelAnzahl = 0;
static ampel *ampelListe;
static int aktiveAmpel = -1;
static int aktuelleRunde = 0;
static int berechneRunden;

int main() {
// Funktion aufrufen die Speicher freigibt
atexit(schliesseSchaltung);

printf("Verkehrsampeln in Erstellung: %d\n", 4);
erstelleAmpel(NORD);
erstelleAmpel(OST);
erstelleAmpel(SUED);
erstelleAmpel(WEST);

// Die Partner-Ampel verbinden
verbindeAmpel(0, 2);
verbindeAmpel(1, 3);

// Hauptschleife
while (true) {

// Eingabe der Schritte der Berechnung in 500ms Schritten * 2
printf("Wieviele Runden berechnen (0 = Abbruch)\n");
scanf("%d", &berechneRunden);
printf("Runden: %d\n", berechneRunden);

// Wenn 0 beenden
if (berechneRunden <= 0) {
break;
}

aktuelleRunde = 0;

// Berechnungsschleife und Ampeln durchschalten, Zeiten erhöhen, Logik
while (aktuelleRunde < (berechneRunden * 2)) {

// Fahrzeuge bei Ampeln erhöhen nach Zufall und
// Wartezeit um 500ms erhöhen
for (int i = 0; i < ampelAnzahl; i++) {

// Überlauf verhindern, nicht weiter relevant
if (ampelListe.autosInWarteschlange > 5000) {
ampelListe.autosInWarteschlange = 0;
}

// Fahrzeuge zufällig an Ampel erhöhen
ampelListe.autosInWarteschlange += (rand() % 2);
ampelListe.warteZeit += 500;

}

int hoechsterIndex = 0;
int hoechstePrioritaet = ampelAnzahl > 0 ? ampelListe[0].prioritaet : 0;
for (int i = 0; i < ampelAnzahl; i++) {
if (ampelListe.prioritaet > hoechstePrioritaet) {
hoechsterIndex = i;
hoechstePrioritaet = ampelListe.prioritaet;
}
}

for (int i = 0; i < ampelAnzahl; i++) {
if (aktiveAmpel == -1 || ampelListe.warteZeit >= ampelListe.warteZeitLimit) {

// Wenn wir eine aktive Ampel haben, ist dies die aktive bzw. deren Partnerampel?
if (aktiveAmpel != -1 && (aktiveAmpel != i && (ampelListe.partnerAmpel != NULL && ampelListe.partnerAmpel->index != i))) {
ampelListe.prioritaet++;
continue;
}

// Keine aktive Ampel, ist dies eine der Ampeln mit der höchsten Priorität bzw. deren Partnerampel falls vorhanden?
if (aktiveAmpel == -1 && (hoechsterIndex != i && (ampelListe.partnerAmpel != NULL && ampelListe.partnerAmpel->index != hoechsterIndex))) {
ampelListe.prioritaet++;
continue;
}

// Aktive Ampel setzen und eventuelle Partnerampel
// einspannen
aktiveAmpel = i;
ampelListe.warteZeit = 0;
ampelListe.prioritaet = 0;

if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->warteZeit = 0;
ampelListe.partnerAmpel->prioritaet = 0;
}

// Wechsele die Phasen der Ampel nach aktuellem Farbenstand
switch (ampelListe.phase) {
case ROT:
// Phase Rot
if (ampelListe.vorgaengerPhase == GELB) {
// Wenn die Ampel vorher auf Gelb stand,
// also die Rotphase + Wartezeit rum ist,
// platz für die nächste Ampel geben
aktiveAmpel = -1;
ampelListe.warteZeit = 0;
ampelListe.prioritaet = 0;
ampelListe.vorgaengerPhase = ROT;

if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->warteZeit = 0;
ampelListe.partnerAmpel->prioritaet = 0;
ampelListe.partnerAmpel->vorgaengerPhase = ROT;
}

continue;
}

// Die Ampel schaltet von Rot auf Gelb und wird somit in Betrieb genommmen
ampelListe.inBetriebnahmen++;

// Schutz vor Überlauf, nicht relevant
if (ampelListe.inBetriebnahmen > 10000) {
ampelListe.inBetriebnahmen = 0;
}

// Partnerampel auch auf Betrieben setzen
if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->inBetriebnahmen = ampelListe.inBetriebnahmen;
}

// Gelb als aktuelle Phase setzen
ampelListe.phase = GELB;
ampelListe.warteZeitLimit = PHASE_GELB;

// Von Rot auf Gelb geschaltet, Vorgängerphase ist nun Rot
ampelListe.vorgaengerPhase = ROT;

// Das selbe für die Partnerampel machen
if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->phase = GELB;
ampelListe.partnerAmpel->warteZeitLimit = PHASE_GELB;
ampelListe.partnerAmpel->vorgaengerPhase = ROT;
}
break;
case GELB:
// Phase ist Gelb
if (ampelListe.vorgaengerPhase == GRUEN) {
// Phase von vorher Grün auf Rot setzen,
// neues WarteZeitLimit setzen
ampelListe.phase = ROT;
ampelListe.warteZeitLimit = PHASE_ROT_ZUSATZ;
ampelListe.vorgaengerPhase = GELB;

// Für die Partnerampel auch wenn gesetzt
if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->phase = ROT;
ampelListe.partnerAmpel->warteZeitLimit = PHASE_ROT_ZUSATZ;

ampelListe.partnerAmpel->vorgaengerPhase = GELB;
}

} else if (ampelListe.vorgaengerPhase == ROT) {
// Phase war Rot, nun auf Grün schalten,
// neue WarteZeitLimit setzen
ampelListe.phase = GRUEN;
ampelListe.warteZeitLimit = PHASE_GRUEN;

ampelListe.vorgaengerPhase = GELB;

if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->phase = GRUEN;
ampelListe.partnerAmpel->warteZeitLimit = PHASE_GRUEN;

ampelListe.partnerAmpel->vorgaengerPhase = GELB;
}

// Lasse 100 Fahrzeuge passieren
// Der Wert ist nur so hoch weil die Berechnungsschritte
// so gering sind und sich sonst Fahrzeuge anstauen
ampelListe.autosInWarteschlange -= 80;
if (ampelListe.autosInWarteschlange < 0) {
ampelListe.autosInWarteschlange = 0;
}

ampelListe.partnerAmpel->autosInWarteschlange -= 80;
if (ampelListe.partnerAmpel->autosInWarteschlange < 0) {
ampelListe.partnerAmpel->autosInWarteschlange = 0;
}

}
break;
case GRUEN:
// Von Grün auf Gelb schalten
// Vorgängerphase setzen, neues WarteZeitLimit setzen
ampelListe.phase = GELB;
ampelListe.vorgaengerPhase = GRUEN;

ampelListe.warteZeitLimit = PHASE_GELB;

if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->phase = GELB;
ampelListe.partnerAmpel->warteZeitLimit = PHASE_GELB;

ampelListe.partnerAmpel->vorgaengerPhase = GRUEN;
}
break;
}
}
}

aktuelleRunde++;

}

// Ampelstatus ausgeben oder beenden
printf("Ampelstatus ausgeben [j/n/0 = Abbruch]\n");
char ampelStatusAusgeben;
scanf("%s", &ampelStatusAusgeben);

if (ampelStatusAusgeben == 'j') {
for (unsigned int i = 0; i < ampelAnzahl; i++) {
ampelStatus(i);
}
} else if (ampelStatusAusgeben == '0') {
break;
}
}

return (EXIT_SUCCESS);
}

// Eine Ampel erstellen
void erstelleAmpel(unsigned int richtung) {
// Test ob die Himmelsrichtung in einem gültigen Bereich liegt
// ist nicht wirklich relevant und könnte weggelassen werden,
// da die Ampeln selbst verwaltend sind
if (!(richtung >= 0 && richtung <= 3) ) {
printf("Keine gültige Himmelsrichtung für Ampel %d eingegeben\n", ampelAnzahl);
return;
}

// Speicher für neue Ampel erfragen
ampelListe = (ampel*) realloc(ampelListe, sizeof(ampel) * (ampelAnzahl + 1));

// Kein Speicher => Programfehler und beenden
if (ampelListe == NULL) {
printf("Konnte kein Speicher für die Ampelschaltungen belegen... Abbruch.");
schliesseSchaltung();
}

// Die Ampel anlegen
ampelListe[ampelAnzahl].index = ampelAnzahl;
ampelListe[ampelAnzahl].phase = ROT;
ampelListe[ampelAnzahl].vorgaengerPhase = ROT;
ampelListe[ampelAnzahl].gruenPhase = 6000;
ampelListe[ampelAnzahl].gelbPhase = 2500;
ampelListe[ampelAnzahl].rotPhase = 7000;
ampelListe[ampelAnzahl].warteZeit = PHASE_ROT;
ampelListe[ampelAnzahl].warteZeitLimit = PHASE_ROT+2000;
ampelListe[ampelAnzahl].prioritaet = 0;
ampelListe[ampelAnzahl].richtung = richtung;
ampelListe[ampelAnzahl].autosInWarteschlange = 0;
ampelListe[ampelAnzahl].inBetriebnahmen = 0;
ampelListe[ampelAnzahl].partnerAmpel = NULL;

ampelAnzahl++;
return;
}

// Zwei Ampeln verbinden, Partnerampel setzen wenn gegenüber
void verbindeAmpel(unsigned int ampelIndex1, unsigned int ampelIndex2) {
if (ampelIndex1 > ampelAnzahl || ampelIndex2 > ampelAnzahl) {
return;
}

ampelListe[ampelIndex1].partnerAmpel = &ampelListe[ampelIndex2];
ampelListe[ampelIndex2].partnerAmpel = &ampelListe[ampelIndex1];
}

// Ampelstatus ausgeben
void ampelStatus(unsigned int ampelIndex) {
ampel Ampel = ampelListe[ampelIndex];
printf("Ampel-Status:\n");

char *ampelStatusPhase;
char *ampelStatusRichtung;

switch (Ampel.phase) {
case AUSGESCHALTET:
ampelStatusPhase = "Ausgeschaltet";
break;
case GRUEN:
ampelStatusPhase = "Grün";
break;
case GELB:
ampelStatusPhase = "Gelb";
break;
case ROT:
ampelStatusPhase = "Rot";
break;
case DEFEKT_GRUEN:
ampelStatusPhase = "Defekt Grün";
break;
case DEFEKT_GELB:
ampelStatusPhase = "Defekt Gelb";
break;
case DEFEKT_ROT:
ampelStatusPhase = "Defekt Rot";
break;
case DEFEKT:
default:
ampelStatusPhase = "genereller defekt";
break;
}

switch (Ampel.richtung) {
case NORD:
ampelStatusRichtung = "Nord";
break;
case OST:
ampelStatusRichtung = "Ost";
break;
case SUED:
ampelStatusRichtung = "Süd";
break;
case WEST:
ampelStatusRichtung = "West";
break;
}

printf("Ampelindex: %i\n", ampelIndex);
printf("Richtung: %s\n", ampelStatusRichtung);
printf("Phase: %s\n", ampelStatusPhase);
printf("In Betriebnahmen: %d\n", Ampel.inBetriebnahmen);
printf("Warezeit in Sekunden: %.2f\n", (float) Ampel.warteZeit / 1000);
printf("Aktuelle Priorität: %d\n", Ampel.prioritaet);
printf("Partner-Ampel Index: %d\n", Ampel.partnerAmpel != NULL ? Ampel.partnerAmpel->index : -1);
printf("Autos in Schlange: %d\n\n", Ampel.autosInWarteschlange);

return;
}

// Anwendung beenden
void schliesseSchaltung() {
free(ampelListe);
exit(EXIT_SUCCESS);
}
[/src]
 

theSplit

1998
Veteran Barkeeper

Registriert
3 Aug. 2014
Beiträge
28.561
Zwei neue Versionen, eine mit SDL und eine basierend auf Version 0.1 mit kleinen Änderungen.

Zuerst die mit ohne SDL:
[src=c]
/*
*
* Ampelschaltung v0.2 by theSplit @ 23.04.15
* for the new gulli board coding competition
*
*/

// C-Header Datei Import
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

// Funktions Deklaration
void schliesseSchaltung();
void ampelStatus(unsigned int ampelIndex);

void erstelleAmpel(unsigned int richtung);
void verbindeAmpel(unsigned int ampelIndex1, unsigned int ampelIndex2);
void lasseAutoPassieren(unsigned int i);


// Definition der Ampelzustände
enum ampelZustand {
AUSGESCHALTET = 0,
GRUEN = 1,
GELB = 2,
GELB_ROT = 3,
ROT = 4,
DEFEKT_GRUEN = -1,
DEFEKT_GELB = -2,
DEFEKT_ROT = -3,
DEFEKT = -4
};

// Ampel Phasen-Dauer Definition, sollten durch 25 teilbar sein, Angabe in Millisekunden
// aufgrund der Berechnunsschrittgröße
enum ampelZeiten {
PHASE_GRUEN = 6000, // Dauer der Grün-Phase
PHASE_GELB = 2500, // Dauer der Gelb-Phase
PHASE_ROT = 7000, // Dauer der Rot-Phase
PHASE_GELB_ROT = 1500, // Dauer der Gelb-Rot Phase (Anfahrtssignal)
PHASE_ROT_ZUSATZ = 1500 // Extra Dauer nach aktiver Grün und Gelb Phase, in Rot-Phase, bevor die Kreuzung freigegeben wird
};

// Definition der Himmelsrichtungen für Erstellung, nur Orientierungsangabe
enum ampelRichtungen {
NORD = 0,
OST = 1,
SUED = 2,
WEST = 3
};

enum fahrtRichtungen {
GERADEAUS = 0,
LINKS = 1,
RECHTS = 2
};

// Auto Definition
typedef struct pkw {
unsigned int fahrtRichtung = 0;
unsigned int warteZeit = 0;
int geschwindigkeit = 0;

};

// Ampel Definition
typedef struct ampel {
int phase = ROT;
int vorgaengerPhase = ROT;
unsigned int index = 0;
unsigned int warteZeit = 0;
unsigned int warteZeitLimit = 0;
unsigned int prioritaet = 0;
unsigned int richtung = 0;
unsigned int inBetriebnahmen = 0;
unsigned int autosPassiert = 0;
int autosInWarteschlange = 0;
pkw fahrzeugListe[100];
ampel* partnerAmpel;
};

// Variablen Deklaration
static unsigned int ampelAnzahl = 0;
static ampel *ampelListe;
static int aktiveAmpel = -1;
static int aktuelleRunde = 0;
static int berechneRunden;

static unsigned int hoechsterIndex = 0;
static unsigned int hoechstePrioritaet = 0;
static unsigned int i = 0;
static unsigned int zufallsAmpel = 0;

int main() {
// Beenden Funktion definieren die den Speicher freigibt
atexit(schliesseSchaltung);

// Verkehrsampeln erstellen
printf("Verkehrsampeln in Erstellung: %d\n", 4);
erstelleAmpel(NORD);
erstelleAmpel(OST);
erstelleAmpel(SUED);
erstelleAmpel(WEST);

// Die Partner-Ampel verbinden die gegenüber liegen
verbindeAmpel(0, 2);
verbindeAmpel(1, 3);

// Hauptschleife
while (true) {

// Eingabe der Schritte der Berechnung in 500ms Schritten * 2
printf("Wieviele Sekunden berechnen? (0 = Abbruch)\n");
scanf("%d", &berechneRunden);

// Wenn 0 beenden
if (berechneRunden <= 0) {
printf("Beende Ampelschaltung.\n\n");
break;
} else {
printf("Runden: %d\n", berechneRunden);
}

aktuelleRunde = 0;

// Berechnungsschleife und Ampeln durchschalten, Zeiten erhöhen, Logik
while (aktuelleRunde <= (berechneRunden * 2)) {

// Wartezeit um 500ms bei jeder Ampel erhöhen
for (i = 0; i < ampelAnzahl; i++) {
ampelListe.warteZeit += 500;

}

// Fahrzeuge zufällig an Ampel erhöhen
if (rand() % 4 == 3) {
zufallsAmpel = rand() % ampelAnzahl;

ampelListe[zufallsAmpel].autosInWarteschlange++;

// Auskommentiert um nicht ständig zu printen
// printf("Autos in Schlange von Ampel-Index %d: %d\n", zufallsAmpel, ampelListe[zufallsAmpel].autosInWarteschlange);

// Überlauf verhindern, nicht weiter relevant
if (ampelListe[zufallsAmpel].autosInWarteschlange > 100) {
ampelListe[zufallsAmpel].autosInWarteschlange = 100;
} else {
// Neues Auto für Ampel erstellen
pkw fahrzeug;
fahrzeug.fahrtRichtung = rand() % 3;
fahrzeug.warteZeit = 0;
fahrzeug.geschwindigkeit = 0;

// Fahrzeug in die Liste der Fahrzeuge kopieren (auf 100 begrenzt)
memcpy(&ampelListe[zufallsAmpel].fahrzeugListe[ampelListe[zufallsAmpel].autosInWarteschlange-1], &fahrzeug, sizeof(pkw));
}
}

// Welche Ampel hat die höchste Priorität und muss aktiviert werden?
hoechsterIndex = 0;
hoechstePrioritaet = ampelAnzahl > 0 ? ampelListe[0].prioritaet : 0;
for (i = 0; i < ampelAnzahl; i++) {
if (ampelListe.prioritaet > hoechstePrioritaet) {
hoechsterIndex = i;
hoechstePrioritaet = ampelListe.prioritaet;
}
}

// Ampelschaltung Logik
for (i = 0; i < ampelAnzahl; i++) {
if (aktiveAmpel == -1 || ampelListe.warteZeit >= ampelListe.warteZeitLimit) {

// Wenn wir eine aktive Ampel haben, ist dies die aktive bzw. deren Partnerampel?
// Falls nicht die Ampel Prioriät erhöhen
if (aktiveAmpel != -1 && (aktiveAmpel != i && (ampelListe.partnerAmpel != NULL && ampelListe.partnerAmpel->index != i))) {
ampelListe.prioritaet++;
continue;
}

// Keine aktive Ampel, ist dies eine der Ampeln mit der höchsten Priorität bzw. deren Partnerampel falls vorhanden?
// Falls nicht die Ampel Prioriät erhöhen
if (aktiveAmpel == -1 && (hoechsterIndex != i && (ampelListe.partnerAmpel != NULL && ampelListe.partnerAmpel->index != hoechsterIndex))) {
ampelListe.prioritaet++;
continue;
}

// Aktive Ampel setzen und eventuelle Partnerampel
// einspannen falls gesetzt
aktiveAmpel = i;
ampelListe.warteZeit = 0;
ampelListe.prioritaet = 0;

if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->warteZeit = 0;
ampelListe.partnerAmpel->prioritaet = 0;
}

// Wechsele die Phasen der Ampel nach aktuellem Farbenstand
switch (ampelListe.phase) {
case ROT:
// Phase Rot
if (ampelListe.vorgaengerPhase == GELB) {
// Wenn die Ampel vorher auf Gelb stand,
// also die Rotphase + Wartezeit rum ist,
// platz für die nächste Ampel geben
aktiveAmpel = -1;
ampelListe.warteZeit = 0;
ampelListe.prioritaet = 0;
ampelListe.vorgaengerPhase = ROT;
ampelListe.warteZeitLimit = PHASE_ROT;


if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->warteZeit = 0;
ampelListe.partnerAmpel->prioritaet = 0;
ampelListe.partnerAmpel->vorgaengerPhase = ROT;
ampelListe.partnerAmpel->warteZeitLimit = PHASE_ROT;
}

continue;
}

// Die Ampel schaltet von Rot auf Gelb und wird somit in Betrieb genommmen
ampelListe.inBetriebnahmen++;

// Schutz vor Überlauf, nicht relevant
if (ampelListe.inBetriebnahmen == 1000000) {
ampelListe.inBetriebnahmen = 0;
}

// Partnerampel auch auf Betrieben setzen
if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->inBetriebnahmen = ampelListe.inBetriebnahmen;
}

// Gelb-Rot als aktuelle Phase setzen
ampelListe.phase = GELB_ROT;
ampelListe.warteZeitLimit = PHASE_GELB_ROT;

// Von Rot auf Gelb geschaltet, Vorgängerphase ist nun Rot
ampelListe.vorgaengerPhase = ROT;

// Das selbe für die Partnerampel machen
if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->phase = GELB_ROT;
ampelListe.partnerAmpel->warteZeitLimit = PHASE_GELB_ROT;
ampelListe.partnerAmpel->vorgaengerPhase = ROT;
}
break;
case GELB_ROT:
// Phase ist Gelb-Rot auf Grün setzen
ampelListe.phase = GRUEN;
ampelListe.warteZeitLimit = PHASE_GRUEN;
ampelListe.vorgaengerPhase = GELB_ROT;

// Für die Partnerampel auch wenn gesetzt
if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->phase = GRUEN;
ampelListe.partnerAmpel->warteZeitLimit = PHASE_GRUEN;

ampelListe.partnerAmpel->vorgaengerPhase = GELB_ROT;
}

// Lasse Autos über die Ampel fahren (8)
lasseAutoPassieren(i);

break;
case GELB:
// Phase ist Gelb
if (ampelListe.vorgaengerPhase == GRUEN) {
// Phase von vorher Grün auf Rot setzen,
// neues WarteZeitLimit setzen
ampelListe.phase = ROT;
ampelListe.warteZeitLimit = PHASE_ROT_ZUSATZ;
ampelListe.vorgaengerPhase = GELB;

// Für die Partnerampel auch wenn gesetzt
if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->phase = ROT;
ampelListe.partnerAmpel->warteZeitLimit = PHASE_ROT_ZUSATZ;

ampelListe.partnerAmpel->vorgaengerPhase = GELB;
}

} else if (ampelListe.vorgaengerPhase == ROT) {
// Phase war Rot, nun auf Grün schalten,
// neue WarteZeitLimit setzen
ampelListe.phase = GRUEN;
ampelListe.warteZeitLimit = PHASE_GRUEN;

ampelListe.vorgaengerPhase = GELB;

if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->phase = GRUEN;
ampelListe.partnerAmpel->warteZeitLimit = PHASE_GRUEN;

ampelListe.partnerAmpel->vorgaengerPhase = GELB;
}

// Lasse Autos über die Ampel fahren (8)
lasseAutoPassieren(i);

}
break;
case GRUEN:
// Von Grün auf Gelb schalten
// Vorgängerphase setzen, neues WarteZeitLimit setzen
ampelListe.phase = GELB;
ampelListe.vorgaengerPhase = GRUEN;

ampelListe.warteZeitLimit = PHASE_GELB;

if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->phase = GELB;
ampelListe.partnerAmpel->warteZeitLimit = PHASE_GELB;

ampelListe.partnerAmpel->vorgaengerPhase = GRUEN;
}
break;
}
}
}

aktuelleRunde++;

}

// Ampelstatus ausgeben oder beenden
printf("Ampelstatus ausgeben? [j/n/0 = Abbruch]\n");
char ampelStatusAusgeben;
scanf("%s", &ampelStatusAusgeben);

if (ampelStatusAusgeben == 'j') {
for (i = 0; i < ampelAnzahl; i++) {
ampelStatus(i);
}
} else if (ampelStatusAusgeben == '0') {
break;
}
}

return (EXIT_SUCCESS);
}

// Eine Ampel erstellen
void erstelleAmpel(unsigned int richtung) {
// Test ob die Himmelsrichtung in einem gültigen Bereich liegt
// ist nicht wirklich relevant und könnte weggelassen werden,
// da die Ampeln selbst verwaltend sind
if (!(richtung >= 0 && richtung <= 3) ) {
printf("Keine gültige Himmelsrichtung für Ampel %d eingegeben\n", ampelAnzahl);
return;
}

// Speicher für neue Ampel erfragen
ampelListe = (ampel*) realloc(ampelListe, sizeof(ampel) * (ampelAnzahl + 1));

// Kein Speicher => Programfehler und beenden
if (ampelListe == NULL) {
printf("Konnte kein Speicher für die Ampelschaltungen belegen... Abbruch.");
schliesseSchaltung();
}

// Die Ampel anlegen
ampelListe[ampelAnzahl].index = ampelAnzahl;
ampelListe[ampelAnzahl].phase = ROT;
ampelListe[ampelAnzahl].vorgaengerPhase = ROT;
ampelListe[ampelAnzahl].warteZeit = PHASE_ROT;
ampelListe[ampelAnzahl].warteZeitLimit = PHASE_ROT+2000;
ampelListe[ampelAnzahl].prioritaet = 0;
ampelListe[ampelAnzahl].richtung = richtung;
ampelListe[ampelAnzahl].autosInWarteschlange = 0;
ampelListe[ampelAnzahl].inBetriebnahmen = 0;
ampelListe[ampelAnzahl].partnerAmpel = NULL;

ampelAnzahl++;
return;
}

// Zwei Ampeln verbinden, Partnerampel setzen wenn gegenüber
void verbindeAmpel(unsigned int ampelIndex1, unsigned int ampelIndex2) {
if (ampelIndex1 > ampelAnzahl || ampelIndex2 > ampelAnzahl) {
return;
}

ampelListe[ampelIndex1].partnerAmpel = &ampelListe[ampelIndex2];
ampelListe[ampelIndex2].partnerAmpel = &ampelListe[ampelIndex1];
}

// Funktion um Autos über die Ampeln fahren zu lassen
void lasseAutoPassieren(unsigned int i) {
// Lasse 8 Fahrzeuge passieren
ampelListe.autosInWarteschlange -= 8;

if (ampelListe.autosInWarteschlange < 0) {
ampelListe.autosPassiert += (8 + ampelListe.autosInWarteschlange);
ampelListe.autosInWarteschlange = 0;
} else {
ampelListe.autosPassiert += 8;
}

// Schutz vor Überlauf
if (ampelListe.autosPassiert > 150000) {
ampelListe.autosPassiert = 0;
}

// Das gleiche für die Partnerampel
if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->autosInWarteschlange -= 8;
if (ampelListe.partnerAmpel->autosInWarteschlange < 0) {
ampelListe.partnerAmpel->autosPassiert += (8 + ampelListe.partnerAmpel->autosInWarteschlange);
ampelListe.partnerAmpel->autosInWarteschlange = 0;
} else {
ampelListe.partnerAmpel->autosPassiert += 8;
}

// Schutz vor Überlauf
if (ampelListe.partnerAmpel->autosPassiert > 150000) {
ampelListe.partnerAmpel->autosPassiert = 0;
}
}

return;
}

// Ampelstatus ausgeben
void ampelStatus(unsigned int ampelIndex) {
ampel Ampel = ampelListe[ampelIndex];
printf("Ampel-Status:\n");

char *ampelStatusPhase;
char *ampelStatusRichtung;

switch (Ampel.phase) {
case AUSGESCHALTET:
ampelStatusPhase = "Ausgeschaltet";
break;
case GRUEN:
ampelStatusPhase = "Grün";
break;
case GELB:
ampelStatusPhase = "Gelb";
break;
case GELB_ROT:
ampelStatusPhase = "Gelb-Rot";
break;
case ROT:
ampelStatusPhase = "Rot";
break;
case DEFEKT_GRUEN:
ampelStatusPhase = "Defekt Grün";
break;
case DEFEKT_GELB:
ampelStatusPhase = "Defekt Gelb";
break;
case DEFEKT_ROT:
ampelStatusPhase = "Defekt Rot";
break;
case DEFEKT:
default:
ampelStatusPhase = "genereller defekt";
break;
}

switch (Ampel.richtung) {
case NORD:
ampelStatusRichtung = "Nord";
break;
case OST:
ampelStatusRichtung = "Ost";
break;
case SUED:
ampelStatusRichtung = "Süd";
break;
case WEST:
ampelStatusRichtung = "West";
break;
}

printf("Ampelindex: %i\n", ampelIndex);
printf("Richtung: %s\n", ampelStatusRichtung);
printf("Phase: %s\n", ampelStatusPhase);
printf("In Betriebnahmen: %d\n", Ampel.inBetriebnahmen);
printf("Aktuelle Warezeit in Phase (Sekunden): %.2f\n", (float) Ampel.warteZeit / 1000);
printf("Normale Wartezeit in Phase (Sekunden): %.2f\n", (float) Ampel.warteZeitLimit / 1000);
printf("Aktuelle Priorität: %d\n", Ampel.prioritaet);
printf("Partner-Ampel Index: %d\n", Ampel.partnerAmpel != NULL ? Ampel.partnerAmpel->index : -1);
printf("Autos in Schlange: %d\n", Ampel.autosInWarteschlange);
printf("Passierte Autos: %d\n\n", Ampel.autosPassiert);

return;
}

// Anwendung beenden
void schliesseSchaltung() {
free(ampelListe);
exit(EXIT_SUCCESS);
}
[/src]


Keine Nennenswerten Ergänzung zur Vorgängerversion, lediglich Code cleanups und es gibt nun eine Gelb-Rot Phase zusätzlich.



Die SDL Version (SDL2.0.x) (nur getestet mit SDL Version 2.0.4):
Muss mit SDL2 gelinkt werden, sieht wie folgt aus:
"g++ ampelschaltung_sdl.c -w -lSDL2 -o ampel" (hier als "ampelschaltung_sdl.c" hinterlegt)

Features:
visueller Verkehrsfluss bei dem die Autos gerade aus fahren
Ampelschaltung mit normalen Phasen und Gelb-Rot Phase
Autos werden von dem Ampeln gesteuert
Zufällige Fahrzeugfarben, danke für die Idee!
Das Verkehrsaufkommen ist zufällig.

*Wegen der tollen Idee von KapPiTN habe ich auch mal ein Video der SDL Version hochgeladen.
Video-Link


[src=c]/*
*
* Ampelschaltung v0.2b by theSplit @ 03.05.15
* for the new gulli board coding competition
*
*/

// C-Header inkludieren
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

// SDL Header inkludieren
#include <SDL2/SDL.h>
#include <SDL2/SDL_timer.h>
#include <SDL2/SDL_events.h>

// Funktions Deklaration
void schliesseSchaltung();
void ampelStatus(unsigned int ampelIndex);

void erstelleAmpel(unsigned int richtung);
void verbindeAmpel(unsigned int ampelIndex1, unsigned int ampelIndex2);
void lasseAutoPassieren(unsigned int i);

// Definition der Ampelzustände
enum ampelZustand {
AUSGESCHALTET = 0,
GRUEN = 1,
GELB = 2,
GELB_ROT = 3,
ROT = 4,
DEFEKT_GRUEN = -1,
DEFEKT_GELB = -2,
DEFEKT_ROT = -3,
DEFEKT = -4
};

// Ampel Phasen-Dauer Definition, sollten durch 500 teilbar sein, Angabe in Sekunden
// aufgrund der Berechnunsschrittgröße
enum ampelZeiten {
PHASE_GRUEN = 6000, // Dauer der Grün-Phase
PHASE_GELB = 2500, // Dauer der Gelb-Phase
PHASE_ROT = 7000, // Dauer der Rot-Phase
PHASE_GELB_ROT = 1500, // Dauer der Gelb-Rot Phase (Anfahrtssignal)
PHASE_ROT_ZUSATZ = 1500 // Extra Dauer nach aktiver Grün und Gelb Phase, in Rot-Phase, bevor die Kreuzung freigegeben wird
};

// Definition der Himmelsrichtungen für Erstellung, nur Orientierungsangabe
enum ampelRichtungen {
NORD = 0,
OST = 1,
SUED = 2,
WEST = 3
};

enum fahrtRichtungen {
GERADEAUS = 0,
LINKS = 1,
RECHTS = 2
};

// Auto Definition
typedef struct fahrzeugFarbe {
unsigned char r = 0;
unsigned char g = 0;
unsigned char b = 0;
};

typedef struct pkw {
bool kannFahren = false;
unsigned int fahrtRichtung = 0;
unsigned int warteZeit = 0;
int geschwindigkeit = 0;
int ps = 0;
int x = 0;
int y = 0;
fahrzeugFarbe farbe;

};



// Ampel Definition
typedef struct ampel {
int phase = ROT;
int vorgaengerPhase = ROT;
unsigned int index = 0;
unsigned int warteZeit = 0;
unsigned int warteZeitLimit = 0;
unsigned int prioritaet = 0;
unsigned int richtung = 0;
unsigned int inBetriebnahmen = 0;
unsigned int autosPassiert = 0;
int autosInWarteschlange = 0;
pkw fahrzeugListe[100];
ampel* partnerAmpel;
};

// Variablen Deklaration
static unsigned int ampelAnzahl = 0;
static ampel *ampelListe;
static int aktiveAmpel = -1;
static int aktuelleRunde = 0;
static int berechneRunden;

static unsigned int hoechsterIndex = 0;
static unsigned int hoechstePrioritaet = 0;
static unsigned int i, j = 0;
static unsigned int zufallsAmpel = 0;

// Zeichenvariablen
static int lineYStart = 0;
static int lineXStart = 0;

// SDL Deklaration
static SDL_Window *appWindow = NULL;
static SDL_Renderer *appRender = NULL;

static const int windowWidth = 640;
static const int windowHeight = 640;


int main() {
// Beenden Funktion definieren die den Speicher freigibt
atexit(schliesseSchaltung);

// Verkehrsampeln erstellen
printf("Verkehrsampeln in Erstellung: %d\n", 4);
erstelleAmpel(NORD);
erstelleAmpel(OST);
erstelleAmpel(SUED);
erstelleAmpel(WEST);

// Die Partner-Ampel verbinden die gegenüber liegen
verbindeAmpel(0, 2);
verbindeAmpel(1, 3);

// SDL Video initialisieren
SDL_Init(SDL_INIT_VIDEO);

appWindow = SDL_CreateWindow("Ampelschaltung by theSplit for ngb", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, windowWidth, windowHeight, 0);
appRender = SDL_CreateRenderer(appWindow, -1, SDL_RENDERER_ACCELERATED);
SDL_Event eventHandle;

// Hauptschleife
while (true) {

if (SDL_PollEvent(&eventHandle)) {
if (eventHandle.type == SDL_QUIT) {
return(EXIT_SUCCESS);
}
}

// Wartezeit um 500ms bei jeder Ampel erhöhen
for (i = 0; i < ampelAnzahl; i++) {
ampelListe.warteZeit += 15;
}

// Fahrzeuge zufällig an Ampel erhöhen
if (rand() % 70 == 69) {
zufallsAmpel = rand() % ampelAnzahl;

ampelListe[zufallsAmpel].autosInWarteschlange++;

// Auskommentiert um nicht ständig zu printen
// printf("Autos in Schlange von Ampel-Index %d: %d\n", zufallsAmpel, ampelListe[zufallsAmpel].autosInWarteschlange);

// Überlauf verhindern, nicht weiter relevant
if (ampelListe[zufallsAmpel].autosInWarteschlange > 100) {
ampelListe[zufallsAmpel].autosInWarteschlange = 100;
} else {
// Neues Auto für Ampel erstellen
pkw fahrzeug;
fahrzeug.fahrtRichtung = rand() % 3;
fahrzeug.warteZeit = 0;
fahrzeug.geschwindigkeit = 0;
fahrzeug.ps = 140;
fahrzeug.farbe.r = (unsigned char) rand() % 151 + 70;
fahrzeug.farbe.g = (unsigned char) rand() % 151 + 70;
fahrzeug.farbe.b = (unsigned char) rand() % 151 + 70;
fahrzeug.kannFahren = false;

// An Eckkoordinaten, außerhalb des Fensters, erstellen
int baseX = 0;
int baseY = 0;
switch (ampelListe[zufallsAmpel].richtung) {
case OST:
baseX = windowWidth;
baseY = 270;
break;
case WEST:
baseX = -55;
baseY = 350;
break;
case NORD:
baseX = 280;
baseY = -55;
break;
case SUED:
baseX = 340;
baseY = windowHeight;
break;
}
fahrzeug.x = baseX;
fahrzeug.y = baseY;


// Fahrzeug in die Liste der Fahrzeuge kopieren (auf 100 begrenzt)
memcpy(&ampelListe[zufallsAmpel].fahrzeugListe[ampelListe[zufallsAmpel].autosInWarteschlange-1], &fahrzeug, sizeof(pkw));
}
}

// Welche Ampel hat die höchste Priorität und muss aktiviert werden?
hoechsterIndex = 0;
hoechstePrioritaet = ampelAnzahl > 0 ? ampelListe[0].prioritaet : 0;
for (i = 0; i < ampelAnzahl; i++) {
if (ampelListe.prioritaet > hoechstePrioritaet) {
hoechsterIndex = i;
hoechstePrioritaet = ampelListe.prioritaet;
}
}

// Ampelschaltung Logik
for (i = 0; i < ampelAnzahl; i++) {
if (aktiveAmpel == -1 || ampelListe.warteZeit >= ampelListe.warteZeitLimit) {

// Wenn wir eine aktive Ampel haben, ist dies die aktive bzw. deren Partnerampel?
// Falls nicht die Ampel Prioriät erhöhen
if (aktiveAmpel != -1 && (aktiveAmpel != i && (ampelListe.partnerAmpel != NULL && ampelListe.partnerAmpel->index != i))) {
ampelListe.prioritaet++;
continue;
}

// Keine aktive Ampel, ist dies eine der Ampeln mit der höchsten Priorität bzw. deren Partnerampel falls vorhanden?
// Falls nicht die Ampel Prioriät erhöhen
if (aktiveAmpel == -1 && (hoechsterIndex != i && (ampelListe.partnerAmpel != NULL && ampelListe.partnerAmpel->index != hoechsterIndex))) {
ampelListe.prioritaet++;
continue;
}

// Aktive Ampel setzen und eventuelle Partnerampel
// einspannen falls gesetzt
aktiveAmpel = i;
ampelListe.warteZeit = 0;
ampelListe.prioritaet = 0;

if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->warteZeit = 0;
ampelListe.partnerAmpel->prioritaet = 0;
}

// Wechsele die Phasen der Ampel nach aktuellem Farbenstand
switch (ampelListe.phase) {
case ROT:
// Phase Rot
if (ampelListe.vorgaengerPhase == GELB) {
// Wenn die Ampel vorher auf Gelb stand,
// also die Rotphase + Wartezeit rum ist,
// platz für die nächste Ampel geben
aktiveAmpel = -1;
ampelListe.warteZeit = 0;
ampelListe.prioritaet = 0;
ampelListe.vorgaengerPhase = ROT;
ampelListe.warteZeitLimit = PHASE_ROT;


if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->warteZeit = 0;
ampelListe.partnerAmpel->prioritaet = 0;
ampelListe.partnerAmpel->vorgaengerPhase = ROT;
ampelListe.partnerAmpel->warteZeitLimit = PHASE_ROT;
}

continue;
}

// Die Ampel schaltet von Rot auf Gelb und wird somit in Betrieb genommmen
ampelListe.inBetriebnahmen++;

// Schutz vor Überlauf, nicht relevant
if (ampelListe.inBetriebnahmen == 1000000) {
ampelListe.inBetriebnahmen = 0;
}

// Partnerampel auch auf Betrieben setzen
if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->inBetriebnahmen = ampelListe.inBetriebnahmen;
}

// Gelb-Rot als aktuelle Phase setzen
ampelListe.phase = GELB_ROT;
ampelListe.warteZeitLimit = PHASE_GELB_ROT;

// Von Rot auf Gelb geschaltet, Vorgängerphase ist nun Rot
ampelListe.vorgaengerPhase = ROT;

// Das selbe für die Partnerampel machen
if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->phase = GELB_ROT;
ampelListe.partnerAmpel->warteZeitLimit = PHASE_GELB_ROT;
ampelListe.partnerAmpel->vorgaengerPhase = ROT;
}
break;
case GELB_ROT:
// Phase ist Gelb-Rot auf Grün setzen
ampelListe.phase = GRUEN;
ampelListe.warteZeitLimit = PHASE_GRUEN;
ampelListe.vorgaengerPhase = GELB_ROT;

// Für die Partnerampel auch wenn gesetzt
if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->phase = GRUEN;
ampelListe.partnerAmpel->warteZeitLimit = PHASE_GRUEN;

ampelListe.partnerAmpel->vorgaengerPhase = GELB_ROT;
}

// Lasse Autos über die Ampel fahren (8)
// Nicht mehr nötig in SDL Version
//lasseAutoPassieren(i);

break;
case GELB:
// Phase ist Gelb
if (ampelListe.vorgaengerPhase == GRUEN) {
// Phase von vorher Grün auf Rot setzen,
// neues WarteZeitLimit setzen
ampelListe.phase = ROT;
ampelListe.warteZeitLimit = PHASE_ROT_ZUSATZ;
ampelListe.vorgaengerPhase = GELB;

// Für die Partnerampel auch wenn gesetzt
if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->phase = ROT;
ampelListe.partnerAmpel->warteZeitLimit = PHASE_ROT_ZUSATZ;

ampelListe.partnerAmpel->vorgaengerPhase = GELB;
}

} else if (ampelListe.vorgaengerPhase == ROT) {
// Phase war Rot, nun auf Grün schalten,
// neue WarteZeitLimit setzen
ampelListe.phase = GRUEN;
ampelListe.warteZeitLimit = PHASE_GRUEN;

ampelListe.vorgaengerPhase = GELB;

if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->phase = GRUEN;
ampelListe.partnerAmpel->warteZeitLimit = PHASE_GRUEN;

ampelListe.partnerAmpel->vorgaengerPhase = GELB;
}

// Lasse Autos über die Ampel fahren (8)
// Nicht mehr nötig in SDL Version
//lasseAutoPassieren(i);

}
break;
case GRUEN:
// Von Grün auf Gelb schalten
// Vorgängerphase setzen, neues WarteZeitLimit setzen
ampelListe.phase = GELB;
ampelListe.vorgaengerPhase = GRUEN;

ampelListe.warteZeitLimit = PHASE_GELB;

if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->phase = GELB;
ampelListe.partnerAmpel->warteZeitLimit = PHASE_GELB;

ampelListe.partnerAmpel->vorgaengerPhase = GRUEN;
}
break;
}
}
}

// SDL Zeichenroutinen
SDL_Rect windowRect = {0, 0, windowWidth, windowHeight };
SDL_SetRenderDrawColor(appRender, 110, 110, 110, 255);
SDL_RenderClear(appRender);

// Straßen zeichnen
SDL_SetRenderDrawColor(appRender, 30, 30, 30, 255);
SDL_Rect strasseNordSued = {239, 0, 161, windowHeight};
SDL_Rect strasseWestOst = {0, 239, windowWidth, 161};
SDL_RenderFillRect(appRender, &strasseNordSued);
SDL_RenderFillRect(appRender, &strasseWestOst);

// Straßenlinien zeichnen
SDL_SetRenderDrawColor(appRender, 255, 255, 255, 255);

lineYStart = 10;
for (i = 0; i < 6; i++) {
SDL_RenderDrawLine(appRender, 320, lineYStart, 320, lineYStart+15);
lineYStart += 40;
}

lineYStart = 410;
for (i = 0; i < 6; i++) {
SDL_RenderDrawLine(appRender, 320, lineYStart, 320, lineYStart+15);
lineYStart += 40;
}

lineXStart = 10;
for (i = 0; i < 6; i++) {
SDL_RenderDrawLine(appRender, lineXStart, 320, lineXStart+15, 320);
lineXStart += 40;
}

lineXStart = 410;
for (i = 0; i < 6; i++) {
SDL_RenderDrawLine(appRender, lineXStart, 320, lineXStart+15, 320);
lineXStart += 40;
}

// Ampeln zeichnen
SDL_Rect zeichenAmpel = {180, 100, 40, 100};
SDL_Rect ampelLicht = {8, 10, 20, 20};

for (i = 0; i < ampelAnzahl; i++) {
SDL_SetRenderDrawColor(appRender, 80, 80, 80, 255);
SDL_Rect ampelLicht1 = {0, 0, 25, 25};
SDL_Rect ampelLicht2 = {0, 0, 25, 25};
SDL_Rect ampelLicht3 = {0, 0, 25, 25};

switch(ampelListe.richtung) {
case NORD:
zeichenAmpel = {180, 100, 40, 100};
break;
case OST:
zeichenAmpel = {420, 100, 40, 100};
break;
case SUED:
zeichenAmpel = {420, 420, 40, 100};
break;
case WEST:
zeichenAmpel = {180, 420, 40, 100};
break;
}

SDL_RenderFillRect(appRender, &zeichenAmpel);
ampelLicht1.x = zeichenAmpel.x + ampelLicht.x;
ampelLicht1.y = zeichenAmpel.y + ampelLicht.y;
ampelLicht2.x = zeichenAmpel.x + ampelLicht.x;
ampelLicht2.y = zeichenAmpel.y + ampelLicht.y + 30;
ampelLicht3.x = zeichenAmpel.x + ampelLicht.x;
ampelLicht3.y = zeichenAmpel.y + ampelLicht.y + 60;

// Rot zeichnen
if (ampelListe.phase == ROT || ampelListe.phase == GELB_ROT) {
SDL_SetRenderDrawColor(appRender, 255, 0, 0, 255);
} else {
SDL_SetRenderDrawColor(appRender, 0, 0, 0, 255);
}
SDL_RenderFillRect(appRender, &ampelLicht1);

// Gelb zeichnen
if (ampelListe.phase == GELB || ampelListe.phase == GELB_ROT) {
SDL_SetRenderDrawColor(appRender, 255, 255, 0, 255);
} else {
SDL_SetRenderDrawColor(appRender, 0, 0, 0, 255);
}
SDL_RenderFillRect(appRender, &ampelLicht2);

// Grün zeichnen
if (ampelListe.phase == GRUEN) {
SDL_SetRenderDrawColor(appRender, 0, 255, 0, 255);
} else {
SDL_SetRenderDrawColor(appRender, 0, 0, 0, 255);
}
SDL_RenderFillRect(appRender, &ampelLicht3);
}

// Fahrzeuge bewegen und aussortieren wenn außerhalb des Fensterbereichs
for (i = 0; i < ampelAnzahl; i++) {
int offsetX = 0;
int offsetY = 0;
unsigned int passedIndex = 0;
switch (ampelListe.richtung) {
case NORD:
// Berechnung für Norden
for (j = 0; j < ampelListe.autosInWarteschlange; j++) {
// Animiere die Autos hinein deren y kleiner als 170 ist (Kreuzungslinie)
if (ampelListe.fahrzeugListe[j].y < 170) {
// Haben wir einen Vorgänger, setze den Grenzwert y - mit y letztes Fahrzeug (Stoßstange an Stoßstange)
if (j > 0 && ampelListe.fahrzeugListe[j].y + 55 < ampelListe.fahrzeugListe[j-1].y) {
ampelListe.fahrzeugListe[j].y += 2;
} else if (j == 0) {
ampelListe.fahrzeugListe[j].y += 2;
}
} else if (ampelListe.fahrzeugListe[j].y > 190) {
// Ist das Fahrzeug schon über der Kreuzung, animiere weiter
ampelListe.fahrzeugListe[j].y += 2;
} else if (ampelListe.phase == GRUEN || ampelListe.phase == GELB_ROT || (ampelListe.phase == GELB && ampelListe.fahrzeugListe[j].y > 180)) {
// Ist das Auto noch nicht über die Kreuzung, achte auf die Ampelphasen oder überfahre wenn noch im gültigen Bereich
ampelListe.fahrzeugListe[j].y += 2;
}

// Ist das Auto außerhalb des Fensters animiert?
// Nimm den Index zum löschen auf
if (ampelListe.fahrzeugListe[j].y > windowHeight) {
passedIndex++;
}
}

break;
case OST:
// Gleiche Berechnung für Osten
for (j = 0; j < ampelListe.autosInWarteschlange; j++) {
if (ampelListe.fahrzeugListe[j].x > 430) {
if (j > 0 && ampelListe.fahrzeugListe[j].x - 55 > ampelListe.fahrzeugListe[j-1].x) {
ampelListe.fahrzeugListe[j].x -= 2;
} else if (j == 0) {
ampelListe.fahrzeugListe[j].x -= 2;
}
} else if (ampelListe.fahrzeugListe[j].x < 320) {
ampelListe.fahrzeugListe[j].x -= 2;
} else if (ampelListe.phase == GRUEN || ampelListe.phase == GELB_ROT || (ampelListe.phase == GELB && ampelListe.fahrzeugListe[j].x < 390)) {
ampelListe.fahrzeugListe[j].x -= 2;
}

if (ampelListe.fahrzeugListe[j].x < -55) {
passedIndex++;
}
}
break;
case SUED:
// Gleiche Berechnung für Süden
for (j = 0; j < ampelListe.autosInWarteschlange; j++) {
if (ampelListe.fahrzeugListe[j].y > 430) {
if (j > 0 && ampelListe.fahrzeugListe[j].y - 55 > ampelListe.fahrzeugListe[j-1].y) {
ampelListe.fahrzeugListe[j].y -= 2;
} else if (j == 0) {
ampelListe.fahrzeugListe[j].y -= 2;
}
} else if (ampelListe.fahrzeugListe[j].y < 320) {
ampelListe.fahrzeugListe[j].y -= 2;
} else if (ampelListe.phase == GRUEN || ampelListe.phase == GELB_ROT || (ampelListe.phase == GELB && ampelListe.fahrzeugListe[j].y < 390)) {
ampelListe.fahrzeugListe[j].y -= 2;
}

if (ampelListe.fahrzeugListe[j].y < -55) {
passedIndex++;
}
}
break;
case WEST:
// Gleiche Berechnung für Westen
for (j = 0; j < ampelListe.autosInWarteschlange; j++) {
if (ampelListe.fahrzeugListe[j].x < 170) {
if (j > 0 && ampelListe.fahrzeugListe[j].x + 55 < ampelListe.fahrzeugListe[j-1].x) {
ampelListe.fahrzeugListe[j].x += 2;
} else if (j == 0) {
ampelListe.fahrzeugListe[j].x += 2;
}
} else if (ampelListe.fahrzeugListe[j].x > 190) {
ampelListe.fahrzeugListe[j].x += 2;
} else if (ampelListe.phase == GRUEN || ampelListe.phase == GELB_ROT || (ampelListe.phase == GELB && ampelListe.fahrzeugListe[j].x > 200)) {
ampelListe.fahrzeugListe[j].x += 2;
}

if (ampelListe.fahrzeugListe[j].x > windowWidth) {
passedIndex++;
}
}
break;
}

// Anzahl der Fahrzeuge die das Fenster verlassen haben von Schlange entfernen
if (passedIndex > 0) {
memmove(&ampelListe.fahrzeugListe, &ampelListe.fahrzeugListe[passedIndex], sizeof(pkw) * (100 - passedIndex));
ampelListe.autosInWarteschlange -= passedIndex;
ampelListe.autosPassiert += passedIndex;

// Überlauf Schutz
if (ampelListe.autosPassiert > 250000) {
ampelListe.autosPassiert = 0;
}
}


}

// Fahrzeuge rendern
for (i = 0; i < ampelAnzahl; i++) {
ampel aktiveAmpel = ampelListe;
int offsetX = 0;
int offsetY = 0;
SDL_Rect zeichenFahrzeug = {0, 0, 0, 0};

switch (aktiveAmpel.richtung) {
case NORD:
case SUED:
offsetY = 20;
break;
case OST:
case WEST:
offsetX = 20;
break;
}

for (j = 0; j < aktiveAmpel.autosInWarteschlange; j++) {
SDL_SetRenderDrawColor(appRender, aktiveAmpel.fahrzeugListe[j].farbe.r, aktiveAmpel.fahrzeugListe[j].farbe.g, aktiveAmpel.fahrzeugListe[j].farbe.b, 255);
zeichenFahrzeug.x = aktiveAmpel.fahrzeugListe[j].x;
zeichenFahrzeug.y = aktiveAmpel.fahrzeugListe[j].y;
zeichenFahrzeug.w = 25 + offsetX;
zeichenFahrzeug.h = 25 + offsetY;
SDL_RenderFillRect(appRender, &zeichenFahrzeug);
}
}

// Fenster aktualisieren
SDL_RenderPresent(appRender);

// Verzögerung von 10 Millisekunden
SDL_Delay(10);
}

return (EXIT_SUCCESS);
}

// Eine Ampel erstellen
void erstelleAmpel(unsigned int richtung) {
// Test ob die Himmelsrichtung in einem gültigen Bereich liegt
// ist nicht wirklich relevant und könnte weggelassen werden,
// da die Ampeln selbst verwaltend sind
if (!(richtung >= 0 && richtung <= 3) ) {
printf("Keine gültige Himmelsrichtung für Ampel %d eingegeben\n", ampelAnzahl);
return;
}

// Speicher für neue Ampel erfragen
ampelListe = (ampel*) realloc(ampelListe, sizeof(ampel) * (ampelAnzahl + 1));

// Kein Speicher => Programfehler und beenden
if (ampelListe == NULL) {
printf("Konnte kein Speicher für die Ampelschaltungen belegen... Abbruch.");
schliesseSchaltung();
}

// Die Ampel anlegen
ampelListe[ampelAnzahl].index = ampelAnzahl;
ampelListe[ampelAnzahl].phase = ROT;
ampelListe[ampelAnzahl].vorgaengerPhase = ROT;
ampelListe[ampelAnzahl].warteZeit = PHASE_ROT;
ampelListe[ampelAnzahl].warteZeitLimit = PHASE_ROT+2000;
ampelListe[ampelAnzahl].prioritaet = 0;
ampelListe[ampelAnzahl].richtung = richtung;
ampelListe[ampelAnzahl].autosInWarteschlange = 0;
ampelListe[ampelAnzahl].inBetriebnahmen = 0;
ampelListe[ampelAnzahl].partnerAmpel = NULL;

ampelAnzahl++;
return;
}

// Zwei Ampeln verbinden, Partnerampel setzen wenn gegenüber
void verbindeAmpel(unsigned int ampelIndex1, unsigned int ampelIndex2) {
if (ampelIndex1 > ampelAnzahl || ampelIndex2 > ampelAnzahl) {
return;
}

ampelListe[ampelIndex1].partnerAmpel = &ampelListe[ampelIndex2];
ampelListe[ampelIndex2].partnerAmpel = &ampelListe[ampelIndex1];
}

// Funktion um Autos über die Ampeln fahren zu lassen
void lasseAutoPassieren(unsigned int i) {
// Lasse 8 Fahrzeuge passieren
ampelListe.autosInWarteschlange -= 8;



if (ampelListe.autosInWarteschlange < 0) {
ampelListe.autosPassiert += (8 + ampelListe.autosInWarteschlange);
ampelListe.autosInWarteschlange = 0;
} else {
ampelListe.autosPassiert += 8;
}

// Schutz vor Überlauf
if (ampelListe.autosPassiert > 150000) {
ampelListe.autosPassiert = 0;
}

// Das gleiche für die Partnerampel
if (ampelListe.partnerAmpel != NULL) {
ampelListe.partnerAmpel->autosInWarteschlange -= 8;
if (ampelListe.partnerAmpel->autosInWarteschlange < 0) {
ampelListe.partnerAmpel->autosPassiert += (8 + ampelListe.partnerAmpel->autosInWarteschlange);
ampelListe.partnerAmpel->autosInWarteschlange = 0;
} else {
ampelListe.partnerAmpel->autosPassiert += 8;
}

// Schutz vor Überlauf
if (ampelListe.partnerAmpel->autosPassiert > 150000) {
ampelListe.partnerAmpel->autosPassiert = 0;
}
}

return;
}

// Ampelstatus ausgeben, nicht mehr in SDL Version verwendet
void ampelStatus(unsigned int ampelIndex) {
ampel Ampel = ampelListe[ampelIndex];
printf("Ampel-Status:\n");

char *ampelStatusPhase;
char *ampelStatusRichtung;

switch (Ampel.phase) {
case AUSGESCHALTET:
ampelStatusPhase = "Ausgeschaltet";
break;
case GRUEN:
ampelStatusPhase = "Grün";
break;
case GELB:
ampelStatusPhase = "Gelb";
break;
case GELB_ROT:
ampelStatusPhase = "Gelb-Rot";
break;
case ROT:
ampelStatusPhase = "Rot";
break;
case DEFEKT_GRUEN:
ampelStatusPhase = "Defekt Grün";
break;
case DEFEKT_GELB:
ampelStatusPhase = "Defekt Gelb";
break;
case DEFEKT_ROT:
ampelStatusPhase = "Defekt Rot";
break;
case DEFEKT:
default:
ampelStatusPhase = "genereller defekt";
break;
}

switch (Ampel.richtung) {
case NORD:
ampelStatusRichtung = "Nord";
break;
case OST:
ampelStatusRichtung = "Ost";
break;
case SUED:
ampelStatusRichtung = "Süd";
break;
case WEST:
ampelStatusRichtung = "West";
break;
}

printf("Ampelindex: %i\n", ampelIndex);
printf("Richtung: %s\n", ampelStatusRichtung);
printf("Phase: %s\n", ampelStatusPhase);
printf("In Betriebnahmen: %d\n", Ampel.inBetriebnahmen);
printf("Aktuelle Warezeit in Phase (Sekunden): %.2f\n", (float) Ampel.warteZeit / 1000);
printf("Normale Wartezeit in Phase (Sekunden): %.2f\n", (float) Ampel.warteZeitLimit / 1000);
printf("Aktuelle Priorität: %d\n", Ampel.prioritaet);
printf("Partner-Ampel Index: %d\n", Ampel.partnerAmpel != NULL ? Ampel.partnerAmpel->index : -1);
printf("Autos in Schlange: %d\n", Ampel.autosInWarteschlange);
printf("Passierte Autos: %d\n\n", Ampel.autosPassiert);

return;
}

// Anwendung beenden
void schliesseSchaltung() {
// Speicher der Ampeln freigeben
printf("Ampelspeicher freigeben...\n");
free(ampelListe);

// SDL aufräumen
printf("SDL-Ressourcen freigeben...\n");
SDL_DestroyRenderer(appRender);
SDL_DestroyWindow(appWindow);
SDL_Quit();
printf("Ampelschaltung beendet.\n\n");
exit(EXIT_SUCCESS);
}
[/src]
 
Zuletzt bearbeitet:

KaPiTN

♪♪♫ wild at heart ♪♫♫♪

Registriert
14 Juli 2013
Beiträge
29.138
Da ich beim Berufspendeln ja bereits im Kopf programmiert habe (C#), habe ich es dann halt mal aufgeschrieben. Jetzt muß ich das noch dokumentieren oder zumindest kommentieren (Christi Himmelfahrt? :unknown:), dann poste ich das auch. Änderungen gibt es sicher auch noch. Ich habe gar keine Verkehrssteuerung drin, fällt mir gerade ein.

So sieht es in etwas aus:

kr.gif

Statt zu dokumentieren, mußte der Verkehrsfluß dynamischer werden. Das galt aber dann auch für den Code.

 
Zuletzt bearbeitet:
Oben