NegaMax für TicTacToe in JS gewinnt nicht...

X

Xyz1

Gast
moin & frohes Neues!! Gegeben sei dieser folgende JavaScript-Code:
Javascript:
let array1 = [0, 0, 0, 0, 0, 0, 0, 0, 0];
let player1 = -1;
let move1 = -1;

function hasWon(array, player) {
  for (let i = 0; i < 3; i++) {
    let c1 = 0;
    let c2 = 0;
    for (let j = 0; j < 3; j++) {
      const idx = i * 3 + j;
      if (array[idx] == player)
        c1++;
      if (array[j * 3 + i] == player)
        c2++;
    }
    if (c1 == 3 || c2 == 3) {
      return true;
    }
  }
  let c1 = 0;
  let c2 = 0;
  for (let i = 0; i < 3; i++) {
    const idx1 = i * 3 + i;
    const idx2 = i * 3 + (2 - i);
    if (array[idx1] == player)
      c1++;
    if (array[idx2] == player)
      c2++;
  }
  if (c1 == 3 || c2 == 3) {
    return true;
  }
  return false;
}

function minimax(array, player) {
  if (hasWon(array, player) || hasWon(array, -player)) {
    return player;
  }

  let score = -2;
  let move = -1;
  for (let i = 0; i < array.length; i++) {
    if (array[i] == 0) {
      array[i] = player;
      let score2 = -minimax(array, -player);
      array[i] = 0;
      if (score2 > score) {
        score = score2;
        move = i;
        move1 = i;
      }
    }
  }

  if (move == -1)
    return 0;
  return score;
}

... ist an der Bewertungsfunktion etwas falsch?
 
X

Xyz1

Gast
Wenn ich das so umändere,
Javascript:
function minimax(array, player) {
  if (hasWon(array, player)) {
    return 1;
  }

  let score = -2;
  let move = -1;
  for (let i = 0; i < array.length; i++) {
    if (array[i] == 0) {
      array[i] = player;
      let score2 = -minimax(array, -player);
      array[i] = 0;
      if (score2 > score) {
        score = score2;
        move = i;
        move1 = i;
      }
    }
  }

  if (move == -1)
    return 0;
  return score;
}

dann versucht er zu gewinnen, blockt dabei aber nicht Spieler A.
 
K

kneitzel

Gast
Na ja - dann informiere Dich bevor Du antwortest... https://de.wikipedia.org/wiki/Minimax-Algorithmus#Implementierung
(Das ist i. A. eine gute Idee)
Deine Verlinkung hilft mir nebenbei angemerkt 0.

Erst einmal Danke für den Link. Den Wikipedia Aktikel hat er mir erst einmal nicht gebracht, als ich danach gesucht habe. (Und dass ich das durchaus versucht habe, war eigentlich doch verständlich. Diese schnippische Antwort bei jemanden, der es noch nicht einmal schafft, die vermeintlichen Probleme zu beschreiben, die sein Code hat, ist für mich unverständlich.)

Was mir auffällt:
Javascript:
  if (hasWon(array, player)) {
    return 1;
  }
Denn hier wird die Bewertung immer 1 angenommen. Aber die Bewertung ist abhängig vom Spieler. Eigener Sieg ist 1, Gegnerischer Sieg aber -1.
(Dein Wikipedia Artikel: "Eine ideale Bewertungsfunktion ordnet einer Stellung den Wert +1 zu, wenn Spieler A gewinnt, und den Wert −1, wenn Spieler B gewinnt, und 0 bei Unentschieden.")
 
K

kneitzel

Gast
Also das war etwas voreilig. Wenn man das im Detail betrachtet, dann kommen zwei Fehler auf:
a) Bewertung ist falsch. bewertung(spieler) muss natürlich auch erkennen, wenn der andere Spieler gewonnen hat. Also wenn player dran ist und der Zug zu einem Sieg führen würde, dann wird das nicht richtig erkannt.
b) Die tiefe braucht man nicht als Parameter, aber tiefe==gewünschte tiefe prüft, ob man beim ersten Zug ist. Nur der nächste Zug ist natürlich interessant. Also alles, was in Rekursionen später kommt, soll nicht berücksichtigt werden.

