function mouseCoords (e)

{
   var x = e.pageX
   var y = e.pageY

   // Internet Explorer.
   if ( ( ! e.pageX ) && ( ! e.pageY ) ) {

	x = e.clientX
	y = e.clientY

	// Change the relative coordinates to absolute.
	if ( typeof ( window.pageYOffset ) == "number" ) {

		x += window.pageXOffset
		y += window.pageYOffset

	} else if ( document.body && ( document.body.scrollLeft
						|| document.body.scrollTop ) ) {

		x += document.body.scrollLeft
		y += document.body.scrollTop

	} else if ( document.documentElement
		&& ( document.documentElement.scrollLeft
				|| document.documentElement.scrollTop ) ) {

		x += document.documentElement.scrollLeft
		y += document.documentElement.scrollTop
	}
   }

   var gameFrame = document.getElementById ("gameFrame")
   x -= ( gameFrame.offsetLeft + 4 )
   y -= gameFrame.offsetTop

   return ( { x:x, y:y } )
}


function addDisk ( player )

{
   var disks = 0

   if ( ! this.player || this.player == player ) {

	this.player = player
	this.disks++
	disks = this.disks

   } else {

	this.player = -1
	this.disks = -1
   }

   return ( disks )
}


function resetWinner ()

{
   this.next = null
   this.player = 0
   this.disks = 0
}


function Winner ( row, column, dr, dc )

{
   // Methods.
   this.addDisk = addDisk
   this.reset = resetWinner

   // Properties.
   this.row = row
   this.column = column
   this.dr = dr
   this.dc = dc
}

function startAnimation ()

{
   // Setup the next segment of the animation.
   if ( this.nextStop != null ) delete this.nextStop
   this.nextStop = null

   this.timeInc = this.originalTimeInc
   this.dx = 0
   this.dy = 0

   // Make sure that we aren't already there.
   if ( this.stops.length > 0 ) {

	this.nextStop = this.stops.pop()
	this.dx = this.nextStop.x - this.x
	this.dy = this.nextStop.y - this.y

	// Calculate the length of the segment.
	this.s = Math.abs ( this.dx + this.dy )

	// Calculate the number of frames to display on this segment.
	this.n = Math.round ( this.s / this.speed )
	if ( this.n == 0 ) this.n = 1

	// Incremental distance covered, approximately.
	this.ds = Math.floor ( this.s / this.n )
	this.bigSdec = this.ds * this.n
	this.sBalance = 0

	// Adjust the time increment to keep a constant speed.
	this.timeConstant = this.timeInc * this.s
	this.timeDec = this.n * this.speed
	this.timeInc = Math.floor ( ( this.timeInc * this.s )
					/ ( this.n * this.speed ) )
	this.bigTimeDec = this.timeDec * this.timeInc
   }
}


function Animation ( disk, destX, destY, speed, timeInc )

{
   // Method to setup the next segment of the animation.
   this.start = startAnimation

   // Properties.
   this.speed = speed
   this.originalTimeInc = timeInc
   this.timeBalance = 0
   this.disk = disk			// The disk being moved.
   this.nextStop = null			// End point of active segment.
   this.stops = new Array()		// The end-points of the segments.
   this.x = parseInt ( disk.img.style.left )
   this.y = parseInt ( disk.img.style.top )

   // Final destination.
   this.stops.push ( { x:destX, y:destY } )

   if ( this.x != destX ) {

	// Center disk over the selected column.
	this.stops.push ( { x:destX, y:this.y } )
   }
}

 
function deleteDisk ()

{
   this.gameFrame.removeChild ( this.img )
   delete ( this.img )
   this.gameFrame.removeChild ( this.shadow )
   delete ( this.shadow )
}


function Disk ( color, gameFrame, diskY )

