function chessGame() {

	this.Z0 = false;
	
	this.guesses = 0;

	// Board square notation
	this.numbers = [0, 8, 7, 6, 5, 4, 3, 2, 1];
	this.letters = ["0", "a", "b", "c", "d", "e", "f", "g", "h"];

	// Raw movetext with additional tokens (comments, NAGs, recursive variations)
	this.movetext;

	// Parse and saved moves in from-to format (used to display moves)
	this.moves = [];
	// Main 
	this.moves[0] = [];
	//this.moves[1] = [];

	// Storage of recursive variations
	this.variations = [];
	this.commentaries = [];

	// Variables used to load/save FEN
	this.currentMove;
	this.castling;
	this.enPassant;
	this.halfMoves;
	this.fullMoves;

	// Game tags (from PGN)
	this.tags = [];
	
	// After we parse the movetext, the whole game is stored in FENs for every consecutive move.
	// This way its so much easier to handle move jumps
	this.FENs = [];
	this.varFENs = [];
	this.currFEN;
	this.prevFEN;

	// Pieces 
	this.pieces = [];

	// Board squares
	// These that hold a piece contain reference to piece object
	// Refer to boardSquare.class
	this.squares = [];
	this.squares["a"] = [];
	this.squares["b"] = [];
	this.squares["c"] = [];
	this.squares["d"] = [];
	this.squares["e"] = [];
	this.squares["f"] = [];
	this.squares["g"] = [];
	this.squares["h"] = [];
	for(keyVar in this.squares) {
		for(j = 1; j <= 8; j++) {
			this.squares[keyVar][j] = new boardSquare(keyVar, j);
		}
	}

	// Board init
	this.initBoard = 
	function () {
		// Clear moves
		delete this.moves;
		this.moves = [];
		this.moves[0] = [];
		delete this.FENs;
		this.FENs = [];
		delete this.varFENs;
		this.varFENs = [];
		// Determine starting position
		if (this.tags['SetUp'])
			this.FENs[0] = this.tags['FEN']
		else {
			// Default starting position
			this.FENs[0] = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
			this.currFEN = this.FENs[0];
			this.prevFEN = this.FENs[0];
		}
		// Initialize the board (create pieces' objects and assign them to squares)
		this.loadFEN(this.FENs[0]);
	}

}
chessGame.prototype.flushBoard = 
	function() {
		for(keyVar in this.squares) {
			for(j = 1; j <= 8; j++) {
				this.squares[keyVar][j].piece = null;
			}
		}
		delete this.pieces;
		this.pieces = [];
	}
// Prototype function used to load FEN into board
chessGame.prototype.loadFEN = 
	function(FEN) {
		this.flushBoard();
		FENArray = FEN.split(" ");
		boardArray = FENArray[0].split("/");
		for(var lines = 1; lines <= 8; lines++) {
			line = boardArray[lines - 1].split("");
			colsY = 1;
			for(var cols = 1; cols <= line.length; cols++) {
				letter = line[cols - 1];
				if (/[rbqkpn]/.test(letter)) {
					color = "black";
				} else if (/[RBQKPN]/.test(letter)) {
					color = "white";
				} else {
					colsY = parseInt(colsY) + parseInt(letter);
					continue;
				}
				switch(letter.toLowerCase()) {
					case "r":
						name = "rook";
						break;
					case "b":
						name = "bishop";
						break;
					case "q":
						name = "queen";
						break;
					case "k":
						name = "king";
						break;
					case "p":
						name = "pawn";
						break;
					case "n":
						name = "knight";
						break;
					default:
						break;
				}
				x = this.letters[colsY];
				y = this.numbers[lines];
				this.addPiece(name, color, x, y);
				colsY++;
			}
		}
		if (FENArray[1] == "b")
			this.currentMove = "black";
		else
			this.currentMove = "white";
		this.castling = FENArray[2];
		this.enPassant = FENArray[3];
		this.halfMoves = FENArray[4];
		this.fullMoves = FENArray[5];
	}
// Create piece objects and place a reference to them for square they're in
// Refer to boardPiece.class
chessGame.prototype.addPiece = 
	function(name, color, x, y) {
		newPiece = new boardPiece(name, color);
		newPiece.square = this.squares[x][y];
		this.pieces.push(newPiece);
		this.squares[x][y].piece = newPiece;
	}