Generell wäre also meine Empfehlung, hier immer erst den original Meta-Code umzusetzen. Der findet sich z.B. unter dem Link, den Du gegeben hast Tobias:
Code:
    if (tiefe == 0 or keineZuegeMehr(spieler))
       return bewerten(spieler);
    int maxWert = -unendlich;
    generiereMoeglicheZuege(spieler);
    while (noch Zug da) {
       fuehreNaechstenZugAus();
       int wert = -miniMax(-spieler, tiefe-1);
       macheZugRueckgaengig();
       if (wert > maxWert) {
          maxWert = wert;
          if (tiefe == gewuenschteTiefe)
             gespeicherterZug = Zug;
       }
    }
    return maxWert;
 }

Also geht es darum, dass man benötigt:
a) keineZuegeMehr(spieler) -> Hier kann man Spieler weg lassen, denn keine Züge mehr ist unabhängig davon, wer dran ist.
b) bewerten(spieler) -> Bewertung des Feldes aus Sicht von spieler.
Da das Array übergeben werden soll in Deinem Code, habe ich das auch erst einmal so gelassen. Dann wären diese Funktionen z.B.:

Javascript:
    function keineZuegeMehr(array) {
      if (hasWon(array, player1)) {
          return true;
      }

            if (hasWon(array, -player1)) {
          return true;
      }
      
          for (let i = 0; i < array.length; i++) {
            if (array[i] == 0) {
          return false;
        }
      }
      
      return true;
    }

    function bewerte(array, player) {
      if (hasWon(array, player)) {
        return -1;
      }
      if (hasWon(array, -player)) {
        return 1;
      }
      return 0;
    }

Dann hatte ich gesagt: Tiefe ist wichtig. Im Algorithmus ist die Tiefe aber nur ein Zähler, der herunter gezählt wird. Das Abbruchkriterium ist hier nicht gewünscht, so dass lediglich das erwähnte Kriterium Tiefe == GewünschteTiefe bleibt. Das ist aber einfach die Frage: Bin ich im ersten Aufruf oder in einem rekursiven Aufruf. Also z.B. ein boolean Parameter, der true bzw. false ist.

Damit würde dann minmax so aussehen können:
Javascript:
    function minimax(array, player, recursiv) {
      if (keineZuegeMehr(array)) {
        return bewerte(array, player)
      }

          let maxScore = -2;
          for (let i = 0; i < array.length; i++) {
            if (array[i] == 0) {
              array[i] = player;
          if (hasWon(array, player)) {
            array[i] = 0;
            return 1;
          }
              let score = -minimax(array, -player, true);
              array[i] = 0;
              if (score > maxScore) {
                maxScore = score;
            if (!recursiv ) {
                    bestMove = i;
            }
              }
            }
          }

          return maxScore;
        }

