A DOM-Based Snakes Game, Part I: The Code | WebReference

A DOM-Based Snakes Game, Part I: The Code


A DOM-Based Snakes Game, Part I (7)

The Code

<HTML>
<HEAD>
<TITLE>Snakes</TITLE>
<SCRIPT LANGUAGE = "JavaScript">
<!--
var maxRowCount = 13;
var maxColumnCount = 23;
var rightBorder = maxColumnCount - 2;
var leftBorder = 0;
var topBorder = 0;
var bottomBorder = maxRowCount - 1;
var bottomLine = bottomBorder - 1;
var borderGif = "border.gif";
var coreGif = "back.gif";
var snakeGif = "snake.gif";
var targetGif = "apple.gif";
var snakeInitialLength = maxRowCount - 5;
var snakeRowPos = new Array(maxRowCount * maxColumnCount);
var snakeColumnPos = new Array(maxRowCount * maxColumnCount);
var snakeLength;
var headColumnChange;
var headRowChange;
var targetRow;
var tagetColumn;
var afterTailRow, afterTailColumn;
var interval = 50;
var score;
var asciiU = 85;
var asciiu = 117;
var asciiD = 78;
var asciid = 110;
var asciiR = 75;
var asciir = 107;
var asciiL = 72;
var asciil = 104;
var ascii8 = 56;
var ascii2 = 50;
var ascii4 = 52;
var ascii6 = 54;
function Is () 
{   // convert all characters to lowercase to simplify testing 
    var agt=navigator.userAgent.toLowerCase(); 
    // *** BROWSER VERSION *** 
    // Note: On IE5, these return 4, so use is.ie5up to detect IE5. 
    this.major = parseInt(navigator.appVersion); 
    this.minor = parseFloat(navigator.appVersion); 
    this.nav  = ((agt.indexOf('mozilla')!=-1) && (agt.indexOf('spoofer')==-1) 
                && (agt.indexOf('compatible') == -1) && (agt.indexOf('opera')==-1) 
                && (agt.indexOf('webtv')==-1)); 
    this.nav2 = (this.nav && (this.major == 2)); 
    this.nav3 = (this.nav && (this.major == 3)); 
    this.nav4 = (this.nav && (this.major == 4)); 
    this.nav4up = (this.nav && (this.major >= 4)); 
    this.navonly      = (this.nav && ((agt.indexOf(";nav") != -1) || 
                          (agt.indexOf("; nav") != -1)) ); 
    this.nav5 = (this.nav && (this.major == 5)); 
    this.nav5up = (this.nav && (this.major >= 5)); 
    this.ie   = (agt.indexOf("msie") != -1); 
    this.ie3  = (this.ie && (this.major < 4)); 
    this.ie4  = (this.ie && (this.major == 4) && (agt.indexOf("msie 5.")==-1) ); 
    this.ie4up  = (this.ie  && (this.major >= 4)); 
    this.ie5  = (this.ie && (this.major == 4) && (agt.indexOf("msie 5.")!=-1) ); 
    this.ie5up  = (this.ie  && !this.ie3 && !this.ie4); 
    // KNOWN BUG: On AOL4, returns false if IE3 is embedded browser 
    // or if this is the first browser window opened.  Thus the 
    // properties is.aol, is.aol3, and is.aol4 aren't 100% reliable. 
    this.aol   = (agt.indexOf("aol") != -1); 
    this.aol3  = (this.aol && this.ie3); 
    this.aol4  = (this.aol && this.ie4); 
    this.opera = (agt.indexOf("opera") != -1); 
    this.webtv = (agt.indexOf("webtv") != -1); 
    // *** JAVASCRIPT VERSION CHECK *** 
    if (this.nav2 || this.ie3) this.js = 1.0 
    else if (this.nav3 || this.opera) this.js = 1.1 
    else if ((this.nav4 && (this.minor <= 4.05)) || this.ie4) this.js = 1.2 
    else if ((this.nav4 && (this.minor > 4.05)) || this.ie5) this.js = 1.3 
    else if (this.nav5) this.js = 1.4 
    // NOTE: In the future, update this code when newer versions of JS 
    // are released. For now, we try to provide some upward compatibility 
    // so that future versions of Nav and IE will show they are at 
    // *least* JS 1.x capable. Always check for JS version compatibility 
    // with > or >=. 
    else if (this.nav && (this.major > 5)) this.js = 1.4 
    else if (this.ie && (this.major > 5)) this.js = 1.3 
    // HACK: no idea for other browsers; always check for JS version with > or >= 
    else this.js = 0.0; 
    // *** PLATFORM *** 
    this.win   = ( (agt.indexOf("win")!=-1) || (agt.indexOf("16bit")!=-1) ); 
    // NOTE: On Opera 3.0, the userAgent string includes "Windows 95/NT4" on all 
    //        Win32, so you can't distinguish between Win95 and WinNT. 
    this.win95 = ((agt.indexOf("win95")!=-1) || (agt.indexOf("windows 95")!=-1)); 
    // is this a 16 bit compiled version? 
    this.win16 = ((agt.indexOf("win16")!=-1) || 
                  (agt.indexOf("16bit")!=-1) || (agt.indexOf("windows 3.1")!=-1) || 
                  (agt.indexOf("windows 16-bit")!=-1) ); 
    this.win31 = ((agt.indexOf("windows 3.1")!=-1) || (agt.indexOf("win16")!=-1) || 
                  (agt.indexOf("windows 16-bit")!=-1)); 
    // NOTE: Reliable detection of Win98 may not be possible. It appears that: 
    //       - On Nav 4.x and before you'll get plain "Windows" in userAgent. 
    //       - On Mercury client, the 32-bit version will return "Win98", but 
    //         the 16-bit version running on Win98 will still return "Win95". 
    this.win98 = ((agt.indexOf("win98")!=-1) || (agt.indexOf("windows 98")!=-1)); 
    this.winnt = ((agt.indexOf("winnt")!=-1) || (agt.indexOf("windows nt")!=-1)); 
    this.win32 = ( this.win95 || this.winnt || this.win98 || 
                   ((this.major >= 4) && (navigator.platform == "Win32")) || 
                   (agt.indexOf("win32")!=-1) || (agt.indexOf("32bit")!=-1) ); 
    this.os2   = ((agt.indexOf("os/2")!=-1) || 
                  (navigator.appVersion.indexOf("OS/2")!=-1) || 
                  (agt.indexOf("ibm-webexplorer")!=-1)); 
    this.mac    = (agt.indexOf("mac")!=-1); 
    this.mac68k = (this.mac && ((agt.indexOf("68k")!=-1) || 
                               (agt.indexOf("68000")!=-1))); 
    this.macppc = (this.mac && ((agt.indexOf("ppc")!=-1) || 
                               (agt.indexOf("powerpc")!=-1))); 
    this.sun   = (agt.indexOf("sunos")!=-1); 
    this.sun4  = (agt.indexOf("sunos 4")!=-1); 
    this.sun5  = (agt.indexOf("sunos 5")!=-1); 
    this.suni86= (this.sun && (agt.indexOf("i86")!=-1)); 
    this.irix  = (agt.indexOf("irix") !=-1);    // SGI 
    this.irix5 = (agt.indexOf("irix 5") !=-1); 
    this.irix6 = ((agt.indexOf("irix 6") !=-1) || (agt.indexOf("irix6") !=-1)); 
    this.hpux  = (agt.indexOf("hp-ux")!=-1); 
    this.hpux9 = (this.hpux && (agt.indexOf("09.")!=-1)); 
    this.hpux10= (this.hpux && (agt.indexOf("10.")!=-1)); 
    this.aix   = (agt.indexOf("aix") !=-1);      // IBM 
    this.aix1  = (agt.indexOf("aix 1") !=-1); 
    this.aix2  = (agt.indexOf("aix 2") !=-1); 
    this.aix3  = (agt.indexOf("aix 3") !=-1); 
    this.aix4  = (agt.indexOf("aix 4") !=-1); 
    this.linux = (agt.indexOf("inux")!=-1); 
    this.sco   = (agt.indexOf("sco")!=-1) || (agt.indexOf("unix_sv")!=-1); 
    this.unixware = (agt.indexOf("unix_system_v")!=-1); 
    this.mpras    = (agt.indexOf("ncr")!=-1); 
    this.reliant  = (agt.indexOf("reliantunix")!=-1); 
    this.dec   = ((agt.indexOf("dec")!=-1) || (agt.indexOf("osf1")!=-1) || 
         (agt.indexOf("dec_alpha")!=-1) || (agt.indexOf("alphaserver")!=-1) || 
         (agt.indexOf("ultrix")!=-1) || (agt.indexOf("alphastation")!=-1)); 
    this.sinix = (agt.indexOf("sinix")!=-1); 
    this.freebsd = (agt.indexOf("freebsd")!=-1); 
    this.bsd = (agt.indexOf("bsd")!=-1); 
    this.unix  = ((agt.indexOf("x11")!=-1) || this.sun || this.irix || this.hpux || 
                 this.sco ||this.unixware || this.mpras || this.reliant || 
                 this.dec || this.sinix || this.aix || this.linux || this.bsd || 
                 this.freebsd); 
    this.vms   = ((agt.indexOf("vax")!=-1) || (agt.indexOf("openvms")!=-1)); 
}
function loadPicture() {
  loadBoardCore();
  loadRow(0, borderGif);
  loadRow(maxRowCount - 1, borderGif);
  loadColumn(0, borderGif);
  loadColumn(maxColumnCount - 2, borderGif);
}
function loadRow(rowNum, gif) {
  for(var i = 0; i < maxColumnCount - 1; i++) {
    divNode.childNodes[domIndex(i, rowNum)].src = gif;
  }
}
function loadColumn(colNum, gif) {
  for(var i = 0; i < maxRowCount; i++) {
    divNode.childNodes[domIndex(colNum, i)].src = gif;
  }
}
function loadBoardCore() {
  for(var i = 0; i < maxRowCount; i++) {
    loadRow(i, coreGif);
  }
}
function domIndex(x, y) {
  return (y * maxColumnCount + x);
}
function loadSnake() {
  var snakeRow =  maxRowCount - 2;
  for(var i = 1; i <= snakeInitialLength; i++) {
    divNode.childNodes[domIndex(i, snakeRow)].src = snakeGif;
    snakeRowPos[snakeInitialLength + 1 - i] = snakeRow;
    snakeColumnPos[snakeInitialLength + 1 - i] = i;
  }
  snakeLength = snakeInitialLength;
  headColumnChange = 1;
  headRowChange = 0;
}
  