{
   // Method.
   this.remove = deleteDisk

   // Properties.
   this.active = 0
   this.color = color
   this.next = null		// List of winner disks to blink.
   this.gameFrame = gameFrame

   this.img = new Image()
   this.gameFrame.appendChild ( this.img )
   this.img.src = "images/" + ( ( color == 1 ) ? "Red" : "Green" )
								+ " Piece.gif"
   this.img.style.position = "absolute"
   this.img.style.top = "10px"
   this.img.style.left = "10px"
   this.img.style.zIndex = 3

   this.shadow = new Image ()
   this.gameFrame.appendChild ( this.shadow )
   this.shadow.src = "images/Disk Shadow.gif"
   this.shadow.style.position = "absolute"
   this.shadow.style.top = ( diskY + 15 ) + "px"
   this.shadow.style.left = "49px"
   this.shadow.style.zIndex = 1
}


function resetCell ()

{
   if ( this.disk ) {

	this.disk.remove ()
	delete ( this.disk )
	this.disk = null
   }

   this.threats = 0
   this.nextThreat = -1

   this.potentialThreats [1] = 0
   this.potentialThreats [2] = 0
}


function Cell ()

{
   // Method.
   this.reset = resetCell

   this.potentialThreats = new Array()
}


function simpleEval ( row, column )

{
   var score = this.grid[row][column].potentialThreats[this.player]
		+ this.grid[row][column].potentialThreats[3 - this.player]

   if ( row < 5 ) score
	-= this.grid[row + 1][column].potentialThreats[3 - this.player]

   return ( score )
}


function evalMove ( column )

{
   var score = 23
   var row = this.column [column]

   if ( this.grid[row][column].threats ) {

	if ( this.grid[row][column].threats != ( 3 - this.player ) ) score = 45
	else if ( this.searchDepth > 0 ) score = this.lookAhead ( column )
	else score += this.simpleEval ( row, column )

   } else if ( row < 5 && this.grid[row + 1][column].threats
		&& this.grid[row + 1][column].threats != this.player ) {

	score = 1

   } else if ( this.searchDepth > 0 ) score = this.lookAhead ( column )
   else score += this.simpleEval ( row, column )

   return ( score )
}


function chooseMove ()

{
   var move = 0
   var potentialMove = new Array()
   var potentialMoves = 0
   var highScore = 1
   var choice = 0

   if ( this.disksToPlay == 42 ) {

	for ( var column = 0; column < 7; column++ ) potentialMove [column] = 1

   } else for ( var column = 0; column < 7; column++ ) {

	var row = this.column[column]

	if ( row < 6 ) {

		if ( this.grid[row][column].threats ) {

			if ( this.grid[row][column].threats
						== ( 3 - this.player ) ) 
						potentialMove[column] = 46
			else potentialMove[column] = 47

		} else if ( highScore < 46 ) {

			potentialMove[column] = this.evalMove ( column )

		} else potentialMove[column] = 0

		if ( potentialMove [column] > highScore ) {

			highScore = potentialMove [column]
		}

	} else potentialMove[column] = 0
   }

   for ( var i = 0; i < 7; i++ ) {

	if ( potentialMove [i] == highScore ) {

		potentialMove [i] = 10 / ( 1 + ( i - 3 ) * ( i - 3 ) )
		potentialMove [i] *= potentialMove [i]
		potentialMoves += potentialMove [i]

	} else potentialMove [i] = 0
   }

   choice = Math.ceil ( potentialMoves * Math.random() )

   if ( choice > potentialMoves ) choice -= potentialMoves

   while ( ( choice -= potentialMove[move] ) > 0 ) move++

   if ( highScore == 43 || highScore == 45 )
	   document.getElementById ( "WinMsg" ).innerHTML = "You are toast."

   return ( move )
}


function makeMove ()

{
   var column = this.pendingMove

   this.disksToPlay--
   this.column [column]++
   this.recordMove ( this.column [column] - 1, column )
}


function showMove ()

{
   var column = this.pendingMove
   var row = this.column[column] + 1

   this.animation = new Animation ( this.activeDisk,
				this.firstColumn + ( ( 2 * column + 1 )
				* this.columnWidth - this.diskDiameter ) / 2,
				this.bottom - row * this.diskDiameter,
				this.speed, this.timeInc )

   this.animate ()
}


function blinkWinners ( blinkCount )