Der ganze Code wäre dann (Ich habe noch ein <div id="message"></div> eingefügt:
Javascript:
        let array1 = [0, 0, 0, 0, 0, 0, 0, 0, 0];
        let player1 = -1;
        let bestMove = -1;

        function hasWon(array, player) {
          for (let i = 0; i < 3; i++) {
            let c1 = 0;
            let c2 = 0;
            for (let j = 0; j < 3; j++) {
              const idx = i * 3 + j;
              if (array[idx] == player)
                c1++;
              if (array[j * 3 + i] == player)
                c2++;
            }
            if (c1 == 3 || c2 == 3) {
              return true;
            }
          }
          let c1 = 0;
          let c2 = 0;
          for (let i = 0; i < 3; i++) {
            const idx1 = i * 3 + i;
            const idx2 = i * 3 + (2 - i);
            if (array[idx1] == player)
              c1++;
            if (array[idx2] == player)
              c2++;
          }
          if (c1 == 3 || c2 == 3) {
            return true;
          }
          return false;
        }
    
    function keineZuegeMehr(array) {
      if (hasWon(array, player1)) {
          return true;
      }

            if (hasWon(array, -player1)) {
          return true;
      }
      
          for (let i = 0; i < array.length; i++) {
            if (array[i] == 0) {
          return false;
        }
      }
      
      return true;
    }

    function bewerte(array, player) {
      if (hasWon(array, player)) {
        return -1;
      }
      if (hasWon(array, -player)) {
        return 1;
      }
      return 0;
    }
    
    function minimax(array, player, recursiv) {
      if (keineZuegeMehr(array)) {
        return bewerte(array, player)
      }

          let maxScore = -2;
          for (let i = 0; i < array.length; i++) {
            if (array[i] == 0) {
              array[i] = player;
          if (hasWon(array, player)) {
            array[i] = 0;
            return 1;
          }
              let score = -minimax(array, -player, true);
              array[i] = 0;
              if (score > maxScore) {
                maxScore = score;
            if (!recursiv ) {
                    bestMove = i;
            }
              }
            }
          }

          return maxScore;
        }

        function makeMove() {
          let score = minimax(array1, player1, false);
          if (bestMove != -1) {
        document.getElementById('message').innerHTML += "<br>Next move is: " + bestMove;
            array1[bestMove] = player1;
            player1 = -player1;
            bestMove = -1;
            makeTable();
          } else {
        document.getElementById('message').innerHTML += "<br>No more moves!";
      }
        }

        function clickl(index) {
          if (array1[index] == 0) {
            array1[index] = player1;
            player1 = -player1;
            makeTable();
            makeMove();
          }
        }

        function makeTable() {
          document.getElementById('ta1').innerHTML = '';
          for (let i = 0; i < 3; i++) {
            let tr = document.createElement('tr');
            for (let j = 0; j < 3; j++) {
              const idx = i * 3 + j;
              let td = document.createElement('td');
              let bt = document.createElement('button');
              bt.style.width = '50px';
              bt.style.height = '25px';
              bt.style.border = '1px solid black';
              bt.appendChild(document.createTextNode(array1[idx]));
              bt.addEventListener('click', function() {
                clickl(idx);
              });
              td.appendChild(bt);
              tr.appendChild(td);
            }
            document.getElementById('ta1').appendChild(tr);
          }
        }

        makeTable();

Ich denke, dass ich damit die beiden prinzipiellen Fehler aufgedeckt habe und ich hoffe, dass die Erklärung auch verständlich war.
 
X

Xyz1

Gast
Funktioniert leider noch nicht, er spielt "manchmal falsch" und verhindert zum Beispiel nicht obwohl möglich dass Spieler A gewinnt.
Da beide Spieler maximieren, muss die Bewertungsfunktion umso größere Werte liefern, je besser die Brettposition des gerade Ziehenden ist (Funktion bewerten(spieler)). Der Wert wird immer aus dessen Sicht angegeben
Hast Du das auch gelesen?
 
K

kneitzel

Gast
Jetzt hatte ich noch einmal kurz Zeit und habe da noch einmal drüber nachgedacht. Was mich an der ganzen Thematik gestört hat, war der fehlende Debugger! Das war ein Zustand, der so für mich nicht akzeptabel war und daher habe ich mich jetzt noch einmal kurz hingesetzt.

Ich habe bisher eigentlich diese ganze JavaScript Entwicklung gescheut aber es ist total einfach und daher einfach einmal kurz der Ablauf ohne eben so Web-Frontends (Die finde ich kontraproduktiv, so schön jsfiddle evtl. am Anfang aussah - eine Debug-Möglichkeit habe ich da zumindest auf Anhieb nicht gefunden....)

Aufbau ist total einfach. Eine einfache html Datei reicht ja schon. Dabei dann einfach einen Rahmen wie folgt nehmen:
HTML:
<html>
    <body>
        <!-- Hier kommt der HTML Code rein, den man bei jsfiddle in die HTML Box geschrieben hat -->
        <table id="ta1"></table>
        <div id="message"></div>
        <!-- End of insert -->
        
        <!-- Innerhalb des scrript tags kommt dann 1:1 das Script -->
        <script>
            // Weggelassen ... siehe letzten Post für ganzes Script...
        </script>
    </body>
</html>

Sowas hat dann den Vorteil, dass es eben eine in sich geschlossene Sache ist, die für jeden relativ einfach zu verwenden ist.

Wenn man das dann z.B. in Chrome öffnet, dann hat man die entsprechende Lösung. Um an den Debugger zu kommen, einfach einmal die Entwicklertools öffnen. Dann kann man auf den Tab Sources clicken, dann sieht man zum einen eine Baumansicht der Sourcen, kann da auf die Datei klicken um da dann Breakpoints zu setzen. Fand ich intuitiv bedienbar. Ansonsten gibt es aber auch Dokumentation z.B. https://developers.google.com/web/tools/chrome-devtools/javascript.

Funktioniert leider noch nicht, er spielt "manchmal falsch" und verhindert zum Beispiel nicht obwohl möglich dass Spieler A gewinnt.

Das habe ich bei der letzten, aktuellen Version so nicht gehabt. Da hat er es immer verhindert. Wenn der Computer gewinnen kann, dann zeigt er den letzten Zug nicht mehr an sondern sagt direkt "No more moves!", das ich dafür noch eingebaut hatte ... Dem könnte man noch einmal nachgehen ...

Kannst Du einmal schreiben, bei welcher Kombination diese Problematik von Dir festgestellt wurde?

Meine aktuelle Version findet sich bei jsfiddler unter https://jsfiddle.net/br3sf2vt/38/

HTML:
<html>
<body>
<table id="ta1"></table>
<div id="message"></div>
<script>
        let array1 = [0, 0, 0, 0, 0, 0, 0, 0, 0];
        let player1 = -1;
        let bestMove = -1;

        function hasWon(array, player) {
          for (let i = 0; i < 3; i++) {
            let c1 = 0;
            let c2 = 0;
            for (let j = 0; j < 3; j++) {
              const idx = i * 3 + j;
              if (array[idx] == player)
                c1++;
              if (array[j * 3 + i] == player)
                c2++;
            }
            if (c1 == 3 || c2 == 3) {
              return true;
            }
          }
          let c1 = 0;
          let c2 = 0;
          for (let i = 0; i < 3; i++) {
            const idx1 = i * 3 + i;
            const idx2 = i * 3 + (2 - i);
            if (array[idx1] == player)
              c1++;
            if (array[idx2] == player)
              c2++;
          }
          if (c1 == 3 || c2 == 3) {
            return true;
          }
          return false;
        }
    
    function keineZuegeMehr(array) {
      if (hasWon(array, player1)) {
          return true;
      }

            if (hasWon(array, -player1)) {
          return true;
      }
      
          for (let i = 0; i < array.length; i++) {
            if (array[i] == 0) {
          return false;
        }
      }
      
      return true;
    }

    function bewerte(array, player) {
      if (hasWon(array, player)) {
        return -1;
      }
      if (hasWon(array, -player)) {
        return 1;
      }
      return 0;
    }
    
    function minimax(array, player, recursiv) {
      if (keineZuegeMehr(array)) {
        return bewerte(array, player)
      }

          let maxScore = -2;
          for (let i = 0; i < array.length; i++) {
            if (array[i] == 0) {
              array[i] = player;
          if (hasWon(array, player)) {
            array[i] = 0;
            return 1;
          }
              let score = -minimax(array, -player, true);
              array[i] = 0;
              if (score > maxScore) {
                maxScore = score;
            if (!recursiv ) {
                    bestMove = i;
            }
              }
            }
          }

          return maxScore;
        }

        function makeMove() {
          let score = minimax(array1, player1, false);
          if (bestMove != -1) {
        document.getElementById('message').innerHTML += "<br>Next move is: " + bestMove;
            array1[bestMove] = player1;
            player1 = -player1;
            bestMove = -1;
            makeTable();
          } else {
        document.getElementById('message').innerHTML += "<br>No more moves!";
      }
        }

        function clickl(index) {
          if (array1[index] == 0) {
            array1[index] = player1;
            player1 = -player1;
            makeTable();
            makeMove();
          }
        }

        function makeTable() {
          document.getElementById('ta1').innerHTML = '';
          for (let i = 0; i < 3; i++) {
            let tr = document.createElement('tr');
            for (let j = 0; j < 3; j++) {
              const idx = i * 3 + j;
              let td = document.createElement('td');
              let bt = document.createElement('button');
              bt.style.width = '50px';
              bt.style.height = '25px';
              bt.style.border = '1px solid black';
              bt.appendChild(document.createTextNode(array1[idx]));
              bt.addEventListener('click', function() {
                clickl(idx);
              });
              td.appendChild(bt);
              tr.appendChild(td);
            }
            document.getElementById('ta1').appendChild(tr);
          }
        }

        makeTable();
</script>
</body>
</html>

Hast Du das auch gelesen?
Damit hatte ich mich noch nicht im Detail beschäftigt. Ich hatte mir jetzt nur den Negamax Algorithmus etwas angesehen - bisher kannte ich nur den reinen MinMax ohne diese "Erweiterung". Und ich habe beim Tic Tac Toe auch bisher keine Gedanken darauf verschwendet, wie welcher Zug zu bewerten ist. Aus meiner Sicht ist da evtl. eine Verbesserung über flexible Werte denkbar, so dass nicht nur -1, 0 und 1 als Bewertungen erlaubt sind. Dann kann man deutlich dynamischer etwas bewerten. Da wir hier nur ein Gewinnt / Verliert bewertet, wäre da evtl. eine Bewertung a.la. "Sieg in 1 Zug" ist besser als "Sieg in 3 Zügen"....

Daher weiß ich nicht, ob sowas gemeint ist oder nicht.

Als Parallelen aus der Schach-Programmierung wären noch Anregungen:
Wenn der Computer an der Reihe ist und die Mitte ich noch nicht belegt, dann nimmt er die Mitte. (Das könnte eine Parallele sein zu den Eröffnungsbibliotheken.) Aber das könnte auch eine Folge sein von einer Bewertung der Felder. Mitte ist am wertvollsten, dann würde ich gefühlsmäßig die Ecken nehmen und dann erst die mittleren Randfelder.

Ansonsten möchte ich nur kurz anmerken:
Diese JavaScript Entwicklung ist nichts, was ich als mein "Fachgebiet" bezeichnen würde. Die HTML/CSS/JS Grundlagen sind wirklich reine Grundlagen und ich pfusche da den Kollegen da normalerweise nicht in ihr Handwerk :)
 