// Handles the castling
chessGame.prototype.castle = 
	function(castling, variation, varNum) {
		if (this.currentMove == "white")
			line = 1;
		else
			line = 8;
			
		if (/^O-O$/.test(castling)) {
			this.makeMove("e", line, "g", line);
			this.makeMove("h", line, "f", line);
			if (variation && !this.moves[varNum + 1]) {
				this.moves[varNum + 1].push({fromX: "e", fromY: line, toX: "g", toY: line, guess: false, variated: [], markers: '', promoteTo: ''});
			} else if (variation) {
				this.moves[varNum + 1].push({fromX: "e", fromY: line, toX: "g", toY: line, guess: false, variated: [], markers: '', promoteTo: ''});
			} else {
				this.moves[0].push({fromX: "e", fromY: line, toX: "g", toY: line, guess: false, variated: [], markers: '', promoteTo: ''});
			}
			this.squares["h"][line].moved = true;
		} else {
			this.makeMove("e", line, "c", line);
			this.makeMove("a", line, "d", line);
			this.squares["a"][line].moved = true;
			if (variation && !this.moves[varNum + 1]) {
				this.moves[varNum + 1].push({fromX: "e", fromY: line, toX: "c", toY: line, guess: false, variated: [], markers: '', promoteTo: ''});
			} else if (variation) {
				
				this.moves[varNum + 1].push({fromX: "e", fromY: line, toX: "c", toY: line, guess: false, variated: [], markers: '', promoteTo: ''});
			} else {
				this.moves[0].push({fromX: "e", fromY: line, toX: "c", toY: line, guess: false, variated: [], markers: '', promoteTo: ''});
			}
			this.squares["h"][line].moved = true;
		}
		
		if (this.currentMove == "white")
			castlestrip = /KQ/;
		else
			castlestrip = /kq/;

		this.enPassant = "-";
		this.halfMoves++;
		if (this.currentMove == "black")
			this.fullMoves++;
		this.castling = this.castling.replace(castlestrip, "");
		if (this.castling == "")
			this.castling = "-";
		this.switchMove();
		this.saveFEN(variation, varNum);
	}
// MoveHandler
chessGame.prototype.moveHandler =
	function(piece, fromX, fromY, toX, toY, capture, promotion, promoteTo, variation, varNum) {
		// Get the piece
		pieceXY = eval("moveRules." + piece + "(this, fromX, fromY, toX, toY, capture);");
		// Make piece move
		this.makeMove(pieceXY[0], pieceXY[1], toX, toY, capture);
		if (variation && !this.moves[varNum + 1]) {
			this.moves[varNum + 1].push({fromX: pieceXY[0], fromY: pieceXY[1], toX: toX, toY: toY, guess: false, variated: [], markers: '', promoteTo: promoteTo.charAt(0)});
			
		} else if (variation) {
			this.moves[varNum + 1].push({fromX: pieceXY[0], fromY: pieceXY[1], toX: toX, toY: toY, guess: false, variated: [], markers: '', promoteTo: promoteTo.charAt(0)});
		} else {
			this.moves[0].push({fromX: pieceXY[0], fromY: pieceXY[1], toX: toX, toY: toY, guess: false, variated: [], markers: '', promoteTo: promoteTo.charAt(0)});
		}
		if (piece == "pawn") {
			// White pawns move "up", black move "down"
			if (this.currentMove == "white") 
				mod = 1;
			else
				mod = -1;
			// if enPassant capture, manually remove piece, as makeMove is simple and doesn't handle this
			if (capture && toX + toY == this.enPassant) {
				this.squares[toX][toY - mod].piece.square = null;
				this.squares[toX][toY - mod].piece = null;
			}
			// Set enPassant if needed
			if (Math.abs(toY - pieceXY[1]) == 2)
				this.enPassant = toX + (parseInt(toY) - mod);
			else
				this.enPassant = "-";
			// Set the promotion piece if so
			if(promotion) {
				this.squares[toX][toY].piece.name = promoteTo;
				}
		} else {
			this.enPassant = "-";
			// Handle castling if rook moves
			if (piece == "rook" && this.castling != "-" && (piece[0] == "a" && (piece[1] == 1 || piece[1] == 8)) || (piece[0] == "h" && (piece[1] == 1 || piece[1] == 8)) && !this.squares[piece[0]][piece[1]].moved) {
				this.squares[piece[0]][piece[1]].moved = true;
				if (piece[0] == "a" && piece[1] == 8)
					this.castling = this.castling.replace(/q/, "");
				else if (piece[0] == "h" && piece[1] == 8)
					this.castling = this.castling.replace(/k/, "");
				else if (piece[0] == "a" && piece[1] == 1)
					this.castling = this.castling.replace(/Q/, "");
				else if (piece[0] == "h" && piece[1] == 1)
					this.castling = this.castling.replace(/K/, "");
			}
			if (piece == "king" && this.castling != "-") {
				if (this.currentMove == "white") {
					this.castling = this.castling.replace(/K/, "");
					this.castling = this.castling.replace(/Q/, "");
				} else {
					this.castling = this.castling.replace(/k/, "");
					this.castling = this.castling.replace(/q/, "");
				}
			}
			// Something I missed at a first glance and figured out almost 2 months later 
			if (this.castling == "")
				this.castling = "-";
		}

		if(promotion || capture)
			this.halfMoves = 0;
		else
			this.halfMoves++;
		if (this.currentMove == "black")
			this.fullMoves++;
		this.switchMove();
		this.saveFEN(variation, varNum);
	}