{
   var disk = this.blinkDisks

   while ( disk ) {

	disk.img.src = "images/" + ( disk.color ? "Red " : "Green "  )
			+ ( ( blinkCount % 2 ) ? "Wins" : "Piece" ) + ".gif"

	disk = disk.next
   }

   if ( --blinkCount > 0 ) {

	this.stopBlink = setTimeout ( this.name + ".blink(" + blinkCount + ")",
									500 )
   }
}


function playGame ()

{
   if ( this.wins ) {

	var wins = this.wins

	while ( wins ) {

		var r = wins.row
		var c = wins.column

		for ( var i = 0; i < 4; i++ ) {

			var disk = this.grid[r][c].disk

			if ( ! disk.next ) {

				disk.next = this.blinkDisks
				this.blinkDisks = disk
			}

			r += wins.dr
			c += wins.dc
		}

		wins = wins.next
	}

	document.getElementById ( "WinMsg" ).innerHTML = "You "
		+ ( this.player == this.computerPlayer ? "win" : "lose" ) + "!"

	this.blink ( 9 )

   } else if ( this.disksToPlay > 0 ) {

	this.activeDisk = new Disk ( this.disksToPlay % 2,
					this.gameFrame, this.bottom
					- 7 * this.diskDiameter - 15 )

	if ( this.player != this.computerPlayer ) this.humanMove = 1
	else setTimeout ( this.name + ".computerMove()", this.timeInc )

   } else {

	this.humanMove = 0
	document.getElementById ( "WinMsg" ).innerHTML = "Drawn game"
   }
}


function dropDisk (e)

{
   if ( this.humanMove && ! this.animation ) {

	var mouse = mouseCoords (e)

	this.humanMove = 0

	if ( mouse.x < this.firstColumn || mouse.x >= this.firstColumn + 7
							* this.columnWidth ) {

		alert
	( "Invalid move, move disk over the game\nboard before dropping it." )

		this.humanMove = 1

	} else {

		var column = ( mouse.x - this.firstColumn )

		column -= ( column % this.columnWidth )
		column /= this.columnWidth

		if ( this.column [column] < 6 ) {

			this.pendingMove = column
			this.showMove ()
			this.move ()

		} else {

			alert
		( "That column is full, please make another selection." )

			this.humanMove = 1
		}
	}
   }
}


function dragDisk (e)

{
   if ( this.humanMove && ! this.animation ) {

	var mouse = mouseCoords (e)

	if ( ! this.activeDisk.active ) {

		var diskRadius = this.diskDiameter / 2
		var dx = mouse.x - ( 10 + diskRadius )
		var dy = mouse.y - ( 10 + diskRadius )

		if ( ( dx * dx + dy * dy ) < ( diskRadius * diskRadius ) )
						this.activeDisk.active = 1
	}

	if ( this.activeDisk.active ) {

		var x = mouse.x - this.diskDiameter/2
		var frameWidth = parseInt ( this.gameFrame.style.width )
							- this.diskDiameter
		if ( x < 0 ) x = 0
		else if ( x > frameWidth ) x = frameWidth

		this.activeDisk.img.style.left = x + "px"

		this.activeDisk.shadow.style.left = ( x + 39 ) + "px"

	}
   }
}


function animateDisk ()

{
   var	animation = this.animation

   this.stopAnimation = null

   if ( animation.nextStop == null ) animation.start ()
   else {

	var diskImg = animation.disk.img
	var shadowImg = animation.disk.shadow
	var ds = animation.ds

	animation.sBalance += animation.s

	animation.sBalance -= animation.bigSdec

	if ( animation.sBalance > 0 ) {

		animation.sBalance -= animation.n
		ds++
	}

	if ( animation.dx != 0 ) {

		if ( animation.dx < 0 ) animation.x -= ds
		else animation.x += ds

		diskImg.style.left = animation.x + "px"
		shadowImg.style.left = ( animation.x + 39 ) + "px"

	} else if ( animation.dy != 0 ) {

		if ( animation.dy < 0 ) animation.y -= ds
		else animation.y += ds

		diskImg.style.top = animation.y + "px"
		shadowImg.style.top = ( animation.y + 15 ) + "px"
	}

	if ( animation.x == animation.nextStop.x
			&& animation.y == animation.nextStop.y ) {

		animation.start ()
	}
   }

   if ( animation.nextStop != null ) {

	var dt = animation.timeInc

	animation.timeBalance += animation.timeConstant

	animation.timeBalance -= animation.bigTimeDec

	if ( animation.timeBalance > 0 ) {

		animation.timeBalance -= animation.timeDec
		dt++
	}

	this.stopAnimation = setTimeout ( this.name + ".animate()", dt )

   } else {

	var dt = this.animation.originalTimeInc
	var column = this.pendingMove
	var row = this.column[column] - 1

	this.grid [row][column].disk = this.activeDisk
	this.activeDisk = null

	delete ( this.animation )
	this.animation = null
	this.player = 3 - this.player
	this.play()
   }
}