X

Xyz1

Gast
Hmm, irgendwie spielt er jetzt wieder anders als die vorherigen zwei:
12818

(Spieler B ist dran und kann gewinnen, weil Spieler A zuvor nicht bestmöglich gespielt hat)

An sich ist MiniMax ja sehr "mächtig" und TicTacToe sehr simple... deswegen denke ich eigentlich, dass es damit auch irgendwie möglich wär.

Vielen Dank für deine Antworten :D
 
K

kneitzel

Gast
Ach je - ich hatte da absolut nicht aufgepasst bei meinem Code. Sorry:

a) Ich habe in der Methode minimax noch einen Check drin gehabt, ob ein Zug zum Sieg führen würde - der ist natürlich absoluter Quatsch! (Das war am Anfang nur ein Versuch um zu schauen, ob so irgendwie die erste Thematik gelöst werden könnte und ist natürlich Müll.

b) Auf Grund von a) gar nicht gesehen: Ich gebe genau die falschen Werte zurück beim bewerten. Wenn der Spieler, der übergeben wird, gewinnt, dann ist 1 zurück zu geben und nicht -1! (Das ist mir nicht aufgefallen, da er durch a) noch auf richtige Züge gekommen ist. ==> Das mit dem Debugger hätte ich sofort machen sollen - da sieht man sowas schnell...

