lehrkraefte:blc:informatik:ffprg1-2023:js-connect-4:start

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
lehrkraefte:blc:informatik:ffprg1-2023:js-connect-4:start [2023/04/04 11:00] – [Mögliche Lösung] Ivo Blöchligerlehrkraefte:blc:informatik:ffprg1-2023:js-connect-4:start [2023/05/16 09:49] (current) – [Computer Gegner] Ivo Blöchliger
Line 1: Line 1:
 +====== 4-Gewinnt ======
 +<WRAP todo>
 +**Vorbereitung**
  
 +Laden Sie sich folgendes zip-File herunter: {{lehrkraefte:blc:informatik:ffprg1-2023:js-connect-4:06-connect-4.zip}}
 +
 +Das Archiv enthält mehrere Unterverzeichnisse mit dem Spiel.
 +</WRAP>
 +
 +===== Spielfeld generieren, CSS-Tricks =====
 +<WRAP todo>
 +  * Studieren Sie den HTML, CSS und JS-Code im Verzeichnis ''01-connect-4'' und testen Sie diesen Code. Studieren Sie auch die Ausgabe auf der Console.
 +  * Schaffen Sie es, dass die Farbe eines Felds auf rot (oder blau) gesetzt wird, wenn man darauf klickt?
 +  * Verstehen Sie den Zusammenhang zwischen der Zeile ''div.className = feldklassen[wert];'' und der CSS-Datei.
 +  * Wenn Sie möchten, finden Sie besseren CSS-Code für die Felder (angefangen bei den Farben). Es sind mit CSS auch runde Felder bzw. Hintergrundbilder möglich.
 +
 +</WRAP>
 +
 +===== Spielfeld Zustand speichern und manipulieren =====
 +So wie es im Moment programmiert ist, ist die Information über den Feldzustand an zwei Orten gespeichert: Im Attribut ''wert'' und in der Klasse des jeweiligen Elements (eine von ''feldleer'', ''feldeins'' und ''feldzwei'').
 +
 +Zum Auslesen und Setzen dieser Werte ist das aber unpraktisch.
 +
 +<WRAP todo>
 +  * Schreiben Sie eine Funktion ''getWert(div)'' die den Wert als Zahl zurück gibt (benutzen Sie die ''Number()''-Funktion, damit man nicht den String (Zeichenkette) erhält.
 +  * Schreiben Sie eine Funtion ''setWert(div, wert)'', die das ''wert''-Attribut setzt und auch die entsprechende Klasse.
 +  * Testen Sie die Funktion, indem Sie damit das Feld jeweils «eins weiter» schalten beim Klicken.
 +  * Implementieren Sie eine ''reset''-Funktion, die alle Felder auf grau setzt (verwenden Sie dazu folgendes):
 +<code javascript>
 +for (let div of spieldfeld.children) {
 +  // ...
 +}
 +</code>
 +  * Implementieren Sie eine Funktion ''getDiv(spalte, zeile)'', die das richtige Element aus den 42 Elementen zurückliefert mit ''spielfeld.children.item(nummer)'', wobei ''nummer'' natürlich aus ''spalte'' und ''zeile'' berechnet werden muss.
 +</WRAP>
 +
 +===== Spielablauf =====
 +<WRAP todo>
 +  * Überlegen Sie sich, was alles bekannt sein muss, um einen beliebigen Spielzustand im «Vier gewinnt» zu beschreiben und wie man dies in Variablen speichern könnte.
 +  * Fügen Sie diese Variablen im Code hinzu und initialisieren Sie diese in der ''reset''-Funktion.
 +  * Bei einem klick auf ein Feld soll überprüft werden, ob überhaupt noch ein Stein in die entsprechende Spalte gesetzt werden kann, und wenn ja, auf welcher Höhe.
 +  * Die Farben sollen immer abwechseln.
 +</WRAP>
 +
 +===== Spielende überprüfen =====
 +Das Spiel kann auf zwei Arten enden: 
 +  * Alle Plätze sind besetzt
 +  * Jemand hat vier in einer Reihe
 +Der erste Fall kann relativ einfach überprüft werden, indem einfach gezählt wird, wie viele Steine schon gesetzt wurden.
 +
 +Der zweite Fall hat viel mehr Fleisch am Knochen. Überlegen Sie sich Strategien dazu.
 +
 +==== Mögliche Lösung ====
 +
 +<code javascript>
 +// Zugriff auf Feld etwas vereinfachen:
 +function getValueAt(x,y) {
 +   // wenn x,y nicht auf dem Brett, 0 züruckgeben
 +   // sonst den Wert vom Feld x,y
 +}
 +
 +// Gibt die Anzahl gleicher Felder an, wenn man bei (startx, starty) startet und in Richtung (dx,dy) weiter geht.
 +// Ist das Startfeld schon 0, wird sofort 0 zurückgegeben
 +function count(startx, starty, dx, dy) {
 +   let wert = getValueAt(startx,starty);             // Wert auf Startfeld
 +   if (wert==0) return 0;                            // Keine Nuller zählen
 +   let anzahl = 0;
 +   while (wert==getValueAt(startx,starty)) {         // Immer noch das Gleiche?
 +       anzahl++;
 +       startx+=dx;                                   // Vorwärts
 +       starty+=dy;
 +   }
 +   return anzahl;
 +}
 +
 +// Liefert true, wenn die Position (x, y) Teil eines Vierers ist
 +function pruefen(x, y) {
 +    let dirs = [[1,0], [1,1], [0,1], [-1,1]]; // Trigonometrisch, 45 Grad Schritte.
 +    for (let d of dirs) {
 +        let anzahl = count(x, y, d[0], d[1]) + 
 +                     count(x, y, -d[0], -d[1]) - 1;
 +        if (anzahl>=4) {
 +            return true;
 +        }
 +    }
 +    return false;
 +}
 +</code>
 +==== Popup-Nachricht / Gewinnsteine markieren ====
 +Um das Spielende anzuzeigen, könnte ein «Popup» verwendet werden.
 +  * Z.B. ein div, das normalerweise mit ''display:none;'' formatiert ist
 +  * Oder ein ''<dialog>''.
 +
 +Um die Gewinnsteine zu markieren, erweitern Sie die Funktion ''pruefen'' um einen Parameter (z.B. ''mark=false''), der angibt, ob die Felder markiert werden sollen.
 +Fügen Sie eine zusätzliche Klasse in der CSS-Datei an, die angibt, wie die Felder markiert werden sollen, z.B. durch eine CSS-Animation mit ''filter:brightness(150%)''...
 +
 +
 +===== Computergegner =====
 +Idee: Bis zu einer gewissen Tiefe alle möglichen Züge durchprobieren und jeweils den besten davon auswählen und dessen Bewertung zurückgeben. Ist die maximale Tiefe erreicht, wird die Spielsituation heuristisch bewertet.
 +
 +Eine mögliche, minimale Implementation finden Sie hier: {{lehrkraefte:blc:informatik:ffprg1-2023:js-connect-4:04-computer-opponent.zip}}