function strategyEval ()

{
   var myThreats = 0
   var hisThreats = 0
   var myClosers = 0
   var hisClosers = 0
   var parity = 0

   // Count the threats.
   for ( var i = 0; i < 7; ++i ) {

	var threatLevel = this.grid[0][i].nextThreat
	var lastThreats = 0

	while ( threatLevel ) {

		var nextThreat = this.grid[threatLevel][i].nextThreat
		var threats = this.grid[threatLevel][i].threats
		var threatParity = ( ( nextThreat ? nextThreat : 5 )
							- threatLevel ) % 2
		parity += ( 5 - threatLevel )

		if ( threatParity && threats != 3 ) {

			if ( lastThreats ) {

				if ( threats == lastThreats ) {

					if ( threats == this.player )
								myThreats++
					else hisThreats++

				} else {

					if ( threats == this.player )
								hisThreats--
					else myThreats--

					nextThreat = 0
				}

			} else {

				if ( threats == this.player ) myThreats++
				else hisThreats++
			}

			threatLevel = nextThreat

		} else {

			if ( threats != this.player ) hisClosers++

			if ( threats != ( 3 - this.player ) ) myClosers++

			threatLevel = 0
		}

		lastThreats = threats
	}
   }

   if ( ( parity + this.player ) % 2 ) {

	if ( hisClosers ) hisThreats++

   } else {

	if ( myClosers ) myThreats++
   }

   this.strategyPoints = myThreats - hisThreats
}


function listNewThreat ( row, column )

{
   // Is it a potentially useful threat?
   if ( this.column[column] < row
		&& ( ! this.grid[row - 1][column].threats
		|| this.grid[row - 1][column].threats == this.player ) ) {

	var	prevThreat = 0
	var	nextThreat = this.grid[0][column].nextThreat

	// Find insertion point.
	while ( nextThreat && nextThreat < row ) {

		prevThreat = nextThreat
		nextThreat = this.grid[prevThreat][column].nextThreat
	}

	if ( ! prevThreat || this.grid[prevThreat][column].threats != 3 ) {

		this.grid[row][column].nextThreat = nextThreat
		this.grid[prevThreat][column].nextThreat = row

		// See if we just neutralized a threat.
		if ( nextThreat > 0 && this.grid[nextThreat][column].threats
						== ( 3 - this.player ) ) {

			if ( nextThreat == ( row + 1 ) ) {

				this.grid[row][column].nextThreat
					= this.grid[row + 1][column].nextThreat
				this.grid[row + 1][column].nextThreat = -1
			}
		}
	}
   }
}


function truncateThreats ( row, column )

{
   // Is this a strategic threat?
   if ( this.column[column] < row ) {

	if ( this.grid[row][column].nextThreat == -1 ) {

		var r = row - 1
		var b = this.column[column]

		while ( r > b && this.grid[r][column].nextThreat == -1 ) --r

		if ( r == b ) r == 0

		if ( r == 0 || this.grid[r][column].threats != 3 ) {

			this.grid[row][column].nextThreat
					= this.grid[r][column].nextThreat
			this.grid[r][column].nextThreat = row
		}
	}

	if ( this.grid[row][column].nextThreat != -1 ) {

		var r = this.grid[row][column].nextThreat

		this.grid[row][column].nextThreat = 0

		while ( r != 0 ) {

			var nextThreat = this.grid[r][column].nextThreat

			this.grid[r][column].nextThreat = -1
			r = nextThreat
		}
	}
   }
}


