Im letzten Teil haben wir den ersten Schritt in die JavaScript-Welt getan. Nun geben wir etwas Gas und programmieren einen Schachturnier Manager. Der Sprung erscheint auf den ersten Blick als groß, aber im Kern sind die meisten Aufgaben lediglich Erweiterungen von Grundlagen.
Das Ziel
Der Schachturnier Manager sollte folgende Kriterien erfüllen:
- Man soll die Anzahl der Spieler festlegen können.
- Man soll die Namen der Spieler eingeben können.
- Die Paarungen sollten angegeben werden können.
- Die Ergebnisse sollen eingegeben werden.
- Die Tabelle soll erzeugt werden.
- Die Seite soll nicht laufend neu geladen werden müssen.
Neben den wesentlichen Zielen gibt es noch sekundäre. Zum Beispiel die Überprüfung, dass die Anzahl der Spieler eine gerade Zahl sein muss. Bei den Ergebnissen ist es wichtig, dass, wie im Schach üblich, nur die Zahlen 0, 0,5 und 1 möglich sind.
Was wir nicht machen werden: Es gibt keinen Spielplan-Generator. Das hätte den Rahmen gesprengt. Ich liefere dazu unten weitere Informationen, falls sich jemand dafür interessiert. Die Tabelle wird am Ende nur Alphabetisch sortiert, aber auch dazu gibt es ein paar Hinweise.
Hier kann das Ergebnis angeschaut und getestet werden.
index.html
Wie in den vergangenen Tutorials auch, brauchen wir eine index.html. Außerdem lediglich eine main.js, die wir im Ordner js anlegen.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <!DOCTYPE html> <html lang="de"> <head> <meta charset="utf-8"> <title>Schachturnier Manager</title> <script src="js/main.js"></script> </head> <body> <h1>Schachturnier Manager</h1> <div id="spielerZahl"> <p>Geben Sie die Anzahl der Spieler ein. Für das Turnier werden <b>nur gerade Zahlen</b> zugelassen.</p> <form id="form1" action="javascript:;" onsubmit="step1(document.getElementById('zahl').value)"> <input type="number" id="zahl" min="2" step="2" value="6" required> <button type="submit">Abschicken</button> </form> </div> <div id="spielerNamen"> <form id="form2" action="javascript:;" onsubmit="step2()"> </form> </div> <div id="ergebisse"> <form id="form3" action="javascript:;" onsubmit="step3()"> </form> </div> <div id="tabelle"> </div> </body> </html> |
Wer sich das fertige Programm angeschaut hat, wird vielleicht ein wenig staunen, dass wir so wenig in der index.html stehen haben. Nahezu alles, was wir brauchen, ist in der JavaScript Datei und wird nach Bedarf in die Divs gelegt, aber dazu gleich mehr.
Über den Header muss ich nicht mehr reden. Dazu habe ich schon genug Worte in den vorherigen Tutorials verloren. Wir konzentrieren uns also auf den body-Bereich. Neben der Überschrift (h1) finden wir nur vier Div-Bereiche. In drei davon finden wir noch Formulare.
<div> steht für Division, man kann es auch als Sektion bezeichnen. Innerhalb einer Sektion kann man alles mögliche anlegen. Sektionen können Klassen zugeordnet werden, was später in Bezug auf CSS interessant sein wird. Momentan ist für uns die Möglichkeit spannend, dass wir IDs vergeben können. Das kann man nicht nur bei Divs so machen, sondern, wie man sehen kann, auch bei Formularen. Nachher werden wir sehen, dass das auch bei Eingabefeldern funktioniert.
Die ID ist wichtig, damit wir die Positionen später finden. Hier werden Werte entweder ausgelesen oder Inhalte platziert bzw. auch gelöscht.
Im ersten div haben wir ein kleines Formular mit einem Button. Damit etwas passiert, wenn wir den Knopf rücken, haben wir das Formular wie folgt definiert:
1 | <form id="form1" action="javascript:;" onsubmit="step1(document.getElementById('zahl').value)"> |
Mit action und onsubmit sorgen wir dafür, dass die Funktion step1 in der JS-Datei ausgeführt wird. Mit document.getElementById(‘zahl’).value übergeben wir einen Parameter an die Funktion step1. Der Parameter ist die Anzahl der Spieler.
Wer kontrolliert wen?
Besonders bei Formularen kommt man nicht umhin, die Eingaben zu kontrollieren. Früher war das eine große Aufgabe von JavaScript. Da der HTML-Standard aber irgendwann erweitert wurde, können wir viele Dinge bereits von HTML prüfen lassen.
1 | <input type="number" id="zahl" min="2" step="2" value="6" required> |
Das ist unser Eingabefeld vom Typ number. Man kann nur Zahlen, keine Buchstaben eingeben. Die Zahl muss mindestens 2 sein (min=”2″), muss gerade sein, was wir durch step=”2″ erreichen. Der Standardwert steht bei 6 (value=”6″). Der Zusatz required sagt aus, dass eine Eingabe erfolgen muss.
Die Kontrolle der Eingabe übernimmt der HTML-Part und wir können uns das in JavaScript alles sparen. Dennoch habe ich in der ersten Funktion eine kleine Kontrolle eingebaut, um zu zeigen, wie das aussehen kann.
JavaScript-Header
Was jetzt folgt, landet alles in der Datei main.js. Es gibt einen kleinen „header”, drei Funktionen und eine Bonusfunktion. Doch zunächst eine kurze Erklärung, was wir eigentlich wollen.
Das erste Formular haben wir in HTML erstellt. Ab jetzt übernimmt JavaScript. Die Eingaben werden verarbeitet und es wird jeweils ein neues Formular bzw. am Ende eine Tabelle erstellt. Zwischen den Funktionen müssen die Werte wie Anzahl Spieler und Spielernamen etc. gespeichert werden. Hierfür gibt es mehrere Möglichkeiten. Ich habe mich für ein Objekt entschieden. JavaScript ist eine klassenlose, objektorientierte Programmiersprache, also wollen wir dies auch ein bisschen nutzen.
1 2 3 4 5 6 7 8 9 | "use strict"; let schachturnier = new Object(); schachturnier.spielerZahl = 0; schachturnier.spielLos = 0; schachturnier.spielerNamen = []; schachturnier.spielerPunkte = []; schachturnier.spielerSiege = []; schachturnier.spielerUnentschieden = []; schachturnier.spielerNiederlagen = []; |
Wir erstellen ein Objekt mit dem Namen schachturnier. In dieses Objekt speichern wir einige Variablen und Arrays. Das System lässt sich natürlich erweitern. Wir brauchen:
- spielerZahl -> Anzahl Spieler
- spielLos -> Das sind die Select-Felder bei den Spielernamen im Spielplan
- spielerNamen -> Ein Array mit den Namen der Spieler
- spielerPunkte, spielerSiege, spielerUnentschieden und spielerNiederlagen zählt später die entsprechenden Resultate pro Spieler auf
function step1(zahl)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | // Spielername function step1(zahl) { if ((zahl%2)===0) { document.getElementById('spielerZahl').innerHTML = „"; // Wir löschen den Inhalt des ersten Formulars schachturnier.spielerZahl = zahl; let formular = '<br><p>Geben Sie die Namen der Spieler ein:</p>'; let counter = 1; for (let i=0; i<zahl; i++) { formular += '<input type=\"text\" id=\"s' + counter + '\" placeholder=\"Spieler ' + counter + '" required><br>'; counter++; } formular += '<br><button type=\"submit\">Abschicken</button>'; document.getElementById('form2').innerHTML = formular; } else { let output = zahl + ' ist keine gerade Zahl!'; alert(output); } return false; } |
Was diese Funktion macht: Sie prüft, ob die Zahl der Spieler gerade ist. Wenn ja, wird das alte Formular gelöscht und ein neues Formular erstellt. Wenn nein, gibt sie eine Fehlermeldung aus.
Schauen wir es im Detail an.
1 | if ((zahl%2)===0) |
Damit prüfen wir, ob die Zahl gerade ist.
1 | document.getElementById('spielerZahl').innerHTML = „"; |
Im Kommentar steht zwar, dass wir den Inhalt löschen, aber so ganz richtig ist es nicht. Der Inhalt wird nicht gelöscht, er wird lediglich gegen nichts (“”) ersetzt. Das ist ein feiner Unterschied. Konkret wird auch nicht das Formular, sondern der ganze Inhalt von <div id=”spielerZahl”> ersetzt. Für den Anwender verschwindet er einfach.
1 | schachturnier.spielerZahl = zahl; |
Hier übergeben wir die Spielerzahl an das Objekt. In den nachfolgenden Funktionen wird dieser Wert übergeben. So müssen wir nicht laufend von einer Funktion Werte an eine andere Funktion übergeben.
1 | let formular = '<br><p>Geben Sie die Namen der Spieler ein:</p>'; |
Die Variable formular wird später der neue Inhalt. Zunächst weisen wir ihr die erste Zeile zu. Es ist leicht zu erkennen, dass wir innerhalb der einfachen Anführungszeichen HTML-Code haben. <br> ist der Zeilenumbruch. <p> ist der Paragraph mit dem entsprechenden Text darin. Man muss es ein bisschen auf sich wirken lassen, aber dann merkt man, dass sich dadurch viele coole Möglichkeiten ergeben.
1 2 3 4 5 6 7 8 9 | let counter = 1; for (let i=0; i<zahl; i++) { formular += '<input type=\"text\" id=\"s' + counter + '\" placeholder=\"Spieler ' + counter + '" required><br>'; counter++; } formular += '<br><button type=\"submit\">Abschicken</button>'; |
Mit der for-Schleife erzeigen wir die Eingabefelder für die Namen. Den counter nehmen wir, damit die Felder und der Platzhalter bei 1 und nicht bei 0 beginnen.
Wichtig ist immer das formular += ! Damit fügen wir der Variable formular neuen Content hinzu.
1 | document.getElementById('form2').innerHTML = formular; |
Damit fügen wir den Inhalt dem zweiten Formular mit der ID form2 hinzu.
function step2()
Bevor wir beginnen: Die nachfolgende Funktion beinhaltet keinen Spielplan-Generator. Das wäre wirklich zu viel des Guten geworden. Stattdessen bekommt man für die Anzahl der Spiele (Hin- und Rückspiel im Ligamodus) Auswahlfelder.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | // Partien function step2() { let zahl = schachturnier.spielerZahl; // Wir ermitteln das aktuelle Datum let today = new Date(); let dd = String(today.getDate()).padStart(2, '0'); let mm = String(today.getMonth() + 1).padStart(2, '0'); let yyyy = today.getFullYear(); today = dd + '.' + mm + '.' + yyyy; // heute ist... let formular = '<br><p>Geben Sie die Ergebnisse der Spiele für den ' + today + ' ein:</p>'; // Wir lesen die Namen aus dem vorherigen Formular und speichern sie im Objekt let counter = 1; for (let i=0; i<zahl; i++) { schachturnier.spielerNamen[i] = document.getElementById('s'+counter).value; counter++; } document.getElementById('spielerNamen').innerHTML = „"; // Wir löschen den Inhalt des zweiten Formulars let anzSpiele = Math.pow(zahl, 2)-zahl; // Wir berechnen die Anzahl der Spiele formular += '<table>'; formular += '<th>Paarung</th><th>Resultat</th>'; counter = 1; for (let x = 0; x<anzSpiele; x++) { formular += '<tr><td>'; // Auswahlfelder für die Spieler formular += '<select name="player" id="pf' + schachturnier.spielLos + '">'; formular += '<option value="-1" selected=\"selected\">Spieler wählen</option>'; for (let y = 0; y<zahl; y++) { formular += '<option value="' + y + '">' + schachturnier.spielerNamen[y] + '</option>'; } formular += '</select>' schachturnier.spielLos++; formular += ' - ' formular += '<select name="player" id="pf' + schachturnier.spielLos + '">'; formular += '<option value="-1" selected=\"selected\">Spieler wählen</option>'; for (let y = 0; y<zahl; y++) { formular += '<option value="' + y + '">' + schachturnier.spielerNamen[y] + '</option>'; } formular += '</select>' schachturnier.spielLos++; formular += '</td><td>'; formular += ' <input type=\"number\" id=\"g' + counter + '\"size=\"4\" min=\"0\" max=\"1\" step=\"0.5\" required> - '; counter++; formular += '<input type=\"number\" id=\"g' + counter + '\"size=\"4\" min=\"0\" max=\"1\" step=\"0.5\" required>'; formular += '</td></tr>'; counter++; } formular += '</table>'; formular += '<br><button type=\"submit\">Abschicken</button>'; document.getElementById('form3').innerHTML = formular; return false; } |
Viele Prinzipien haben wir uns bereits in der vorherigen Funktion angeschaut, weshalb ich nur auf das Wesentliche eingehe.
1 2 3 4 5 | // Wir ermitteln das aktuelle Datum let today = new Date(); let dd = String(today.getDate()).padStart(2, '0'); let mm = String(today.getMonth() + 1).padStart(2, '0'); let yyyy = today.getFullYear(); |
Wäre nicht nötig gewesen, dachte aber, dass es eine ganz gute Gelegenheit ist, ein wenig die Datumsfunktionen zu zeigen.
1 2 3 4 5 6 7 8 9 | // Wir lesen die Namen aus dem vorherigen Formular und speichern sie im Objekt let counter = 1; for (let i=0; i<zahl; i++) { schachturnier.spielerNamen[i] = document.getElementById('s'+counter).value; counter++; } document.getElementById('spielerNamen').innerHTML = „"; // Wir löschen den Inhalt des zweiten Formulars |
Klingt selbstredend, aber dennoch: Erst lesen wir die Namen aus dem vorherigen Formular aus, dann „löschen” wir es. Dabei werden die Namen in schachturnier.spielerNamen geschrieben.
1 | let anzSpiele = Math.pow(zahl, 2)-zahl; |
Die allgemeine Formel lautet: x2-x. Bei 6 Spielern gibt es 30 Spiele, bei 10 Spielern sogar 90.
1 |
for (let x = 0; x<anzSpiele; x++)[/crayon]
Für jedes Spiel erstellen wir eine Zeile in der Tabelle. In der Variable schachturnier.spielLos zählen wir hoch, wie viele Eingabefelder wir haben. Theoretisch hätten wir auch einfach anzSpiele * 2 nehmen können, aber da wir die Select-Felder durchnummerieren und wir ohnehin einen Counter brauchen (pro Zeile kommen wir auf zwei Felder) kann man das Problem gleich so lösen.
Was wir erzeugen, kann in etwa so aussehen:
Man muss wissen, dass in die Auswahlfelder die IDs der Spieler als Value angegeben werden. Deshalb ist default auch -1. Theoretisch könnte man dies noch abfragen, bevor es weiter geht. Wichtig ist momentan nur, dass wir den Wert auslesen und damit dem Spieler zuordnen können.
function step3()
Am Ende werden die Partien ausgewertet und in einer Tabelle dargestellt.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | // Tabelle function step3() { let zahl = schachturnier.spielerZahl; let los = schachturnier.spielLos; let player; let score; let counter = 1; let formular = '<h2>Tabelle</h2>'; // Auswertung der Spiele for (let i=0; i<los; i++) { // Spieler ID aus dem Auswahlfeld let e = document.getElementById('pf'+i); player = e.options[e.selectedIndex].value; // Wir schauen, ob die Variablen bereits definiert wurden if (typeof schachturnier.spielerPunkte[player] === „undefined") { schachturnier.spielerPunkte[player] = 0; schachturnier.spielerSiege[player] = 0; schachturnier.spielerUnentschieden[player] = 0; schachturnier.spielerNiederlagen[player] = 0; } score = document.getElementById('g'+counter).value; schachturnier.spielerPunkte[player] += +score; switch (score) { case '0': schachturnier.spielerNiederlagen[player] += 1; break; case '0.5': schachturnier.spielerUnentschieden[player] += 1; break; case '1': schachturnier.spielerSiege[player] += 1; break; } counter++; } document.getElementById('ergebisse').innerHTML = „"; // Wir löschen den Inhalt des dritten Formulars formular += '<table border=\"1\" id="\Tabelle\">'; formular += '<th>Spieler</th><th>S</th><th>U</th><th>N</th><th>Punkte</th>'; counter = 1; for (let x=0; x<zahl; x++) { formular += '<tr><td>'; formular += schachturnier.spielerNamen[x]; formular += '</td><td>'; formular += schachturnier.spielerSiege[x]; formular += '</td><td>'; formular += schachturnier.spielerUnentschieden[x]; formular += '</td><td>'; formular += schachturnier.spielerNiederlagen[x]; formular += '</td><td>'; formular += schachturnier.spielerPunkte[x]; formular += '</td></tr>'; counter++; } formular += '</table>'; document.getElementById('tabelle').innerHTML = formular; sortTable(); } |
Nachdem wir am Anfang die Variablen definiert und die Überschrift festgelegt haben, geht es bereits mit der ersten Schleife los.
1 | for (let i=0; i<los; i++) |
Das vorherige Formular wird noch nicht gelöscht. Wir gehen alle Felder durch und weisen die Resultate den entsprechenden Spielern zu.
1 2 3 4 5 6 | .value; </pre> <p>Damit lesen wir die ID des Spielers aus. Um es auf das oben stehende Screenshot zu beziehen: Volker hat die ID 0, Sven die ID 1 etc.</p> <pre class= lang_js decode_true „]// Spieler ID aus dem Auswahlfeld let e = document.getElementById('pf'+i); player = e.options[e.selectedIndex].value; |
Damit lesen wir die ID des Spielers aus. Um es auf das oben stehende Screenshot zu beziehen: Volker hat die ID 0, Sven die ID 1 etc.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | === „undefined ) { schachturnier.spielerPunkte[player] = 0; schachturnier.spielerSiege[player] = 0; schachturnier.spielerUnentschieden[player] = 0; schachturnier.spielerNiederlagen[player] = 0; } </pre]// Wir schauen, ob die Variablen bereits definiert wurden if (typeof schachturnier.spielerPunkte[player] === „undefined") { schachturnier.spielerPunkte[player] = 0; schachturnier.spielerSiege[player] = 0; schachturnier.spielerUnentschieden[player] = 0; schachturnier.spielerNiederlagen[player] = 0; } |
Das sieht komisch aus. Wir müssen schauen, ob die Variable definiert ist. Wenn nicht, weisen wir den vier Variablen, die alle zu einem Spieler gehören, den Wert 0 hinzu. Anschließend können wir damit arbeiten.
1 | score = document.getElementById('g'+counter).value; |
Wir lesen den Wert beim Ergebnis aus.
1 2 3 | += +score;</pre> <p>Nun addieren wir den Wert dem Player hinzu. Wichtig: Das <em>+= +score</em> sieht komisch aus, muss aber so sein. <em>+=</em> addiert dem vorhandenen Wert den neuen Wert hinzu. Das <em>+score</em> muss man so schreiben, damit JavaScript weiß, dass wir zwei Zahlen addieren. So wird aus 0 + 1 = 1 statt 0 + 1 = 01.</p> <pre class= lang_js decode_true „]schachturnier.spielerPunkte[player] += +score; |
Nun addieren wir den Wert dem Player hinzu. Wichtig: Das += +score sieht komisch aus, muss aber so sein. += addiert dem vorhandenen Wert den neuen Wert hinzu. Das +score muss man so schreiben, damit JavaScript weiß, dass wir zwei Zahlen addieren. So wird aus 0 + 1 = 1 statt 0 + 1 = 01.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | += 1; break; case '0.5': schachturnier.spielerUnentschieden[player] += 1; break; case '1': schachturnier.spielerSiege[player] += 1; break; } </pre> <p>Ja nach Niederlage, Unentschieden oder Sieg addieren wir der Zahl eins hinzu. Das brauchen wir später für die Tabelle.</p> <p>Wenn die Schleife durchlaufen wurde, können wir das vorherige Formular löschen und die Tabelle erstellen.</p> <pre class= lang_js decode_true „]switch (score) { case '0': schachturnier.spielerNiederlagen[player] += 1; break; case '0.5': schachturnier.spielerUnentschieden[player] += 1; break; case '1': schachturnier.spielerSiege[player] += 1; break; } |
Ja nach Niederlage, Unentschieden oder Sieg addieren wir der Zahl eins hinzu. Das brauchen wir später für die Tabelle.
Wenn die Schleife durchlaufen wurde, können wir das vorherige Formular löschen und die Tabelle erstellen.
1 | sortTable(); |
Am Ende rufen wir noch die Funktion sortTable(); auf, um die Tabelle zu sortieren. Das Skript kommt aber nicht von mir sondern von der w3school. Hier kann es angeschaut und heruntergeladen werden.
Spielplan Generator
Wie bereits zweimal gesagt, wäre das etwas zu viel gewesen. Der Sprung jetzt war bereits ohne den Generator recht groß. Wer Interesse hat, kann das Skript noch erweitern, etwa indem er die Rückrunde optional macht, zählt, wie viele Punkte die einzelnen Farben geholt haben etc.
Wer sich mit dem Generator befassen will, sollte sich folgende Seite anschauen: Kantenfärbungs Algorithmus
Einen Code, allerdings in PHP, findet man auf GitHub.
Ausblick
In der nächsten Folge bleiben wir bei JavaScript und wollen ein bisschen was mit Grafiken machen. Ich denke, von Daten hin und her schaufeln hat jetzt jeder genug. 😆
Überblick Webdev-Serie
Webentwicklung Grundkurs Teil 1 – Einstieg
Webentwicklung Grundkurs Teil 2 – Aufbau von Webseiten
Webentwicklung Grundkurs Teil 3 – Datei- und Ordnerstrukturen
Webentwicklung Grundkurs Teil 4 – Einstieg in JavaScript
Webentwicklung Grundkurs Teil 5 – Datenverarbeitung und Formulare mit JavaScript
Webentwicklung Grundkurs Teil 6 – Canvas kann was
Überblick Interviews
Interview mit Magnus Reiß – Webgamers
Interview mit Wolfgang Scheidle – Tischtennis Manager
Interview mit Warg – Drifting Souls II