Javascript:
        let array1 = [0, 0, 0, 0, 0, 0, 0, 0, 0];
        let player1 = -1;
        let bestMove = -1;

        function hasWon(array, player) {
          for (let i = 0; i < 3; i++) {
            let c1 = 0;
            let c2 = 0;
            for (let j = 0; j < 3; j++) {
              const idx = i * 3 + j;
              if (array[idx] == player)
                c1++;
              if (array[j * 3 + i] == player)
                c2++;
            }
            if (c1 == 3 || c2 == 3) {
              return true;
            }
          }
          let c1 = 0;
          let c2 = 0;
          for (let i = 0; i < 3; i++) {
            const idx1 = i * 3 + i;
            const idx2 = i * 3 + (2 - i);
            if (array[idx1] == player)
              c1++;
            if (array[idx2] == player)
              c2++;
          }
          if (c1 == 3 || c2 == 3) {
            return true;
          }
          return false;
        }
    
    function keineZuegeMehr(array) {
      if (hasWon(array, player1)) {
          return true;
      }

            if (hasWon(array, -player1)) {
          return true;
      }
      
          for (let i = 0; i < array.length; i++) {
            if (array[i] == 0) {
          return false;
        }
      }
      
      return true;
    }

    function bewerte(array, player) {
      if (hasWon(array, player)) {
        return 1;
      }
      if (hasWon(array, -player)) {
        return -1;
      }
      return 0;
    }
    
    function minimax(array, player, recursiv) {
      if (keineZuegeMehr(array)) {
        return bewerte(array, player)
      }

          let maxScore = -2;
          for (let i = 0; i < array.length; i++) {
            if (array[i] == 0) {
              array[i] = player;
              let score = -minimax(array, -player, true);
              array[i] = 0;
              if (score > maxScore) {
                maxScore = score;
            if (!recursiv ) {
                    bestMove = i;
            }
              }
            }
          }

          return maxScore;
        }

        function makeMove() {
          let score = minimax(array1, player1, false);
          if (bestMove != -1) {
        document.getElementById('message').innerHTML += "<br>Next move is: " + bestMove;
            array1[bestMove] = player1;
            player1 = -player1;
            bestMove = -1;
            makeTable();
          } else {
        document.getElementById('message').innerHTML += "<br>No more moves!";
      }
        }

        function clickl(index) {
          if (array1[index] == 0) {
            array1[index] = player1;
            player1 = -player1;
            makeTable();
            makeMove();
          }
        }

        function makeTable() {
          document.getElementById('ta1').innerHTML = '';
          for (let i = 0; i < 3; i++) {
            let tr = document.createElement('tr');
            for (let j = 0; j < 3; j++) {
              const idx = i * 3 + j;
              let td = document.createElement('td');
              let bt = document.createElement('button');
              bt.style.width = '50px';
              bt.style.height = '25px';
              bt.style.border = '1px solid black';
              bt.appendChild(document.createTextNode(array1[idx]));
              bt.addEventListener('click', function() {
                clickl(idx);
              });
              td.appendChild(bt);
              tr.appendChild(td);
            }
            document.getElementById('ta1').appendChild(tr);
          }
        }

        makeTable();