function recordThreats ( winner )

{
   if ( winner.player == this.player && winner.disks > 1 ) {

	r = winner.row
	c = winner.column

	for ( i = 0; i < 4; i++ ) {

		if ( this.column [c] <= r ) {

			if ( winner.disks == 3 ) {

				var newThreat = 0

				if ( ! this.grid[r][c].threats ) {

					newThreat = this.player

					// Add to list of strategic threats?
					if ( winner.dc )
						this.listNewThreat ( r, c )

				} else if ( this.grid[r][c].threats
						== ( 3 - this.player ) ) {

					newThreat = 3

					// Make sure this terminates threat
					// list.
					if ( winner.dc )
						this.truncateThreats ( r, c )
				}

				if ( newThreat ) {

					this.grid[r][c].threats = newThreat

					if ( this.column[c] == r
						|| ( this.column[c]
							== ( r - 1 )
						&& this.grid[r - 1][c].threats
							== this.player ) )
						++this.tacticalThreats
				}

				--this.grid[r][c].potentialThreats[this.player]

			} else ++this.grid[r][c].potentialThreats[this.player]
		}

		r += winner.dr
		c += winner.dc
	}
   }
}


function recordMove ( row, column )

{
   var r = row
   var c = column
   var l = column - 3

   this.tacticalThreats = 0

   // if this move gives up a strategic threat, remove it from the list.
   if ( this.column[column] == this.grid[0][column].nextThreat ) {

	var lostThreat = this.column[column]
	var newThreat = this.grid[lostThreat][column].nextThreat

	this.grid[0][column].nextThreat = newThreat
	this.grid[lostThreat][column].nextThreat = -1
   }

   // Check horizontal winners.
   if ( l < 0 ) l = 0
   else if ( c > 3 ) c = 3

   while ( c >= l ) {

	var disks = this.hWinners[r][c].addDisk ( this.player )

	if ( disks == 4 ) {

		this.hWinners[r][c].next = this.wins
		this.wins = this.hWinners[r][c]

	} else this.recordThreats ( this.hWinners[r][c] )

	--c
   }

   // Check vertical winners.
   c = column
   l = row - 3

   if ( l < 0 ) l = 0
   else if ( r > 2 ) r = 2

   while ( r >= l ) {

	var disks = this.vWinners[r][c].addDisk ( this.player )

	if ( disks == 4 ) {

		this.vWinners[r][c].next = this.wins
		this.wins = this.vWinners[r][c]

	} else this.recordThreats ( this.vWinners[r][c] )

	--r
   }

   // Check rising diagonal winners.
   r = row
   l = column - 3

   if ( r < 3 ) l = column - r

   if ( l < 0 ) l = 0

   if ( c > 3 ) {

	r -= ( c - 3 )
	c = 3
   }

   if ( r > 2 ) {

	c -= ( r - 2 )
	r = 2
   }

   while ( c >= l ) {

	var disks = this.rWinners[r][c].addDisk ( this.player )

	if ( disks == 4 ) {

		this.rWinners[r][c].next = this.wins
		this.wins = this.rWinners[r][c]

	} else this.recordThreats ( this.rWinners[r][c] )

	--r
	--c
   }

   // Check declining diagonal winners.
   r = row
   c = column
   l = column - 3

   if ( r > 2 ) l = column - ( 5 - r )

   if ( l < 0 ) l = 0

   if ( c > 3 ) {

	r += ( c - 3 )
	c = 3
   }

   if ( r < 3 ) {

	c -= ( 3 - r )
	r = 3
   }

   while ( c >= l ) {

	var disks = this.dWinners[r][c].addDisk ( this.player )

	if ( disks == 4 ) {

		this.dWinners[r][c].next = this.wins
		this.wins = this.dWinners[r][c]

	} else this.recordThreats ( this.dWinners[r][c] )

	++r
	--c
   }

   this.strategyEval ()
}