function loadTarget() {
  while(true) {
    targetColumn = 1 + Math.round(Math.random() * (maxColumnCount - 4));
    targetRow = 1 + Math.round(Math.random() * (maxRowCount - 3))
	if (!(targetOverlapsSnake())) break;
  }
  divNode.childNodes[domIndex(targetColumn, targetRow)].src = targetGif;
} 
function targetOverlapsSnake() {
  for (var i = 1; i <= snakeLength; i++) {
    if (targetRow == snakeRowPos[i] && targetColumn == snakeColumnPos[i]) return true;
  }
  return false;
}
function moveOne() {
  if (processBorderCases()) restartGame();
  var tailRowPos = snakeRowPos[snakeLength];
  var tailColumnPos = snakeColumnPos[snakeLength];
  updateSnake(); 
  var headRowPos = snakeRowPos[1];
  var headColumnPos = snakeColumnPos[1];
  divNode.childNodes[domIndex(headColumnPos, headRowPos)].src = snakeGif;
  divNode.childNodes[domIndex(tailColumnPos, tailRowPos)].src = coreGif;
}
function startGame() {
  score = 0;
  window.status = "Turn with (u, h, n, k) or with NumLock (8, 4, 2, 6); Your score is " + score;
  loadSnake();
  loadTarget();
}
function restartGame() {
  for (var i = 1; i <= snakeLength; i++) {
    replaceObj = divNode.childNodes[domIndex(snakeColumnPos[i], snakeRowPos[i])];
    replaceObj.src = coreGif;
  }
  replaceObj = divNode.childNodes[domIndex(targetColumn, targetRow)]
  replaceObj.src = coreGif;
  startGame();  
}
function updateSnake() {
  afterTailRow = snakeRowPos[snakeLength];
  afterTailColumn = snakeColumnPos[snakeLength];
  for(var i = snakeLength; i >= 2; i--) {
    snakeRowPos[i] = snakeRowPos[i - 1];
    snakeColumnPos[i] = snakeColumnPos[i - 1]
  }
  snakeRowPos[1] += headRowChange;
  snakeColumnPos[1] += headColumnChange;
}
function processBorderCases() {
  processTargetCollision();
  if (processBorderCollision()) return true;
  if (processSelfCollision()) return true;
}
function processTargetCollision() {
  if (snakeRowPos[1] == targetRow && snakeColumnPos[1] == targetColumn){
    snakeLength++;
    snakeRowPos[snakeLength] = afterTailRow;
	snakeColumnPos[snakeLength] = afterTailColumn;
	loadTarget();
	divNode.childNodes[domIndex(afterTailColumn, afterTailRow)].src = snakeGif;
	score++;
	window.status = "Turn with (u, h, n, k) or with NumLock (8, 4, 2, 6); Your score is " + score;
  }
}
function processBorderCollision() {
  if (snakeRowPos[1] + headRowChange == topBorder || snakeRowPos[1] + headRowChange == bottomBorder || snakeColumnPos[1] + headColumnChange == leftBorder || snakeColumnPos[1] + headColumnChange == rightBorder) return true;
  return false;
}
function processSelfCollision() {
  for (var i = 2; i <= snakeLength; i++) {
    if (snakeRowPos[1] == snakeRowPos[i] && snakeColumnPos[1] == snakeColumnPos[i]) return true;
  }
  return false;
}
function handleClick() {
  if (window.event.keyCode == asciiU || window.event.keyCode == asciiu || window.event.keyCode == ascii8) {
    if (headRowChange == 0) {
	  headRowChange = -1;
	  headColumnChange = 0;
	}
  }
  else if (window.event.keyCode == asciiD || window.event.keyCode == asciid || window.event.keyCode == ascii2) {
    if (headRowChange == 0) {
	  headRowChange = 1;
	  headColumnChange = 0;
	}
  }
  else if (window.event.keyCode == asciiR || window.event.keyCode == asciir || window.event.keyCode == ascii6) {
    if (headColumnChange == 0) {
      headRowChange = 0;
	  headColumnChange = 1;
	}
  }
  else if (window.event.keyCode == asciiL || window.event.keyCode == asciil || window.event.keyCode == ascii4) {
    if (headColumnChange == 0) {
      headRowChange = 0;
	  headColumnChange = -1;
	}
  }
}
function addOneRow() {
  for (var i = 0; i < maxColumnCount -1; i++) {
    tempSquareNode = squareNode.cloneNode();
    divNode.appendChild(tempSquareNode);
  }
}
function addBr() {
  tempBrNode = brNode.cloneNode();
  divNode.appendChild(tempBrNode);
}
function buildBoard() {
  for(var i = 0; i < maxRowCount; i++) {
    addOneRow();
    addBr();
  }
}
function displayGreeting() {
  alert("Welcome to the Snakes game.\n" +
        "You get one point every time you eat the target.\n" +
		"Watch your score on the status line.\n" + 
        "Turn up with the u character or with NumLock(8).\n" +
		"Turn down with the n character or with NumLock(2).\n" +
		"Turn right with the k character or with NumLock(6).\n" +
		"Turn left with the h character or with NumLock(4).");
}
// -->
</SCRIPT>
</HEAD>
<BODY BGCOLOR="#ffffff" onkeypress=handleClick() ID="bodyNode">
<SCRIPT LANGUAGE = "JavaScript">
<!--
var is; 
is = new Is(); 
if (!(is.ie5up || is.nav5up)) alert("Snakes is supported by Version 5 and up only")
else {
  var divNode = document.createElement("DIV");
  divNode.align = "center";
  bodyNode.appendChild(divNode);
  var squareNode = document.createElement("IMG");
  var brNode = document.createElement("BR");
  buildBoard();
  loadPicture();
  displayGreeting();
  startGame();
  setInterval("moveOne()", interval);
}
// -->
</SCRIPT>
</BODY>
</HTML>

http://www.internet.com

Produced by Yehuda Shiran and Tomer Shiran

Created: August 16, 1999
Revised: March 7, 2000

URL: http://www.webreference.com/js/column46/code1.html