Damit funktioniert es nun hoffentlich. Die ersten Tests waren erfolgversprechend. Was man noch machen könnte, wäre nach jedem Zug prüfen, ob noch Züge möglich sind. Jetzt gewinnt er aber ohne das Spiel direkt als beendet zu erklären. Also z.B. im click1() prüfen:
- direkt am Anfang: Wenn keine Züge mehr möglich, dann direkt return (=> User clickt obwohl Spiel beendet)
- nach dem setzen: prüfen: Hat der Spieler gewonnen? Wenn ja: Spiel beenden sonst makeMove aufrufen.
- nach makeMove prüfen, ob Computer gewonnen hat und entsprechend reagieren.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
B Javascript Tutorial für DOM Manipulationen? Angular, React, JQuery - Fragen zu JavaScript 0
R Die Typisierung Service[] ergibt für mich keinen Sinn Angular, React, JQuery - Fragen zu JavaScript 5
Q Typsichers Binding für matSortDirection Angular, React, JQuery - Fragen zu JavaScript 10
N Cookies setzen für Verzeichnis Angular, React, JQuery - Fragen zu JavaScript 4
N Überprüfungsbutton für ein Eingabeformular erstellen Angular, React, JQuery - Fragen zu JavaScript 16
B PullDown erstellen für webseite? Angular, React, JQuery - Fragen zu JavaScript 12
P Bildschirmtastatur für Spiele Angular, React, JQuery - Fragen zu JavaScript 6
M Mit Ajax Daten als Eingabe für Dyngraph erzeugen Angular, React, JQuery - Fragen zu JavaScript 6
L [JavaScript] Mehrere Variablen für Live-Suche in MySql-DB Angular, React, JQuery - Fragen zu JavaScript 0
A Hilfe für guten Zweck Angular, React, JQuery - Fragen zu JavaScript 6
J Lese Webseite aus für LinkPreview Angular, React, JQuery - Fragen zu JavaScript 1
A Script für Benachrichtigung Angular, React, JQuery - Fragen zu JavaScript 9
S Suche Lösung für einen Slider mit Textverlinkung Angular, React, JQuery - Fragen zu JavaScript 2
L Suche D3 Tutorial (speziell für Sunburst-Darstellung...) Angular, React, JQuery - Fragen zu JavaScript 2
H Javascript für wordpress "open new window" Angular, React, JQuery - Fragen zu JavaScript 1
N JavaScript für Touch Devices bei DropDown Menü Angular, React, JQuery - Fragen zu JavaScript 4
F Schnellen Browser für HTML mit JS drin. Angular, React, JQuery - Fragen zu JavaScript 6
Fab1 [SUCHE] JavaScript Buch für Umsteiger Angular, React, JQuery - Fragen zu JavaScript 4
K Webapp für Iphone Safari Browser und Links Angular, React, JQuery - Fragen zu JavaScript 6
H HTML5 basierter Client für Webkartendienste auf Smartphones Angular, React, JQuery - Fragen zu JavaScript 2
F Dropdownmenü für JavaScript Angular, React, JQuery - Fragen zu JavaScript 5
S OnKlick für alle Objekte gleicher Art Angular, React, JQuery - Fragen zu JavaScript 17
J Dynamic Markers für POIs aus Postgresdatenbank Angular, React, JQuery - Fragen zu JavaScript 8
H Gadgeterweitung für Kostal Piko Angular, React, JQuery - Fragen zu JavaScript 5
R Anleitung für einen Konfetti Regen Angular, React, JQuery - Fragen zu JavaScript 9
D Kontrollkästchen/Checkbox automatisch aktivieren ! (für Profis) JavaScript Angular, React, JQuery - Fragen zu JavaScript 4
S Javascript für Teamvergabe gesucht. Angular, React, JQuery - Fragen zu JavaScript 4
S Skript für Greasemonkey Angular, React, JQuery - Fragen zu JavaScript 3
C Play und Stop-Error für Musik Angular, React, JQuery - Fragen zu JavaScript 4
A Programmierer für "kleines" Javaprogramm gesucht Angular, React, JQuery - Fragen zu JavaScript 2
G finde Einstellmöglichkeiten für Menue nicht. Angular, React, JQuery - Fragen zu JavaScript 2
M Hilfe gesucht für ein Projekt Angular, React, JQuery - Fragen zu JavaScript 1
K Suche Scrollscript für Objekte Angular, React, JQuery - Fragen zu JavaScript 3
E Fragen zu java Navigation für Internetseite Angular, React, JQuery - Fragen zu JavaScript 2
T Höhe und Breite übergeben für IE! Angular, React, JQuery - Fragen zu JavaScript 2
L Dauerlaufzeile mit Fotos für html Angular, React, JQuery - Fragen zu JavaScript 2
B Einen Timer für Windows Angular, React, JQuery - Fragen zu JavaScript 4
M Script für Namen? Angular, React, JQuery - Fragen zu JavaScript 5
D Inputfeld für Preiseingabe Angular, React, JQuery - Fragen zu JavaScript 6
K Fragen für Praktikum-aber keine Ahnung! Angular, React, JQuery - Fragen zu JavaScript 4
B Zähler für Eingabefeld Angular, React, JQuery - Fragen zu JavaScript 5
D 5 € Musicload Gutschein für Antwort: Formular mit JavaScript Angular, React, JQuery - Fragen zu JavaScript 10
N Java Refresh-Script für Java-Newb Angular, React, JQuery - Fragen zu JavaScript 4
K Bild soll nach 5 Sekunden für 5 Sekunden erscheinen Angular, React, JQuery - Fragen zu JavaScript 5
S Skript für Bannerwechsel Angular, React, JQuery - Fragen zu JavaScript 3
N Java script für detailierten Text anzeigen gesucht Angular, React, JQuery - Fragen zu JavaScript 4
A Timeoutfunktion für JavaScript Angular, React, JQuery - Fragen zu JavaScript 2

Ähnliche Java Themen

Neue Themen


Oben