function copyGame ()

{
   var copy = new Game ( "copy" + this.searchDepth, 0, 0, 0, 0 )

   copy.player = this.player
   copy.disksToPlay = this.disksToPlay
   copy.searchDepth = this.searchDepth - 1

   for ( var i = 0; i < 7; i++ ) {

	copy.column [i] = this.column [i]
   }

   for ( var i = 0; i < 6; i++ ) {

	for ( var j = 0; j < 4; j++ ) {

		copy.hWinners[i][j].player = this.hWinners[i][j].player
		copy.hWinners[i][j].disks = this.hWinners[i][j].disks
	}
   }

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

	for ( var j = 0; j < 7; j++ ) {

		copy.vWinners[i][j].player = this.vWinners[i][j].player
		copy.vWinners[i][j].disks = this.vWinners[i][j].disks
	}
   }

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

	for ( var j = 0; j < 4; j++ ) {

		copy.rWinners[i][j].player = this.rWinners[i][j].player
		copy.rWinners[i][j].disks = this.rWinners[i][j].disks
	}
   }

   for ( var i = 3; i < 6; i++ ) {

	for ( var j = 0; j < 4; j++ ) {

		copy.dWinners[i][j].player = this.dWinners[i][j].player
		copy.dWinners[i][j].disks = this.dWinners[i][j].disks
	}
   }

   for ( var i = 0; i < 6; i++ ) {

	for ( var j = 0; j < 7; j++ ) {

		copy.grid[i][j].threats = this.grid[i][j].threats
		copy.grid[i][j].threats = this.grid[i][j].threats
		copy.grid[i][j].nextThreat = this.grid[i][j].nextThreat

		copy.grid[i][j].potentialThreats[1]
			= this.grid[i][j].potentialThreats[1]
		copy.grid[i][j].potentialThreats[2]
			= this.grid[i][j].potentialThreats[2]
	}
   }

   return ( copy )
}


function lookAhead ( proposedMove )

{
   var gameCopy = this.copy ()
   var highScore = 0
   var score = 23

   gameCopy.pendingMove = proposedMove
   gameCopy.move()

   // Look for tactical advantage.
   if ( gameCopy.tacticalThreats > 1 ) score = 43
   else if ( gameCopy.disksToPlay > 0 ) {

	highScore = 0

	gameCopy.player = 3 - this.player

	for ( var c = 0; c < 7; c++ ) {

		if ( gameCopy.column[c] < 6 ) {

			score = gameCopy.evalMove ( c )

			if ( score > highScore ) highScore
							= score
		}
	}

	score = 46 - highScore

	if ( gameCopy.searchDepth == 0 && score > 4 && score < 42 ) {

		var strategyPoints = ( gameCopy.strategyPoints
						+ this.strategyPoints ) * 7

		score += strategyPoints

		if ( score < 4 ) score = 4
		else if ( score > 42 ) score = 42
	}
   }

   return ( score )
}


function resetGame ()

{
   this.humanMove = 0

   if ( this.stopAnimation ) {

	clearTimeout ( this.stopAnimation )
	this.stopAnimation = null
	delete ( this.animation )
	this.animation = null
   }

   if ( this.stopBlink ) {

	clearTimeout ( this.stopBlink )
	this.stopBlink = null
   }

   this.searchDepth = document.getElementById("depth").selectedIndex
   this.player = 1
   this.disksToPlay = 42
   this.computerPlayer = 2 - document.getElementById("player").selectedIndex

   // Lists of winning position(s).
   this.wins = null		// Winning groups of 4 in a row.
   this.blinkDisks = null	// Actual disks in these groups.

   if ( this.activeDisk ) {

	this.activeDisk.remove()
	delete ( this.activeDisk )
	this.activeDisk = null
   }

   // Tactics and strategy
   this.tacticalThreats = 0
   this.strategyPoints = 0

   for ( var i = 0; i < 7; ++i ) {

	this.column [i] = 0
   }

   for ( var i = 0; i < 6; i++ ) {

	for ( var j = 0; j < 4; j++ ) {

		this.hWinners[i][j].player = 0
		this.hWinners[i][j].disks = 0
	}
   }

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

	for ( var j = 0; j < 7; j++ ) {

		this.vWinners[i][j].player = 0
		this.vWinners[i][j].disks = 0
	}
   }

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

	for ( var j = 0; j < 4; j++ ) {

		this.rWinners[i][j].player = 0
		this.rWinners[i][j].disks = 0
	}
   }

   for ( var i = 3; i < 6; i++ ) {

	for ( var j = 0; j < 4; j++ ) {

		this.dWinners[i][j].player = 0
		this.dWinners[i][j].disks = 0
	}
   }

   for ( var i = 0; i < 6; i++ ) {

	for ( var j = 0; j < 7; j++ ) {

		this.grid[i][j].reset()
	}
   }

   // Make empty threat lists.
   for ( var i = 0; i < 7; i++ ) this.grid[0][i].nextThreat = 0

   document.getElementById ( "WinMsg" ).innerHTML = ""

   this.play()
}