// Get piece positions in pieces by name, color and either (or both) of coordinates
// Returns an array of matches (from 1 with King and captures to 8 with initial pawns)
chessGame.prototype.getPiece = 
	function(name, color, x, y) {
		var result = new Array();
		for(i = 0; i < this.pieces.length; i++) {
			if (this.pieces[i].name == name && this.pieces[i].color == color && this.pieces[i].square != null && ((x && this.pieces[i].square.x == x) || !x) && ((y && this.pieces[i].square.y == y) || !y)) {
				result.push(i);
			}
		}
		return result;
	}
// Switches the current move
chessGame.prototype.switchMove =
	function() {
		if (this.currentMove == "white")
			this.currentMove = "black";
		else
			this.currentMove = "white";
	}
// Simple move function with from&to variables
chessGame.prototype.makeMove =
	function(fromX, fromY, toX, toY, capture) {
		previousPiece = this.squares[fromX][fromY].piece;
		previousPiece.square = this.squares[toX][toY];
		if (capture && this.squares[toX][toY].piece != null) {
			this.squares[toX][toY].piece.square = null;
		}
		this.squares[toX][toY].piece = previousPiece;
		this.squares[fromX][fromY].piece = null;
	}
// Reads current board position and pushes it to FENs array
chessGame.prototype.saveFEN =
	function(variation, varNum) {
		var FEN="";
		for (var num = 8; num >= 1; num--) {
			var emptyCounter = 0;
			for (keyVar in this.squares) {
				if (this.squares[keyVar][num].piece != null) {
					if (emptyCounter != 0) {
						FEN += emptyCounter;
						emptyCounter = 0;
					}
					pieceName = this.squares[keyVar][num].piece.name;
					pieceColor = this.squares[keyVar][num].piece.color;
					switch (pieceName) {
						case "rook":
						name = "r";
						break;
					case "bishop":
						name = "b";
						break;
					case "queen":
						name = "q";
						break;
					case "king":
						name = "k";
						break;
					case "pawn":
						name = "p";
						break;
					case "knight":
						name = "n";
						break;
					default:
						break;
					}
					if (pieceColor == "white") {
						name = name.toUpperCase();
						FEN += name;
					}
					else 
						FEN += name;
				} else
					emptyCounter++;
			}
			if (emptyCounter != 0)
				FEN += emptyCounter;
			if (num != 1)
				FEN += "/";
		}
		FEN += " " + this.currentMove.substr(0,1);
		FEN += " " + this.castling;
		FEN += " " + this.enPassant;
		FEN += " " + this.halfMoves;
		FEN += " " + this.fullMoves;
		this.prevFEN = this.currFEN;
		this.currFEN = FEN;
		//document.write(FEN + "<BR />");
		if (variation) {
			this.varFENs[varNum].push(FEN);
		} else
			this.FENs.push(FEN);
	}

// Get controlled squares for a piece on a supplied square
chessGame.prototype.controlledSquares = 
	function (fromX, fromY) {
		var result = [];
		piece = this.squares[fromX][fromY].piece;
		if (piece != undefined && piece.color == this.currentMove) {
			result = eval("chessRules." + piece.name + "(\"" + fromX + "\", " + fromY + ", \"" + piece.color + "\")");
		}
		return result;
	}
