Banner
{ Deutsch | English }
Tic Tac Toe

Tic Tac Toe − LX



Quellcode


Die folgenden Zeilen umfassen die Deklarationen der Grafiken. Jeder Spieler hat 7 verschiedene Grafiken für seine Markierungen, obwohl eine ausreichen würde. Dies ist nur aus optischen Gründen.
<SCRIPT type="text/javascript"> var X1 = new Image; X1.src = 'X1.gif'; var X2 = new Image; X2.src = 'X2.gif'; var X3 = new Image; X3.src = 'X3.gif'; var X4 = new Image; X4.src = 'X4.gif'; var X5 = new Image; X5.src = 'X5.gif'; var X6 = new Image; X6.src = 'X6.gif'; var X7 = new Image; X7.src = 'X7.gif'; var O1 = new Image; O1.src = 'O1.gif'; var O2 = new Image; O2.src = 'O2.gif'; var O3 = new Image; O3.src = 'O3.gif'; var O4 = new Image; O4.src = 'O4.gif'; var O5 = new Image; O5.src = 'O5.gif'; var O6 = new Image; O6.src = 'O6.gif'; var O7 = new Image; O7.src = 'O7.gif'; var leer = new Image; leer.src = 'leer.gif';
Zählvariablen
var i,j,k;
temporäre Variable für mehrere Verwendungszwecke
var temp;
Wenn das Spiel zu Ende ist (egal ob gewonnen oder verloren) ist dieser Wert 1, ansonsten 0.
var gewonnen;
wenn der Computer bereits eine Markierung gesetzt hat (1 wenn wahr, 0 wenn falsch)
var gesetzt;
Variablen, die den momentanen Spielstatus beinhalten
var Fertig,Xreihe,Oreihe;
verhindern[] beinhaltet die Felder, mit denen der Spieler im nächsten Zug gewinnen und gewinnen[] die Felder, mit denen der Computer das Spiel für sich entscheiden könnte.
var verhindern = new Array(); var gewinnen = new Array();
wechselt immer, je nach dem ob der Computer oder der Spieler das erste Symbol zeichnen soll
var alternate = 1;
das Spielfeld
var Spielfeld = new Array();
Diese Funktion initialisiert das Spiel. Alle Variablen werden auf den Startwert gesetzt und die Felder gelöscht (wenn vorher bereits eine Runde gespielt wurde).
function init() { for (i = 0; i < 10; i++) { Spielfeld[i] = [0,0]; }
Spielfeld[0][0] wird nicht benutzt, deshalb wird es behandelt als wenn sich bereits eine Markierung in diesem Feld befinden würde.
Spielfeld[0][0] = 1; gewonnen = 0;
Xreihe und Oreihe sind Zahlen, die durch Multiplikation von Primzahlen entstehen. Mit diesem Produkt wird geprüft, ob sich bereits 3 gleiche Markierungen in einer Reihe befinden.
Xreihe = 1; Oreihe = 1; Fertig = 0; for (i = 0; i < verhindern.length; i++) { verhindern.pop(); } for (i = 0; i < gewinnen.length; i++) { gewinnen.pop(); } for (i = 0; i < 9; i++) { window.document.images[("Z" + i)].src = leer.src; }
bestimmt, ob der Computer den ersten Zug machen soll
if (!(alternate % 2)) Computerzug();
Das ist der Neues Spiel-Button. Dieser ist versteckt, solange das Spiel noch läuft.
if (!document.layers) document.out.neu.style.visibility = 'hidden'; }
Die folgende Funktion setzt eine Markierung des Spielers welches in das Feld Zelle.
function setzen(Zelle,welches) {
Erhöhe Fertig; wenn diese Zahl 9 erreicht sind alle Felder mit Markierungen besetzt und das Spiel ist vorbei (unentschieden).
Fertig++;
Bestimmt ob entweder Oreihe oder Xreihe geändert werden müss.
i = eval(welches + 'reihe');
Multipliziert die Variable mit einer bestimmten Primzahl, je nach dem Feld, in das die Markierung gesetzt wird.
switch (Zelle) { case 1: i *= 2; break; case 2: i *= 3; break; case 3: i *= 5; break; case 4: i *= 7; break; case 5: i *= 11; break; case 6: i *= 13; break; case 7: i *= 17; break; case 8: i *= 19; break; case 9: i *= 23; break; } if (welches == 'X') Xreihe = i; else Oreihe = i;
setzt die Markierung
Spielfeld[Zelle][1] = welches;
Dieser Funktionsaufruf lässt den Computer den Zug antizipieren, den er im folgenden Zug ausführen soll.
Antizipation(Zelle,welches);
berechnet eine Zufallszahl, um eine der 7 Grafiken zu bestimmen, die nun gesetzt werden soll
welches += Math.ceil((Math.random() * 1000) % 7); window.document.images[('Z' + Zelle)].src = eval(welches).src;
zeigt an, dass sich bereits eine Markierung auf diesem Feld befindet und ändert gesetzt sodass der Computer weiß, dass er bereits gesetzt hat
Spielfeld[Zelle][0] = 1; gesetzt = 1; }
Diese Funktion ermittelt, ob einer der Spieler gewonnen hat.
function checkWin(Spieler) { temp = eval(Spieler + 'reihe');
Die Variable wird durch die für die jeweilige Reihe berechnete Zahl dividiert. Die Felder der ersten Zeile beispielsweise sind mit den Primzahlen 2, 3 und 5 verknüpft. Alle drei miteinander multipliziert ergibt 30. Wenn man also die Variable durch 30 dividieren kann ohne dass ein Rest übrigbleibt, so weiß man, dass die erste Zeile 3 Markierungen enthält und der Spieler gewonnen hat.
if (!(temp % 30) || !(temp % 1001) || !(temp % 7429) || !(temp % 238) || !(temp % 627) || !(temp % 1495) || !(temp % 506) || !(temp % 935)) {
Der document.layers-Check ist hier nur, um Kompatibilität mit Netscape4 zu gewährleisten. Wenn diese Abfrage hier nicht stehen würde, dann würde Netscape4 hier einfach abbrechen, da dieser Browser die Funktion dahinter nicht versteht, welche auf einen CSS Stylesheet zugreift, das den Neues Spiel-Button sichtbar macht.
if (!document.layers) document.out.neu.style.visibility = 'visible'; return 'gewonnen'; } else return 'nix'; }
Diese Funktion wird aufgerufen, wenn man auf das Feld hier klickt.
function kreuz(hier) {
Wenn das Spiel bereits zuende ist, werden keine weiteren Klicks mehr zugelassen.
if (gewonnen != 'gewonnen') {
Wenn bereits eine Markierung auf dem Feld ist (Spielfeld[hier][0] == 1) wird auch kein Klick registriert.
if (!Spielfeld[hier][0]) { setzen(hier,'X');
Prüft, ob dieser Klick das Spiel entschieden hat.
gewonnen = checkWin('X');
Wenn eine Partei gewonnen hat, wird deren Zähler um 1 erhöht.
if (gewonnen == 'gewonnen') document.out.scoreX.value++;
Solange noch nicht 9 Markierungen auf dem Spielfeld sind, wird der Computer den nächsten Zug machen. Ansonsten erscheint der Neues Spiel-Button, da das Spiel unentschieden endet.
else if (Fertig < 9) { Computerzug(hier); gewonnen = checkWin('O'); if (gewonnen == 'gewonnen') document.out.scoreO.value++; } else if (!document.layers) document.out.neu.style.visibility = 'visible'; } } }
Der schwierigste Teil des Spiels: die K.I. (weit davon entfernt perfekt zu sein, aber es reicht für dieses Spiel).
function Computerzug(hier) { gesetzt = 0; do {
Wenn der Computer noch kein Symbol gezeichnet hat und der Array gewinnen[] Einträge enthält − wenn der Computer also eine Markierung in ein Feld aus diesem Array setzt, gewinnt er das Spiel.
if (!gesetzt && (gewinnen.length > 0)) { for (i = 0; i < gewinnen.length; i++) {
Setzt die Markierung (beachte: wenn sich bereits eine Markierung hier befindet, wird nichts geschehen, wenn eine Markierung durch diesen Teil gesetzt wird, bekommt gesetzt einen Wert).
if (!Spielfeld[(gewinnen[i])][0]) setzen (gewinnen[i],'O'); if (gesetzt) break; }
Hier wird der Array gelöscht für den nächsten Zug.
while (gewinnen.length > 0) { gewinnen.pop(); } }
Wenn der Rechner das Spiel nun nicht selbst durch eine Markierung gewinnen konnte, so wird er versuchen, den Spieler am gewinnen zu hindern. Dies funktioniert auf dieselbe Weise wie eben.
if (!gesetzt && (verhindern.length > 0)) { for (i = 0; i < verhindern.length; i++) { if (!Spielfeld[(verhindern[i])][0]) setzen (verhindern[i],'O'); if (gesetzt) break; } while (verhindern.length > 0) { verhindern.pop(); } }
Wenn beides nicht geklappt hat oder nicht nötig war, wird der Computer eine Markierung in ein zufällig ausgesuchtes Feld setzen. Ich weiß, dass das besser gemacht werden könnte, zum Beispiel indem der Rechner seine Markierung in ein Feld setzt, bei dem die Chancen zu gewinnen größer sind als auf anderen Feldern, aber da das Spielfeld sowieso nur 9 Felder hat, ist der Unterschied nicht allzu groß. Vielleicht werde ich eine bessere K.I. in Zukunft implementieren.
if (!gesetzt) { temp = Math.ceil((Math.random() * 1000) % 9); if (!Spielfeld[temp][0]) { setzen(temp,'O'); } } if (Fertig == 9 && !document.layers) document.out.neu.style.visibility = 'visible'; } while (!gesetzt)}
Diese Funktion prüft, in welchem Feld die letzte Markierung gemacht wurde und leitet an die Funktion schauen() weiter, indem sie die jeweiligen Reihen mit übermittelt, in denen sich dieses Feld befindet.
function Antizipation(Feld,Spieler) { switch(parseInt(Feld)) { case 1: schauen(1,Spieler); schauen(4,Spieler); schauen(7,Spieler); break; case 2: schauen(1,Spieler); schauen(5,Spieler); break; case 3: schauen(1,Spieler); schauen(6,Spieler); schauen(8,Spieler); break; case 4: schauen(2,Spieler); schauen(4,Spieler); break; case 5: schauen(2,Spieler); schauen(5,Spieler); schauen(7,Spieler); schauen(8,Spieler); break; case 6: schauen(2,Spieler); schauen(6,Spieler); break; case 7: schauen(3,Spieler); schauen(4,Spieler); schauen(8,Spieler); break; case 8: schauen(3,Spieler); schauen(5,Spieler); break; case 9: schauen(3,Spieler); schauen(6,Spieler); schauen(7,Spieler); break; } }
Diese Funktion leitet an die nächste Funktion weiter, indem es alle Felder übermittelt, die sich in der jeweiligen Reihe befinden.
function schauen(Reihe,Spieler) { switch(Reihe) { case 1: merke(1,2,3,Spieler); break; case 2: merke(4,5,6,Spieler); break; case 3: merke(7,8,9,Spieler); break; case 4: merke(1,4,7,Spieler); break; case 5: merke(2,5,8,Spieler); break; case 6: merke(3,6,9,Spieler); break; case 7: merke(1,5,9,Spieler); break; case 8: merke(3,5,7,Spieler); break; } }
Diese Funktion schließlich ermittelt, ob sich bereits 2 Markierungen desselben Spielers in dieser Reihe befinden und ergänzt dann abhängig vom Spieler entweder den gewinnen[]- oder den verhindern[]-Array um das jeweils dritte Feld.
function merke(a,b,c,Spieler) { k = 0; i = 0; if ((Spielfeld[a][1] == Spielfeld[b][1]) && (Spielfeld[a][1] == Spieler)) k = c; if ((Spielfeld[b][1] == Spielfeld[c][1]) && (Spielfeld[b][1] == Spieler)) k = a; if ((Spielfeld[c][1] == Spielfeld[a][1]) && (Spielfeld[c][1] == Spieler)) k = b; if (k) { if (Spieler == 'X') { verhindern[i] = k; i++; } else { gewinnen[i] = k; i++; } } } </SCRIPT>
Nun zum HTML-Teil des Spiels. Wir brauchen eine Tabelle mit 9 Zellen für das Spielfeld und 2 Eingabefelder für die Zähler der beiden Spieler. Ich werde hier lediglich die allgemeinen Tags notieren, die Formatierung der Ausgabe ist jedem selbst überlassen.
<FORM name="out" action="">
für Spieler X (Benutzer)
<INPUT type="text" name="scoreX" value="0" size="1">
für Spieler O (Computer)
<INPUT type="text" name="scoreO" value="0" size="1">
nicht zu vergessen, der Neues Spiel-Button
<INPUT type="button" onClick="alternate++; init()" name="neu" value="New Game"> </FORM>
Nun zur Tabelle: Jede Zelle beinhaltet ein leeres (transparentes) Bild, welches ausgetauscht wird, wenn eine Markierung gesetzt wird.
<TABLE> <TR> <TD> <A href="javascript:kreuz(1)"> <img src="leer.gif" alt="" name="Z1" border="0"> </A> </TD> <TD> <A href="javascript:kreuz(2)"> <img src="leer.gif" alt="" name="Z2" border="0"> </A> </TD> <TD> <A href="javascript:kreuz(3)"> <img src="leer.gif" alt="" name="Z3" border="0"> </A> </TD> </TR> <TR> <TD> <A href="javascript:kreuz(4)"> <img src="leer.gif" alt="" name="Z4" border="0"> </A> </TD> <TD> <A href="javascript:kreuz(5)"> <img src="leer.gif" alt="" name="Z5" border="0"> </A> </TD> <TD> <A href="javascript:kreuz(6)"> <img src="leer.gif" alt="" name="Z6" border="0"> </A> </TD> </TR> <TR> <TD> <A href="javascript:kreuz(7)"> <img src="leer.gif" alt="" name="Z7" border="0"> </A> </TD> <TD> <A href="javascript:kreuz(8)"> <img src="leer.gif" alt="" name="Z8" border="0"> </A> </TD> <TD> <A href="javascript:kreuz(9)"> <img src="leer.gif" alt="" name="Z9" border="0"> </A> </TD> </TR> </TABLE>
Schließlich der Funktionsaufruf zur Initialisierung des Spiels:
<SCRIPT type="text/javascript"> init(); </SCRIPT>