function computerMove ()

{
   this.pendingMove = this.chooseMove ()
   this.showMove ()
   this.move ()
}


function Game ( name, firstColumn, bottom, columnWidth, diskDiameter )

{
   // Methods.
   this.play = playGame
   this.move = makeMove
   this.computerMove = computerMove
   this.drag = dragDisk
   this.drop = dropDisk
   this.showMove = showMove
   this.animate = animateDisk
   this.recordMove = recordMove
   this.recordThreats = recordThreats
   this.listNewThreat = listNewThreat
   this.truncateThreats = truncateThreats
   this.chooseMove = chooseMove
   this.evalMove = evalMove
   this.strategyEval = strategyEval
   this.simpleEval = simpleEval
   this.lookAhead = lookAhead
   this.copy = copyGame
   this.reset = resetGame
   this.blink = blinkWinners

   // Properties.
   this.name = name

   // Animation control
   if ( diskDiameter > 0 ) {

	this.diskDiameter = diskDiameter
	this.columnWidth = columnWidth
	this.firstColumn = firstColumn
	this.bottom = bottom

	this.speed = 12
	this.timeInc = 25
	this.gameFrame = document.getElementById ( "gameFrame" )
   }

   // State.
   this.column = new Array()
   this.hWinners = new Array()
   this.vWinners = new Array()
   this.rWinners = new Array()
   this.dWinners = new Array()
   this.grid = new Array()

   // Create winners to keep track of how to win and/or who won.
   for ( var i = 0; i < 6; i++ ) {

	this.hWinners [i] = new Array()

	for ( var j = 0; j < 4; j++ ) this.hWinners[i][j] = new Winner ( i, j,
									0, 1 )
   }

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

	this.vWinners [i] = new Array()

	for ( var j = 0; j < 7; j++ ) this.vWinners[i][j] = new Winner ( i, j,
									1, 0 )
   }

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

	this.rWinners [i] = new Array()

	for ( var j = 0; j < 4; j++ ) this.rWinners[i][j] = new Winner ( i, j,
									1, 1 )
   }

   for ( var i = 3; i < 6; i++ ) {

	this.dWinners [i] = new Array()

	for ( var j = 0; j < 4; j++ ) this.dWinners[i][j] = new Winner ( i, j,
									-1, 1 )
   }

   // Tactics and strategy
   // Grid to keep track of threats (and the displayed disks).
   for ( var i = 0; i < 6; i++ ) {

	this.grid [i] = new Array()

	for ( var j = 0; j < 7; j++ ) {

		this.grid[i][j] = new Cell ()
	}
   }
}


var prefetch = new Array ()

prefetch [0] = new Image ()
prefetch [0].src = "images/Disk Shadow.gif"
prefetch [1] = new Image ()
prefetch [1].src = "images/Green Piece.gif"
prefetch [2] = new Image ()
prefetch [2].src = "images/Red Piece.gif"
prefetch [3] = new Image ()
prefetch [3].src = "images/Green Wins.gif"
prefetch [4] = new Image ()
prefetch [4].src = "images/Red Wins.gif"
