{ Deutsch | English }
Tic Tac Toe

Tic Tac Toe − LX

Source Code

The following are the image declarations. Each party has 7 different images although 1 would do. This is only for optical purposes.
<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';
Counter variables
var i,j,k;
temporary variable for many purposes
var temp;
If the game is over (either won or lost) the value is 1 otherwise it's 0.
var gewonnen;
if the computer already made a mark (1 if true, 0 if false)
var gesetzt;
variables which contain information about the current status of the game
var Fertig,Xreihe,Oreihe;
verhindern[] contains positions where the player could make an X to win, gewinnen[] are those fields where a computer's mark could win the game
var verhindern = new Array(); var gewinnen = new Array();
alternates if either the player or the computer has the first turn
var alternate = 1;
the playing field
var Spielfeld = new Array();
This function initializes the game. All variables are set to their start value and all fields are cleared (if there was already a round before).
function init() { for (i = 0; i < 10; i++) { Spielfeld[i] = [0,0]; }
Spielfeld[0][0] isn't used, therefore it's set as if there's already a mark on it.
Spielfeld[0][0] = 1; gewonnen = 0;
Xreihe and Oreihe are variables that contain a number that is calculated by multiplying primes. By this number you can check if there are three marks of the same player in one row or not.
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; }
determines if the computer has the first turn
if (!(alternate % 2)) Computerzug();
This is the New Game button. It's hidden as long as the game is not over.
if (!document.layers) = 'hidden'; }
The following function puts a mark of player welches in cell Zelle.
function setzen(Zelle,welches) {
Increment Fertig, if this number turns 9 then all cells are marked and the game is over independent if anybody has won it so far or not.
Determines if either Oreihe or Xreihe are to be changed.
i = eval(welches + 'reihe');
Multiplies the variable with a certain prime, depending on what cell you put the mark in.
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;
puts the mark
Spielfeld[Zelle][1] = welches;
This function call lets the computer anticipate which cell could win the game in the next turn.
calculates a random number to put a random of the 7 images per player in the cell
welches += Math.ceil((Math.random() * 1000) % 7); window.document.images[('Z' + Zelle)].src = eval(welches).src;
sets the "there is already a mark on this cell" flag and changes gesetzt so the computer knows it has already put a mark
Spielfeld[Zelle][0] = 1; gesetzt = 1; }
This function checks if either of the players won.
function checkWin(Spieler) { temp = eval(Spieler + 'reihe');
The variable is divided by the calculated numbers of the rows. The first row for example has the cells attached to the primes 2, 3 and 5. All three multiplicated equal 30. So if the number in this variable can be divided by 30 without a rest, then all the first three cells are marked and therefore the player would have won.
if (!(temp % 30) || !(temp % 1001) || !(temp % 7429) || !(temp % 238) || !(temp % 627) || !(temp % 1495) || !(temp % 506) || !(temp % 935)) {
The document.layers check is here for Netscape4 compatibility. If it wasn't there Netscape4 would simply stop because it doesn't know the CSS tag behind, which makes the New Game button visible.
if (!document.layers) = 'visible'; return 'gewonnen'; } else return 'nix'; }
The function called when you click on cell hier.
function kreuz(hier) {
If the game is already over no further clicks are allowed.
if (gewonnen != 'gewonnen') {
If there's already a mark on this cell (Spielfeld[hier][0] == 1) also no click is allowed.
if (!Spielfeld[hier][0]) { setzen(hier,'X');
Checks, if this click won the game.
gewonnen = checkWin('X');
If either party won the game its counter is increased.
if (gewonnen == 'gewonnen') document.out.scoreX.value++;
As long as there aren't 9 marks on the field the computer will make the next turn otherwise the New Game button appears (the game is tied).
else if (Fertig < 9) { Computerzug(hier); gewonnen = checkWin('O'); if (gewonnen == 'gewonnen') document.out.scoreO.value++; } else if (!document.layers) = 'visible'; } } }
The most difficult part of the game: the A.I. (far from being perfect but it's sufficient for this purpose).
function Computerzug(hier) { gesetzt = 0; do {
If the computer didn't already put a mark and the array gewinnen[] contains an entry − e.g. the computer could win this game by putting a mark in the cell specified in this array.
if (!gesetzt && (gewinnen.length > 0)) { for (i = 0; i < gewinnen.length; i++) {
Puts the mark (remember, if there's already a mark on it it will return without having done anything, if it put a mark, then gesetzt would have a value).
if (!Spielfeld[(gewinnen[i])][0]) setzen (gewinnen[i],'O'); if (gesetzt) break; }
Clears the array for the next turn.
while (gewinnen.length > 0) { gewinnen.pop(); } }
Now if the computer can't win the game with one click it checks if it has to block the player from winning. This works the same principle as above.
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(); } }
Now if both didn't work or weren't necessary if puts a mark on a random cell. I know this could be improved that the computer chooses specific cells with a higher possibility to win but since there are only 9 cells it's not that much of a difference. Maybe I'll implement a better A.I. in the future.
if (!gesetzt) { temp = Math.ceil((Math.random() * 1000) % 9); if (!Spielfeld[temp][0]) { setzen(temp,'O'); } } if (Fertig == 9 && !document.layers) = 'visible'; } while (!gesetzt)}
This function checks which cell the last mark was put in and forwards to the next function calling the possible rows in which this cell is.
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; } }
This function forwards to the next function delivering all the cells which are in the same row.
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; } }
This function finally checks if there are already two marks of the same player in this row and if so it remembers the third cell and puts it in the gewinnen[] or verhindern[] array, depending on the player.
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>
Now to the HTML part of the game. We need a TABLE with 9 cells for the playing field and two INPUT fields for the counters how many games a player already won. I'll only put the basic tags and attributes here and leave out formatting.
<FORM name="out" action="">
for player X (user)
<INPUT type="text" name="scoreX" value="0" size="1">
for player O (computer)
<INPUT type="text" name="scoreO" value="0" size="1">
not to forget the New Game button
<INPUT type="button" onClick="alternate++; init()" name="neu" value="New Game"> </FORM>
Now to the table. Each cell contains an empty (transparent) image which is to change when a mark is put.
<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>
Finally the function call for initialization of the game:
<SCRIPT type="text/javascript"> init(); </SCRIPT>