Gunnar Bittersmann: Neues Anfänger-Tutorial für JavaScript: Tic-Tac-Toe

Beitrag lesen

problematische Seite

@@Felix Riesterer

Wäre es nicht sinnvoller, die Daten über den Spielverlauf in einer 3×3-Matrix zu halten? Intitial mit Nullen gefüllt, wenn ❌ ein Spielfeld belegt, wird eine 1 in das entsprechende Feld der Matrix eingetragen, bei ⭕ −1.

dann mach doch mal (am besten ein Fiddle-/CodePen-Beispiel)

Hab ich dann mal gemacht.

na, dann schauen wir einmal in das Beispiel, um zu sehen, inwiefern es sich als Alternative für ein Anfänger-Tutorial eignet.

Das ist Unsinn. Das Beispiel war niemals dafür gedacht, sich in deinem Sinne für ein Anfänger-Tutorial zu eignen.

Es war – wie aus dem Threadverlauf nachvollziebar – dazu bestimmt zu sehen, ob „es nicht sinnvoller [ist], die Daten über den Spielverlauf in einer 3×3-Matrix zu halten“. Nicht mehr und nicht weniger. Da ich schon meine Beispiele auf Codepen hatte, habe ich eins davon als Grundlage genommen und die Spiellogik hinzugefügt. Mein Fehler, ich hätte deinen Code aus dem Artikel verwenden müssen, um auch dir den direkten Vergleich zu ermöglichen.

und vergleiche anschließend die Komplexität des Codes.

Und zwar ausschließlich die Teile mit der Spiellogik.

Aber gut, beschäftigen wir uns erstmal mit was anderem:

Vergleichen wir einmal die Komplexität des Markups, welches im Artikel verwendet wird

Dabei vergleichen wir auch die Sinnhaftigkeit des Markups!

<!-- Wiki-Artikel -->
<table class="tic-tac-toe">
    <tbody>
        <tr>
            <td></td>
            <td></td>
            <td></td>
        <tr>
...
    </tbody>
</table>

Nichts da. Keine Schaltflächen. Du willst dich jetzt nicht daran erfreuen, dass kein Markup auch keine Komplexität hat, oder?

Lass uns mal an der Stelle eins klarstellen: Die Entscheidung, ob progressive enhancement in den Artikel gehört, ist eine technische. Die Entscheidung, ob Barrierefreiheit in den Artikel gehört, ist eine menschliche.

Wenn progressive enhancement rausfällt, sage ich: „Wie dumm! Der Artikel hat eine wertvolle Chance vertan.“ Wenn Barrierefreiheit rausfällt, sage ich: „Nein, das geht gar nicht!“

Das Mindest-Markup für das Tic-Tac-Toe ist

<table class="tic-tac-toe">
    <tbody>
        <tr>
            <td><button>Feld oben links</button></td>
            <td><button>Feld oben Mitte</button></td>
            <td><button>Feld oben rechts</button></td>
        <tr>
...
    </tbody>
</table>

Und du willst mir nicht erzählen, dass die Buttons für Anfänger unbegreiflich wären? Vor allem nicht, weil da noch ein Satz der Erklärung hinzukommt, wozu die Buttons da sind: Weil andere Elemente nicht (so ohne Weiteres) per Tastatursteuerung anwählbar sind.

Eine rein mit CSS gestaltete leere Tabellenzelle ist zwar eine Hürde für sehbehinderte (kann eine Braille-Zeile generated content darstellen?), aber […]

An die Stelle gehört kein Komma und schon gar kein Aber. An die Stelle gehört ein Punkt.

(Als AT für Sehbehinderte hätte ich eher Screenreader als Braille-Zeilen im Sinn.)

Die ganzen Formular-Elemente muss ein Anfänger bei Dir erst einmal lernen und ihren Sinn und Zweck außerhalb eines Formulars verstanden haben

Und das, wo schon nicht einmal du sie verstanden hast. Sie sind nicht wegen Barrierefreiheit da, sondern wegen progressive enhancement – Grundfunktionalität auch ohne JavaScript. Das hatte ich aber lang und breit erklärt.

Ebenso die ersten Codezeilen

if (document.querySelector)
{
    document.documentElement.classList.add('js');
    
    var ticTacToeElement = document.querySelector('#tic-tac-toe');
    var rowElements = ticTacToeElement.rows;
    
    for (var i = 0, cellElements; i < rowElements.length; i++)
    {
        cellElements = rowElements[i].cells;
        
        for (var j = 0, labelElement; j < cellElements.length; j++)
        {
            labelElement = cellElements[j].querySelector('label');
            cellElements[j].innerHTML = '<button data-row="' + i + '" data-column="' + j + '">' + labelElement.innerHTML + '</button>';
        }
    }

Die haben mit der Spiellogik nichts zu tun, sondern ersetzen die „ganzen Formular-Elemente“ im DOM durch die Buttons.

In einem Artikel, der auf progressive enhancement schpfeift, würde man die Buttons gleich ins Markup schreiben (s.o.) und diese Codezeilen fielen weg. (Sähe dann so aus.)

Jedenfalls darfst du die Zeilen beim Vergleich, ob „es nicht sinnvoller [ist], die Daten über den Spielverlauf in einer 3×3-Matrix zu halten“, nicht mitzählen.

Dass Anzahl der Zeilen und Komplexität von Code zwei grundverschiedene Dinge sind, hatte ich schon gesagt. Aber nochmal im Einzelnen:

function ticTacToeClickHandler(event)
{
    var targetElement = event.target;
    var parentElement = targetElement.parentElement;
    var row, column;
    
    if (targetElement.nodeName == 'BUTTON')
    {

Ja, ich bin Freund von Allman-Style: öffnende { in einer neuen Zeile. Wenn du LOC vergleichst, musst du das berücksichtigen.

        row = parseInt(targetElement.dataset.row);
        column = parseInt(targetElement.dataset.column);
        
        board[row][column] = isPlayerXMoving ? 1 : -1;

Das hätte man auch in einer Zeile erledigen können:

        board[parseInt(targetElement.dataset.row)][parseInt(targetElement.dataset.column)] = isPlayerXMoving ? 1 : -1;

Die Aufteilung auf mehrere Zeile dient eben gerade dazu, den Code besser lesbar und verständlich zu machen. Weniger LOC heißt eben nicht verständlicherer Code.

        if (gameOver())
        {
            alert('Game over. ' + (isPlayerXMoving ? '❌' : '⭕') + ' wins.');
        }
        else
        {
            isPlayerXMoving = !isPlayerXMoving;
        }

Auch hier hätte man Zeilen sparen können:

        if (gameOver()) alert('Game over. ' + (isPlayerXMoving ? '❌' : '⭕') + ' wins.');
        else isPlayerXMoving = !isPlayerXMoving;

Aber es gehört zur Wartbarkeit von Code, immer {}-Blöcke bei if, else, for etc. zu verwenden, auch bei nur einer Anweisung im Block.

    var sum;
    
    for (var i = 0; i < 3; i++)
    {
        sum = 0;

Das hätte auch ein Einzeiler sein können:

    for (var sum = 0, i = 0; i < 3; i++)
    {

Aber wäre der Code dadurch besser geworden?

        for (var j = 0; j < 3; j++)
        {
            sum += board[i][j];
        }
        
        if (Math.abs(sum) == 3)
        {
            return true;
        }
    }
    
    for (var j = 0; j < 3; j++)
    {
        sum = 0;
        
        for (var i = 0; i < 3; i++)
        {
            sum += board[i][j];
        }
        
        if (Math.abs(sum) == 3)
        {
            return true;
        }
    }

    sum = 0;

    for (var i = 0; i < 3; i++)
    {
        sum += board[i][i];
    }

    if (Math.abs(sum) == 3)
    {
        return true;
    }

    sum = 0;

    for (var i = 0; i < 3; i++)
    {
        sum += board[i][2 - i];
    }

    if (Math.abs(sum) == 3)
    {
        return true;
    }

    return false;
}

Das wäre der Kern gewesen, den du mit deinen Abfragen der Klassen im DOM hättest vergleichen sollen: Ist die Bildung der Summen und der Vergleich mit 3 einfacher als die Abfrage der Klassen mit AND verknüpt? An der Beantwortung bist du haarscharf vorbeigeschrammt.

Übrigens ist hier noch Optimierungspotential: Es muss nicht das gesamte Spielfeld geprüft werden, sondern nur die Zeile und Spalte und ggfs. Diagonale(n) des gerade ausgewählten Feldes.

Dein Code umfasst abzüglich aller Leerzeilen (Kommentare sind keine vorhanden) 91 Zeilen, also 50% mehr! Damit hast Du schon quantitativ bewiesen, dass Dein Ansatz nicht minimalistisch ist, für ein Anfänger-Tutorial also eher weniger gut geeignet.

Nein, damit hast du bewiesen, dass du 2. nicht zählen kannst und 1. nicht verstanden hast, dass das Zählen von Codezeilen kaum eine Aussage über Komplexität zulässt.

Außerdem ist er nicht in eine Funktion verpackt, sondern liegt im globalen Scope herum. Sowohl die ausschließlich zu dem Spiel gehörenden Funktionen […] als auch die Variablen […] sind Methoden bzw. Eigenschaften von window. Das sollte man Anfängern gleich von vornherein aber abempfehlen, auch wenn man das dahinter steckende Geheimnisprinzip noch nicht offen als solches thematisiert.

Wenn du das Ganze in einen IIFE packen willst – nur zu. Der Anfänger wird das Konstrukt nicht verstehen, und ein Erklärung dazu wäre für diesen Artikel wohl auch zu viel. Aber ja, das könnte man als best practise auch ohne Erklärung in den Code aufnehmen.

Was die tatsächliche Komplexität angeht, so wird in meinem Beispiel lediglich ein spezieller Attributwert von einer Sorte HTML-Element überprüft, bei Dir dagegen muss die ganze Menge an Eingabe-Elementen (select, option und button) abgeklappert werden

Wie gesagt: Das ist Unsinn.

Die Lösung mit einem alert-Aufruf ist in meinen Augen die schlechtestmögliche Lösung eines Problems, das mein Ansatz definitiv unaufdringlicher gelöst hat. Du kennst mit Sicherheit die Probleme, die ein alert in anderen Browsertabs/-fenstern verursacht. Wozu also Anfängern diese Unsitte beibriungen?

Die Ausgabe war von mir mal eben so hingerotzt. Da sollte natürlich eine vernünftige Ausgabe erfolgen.

Den Rest des GUI macht konsequent CSS - bis hin zur Ausgabe des Spielergebnisses.

Die Ausgabe ist aber Inhalt, gehört also ins DOM, nicht ins Stylesheet.

LLAP 🖖

PS:

Dazu kommt noch die Verwendung von id- anstelle von class-Attributen. Mehrere Spiele auf einer Seite (warum auch immer das nützlich oder sinnvoll sein mag) ist damit nicht gegeben.

Muss auch nicht, IMHO. Die Frage „Mehrere Spiele auf einer Seite nützlich oder sinnvoll?“ würde ich mal eben mit nein beantworten. Hier bringst du IMHO unnötige Komplexität in den Code.

--
„Wir haben deinen numidischen Schreiber aufgegriffen, o Syndicus.“
„Hat auf dem Forum herumgelungert …“
(Wachen in Asterix 36: Der Papyrus des Cäsar)
3 205

Neues Anfänger-Tutorial für JavaScript: Tic-Tac-Toe

Felix Riesterer
  • meinung
  • seitenbewertung
  • selfhtml-wiki
  1. 0
    Matthias Scharwies
    1. 0
      Felix Riesterer
      1. 0
        Matthias Apsel
        1. 0
          Felix Riesterer
          1. 0
            Der Martin
            1. 0
              Gunnar Bittersmann
              1. 0
                Der Martin
                1. 0
                  Gunnar Bittersmann
                  1. 0
                    Matthias Apsel
                    1. 0
                      Gunnar Bittersmann
                      1. 0
                        Der Martin
                        1. 0
                          Gunnar Bittersmann
                2. 0
                  Felix Riesterer
                  1. 0
                    Camping_RIDER
                    1. 0
                      Gunnar Bittersmann
                      1. 0
                        Camping_RIDER
          2. 0
            Gunnar Bittersmann
            1. 3
              Felix Riesterer
              1. 1
                Gunnar Bittersmann
                1. 0
                  Felix Riesterer
                  1. 0
                    Gunnar Bittersmann
                    1. 1
                      Matthias Apsel
                      1. 0
                        Gunnar Bittersmann
                        1. 0
                          Matthias Apsel
                          1. 0
                            Gunnar Bittersmann
                            1. 0
                              Camping_RIDER
                              1. 0
                                Gunnar Bittersmann
                                1. 0
                                  JürgenB
                                  1. 0
                                    Gunnar Bittersmann
                                    1. 0
                                      JürgenB
                                      1. 0
                                        Gunnar Bittersmann
                                2. 4
                                  Camping_RIDER
                                  1. 0
                                    Gunnar Bittersmann
                                    1. 0
                                      Camping_RIDER
                                      1. 0
                                        Gunnar Bittersmann
                                        1. 0
                                          Felix Riesterer
                                          1. 0
                                            Gunnar Bittersmann
                                            1. 0
                                              Camping_RIDER
                                              1. 0
                                                Gunnar Bittersmann
                                                1. 1

                                                  Kommunikation

                                                  Camping_RIDER
                                                  • meinung
                                                  • menschelei
              2. 0
                Richard Rüfenacht
                1. 0
                  Gunnar Bittersmann
                  1. 0
                    Richard Rüfenacht
                  2. 0
                    Auge
                    • meinung
                    • selfhtml-wiki
                    1. 0
                      Gunnar Bittersmann
                2. 0
                  Auge
                  • meinung
                  • selfhtml-wiki
    2. 0
      Gunnar Bittersmann
      1. 0
        Felix Riesterer
        1. 0

          Großes ẞ

          Gunnar Bittersmann
          • typografie
          1. 0
            Camping_RIDER
            1. 0
              Gunnar Bittersmann
              1. 0
                Camping_RIDER
                1. 0
                  Gunnar Bittersmann
                  1. 0
                    Camping_RIDER
                    1. 0
                      Der Martin
                      1. 0
                        Christian Kruse
                        1. 0
                          Der Martin
                        2. 0
                          Gunnar Bittersmann
                          1. 0
                            Christian Kruse
                            1. 0
                              Camping_RIDER
                            2. 0
                              Christian Kruse
                          2. 0
                            Der Martin
                            1. 0
                              Gunnar Bittersmann
                              • menschelei
                    2. 0
                      Matthias Apsel
            2. 0
              MudGuard
              1. 0
                Christian Kruse
              2. 0
                Gunnar Bittersmann
                1. 0
                  Felix Riesterer
              3. 0
                Gunnar Bittersmann
                1. 0
                  Matthias Apsel
          2. 2

            Großes ẞ - der Vollständigkeit halber

            Bai Se Wey
            1. 0
              Gunnar Bittersmann
              1. 1

                Großes ẞ - der Kleinlichkeit halber

                Bai Se Wey
      2. 0
        Klawischnigg
        1. 0
          Camping_RIDER
          • menschelei
  2. 0
    Gunnar Bittersmann
    1. 0
      JürgenB
      1. 0
        Matthias Apsel
        1. 0
          Christian Kruse
          1. 0
            JürgenB
            1. 0
              Tabellenkalk
          2. 0
            Camping_RIDER
      2. 0
        Gunnar Bittersmann
        1. 0
          Felix Riesterer
          1. 0
            Gunnar Bittersmann
            • selfhtml-wiki
            • svg
            1. 0
              Felix Riesterer
              1. 0
                Camping_RIDER
                1. 0
                  Gunnar Bittersmann
                  • selfhtml-wiki
                  • typografie
                  1. 0
                    Auge
                    1. 0
                      Gunnar Bittersmann
                      1. 0
                        Christian Kruse
                        1. 0
                          Gunnar Bittersmann
                          1. 3
                            Christian Kruse
              2. 0
                Gunnar Bittersmann
                1. 1
                  Camping_RIDER
                  1. 0
                    Gunnar Bittersmann
    2. 0
      Felix Riesterer
  3. 0
    JürgenB
    1. 0
      Felix Riesterer
      1. 0
        Gunnar Bittersmann
        1. 0
          Matthias Apsel
        2. 0
          Felix Riesterer
        3. 0
          Camping_RIDER
          1. 0
            Gunnar Bittersmann
            1. 0
              JürgenB
              1. 0
                Auge
              2. 0
                Camping_RIDER
              3. 0
                Gunnar Bittersmann
                1. 0
                  Gunnar Bittersmann
      2. 0
        JürgenB
  4. 4
    dedlfix
    1. 0
      Matthias Scharwies
      1. 0
        dedlfix
        1. 0
          Matthias Scharwies
          1. 0
            dedlfix
            1. 0
              Matthias Scharwies
              1. 0
                dedlfix
          2. 0
            Matthias Apsel
            1. 0
              Matthias Scharwies
            2. 0
              Camping_RIDER
    2. 0
      Felix Riesterer
      1. 0
        Gunnar Bittersmann
      2. 0
        dedlfix
  5. 0
    pl
    1. 0
      Felix Riesterer
      1. 0
        pl
        1. 0
          Gunnar Bittersmann
  6. 0
    Msass
  7. 5
    Gunnar Bittersmann
    1. 1
      dedlfix
      1. 0
        Gunnar Bittersmann
        1. 2
          Felix Riesterer
          1. 1
            Gunnar Bittersmann
            1. 1
              Felix Riesterer
              1. 0
                Gunnar Bittersmann
                1. 0
                  Gunnar Bittersmann
                  1. 0
                    Felix Riesterer
                    • meinung
                    • selfhtml-wiki
                2. 0
                  Felix Riesterer
                  • meinung
                  • selfhtml-wiki
            2. 3
              Matthias Apsel
    2. 0
      Matthias Apsel
      1. 0
        Matthias Apsel
        1. 2
          dedlfix
      2. 0
        Gunnar Bittersmann
        1. 0
          Felix Riesterer
          1. 0
            Gunnar Bittersmann
            1. 0
              Camping_RIDER
              1. 0
                Gunnar Bittersmann
                1. 1
                  Felix Riesterer
                  1. 0
                    Gunnar Bittersmann
                    1. 0
                      Felix Riesterer
            2. 0
              Felix Riesterer
              1. 0
                Gunnar Bittersmann
    3. 0
      Felix Riesterer
      1. 1
        Gunnar Bittersmann
        1. 0
          Gunnar Bittersmann
    4. 0

      Wer hat gewonnen?

      Matthias Apsel
      • javascript
      1. 0
        Gunnar Bittersmann
    5. 0
      Matthias Apsel
    6. 0
      Matthias Apsel
      1. 0
        Matthias Apsel
    7. 6
      Felix Riesterer
      1. 1
        Der Martin
        1. 1
          Felix Riesterer
          1. 0
            Matthias Scharwies
            1. 0
              Felix Riesterer
              1. 0
                Gunnar Bittersmann
          2. 1
            Gunnar Bittersmann
            1. 0
              Felix Riesterer
              1. 0
                Gunnar Bittersmann
                1. 0
                  Felix Riesterer
                  1. 0
                    Gunnar Bittersmann
                    1. 0
                      Matthias Apsel
                2. 1

                  Roter-Faden-Artikel in Wikis

                  Camping_RIDER
              2. 0
                Gunnar Bittersmann
      2. 1
        Gunnar Bittersmann
  8. 0
    Gunnar Bittersmann
    1. 0
      Felix Riesterer
      • meinung
      • selfhtml
      • selfhtml-wiki
    2. 0
      Camping_RIDER
  9. 1
    Gunnar Bittersmann
    1. 0
      Felix Riesterer
      1. 0
        Gunnar Bittersmann
        1. 0
          Felix Riesterer
          1. 0
            Gunnar Bittersmann
            1. 2
              Mitleser
              1. 0
                Gunnar Bittersmann
              2. 0
                Matthias Apsel
                1. 0
                  Gunnar Bittersmann
                  1. 1
                    Camping_RIDER
                    1. 1
                      Gunnar Bittersmann
                      1. 1
                        Felix Riesterer
                        • meinung
                        • selfhtml-wiki
                        1. 0
                          Gunnar Bittersmann
                          1. 1
                            Camping_RIDER
                            1. 0
                              Gunnar Bittersmann
                              1. 1
                                Matthias Apsel
                        2. 0
                          Gunnar Bittersmann
                          1. 2
                            Tabellenkalk
                    2. 1
                      Gunnar Bittersmann
                      1. 0
                        Camping_RIDER
                        1. 1
                          Der Martin
                      2. 0
                        Matthias Apsel
          2. 1
            Gunnar Bittersmann
    2. 0
      Camping_RIDER
      1. 0
        Gunnar Bittersmann
        1. 1
          Camping_RIDER