Menu

Instruction "Alert" absente ?

Messages postés
74
Date d'inscription
vendredi 11 juillet 2014
Dernière intervention
9 décembre 2018
- - Dernière réponse : Max747
Messages postés
74
Date d'inscription
vendredi 11 juillet 2014
Dernière intervention
9 décembre 2018
- 9 déc. 2018 à 09:36
Bonjour,

Question se rapportant à un jeu d'échecs.

Comme indiqué dans le titre de cette question, vous trouverez en ligne 48 de ce fichier nommé board.js une instruction qui ne se fait pas.
Celle ci dépend de la condition:
countMoves(myColor) qui doit être égal à zéro et de type numérique à mon avis.
function getObject(obj) {
	if (document.getElementById) {  // Mozilla, FireFox, Explorer 5+, Opera 5+, Konqueror, Safari, iCab, Ice, OmniWeb 4.5
		if (typeof obj == "string") {
			if (document.getElementById(obj)) {
				return document.getElementById(obj);
			} else {
				return document.getElementsByName(obj)[0];
			}
		} else {
			return obj.style;
		}
	}
	if (document.all) {       // Explorer 4+, Opera 6+, iCab, Ice, Omniweb 4.2-
		if (typeof obj == "string") {
			return document.all(obj);
		} else {
			return obj.style;
		}
	}
	if (document.layers) {      // Netscape 4, Ice, Escape, Omniweb 4.2-
		if (typeof obj == "string") {
			return document.layers(obj);
		} else {
			return obj.style;
		}
	}
	alert('Objet non trouvé : ' + obj);
	return false;
}


function isGameDrawn( )
{
	var i,j;

	// Stalemate?  // is all this needed, it is generated in php, so...est tout ce qui est nécessaire, il est généré en php, alors ...
	if (gameState == 'stalemate')
	{
		var myColor = WHITE;

		if (0 <= numMoves && 'b' == FEN[FEN.length - 1].split(' ')[1])
		{
			myColor = BLACK;
		}

		if (0 == countMoves(myColor))
		{
			alert('Nulle (pat)\nVous devriez offrir la nulle à votre adversaire.');
		}

		return "stalemate";
	}

	// Is the game drawn due to insufficient material to checkmate?
	var count = 0;
	var canCheckmate = false;

	for (i = 0; i < 8; i++)
	{
		for (j = 0; j < 8; j++)
		{
			if (board[i][j] != 0 && (board[i][j] & COLOR_MASK) != KING)
			{
				if ((board[i][j] & COLOR_MASK) != KNIGHT && (board[i][j] & COLOR_MASK) != BISHOP)
					canCheckmate = true;
				else
					count++;
			}
		}
	}
	if (count < 2 && ! canCheckmate)
	{
		alert('Nulle (materiel insuffisant pour mater)\nVous devriez offrir la nulle à votre adversaire.');
		return "material";
	}

	// Is the game drawn because this is the third time that the exact same position arises?
	if (numMoves >= 0 && isThirdTimePosDraw(FEN))
	{
		alert('Nulle (cette position a été rencontrée trois fois)\nVous devriez offrir la nulle à votre adversaire.');
		return "3";
	}

	// Draw because of no capture or pawn move for the last 50 moves?
	if (numMoves >= 0 && isFiftyMoveDraw(FEN[FEN.length-1]))
	{
		alert('Nulle (règle des 50 coups)\nVous devriez offrir la nulle à votre adversaire.');
		return "50";
	}

	return false;
}


function displayCaptPieces( )
{
	var i,j;
	var color = 'white';
	var html = '<div>';
	var piece = '';
	var item;

	for(i = 0; i < captPieces.length; i++)
	{
		for(j = 0; j < captPieces[i].length; j++)
		{
			piece = color + '_' + captPieces[i][j];
			html += '<img src="images/' + currentTheme + '/' + piece + '.' + ((-1 !== currentTheme.indexOf('gnuchess')) ? 'png' : 'gif') + '" width="';
			html += parseInt(50 * 3 / 5) + '" height="' + parseInt(50 * 3 / 5) + '" alt="' + piece + '" />';
		}

		html += "</div>\n<div>";
		color = 'black';
	}

	html += '</div>';
	getObject('captures').innerHTML = html;
}


if (0 < numMoves) { // if we have not made a move yet, don't get the previous move
	var prevMove = new previousMove( ); // the previous move info as object
}

var takenPiece = 0; // the captured piece img in the captures section
var captEnPass = 0; // the square the en passant captured pawn was on
function unhighlightCurMove( )
{
	unhighlight(getObject('tsq' + prevMove.fromSq));
	unhighlight(getObject('tsq' + prevMove.toSq));

	if (takenPiece) // if we have a captured piece highlighted
	{
		unhighlight(takenPiece); // unhighlight it
		takenPiece = 0; // and erase the var so we don't keep highlighting it
	}

	if (captEnPass) // if we have an en passant capture
	{
		unhighlight(captEnPass); // unhighlight it
		captEnPass = 0; // and erase the var so we don't keep highlighting it
	}
}


function highlightCurMove( )
{
	var item;

	// check for en passant move
	if (undefined != prevMove.captSq && prevMove.captSq != prevMove.toSq)
	{
		captEnPass = getObject('tsq' + prevMove.captSq);
	}

	if (prevMove.captPiece)
	{
		if ('w' == pieceColor[prevMove.captPiece])
		{
			item = 'white_' + pieceLtrToName[prevMove.captPiece.toLowerCase( )];
		}
		else
		{
			item = 'black_' + pieceLtrToName[prevMove.captPiece.toLowerCase( )];
		}

		var capt = getObject('captures').getElementsByTagName('img');

		var i;
		for (i = 0; i < capt.length; i++)
		{
			if (capt[i].alt == item)
			{
				takenPiece = capt[i];
				break;
			}
		}
	}

	highlight(getObject('tsq' + prevMove.fromSq), 'highlighted');
	setTimeout('highlightCurMoveTo( )', 300);
	setTimeout('unhighlightCurMove( )', 900);
}


function highlightCurMoveTo( )
{
	if (takenPiece)
	{
		highlight(takenPiece, 'taken_highlighted');

		if (captEnPass)
		{
			highlight(captEnPass, 'taken_highlighted');
			highlight(getObject('tsq' + prevMove.toSq), 'highlighted');
		}
		else
		{
			highlight(getObject('tsq' + prevMove.toSq), 'taken_highlighted');
		}
	}
	else
	{
		highlight(getObject('tsq' + prevMove.toSq), 'highlighted');
	}
}


function displayCurFEN(moveIdx)
{
	if (undefined != moveIdx)
	{
		getObject('FENblock').innerHTML = FEN[moveIdx];
	}
	else
	{
		getObject('FENblock').innerHTML = FEN[FEN.length - 1];
	}
}


// these will throw errors, but initializing them as 'undefined' is the
// only way to ensure all-around compatibility no matter what the original colors are.
function moveTo(objMoveId)
{
	var theBoard;

	if (0 < currMoveIdx) // don't try to reset the empty span, it throws errors
	{
		unhighlight(getObject('m' + currMoveIdx)); // reset the previous move box background color
	}

	currMoveIdx = parseInt(objMoveId.id.slice(1)); // get the move number
	FENToBoard(FEN[currMoveIdx]); // convert that FEN to the board var
	displayCurFEN(currMoveIdx); // display that FEN
	FENToCapt(currMoveIdx); // get the captures up to that point
	displayCaptPieces( ); // display those captures
	theBoard = htmlBoard( ); // convert the board var to html code
	getObject('chessboard').innerHTML = theBoard; // display that board
	highlight(getObject('m' + currMoveIdx), 'curmove_highlighted'); // change the move box background color
}


function moveJmp(moveDelta)
{
	var moveIdx = currMoveIdx;

	if (moveIdx + moveDelta > FEN.length - 1)
	{
		moveIdx = FEN.length - 1;
	}
	else if (moveIdx + moveDelta < 0)
	{
		moveIdx = 0;
	}
	else
	{
		moveIdx += moveDelta;
	}

	moveTo(getObject('m' + moveIdx + ''));
}


function displayMoves(replay)
{
	var i;
	var alt = '';
	var objGamebody = getObject('gamebody');
	var theMoves = '\n<span id="m0"></span>';
	var moveId = 1;
	theMoves += '\n<table class="moveList">\n';

	for (i = 0; i < moves.length; i++)
	{
		if ( (i + 1) % 2 == 0)
		{
			alt = ' class="alt"';
		}
		else
		{
			alt = '';
		}

		if ('1' == isGameOver || replay || 'mate' == gameState)
		{
			theMoves += '<tr'+alt+'>\n<td class="mn">' + (i+1) + '.</td>\n';
			theMoves += '<td id="m' + (moveId) + '" class="wm" onclick="moveTo(this);">' + moves[i][0] + '</td>\n';
			theMoves += '<td id="m' + (moveId+1) + '" class="bm" onclick="moveTo(this);">' + moves[i][1] + '</td>\n</tr>';
			moveId = moveId + 2;
		}
		else
		{
			theMoves += '<tr'+alt+'>\n<td class="mn">' + (i+1) + '.</td>\n<td class="wm">';
			theMoves += moves[i][0] + '</td>\n<td class="bm">' + moves[i][1] + '</td>\n</tr>';
		}
	}

	theMoves += '\n</table>\n';

	if ('' != result)
	{
		theMoves += '<span class="ctr">Result: ' + result + '</span>\n';
	}

	objGamebody.innerHTML = theMoves;
	element = document.getElementById('gamebody');
    element.scrollTop = element.scrollHeight;
}


function toggleInvert( )
{
	if ('black' == perspective)
		perspective = 'white';
	else
		perspective = 'black';

	theBoard = htmlBoard( );
	getObject('chessboard').innerHTML = theBoard;
}


function htmlBoard( )
{ // Returns the HTML-code for the current chessboard (Note: Fixed square size and theme)
	var i,j,k;
	var classWSquare;
	var classBSquare;
	var classHeader;
	var fileLabel;
	var xtra;
	var mtra;
	var colorside;
	var invertBoard = (perspective == 'black');
	var rank = 8;
	var rankLabel = rank;

	if ('' == isBoardDisabled && ! watchgame)
	{
		classWSquare = 'light_enabled';
		classBSquare = 'dark_enabled';
		classHeader = 'header_enabled';
	}
	else
	{
		classWSquare = 'light_disabled';
		classBSquare = 'dark_disabled';
		classHeader = 'header_disabled';
	}

	var sqBackground = [classBSquare, classWSquare];

	if (invertBoard)
	{
		rankLabel = 1;
		colorside = "white";
	}
	else
	{
		colorside = "black";
	}

	j = 1;

	//changement du plateau selon le nombre de parteis gagnées

	if(parties_gagnees < 100){
			theBoard = '\n<div id="theBoard" style="background: url(./images/bois.png);">\n';
			var couleur = 'style="color:#111;"'; //correspond aux lettres et chiffres du bord de l'échiquier
	}else if(parties_gagnees >= 100){
			theBoard = '\n<div id="theBoard" style="background: url(./images/marbre.png);">\n';
			var couleur = 'style="color:#555;"'; //correspond aux lettres et chiffres du bord de l'échiquier
	}

	

	theBoard += '<div class="' + classHeader + ' ' + colorside + 'corner"> <\/div>\n';

	for(i = 0; i < 8; i++)
	{
		if(invertBoard)
			fileLabel = Files[7-i];
		else
			fileLabel = Files[i];

		theBoard += '<div '+couleur+' id="file_t' + i + '" class="' + classHeader + ' horz">' + fileLabel + '<\/div>\n';
	}

	theBoard += '<div class="' + classHeader + ' ' + colorside + 'corner"> <\/div>\n';
	theBoard += '<div '+couleur+' id="rank_l' + rank-- + '" class="' + classHeader + ' vert">' + rankLabel + '</div>\n';

	for (k = 63; k >= 0; k--)
	{
		if ((k+1) % 8 == 0)
		{
			i = k - 7;

			if (invertBoard)
				i = 63 - i;
		}
		else
		{
			if (invertBoard)
				i--;
			else
				i++;
		}

		var row = parseInt(i / 8);
		var col = i % 8;

		if (prevMove && row == prevMove.fromRow && col == prevMove.fromCol && '' == isBoardDisabled && ! watchgame && lastMoveIndicator)
			xtra = " fromSquare";
		else if (prevMove && row == prevMove.toRow && col == prevMove.toCol && '' == isBoardDisabled && ! watchgame && lastMoveIndicator)
			xtra = " toSquare";
		else
			xtra = "";

		theBoard += '<div id="tsq' + i + '" class="' + sqBackground[j] + xtra + '">';
		var piece = '';
		var source = '';

		if(board[row][col] != 0)
		{
			piece = getPieceColor(board[row][col]) + '_' + getPieceName(board[row][col]);
			source = 'images/' + currentTheme + '/' + piece + '.' + ((-1 !== currentTheme.indexOf('gnuchess')) ? 'png' : 'gif'); // Update the square
			theBoard += '<img alt="' + piece + '" id="sq' + i + '" ';
			theBoard += 'src="' + source + '" width="50" height="50" />';
		}
		else
		{
			theBoard += '';
		}
		theBoard += '<\/div>\n';
		if ( (k % 8) === 0 )
		{
			theBoard += '<div '+couleur+' id="rank_r' + (rank+1) + '" class="' + classHeader + ' vert">' + rankLabel + '<\/div>\n';
			if (k != 0)
			{
				if(invertBoard)
					rankLabel = 9 - rank;
				else
					rankLabel = rank;

				theBoard += '<div '+couleur+' id="rank_l' + rank-- + '" class="' + classHeader + ' vert">' + rankLabel + '</div>\n';
			}
		}
		else
		{
			j = 1 - j;
		}
	}

	if ("white" == colorside)
		colorside = "black";
	else
		colorside = "white";

	theBoard += '<div '+couleur+' class="' + classHeader + ' ' + colorside + 'corner"> <\/div>\n';

	for (i = 0; i < 8; i++)
	{
		if (invertBoard)
			fileLabel = Files[7-i];
		else
			fileLabel = Files[i];

		xtra = "";mtra = ""; // erase any previous values
		if ("518" != id960 && "header_disabled" != classHeader) // if we are not in a normal game and not disabled
		{
			if ("c" == fileLabel || "g" == fileLabel)
			{
				xtra = "<span class=\"kingto\">K</span>";
				mtra = "<span class=\"spacer\">K</span>";
			}
			else if ("d" == fileLabel)
			{
				xtra = "<span class=\"rookato\">R</span>";
				mtra = "<span class=\"spacer\">R</span>";
			}
			else if ("f" == fileLabel)
			{
				xtra = "<span class=\"rookhto\">R</span>";
				mtra = "<span class=\"spacer\">R</span>";
			}

			var LorigARookPos = origARookPos;
			var LorigKingPos  = origKingPos;
			var LorigHRookPos = origHRookPos;

			if (invertBoard)
			{
				LorigARookPos = 7 - LorigARookPos;
				LorigKingPos  = 7 - LorigKingPos;
				LorigHRookPos = 7 - LorigHRookPos;
			}

			if (i == LorigARookPos)
				fileLabel = '<span class="origarook">' + fileLabel + '</span>';
			else if (i == LorigKingPos)
				fileLabel = '<span class="origking">' + fileLabel + '</span>';
			else if (i == LorigHRookPos)
				fileLabel = '<span class="orighrook">' + fileLabel + '</span>';
		}

		theBoard += '<div '+couleur+' id="file_b' + i + '" class="' + classHeader + ' horz">' + mtra + fileLabel + xtra + '<\/div>\n';
	}

	theBoard += '<div class="' + classHeader + ' ' + colorside + 'corner"> <\/div>\n<\/div>\n';
	return theBoard;
}


// only do disabled = true for btnWakeUp, it is set as disabled if no email is present.

FENToBoard(FEN[FEN.length - 1]); // save the last entry in the FEN array to the board
var theBoard = htmlBoard( ); // The HTML code for the board
var currMoveIdx = 0;
var intervalId = 0;
window.onload = function( )
{
	var i;
	var lastMove;
	var navButtons;
	var gameIdDisplay;
	var invertBoard = (perspective == 'black');

	getObject('chessboard').innerHTML = theBoard;
	//displayCurFEN( );
	FENToCapt(numMoves);
	displayCaptPieces( );


	if (0 != gameId) // is it a database game ?
	{
		gameIdDisplay = 'Partie '  + gameId;
		getObject('btnPGN').disabled = false;
	}
	else // or a PGN file game
	{
		gameIdDisplay = 'PGN Game';
	}

	if ( ! watchgame)
	{
		if ('518' != id960) // if it's a Chess960 game
		{
			gameIdDisplay += ' - ' + id960 // display the id
		}
		else // or a regular game
		{
			getObject("castle").style.display = 'none';
		}
	}

	if ('1' != isBoardDisabled && ! watchgame)
	{
		if (0 < numMoves)
		{
			getObject("btnUndo").disabled = false;
		}

		getObject("btnDraw").disabled = false;
		getObject("btnResign").disabled = false;
		//document.querySelector('btnResign').disabled = false;
	}

	if ( ! watchgame) // are we playing the game
	{
		displayMoves( );

		getObject("btnReload").disabled = false;
		getObject("btnReplay").disabled = false;
		getObject("btnReload").onclick = function( ) { reloadPage(this); };
		getObject("btnReplay").onclick = function( ) { replay( ); };


		if (0 < moves.length) // if there are moves
		{
			lastMove = moves.length + '-'; // get the move number

			if ('' != moves[moves.length-1][1]) // if we are showing a black move
			{
				getObject('curmove').innerHTML = lastMove + ' ... ' + moves[moves.length-1][1];
			}
			else // we are showing a white move
			{
				getObject('curmove').innerHTML = lastMove + ' ' + moves[moves.length-1][0];
			}

			if ('1' != isGameOver)
			{
				getObject("curmove").onclick = function( ) { highlightCurMove( ); };
			}
		}

		if ('check' == gameState)
		{
			getObject('checkmsg').style.display = '';
			getObject('checkmsg').innerHTML = 'Echec !';

			// convert the board border to red if in check
			var divs = document.all ? document.all : document.getElementById("theBoard").getElementsByTagName("div");

			for ( var i = 0; i < divs.length; i++)
			{
				if (divs[i].className.match(/.*?(horz|vert).*?/))
				{
					divs[i].style.backgroundColor = "#BF2F35"; // TODO : stylefix
				}
			}
		}

		if ('' != statusMessage)
		{
			getObject('statusmsg').style.display = '';
			getObject('statusmsg').innerHTML = statusMessage;

			// if the statusMessage says anything about undo's
			// prevent multiple undo's from being requested
			if (statusMessage.match(/ undo /i))
			{
				getObject('btnUndo').disabled = true;
			}
		}
	}
	else // or just watching the game
	{
		displayMoves(true);
	}

	getObject('gameid').innerHTML = gameIdDisplay;
	getObject('players').innerHTML = players;

	//getObject('btnMainMenu').disabled = false;
	getObject('btnPGN').disabled = false;

	//getObject('btnMainMenu').onclick = function( ) { displayMainmenu( ); };
	getObject('btnPGN').onclick = function( ) { downloadPGN( ); };

	if ( ! watchgame)
	{
	    getObject("btnUndo").onclick = function() { 
        alert("Votre demande d'annulation de coup est en attente.");
        undo();
        };
        getObject("btnDraw").onclick = function() { 
        alert("Votre demande de match nul est en attente.");
        draw(); 
        };
        getObject("btnResign").onclick = function() { 
        alert("Votre demande d'abandon est validée.");
        resigngame(); 
        };
	}

	if ('1' == isGameOver || watchgame || 'mate' == gameState) // Allow game replay
	{
		if ( ! watchgame)
		{
			getObject('gamebuttons').style.display = 'none';
			getObject('btnWakeUp').disabled = true;
			getObject('btnReload').disabled = true;
			getObject('btnReplay').disabled = true;
		}

		currMoveIdx = FEN.length - 1;
		navButtons = '<form id="navigation" action="">';
		navButtons += '<span id="navbuttons">';
		navButtons += '<input id="start" title="Début de la partie" type="button" value="Start" />';
		navButtons += '<input id="jmpback" title="Retour en arrière de 5 demi-coups" type="button" value=" << " />';
		navButtons += '<input id="prev" title="Retour en arrière d\'un demi-coup" type="button" value=" < " />';
		navButtons += '<input id="next" title="Avancer d\'un demi-coup" type="button" value=" > " />';
		navButtons += '<input id="jmpfwd" title="Avancer de 5 demi-coups" type="button" value=" >> " />';
		navButtons += '<input id="end" title="Fin de la partie" type="button" value="End" /> <br> ';
		navButtons += '<input style="width:100px" id="invert" title="Inverser" type="button" value="< Tourner" />';
		navButtons += '<input style="width:100px" id="invert2" title="Inverser" type="button" value="Tourner >" disabled />';
		navButtons += '</span>';
		navButtons += '</form>';

		function invert1(){ /*toggleInvert( )*/

			document.getElementById("invert").disabled = true;
			document.getElementById("invert2").disabled = false;
			document.getElementById("theBoard").style.transform = "rotate(180deg)";
			document.getElementById("theBoard").style.transition = ".3s";
			for (var i=0; i < 64; i++) { 
				var element =  document.getElementById("sq"+i);
				if (typeof(element) != 'undefined' && element != null)
					{
						document.getElementById("sq"+i).style.transform = "rotate(180deg)";
					}
				
			}
		};
		function invert2(){ /*toggleInvert( )*/

			document.getElementById("invert2").disabled = true;
			document.getElementById("invert").disabled = false;
			document.getElementById("theBoard").style.transform = "rotate(0deg)";
			document.getElementById("theBoard").style.transition = ".3s";
			for (var i=0; i < 64; i++) { 
				var element =  document.getElementById("sq"+i);
				if (typeof(element) != 'undefined' && element != null)
					{
						document.getElementById("sq"+i).style.transform = "rotate(0deg)";
						//document.getElementById("theBoard").style.transition = ".3s";
					}
			}
			//document.getElementById("invert").style.display = "block";
			//document.getElementById("invert2").style.display = "none";


		};

		getObject('gamenav').innerHTML = navButtons;
		getObject("start").onclick = function( ){if(document.getElementById("invert").disabled == true){invert2();moveJmp(-10000);invert1();}else{moveJmp(-10000)} ;};
		getObject("jmpback").onclick = function( ){if(document.getElementById("invert").disabled == true){invert2();moveJmp(-5);invert1();}else{moveJmp(-5)};};
		getObject("prev").onclick = function( ){if(document.getElementById("invert").disabled == true){invert2();moveJmp(-1);invert1();}else{moveJmp(-1)};};
		getObject("next").onclick = function( ){if(document.getElementById("invert").disabled == true){invert2();moveJmp(1);invert1();}else{moveJmp(1)};};
		getObject("jmpfwd").onclick = function( ){if(document.getElementById("invert").disabled == true){invert2();moveJmp(5);invert1();}else{moveJmp(5)};};
		getObject("end").onclick = function( ){if(document.getElementById("invert").disabled == true){invert2();moveJmp(10000);invert1();}else{moveJmp(10000)};};
		getObject("invert").onclick = function( ){invert1()};
		getObject("invert2").onclick = function( ){invert2()};
	}
	else // game is not over and we are not replaying it - le jeu n'est pas terminé et nous ne le rejouons pas
	{
		isGameDrawn( ); // Alert the players it's stalemate, 50 move draw or the same position has occurred three times - Avertissez les joueurs que c'est dans l'impasse, 50 coups ou la même position s'est produite trois fois

		if (true == isPlayersTurn)
		{ // No need to set event handlers unless it's the player's move - Pas besoin de définir des gestionnaires d'événements à moins que ce ne soit le coup du joueur
			for(i = 0; i < 64; i++)
			{
				getObject('tsq' + i).onclick = function( ) { squareClicked(this); };
			}
			getObject('btnWakeUp').disabled = true;
		}

		if (autoreload > 0 && ! DEBUG) // if we need the board refreshed - si nous avons besoin de rafraîchir le jeu.
		{
			intervalId = setTimeout("window.location.replace('chess.php')", autoreload * 1000); // start the refresh loop
		}
	}
}


A savoir que countMoves(myColor) est une fonction permettant de définir le nombre de mouvements de pièces possible pour un joueur bien défini.Et que si ce joueur ne peut plus jouer (il est pat aux jeu d'échecs) countMoves(myColor) est égal à zéro.
Cette fonction se trouve ici en ligne 1347 du fichier validation.js:
// these functions are used to test the validity of moves
// DEBUG = false;

// global vars
var knightMove = [[-1, -2], [+1, -2], [-2, -1], [-2, +1], [-1, +2], [+1, +2], [+2, -1], [+2, +1]];
var diagonalMove = [[-1, -1], [-1, +1], [+1, +1], [+1, -1]];
var horzVertMove = [[-1, 0], [0, +1], [+1, 0], [0, -1]];
// The array 'direction' is a combination of diagonalMove and horzVertMove
// It could also be created using 'var direction = horzVertMove.concat(diagonalMove)'
// although the order of the elements would be different
var direction = [[-1, -1], [-1, 0], [-1, +1], [0, +1], [+1, +1], [+1, 0], [+1, -1], [0, -1]];
var pawnMove = [[+1, -1], [+1, 0], [+2, 0], [+1, +1]];


// object definition (used by isSafe)
function GamePiece( )
{
	this.piece = 0;
	this.dist = 0;
}


/* isSafe tests whether the square at testRow, testCol is safe */
/* for a piece of color testColor to travel to */
function isSafe(testRow, testCol, testColor)
{
	var i;
	var fromRow;
	var fromCol;
	var pieceFound = new Array( );
	var tmpPiece;
	var kingRow;
	var kingCol;
	var tmpIsSafe;
	/* NOTE: if a piece occupies the square itself,
		that piece does not participate in determining the safety of the square */

	/* IMPORTANT: note that if we're checking to see if the square is safe for a pawn
		we're moving, we need to verify the safety for En-passant */

	/* OPTIMIZE: cache results (if client-side game only, invalidate cache after each move) */

	/* AI NOTE: just because a square isn't entirely safe doesn't mean we don't want to
		move there; for instance, we may be protected by another piece */

	/* DESIGN NOTE: this function is mostly designed with CHECK checking in mind and
		may not be suitable for other purposes */

	my_alert("in isSafe(" + testRow + ", " + testCol + ", " + testColor + ")");

	var enemyColor = 0;
	if ('white' == testColor)
	{
		enemyColor = 128; /* 1000 0000 */
	}

	/* check for knights first */
	for (i = 0; i < 8; i++) // Check all eight possible knight moves
	{
		fromRow = testRow + knightMove[i][0];
		fromCol = testCol + knightMove[i][1];

		if (isInBoard(fromRow,fromCol))
		{
			if (board[fromRow][fromCol] == (KNIGHT | enemyColor))  // Enemy knight found
			{
				my_alert("isSafe -> knight found @ " + fromRow + "," + fromCol)
				return false;
			}
		}
	}

	/* tactic: start at test pos and check all 8 directions for an attacking piece */
	/* directions:
		black
		-----
		0 1 2
		7 * 3
		6 5 4
		-----
		white
	*/
	for (i = 0; i < 8; i++)
		pieceFound[i] = new GamePiece( );

	for (i = 1; i < 8; i++)
	{
		if ((testRow - i) >= 0 && (testCol - i) >= 0)
			if (0 == pieceFound[0].piece && board[testRow - i][testCol - i] != 0)
			{
				pieceFound[0].piece = board[testRow - i][testCol - i];
				pieceFound[0].dist = i;

				my_alert("isSafe -> pieceFound[0] = " + board[testRow - i][testCol - i] + "\ndist = " + i);
			}

		if ((testRow - i) >= 0)
			if (0 == pieceFound[1].piece && board[testRow - i][testCol] != 0)
			{
				pieceFound[1].piece = board[testRow - i][testCol];
				pieceFound[1].dist = i;

				my_alert("isSafe -> pieceFound[1] = " + board[testRow - i][testCol] + "\ndist = " + i);
			}

		if ((testRow - i) >= 0 && (testCol + i) < 8)
			if (0 == pieceFound[2].piece && board[testRow - i][testCol + i] != 0)
			{
				pieceFound[2].piece = board[testRow - i][testCol + i];
				pieceFound[2].dist = i;

				my_alert("isSafe -> pieceFound[2] = " + board[testRow - i][testCol + i] + "\ndist = " + i);
			}

		if ((testCol + i) < 8)
			if (0 == pieceFound[3].piece && board[testRow][testCol + i] != 0)
			{
				pieceFound[3].piece = board[testRow][testCol + i];
				pieceFound[3].dist = i;

				my_alert("isSafe -> pieceFound[3] = " + board[testRow][testCol + i] + "\ndist = " + i);
			}

		if (((testRow + i) < 8) && ((testCol + i) < 8))
			if ((pieceFound[4].piece == 0) && (board[testRow + i][testCol + i] != 0))
			{
				pieceFound[4].piece = board[testRow + i][testCol + i];
				pieceFound[4].dist = i;

				my_alert("isSafe -> pieceFound[4] = " + board[testRow + i][testCol + i] + "\ndist = " + i);
			}

		if ((testRow + i) < 8)
			if ((pieceFound[5].piece == 0) && (board[testRow + i][testCol] != 0))
			{
				pieceFound[5].piece = board[testRow + i][testCol];
				pieceFound[5].dist = i;

				my_alert("isSafe -> pieceFound[5] = " + board[testRow + i][testCol] + "\ndist = " + i);
			}

		if (((testRow + i) < 8) && ((testCol - i) >= 0))
			if ((pieceFound[6].piece == 0) && (board[testRow + i][testCol - i] != 0))
			{
				pieceFound[6].piece = board[testRow + i][testCol - i];
				pieceFound[6].dist = i;

				my_alert("isSafe -> pieceFound[6] = " + board[testRow + i][testCol - i] + "\ndist = " + i);
			}

		if (testCol - i >= 0)
			if (0 == pieceFound[7].piece && board[testRow][testCol - i] != 0)
			{
				pieceFound[7].piece = board[testRow][testCol - i];
				pieceFound[7].dist = i;

				my_alert("isSafe -> pieceFound[7] = " + board[testRow][testCol - i] + "\ndist = " + i);
			}
	}

	/* check pieces found for possible threats */
	for (i = 0; i < 8; i++)
	{
		if (pieceFound[i].piece != 0 && (pieceFound[i].piece & BLACK) == enemyColor)
		{
			switch (i)
			{
				/* diagonally: queen, bishop, pawn, king */
				case 0:
				case 2:
				case 4:
				case 6:
					if ((pieceFound[i].piece & COLOR_MASK) == QUEEN
					 || (pieceFound[i].piece & COLOR_MASK) == BISHOP)
					{
						my_alert("isSafe -> notKnight -> diagonal -> Q or B -> " + getPieceColor(pieceFound[i].piece) + " " + getPieceName(pieceFound[i].piece) + "\ndist = " + pieceFound[i].dist + "\ndir = " + i);
						return false;
					}

					if (1 == pieceFound[i].dist
					 && (pieceFound[i].piece & COLOR_MASK) == PAWN)
					{
						my_alert("isSafe -> notKnight -> diagonal -> Pawn -> " + getPieceColor(pieceFound[i].piece) + " " + getPieceName(pieceFound[i].piece) + "\ndist = " + pieceFound[i].dist + "\ndir = " + i);

						if (WHITE == enemyColor && (0 == i || 2 == i) )
						{
							return false;
						}
						else if (BLACK == enemyColor && (4 == i || 6 == i) )
						{
							return false;
						}
					}

					if (1 == pieceFound[i].dist
						&& (pieceFound[i].piece & COLOR_MASK) == KING)
					{
						my_alert("isSafe -> notKnight -> diagonal -> King -> " + getPieceColor(pieceFound[i].piece) + " " + getPieceName(pieceFound[i].piece) + "\ndist = " + pieceFound[i].dist + "\ndir = " + i);

						/* Are the kings next to each other? */
						if ((board[testRow][testCol] & COLOR_MASK) == KING)
						{
							return false;
						}

						/* save current board destination */
						tmpPiece = board[testRow][testCol];

						/* update board with move (client-side) */
						board[testRow][testCol] = pieceFound[i].piece;

						kingRow = 0;
						kingCol = 0;
						switch (i)
						{
							case 0:
								kingRow = testRow - 1;
								kingCol = testCol - 1;
								break;

							case 1:
								kingRow = testRow - 1;
								kingCol = testCol;
								break;

							case 2:
								kingRow = testRow - 1;
								kingCol = testCol + 1;
								break;

							case 3:
								kingRow = testRow;
								kingCol = testCol + 1;
								break;

							case 4:
								kingRow = testRow + 1;
								kingCol = testCol + 1;
								break;

							case 5:
								kingRow = testRow + 1;
								kingCol = testCol;
								break;

							case 6:
								kingRow = testRow + 1;
								kingCol = testCol - 1;
								break;

							case 7:
								kingRow = testRow;
								kingCol = testCol - 1;
								break;
						}

						board[kingRow][kingCol] = 0;

						/* if king needs to move into check to capture piece, isSafe( ) is true */
						tmpIsSafe = isInCheck(getOtherColor(testColor));

						/* restore board to previous state */
						board[kingRow][kingCol] = pieceFound[i].piece;
						board[testRow][testCol] = tmpPiece;

						/* if king CAN eat target without moving into check, return false */
						/* otherwise, continue checking other piecesFound */
						if ( ! tmpIsSafe)
						{
							return false;
						}
					}
					break;

				/* horizontally/vertically: queen, rook, king */
				case 1:
				case 3:
				case 5:
				case 7:
					if ((pieceFound[i].piece & COLOR_MASK) == QUEEN
						|| (pieceFound[i].piece & COLOR_MASK) == ROOK)
					{
						my_alert("isSafe -> notKnight -> horiz/vert -> Q or R -> " + getPieceColor(pieceFound[i].piece) + " " + getPieceName(pieceFound[i].piece) + "\ndist = " + pieceFound[i].dist + "\ndir = " + i);

						return false;
					}

					if (1 == pieceFound[i].dist
						&& (pieceFound[i].piece & COLOR_MASK) == KING)
					{
						my_alert("isSafe -> notKnight -> horiz/vert -> King -> " + getPieceColor(pieceFound[i].piece) + " " + getPieceName(pieceFound[i].piece) + "\ndist = " + pieceFound[i].dist + "\ndir = " + i);

						/* Are the kings next to each other? */
						if ((board[testRow][testCol] & COLOR_MASK) == KING)
						{
							return false;
						}

						/* save current board destination */
						tmpPiece = board[testRow][testCol];

						/* update board with move (client-side) */
						board[testRow][testCol] = pieceFound[i].piece;

						kingRow = 0;
						KingCol = 0;
						switch (i)
						{
							case 0:
								kingRow = testRow - 1; kingCol = testCol - 1;
								break;

							case 1:
								kingRow = testRow - 1; kingCol = testCol;
								break;

							case 2:
								kingRow = testRow - 1; kingCol = testCol + 1;
								break;

							case 3:
								kingRow = testRow;     kingCol = testCol + 1;
								break;

							case 4:
								kingRow = testRow + 1; kingCol = testCol + 1;
								break;

							case 5:
								kingRow = testRow + 1; kingCol = testCol;
								break;

							case 6:
								kingRow = testRow + 1; kingCol = testCol - 1;
								break;

							case 7:
								kingRow = testRow;     kingCol = testCol - 1;
								break;
						}

						board[kingRow][kingCol] = 0;

						/* if king needs to move into check to capture piece, isSafe( ) is true */
						tmpIsSafe = isInCheck(getOtherColor(testColor));

						/* restore board to previous state */
						board[kingRow][kingCol] = pieceFound[i].piece;
						board[testRow][testCol] = tmpPiece;

						/* if king CAN eat target without moving into check, return false */
						/* otherwise, continue checking other piecesFound */
						if (!tmpIsSafe)
						{
							return false;
						}
					}
					break;
			}
		}
	}

	my_alert("isSafe is true");

	return true;
}

function isValidMoveKing(fromRow, fromCol, toRow, toCol, tmpColor, castleSide)
{
	var i;
	var atkColor;

	// the king cannot move to a square occupied by a friendly piece
	// although the space may be occupied by the rook if it's a castle move
	if ( ! castleSide && 0 != board[toRow][toCol] && getPieceColor(board[toRow][toCol]) == tmpColor)
	{
		return false;
	}

	// if it's a castle move, every square between
	// the king and the final king location must
	// be empty and checked for attacking pieces
	if ('a' == castleSide || 'h' == castleSide)
	{
		// check to see if castling is valid before doing anything
		var CM = FEN[numMoves].split(' ')[2];
		my_alert(CM);
		my_alert(castleSide);

		// set the final locations of the castling pieces
		// and the original rook position
		var origRookPos;
		var finlRookPos;
		var finlKingPos;
		var dirK; var dirR;
		if ('a' == castleSide)
		{
			origRookPos = initpos.indexOf('R');
			finlRookPos = 3;
			finlKingPos = 2;

			if (2 != origKingPos)
			{
				dirK = (finlKingPos - origKingPos) / Math.abs(finlKingPos - origKingPos);
			}
			else
			{
				dirK = 0;
			}

			if (3 != origRookPos)
			{
				dirR = (finlRookPos - origRookPos) / Math.abs(finlRookPos - origRookPos);
			}
			else
			{
				dirR = 0;
			}
		}
		else if ('h' == castleSide)
		{
			origRookPos = initpos.lastIndexOf('R');
			finlRookPos = 5;
			finlKingPos = 6;

			if (6 != origKingPos)
			{
				dirK = (finlKingPos - origKingPos) / Math.abs(finlKingPos - origKingPos);
			}
			else
			{
				dirK = 0;
			}

			if (5 != origRookPos)
			{
				dirR = (finlRookPos - origRookPos) / Math.abs(finlRookPos - origRookPos);
			}
			else
			{
				dirR = 0;
			}
		}
		my_alert('origRookPos = '+origRookPos+'\nfinlRookPos = '+finlRookPos+'\nfinlKingPos = '+finlKingPos+'\ndirK = '+dirK+'\ndirR = '+dirR);

		var cSide;
		var cValid = true;
		if ('white' == tmpColor)
		{
			// if it's a-side, check to make sure that the Q is present in the castle indicator
			// and that the toCol is the same location as the original rook.  this removes errors
			// from having both rooks on the same side as well
			if ('a' == castleSide)
			{
				my_alert('white a = '+castleSide);
				cSide = CM.indexOf('Q');
				if ((-1 == cSide) || (toCol != origRookPos))
				{
					cValid = false;
				}
			}
			// for h-side look for the K and the rook location, same as above
			else if ('h' == castleSide)
			{
				my_alert('white h = '+castleSide);
				cSide = CM.indexOf('K');
				if ((-1 == cSide) || (toCol != origRookPos))
				{
					cValid = false;
				}
			}
		}
		else // black
		{
			if ('a' == castleSide)
			{
				my_alert('black a = '+castleSide);
				cSide = CM.indexOf('q');
				if ((-1 == cSide) || (toCol != origRookPos))
				{
					cValid = false;
				}
			}
			else if ('h' == castleSide)
			{
				my_alert('black h = '+castleSide);
				cSide = CM.indexOf('k');
				if ((-1 == cSide) || (toCol != origRookPos))
				{
					cValid = false;
				}
			}
		}

		if ( ! cValid)
		{
			errMsg = "You can only castle if the king or the castling rook has not moved yet";
			return false;
		}

		my_alert('cSide = ' + cSide + '\ncharAt = ' + CM.charAt(cSide + 1) +
			'\nindexOf = ' + files.indexOf(CM.charAt(cSide + 1)))

		if (-1 != files.indexOf(CM.charAt(cSide + 1)) && '' != CM.charAt(cSide + 1))
		{
			my_alert('Rooks are NOT fine as they are\nThey must be checked');
			origRookPos = files.indexOf(CM.charAt(cSide + 1));
		}
		else
		{
			my_alert('Rooks are fine as they are');
		}

		// check every square between the king and the final king location
		for (var i = origKingPos; i != (finlKingPos + dirK); i += dirK)
		{
			if (i < 0 || i > 7) // just a simple test in case things do get out of hand
				break;

			my_alert('i = ' + i + '\ndirK = ' + dirK + '\noK+d = ' + parseInt(origKingPos + dirK) + '\nfK+d = ' + parseInt(finlKingPos + dirK) +
				'\nboard = ' + board[fromRow][i] + '\norigRookPos = ' + origRookPos);

			if (board[fromRow][i] && (i != origRookPos) && (i != origKingPos))
			{
				errMsg = "Le roque ne peut pas se faire en sautant par dessus d'autres pièces.";
				return false;
			}

			if ( ! isSafe(fromRow,i,tmpColor))
			{
				errMsg = "Pour roquer, le roi ne peut doit être en échec, ne doit pas se mettre en échec et ne peut pas non plus traverser une case où il le serais.";
				return false;
			}
		} // end of king for loop

		// check every square between the rook and the final rook location
		for (i = (origRookPos + dirR); i != (finlRookPos + dirR); i += dirR)
		{
			my_alert('i = ' + i + '\ndirR = ' + dirR + '\noR+d = ' + parseInt(origRookPos + dirR) + '\nfR+d = ' + parseInt(finlRookPos + dirR) +
				'\nboard = ' + board[fromRow][i] + '\norigRookPos = ' + origRookPos);

			if (board[fromRow][i] && i != origKingPos)
			{
				errMsg = "Le roque ne peut pas se faire en sautant par dessus d'autres pièces.";
				return false;
			}
		} // end of rook for loop
		my_alert('All castle tests PASSED\n\nso far...');
		return true;
	} // end of castle tests

	/* temporarily move king to destination to see if in check */
	var tmpPiece = board[toRow][toCol];
	board[toRow][toCol] = board[fromRow][fromCol];
	board[fromRow][fromCol] = 0;

	/* The king does not move to a square that is attacked by an enemy piece */
	if ('white' == tmpColor)
		atkColor = BLACK;
	else
		atkColor = WHITE;

	if (isInCheck(tmpColor))
	{
		/* return king to original position */
		board[fromRow][fromCol] = board[toRow][toCol];
		board[toRow][toCol] = tmpPiece;

		my_alert("king -> destination not safe!");

		errMsg = "Vous êtes en échec.";
		return false;
	}

	/* return king to original position */
	board[fromRow][fromCol] = board[toRow][toCol];
	board[toRow][toCol] = tmpPiece;

	/* NORMAL MOVE: */
	if (1 >= Math.abs(toRow - fromRow) && 1 >= Math.abs(toCol - fromCol))
	{
		my_alert("king -> normal move");
		return true;
	}
	/* CASTLING: leave this here for orthodox castling moves in normal games */
	else if ( (518 != id960 && (-1 == fromCol || -2 == fromCol)) || (518 == id960 && fromRow == toRow && 4 == fromCol && Math.abs(toCol - fromCol) == 2) )
	{
		/*
		The following conditions must be met:
				* The King and rook must occupy the same rank (or row).
				* The rook that makes the castling move has not yet moved in the game.
				* The king has not yet moved in the game

				* all these conditions are checked for in the creation of the FEN, so just use the data there.
		*/
		my_alert("isValidMoveKing -> Castling");

		var rookCol = 0;
		if (toCol - fromCol == 2)
			rookCol = 7;

		// check to see if castling is valid before doing anything
		var CM = FEN[numMoves].split(' ')[2];

		var cSide;
		var cValid = true;
		if ('white' == tmpColor)
		{
			// see above castling for comments
			if (2 == toCol && -1 == (cSide = CM.indexOf('Q')))
				cValid = false;
			else if (6 == toCol && -1 == (cSide = CM.indexOf('K')))
				cValid = false;
		}
		else // black
		{
			if (2 == toCol && -1 == (cSide = CM.indexOf('q')))
				cValid = false;
			else if (6 == toCol && -1 == (cSide = CM.indexOf('k')))
				cValid = false;
		}

		if ( ! cValid)
		{
			errMsg = "You can only castle if the king or the castling rook has not moved yet";
			return false;
		}


		/*
				* All squares between the rook and king before the castling move are empty.
		*/
		var tmpStep = (toCol - fromCol) / 2;
		for (i = 4 + tmpStep; i != rookCol; i += tmpStep)
			if (board[fromRow][i] != 0)
			{
				my_alert("king -> castling -> square not empty");

				errMsg = "Le roque ne peut pas se faire en sautant par dessus d'autres pièces.";
				return false;
			}

		/*
				* The king is not in check.
				* The king does not move over a square that is attacked by an enemy piece during the castling move
		*/

		/* NOTE: the king's destination has already been checked, so */
		/* all that's left is it's initial position and it's final one */
		if (isSafe(fromRow, fromCol, tmpColor)
		 && isSafe(fromRow, fromCol + tmpStep, tmpColor))
		{
			my_alert("king -> castling -> VALID!");

			return true;
		}
		else
		{
			my_alert("king -> castling -> moving over attacked square");

			errMsg = "Le roque ne peut pas se faire en sautant par dessus d'autres pièces.";
			return false;
		}
	}
	/* INVALID MOVE */
	else
	{
		my_alert("king -> completely invalid move\nfrom " + fromRow + ", " + fromCol + "\nto " + toRow + ", " + toCol);
		errMsg = "Le roi ne peut pas aller là.";
		return false;
	}

	if (DEBUG)
	{
		alert("king -> unknown error");
		return false;
	}
}

/* checks whether a pawn is making a valid move */
function isValidMovePawn(fromRow,fromCol,toRow,toCol,tmpDir,epCol)
{
	if (arguments.length < 6) // Was epCol not passed as a parameter to this function?
		epCol = -1; // Make sure that epCol is defined
	if ( ( (toRow - fromRow) / Math.abs(toRow - fromRow) ) != tmpDir)
	{
		errMsg = "Le pion ne peut pas aller là.";
		return false;
	}

	/* standard move */
	if ((tmpDir * (toRow - fromRow) == 1) && (toCol == fromCol) && (board[toRow][toCol] == 0))
		return true;
	/* first move double jump - white */
	if ((tmpDir == 1) && (fromRow == 1) && (toRow == 3) && (toCol == fromCol) && (board[2][toCol] == 0) && (board[3][toCol] == 0))
		return true;
	/* first move double jump - black */
	if ((tmpDir == -1) && (fromRow == 6) && (toRow == 4) && (toCol == fromCol) && (board[5][toCol] == 0) && (board[4][toCol] == 0))
		return true;
	/* standard eating DJ-NOTE: Shouldn't we check that the pawn being eaten is of the correct color? */
	else if ((tmpDir * (toRow - fromRow) == 1) && (Math.abs(toCol - fromCol) == 1) && (board[toRow][toCol] != 0))
		return true;
	/* en passant - white */
	else if ((tmpDir == 1) && (fromRow == 4) && (toRow == 5) && (board[4][toCol] == (PAWN | BLACK)))
	{
		/* can only move en passant if last move is the one where the black pawn moved up two */
		if (epCol == toCol ||
			(numMoves >= 0 && prevMove.fromRow == 6 && prevMove.toRow == 4
							&& prevMove.toCol == toCol))
			return true;
		else
		{
			errMsg = "Le pion ne peut par aller là.";
			return false;
		}
	}
	/* en passant - black */
	else if ((tmpDir == -1) && (fromRow == 3) && (toRow == 2) && (board[3][toCol] == PAWN))
	{
		/* can only move en passant if last move is the one where the white pawn moved up two */
		if ( 0 <= numMoves && files.charAt(toCol) == FEN[numMoves].split(' ')[3].charAt(0))
			return true;
		else
		{
			errMsg = "Le pion ne peut par aller là.";
			return false;
		}
	}
	else
	{
		errMsg = "Le pion ne peut par aller là.";
		return false;
	}
}

/* checks whether a knight is making a valid move */
function isValidMoveKnight(fromRow, fromCol, toRow, toCol)
{
	errMsg = "Le cavalier ne peut pas aller là.";
	if (Math.abs(toRow - fromRow) == 2)
	{
		if (Math.abs(toCol - fromCol) == 1)
			return true;
		else
			return false;
	}
	else if (Math.abs(toRow - fromRow) == 1)
	{
		if (Math.abs(toCol - fromCol) == 2)
			return true;
		else
			return false;
	}
	else
	{
		return false;
	}
}

/* checks whether a bishop is making a valid move */
function isValidMoveBishop(fromRow, fromCol, toRow, toCol)
{
	var i;
	if (Math.abs(toRow - fromRow) == Math.abs(toCol - fromCol))
	{
		if (toRow > fromRow)
		{
			if (toCol > fromCol)
			{
				for (i = 1; i < (toRow - fromRow); i++)
					if (board[fromRow + i][fromCol + i] != 0)
					{
						errMsg = "Le fou ne peut pas aller là.";
						return false;
					}
			}
			else
			{
				for (i = 1; i < (toRow - fromRow); i++)
					if (board[fromRow + i][fromCol - i] != 0)
					{
						errMsg = "Le fou ne saute pas par dessus les pièces.";
						return false;
					}
			}

			return true;
		}
		else
		{
			if (toCol > fromCol)
			{
				for (i = 1; i < (fromRow - toRow); i++)
					if (board[fromRow - i][fromCol + i] != 0)
					{
						errMsg = "Le fou ne saute pas par dessus les pièces.";
						return false;
					}
			}
			else
			{
				for (i = 1; i < (fromRow - toRow); i++)
					if (board[fromRow - i][fromCol - i] != 0)
					{
						errMsg = "Le fou ne saute pas par dessus les pièces.";
						return false;
					}
			}

			return true;
		}
	}
	else
	{
		errMsg = "Le fou ne peut pas aller là.";
		return false;
	}
}

/* checks wether a rook is making a valid move */
function isValidMoveRook(fromRow, fromCol, toRow, toCol)
{
	var i;

	if (toRow == fromRow)
	{
		if (toCol > fromCol)
		{
			for (i = (fromCol + 1); i < toCol; i++)
			{
				if (board[fromRow][i] != 0)
				{
					errMsg = "La tour ne saute pas par dessus les pièces.";
					return false;
				}
			}
		}
		else
		{
			for (i = (toCol + 1); i < fromCol; i++)
			{
				if (board[fromRow][i] != 0)
				{
					errMsg = "La tour ne saute pas par dessus les pièces.";
					return false;
				}
			}
		}

		return true;
	}
	else if (toCol == fromCol)
	{
		if (toRow > fromRow)
		{
			for (i = (fromRow + 1); i < toRow; i++)
			{
				if (board[i][fromCol] != 0)
				{
					errMsg = "La tour ne saute pas par dessus les pièces.";
					return false;
				}
			}
		}
		else
		{
			for (i = (toRow + 1); i < fromRow; i++)
			{
				if (board[i][fromCol] != 0)
				{
					errMsg = "La tour ne saute pas par dessus les pièces.";
					return false;
				}
			}
		}

		return true;
	}
	else
	{
		errMsg = "La tour ne peut pas aller là.";
		return false;
	}
}

/* this function checks whether a queen is making a valid move */
function isValidMoveQueen(fromRow, fromCol, toRow, toCol)
{
	if (isValidMoveRook(fromRow, fromCol, toRow, toCol) || isValidMoveBishop(fromRow, fromCol, toRow, toCol))
		return true;

	if (errMsg.search("jump") == -1)
		errMsg = "La reine ne peut pas aller là.";
	else
		errMsg = "La reine ne saute pas par dessus les pièces.";

	return false;
}

/* this functions checks to see if curColor is in check */
function isInCheck(curColor)
{
	var i,j;
	var targetKing = getPieceCode(curColor, "king");

	/* find king */
	for (i = 0; i < 8; i++)
	{
		for (j = 0; j < 8; j++)
		{
			if (board[i][j] == targetKing)
			{
				/* verify it's location is safe */
				return ! isSafe(i, j, curColor);
			}
		}
	}

	/* the next lines will hopefully NEVER be reached */
	errMsg = "ERREUR CRITIQUE : LE ROI N'EST PAS LA !"
	return false;
}

/* Ignoring pins, could the piece on the from-square move to the to-square? */
function isValidNoPinMove(fromRow, fromCol, toRow, toCol, epCol, castleSide)
{
	var isValid;
	var tmpDir = 1;
	var curColor = "white";

	if (board[fromRow][fromCol] & BLACK)
	{
		tmpDir = -1;
		curColor = "black";
	}

	isValid = false;
	my_alert("isValidNoPinMove -> " + (board[fromRow][fromCol] & COLOR_MASK));
	switch(board[fromRow][fromCol] & COLOR_MASK)
	{
		case PAWN:
			isValid = isValidMovePawn(fromRow, fromCol, toRow, toCol, tmpDir, epCol);
			break;

		case KNIGHT:
			isValid = isValidMoveKnight(fromRow, fromCol, toRow, toCol);
			break;

		case BISHOP:
			isValid = isValidMoveBishop(fromRow, fromCol, toRow, toCol);
			break;

		case ROOK:
			isValid = isValidMoveRook(fromRow, fromCol, toRow, toCol);
			break;

		case QUEEN:
			isValid = isValidMoveQueen(fromRow, fromCol, toRow, toCol);
			break;

		case KING:
			isValid = isValidMoveKing(fromRow, fromCol, toRow, toCol, curColor, castleSide);
			break;

		default:  /* ie: not implemented yet */
			my_alert("unknown game piece");
	}
	return isValid;
}

function isValidMove(fromRow, fromCol, toRow, toCol, epCol, castleSide)
{
	var curColor;
	var isValid;
	var tmpPiece;
	var tmpEnPassant;

	if ( ! isValidNoPinMove(fromRow, fromCol, toRow, toCol, epCol, castleSide) )
		return false; // The piece on the from-square doesn't even move in this way

	/* now that we know the move itself is valid, let's make sure we're not moving into check */
	/* NOTE: we don't need to check for the king since it's covered by isValidMoveKing( ) */

	curColor = "white";
	if (board[fromRow][fromCol] & BLACK)
		curColor = "black";

	isValid = true;

	if ((board[fromRow][fromCol] & COLOR_MASK) != KING)
	{
		my_alert("isValidMove -> are we moving into check?");

		/* save current board destination */
		tmpPiece = board[toRow][toCol];

		/* is it an en passant capture? Then remove the captured pawn */
		tmpEnPassant = 0;
		if (((board[fromRow][fromCol] & COLOR_MASK) == PAWN) && (Math.abs(toCol - fromCol) == 1) && (tmpPiece == 0))
		{
			tmpEnPassant = board[fromRow][toCol];
			board[fromRow][toCol] = 0;
		}

		/* update board with move (client-side) */
		board[toRow][toCol] = board[fromRow][fromCol];
		board[fromRow][fromCol] = 0;

		/* are we in check now? */
		if (isInCheck(curColor))
		{
			my_alert("isValidMove -> moving into check -> CHECK!");

			/* if so, invalid move */
			errMsg = "Vous êtes en échec.";
			isValid = false;
		}

		/* restore board to previous state */
		board[fromRow][fromCol] = board[toRow][toCol];
		board[toRow][toCol] = tmpPiece;
		if (tmpEnPassant != 0)
		{
			board[fromRow][toCol] = tmpEnPassant;
		}
	}

	my_alert("isValidMove returns " + isValid);

	return isValid;
}

function canSquareBeBlocked(testRow, testCol, testColor)
{
	var i,j;
	var fromRow;
	var fromCol;
	/*
	NOTE: This function is similar to isSafe( ); however, the pawn detection
	is different. While the original function checks pawns moving diagonally
	or en-passant, this function doesn't.
	Since this function is intended for checkmate detection, specifically the
	canBlockAttacker( ) function, it must validate pawns moving forward.
	Also, king is not /allowed/ to block a square.
	NOTE: testColor is the attacker color!
	*/

	//var DEBUG=true;

	my_alert("in canSquareBeBlocked(" + testRow + ", " + testCol + ", " + testColor + ")");

	var enemyColor = WHITE;  // Attacking
	var myColor = BLACK;    // Blocking

	if (testColor == 'black')
	{
		enemyColor = BLACK; /* 1000 0000 */
		myColor = WHITE;
	}

	/* check for knights first */
	for (i = 0; i < 8; i++) // Check all eight possible knight moves
	{
		fromRow = testRow + knightMove[i][0];
		fromCol = testCol + knightMove[i][1];
		if (isInBoard(fromRow, fromCol))
			if (board[fromRow][fromCol] == (KNIGHT | myColor))  // Knight found
				if (isValidMove(fromRow, fromCol, testRow, testCol))
					return true;  // It can move and block the attack
	}

	/* tactic: start at test pos and check all 8 directions for an attacking piece */
	/* directions:    BLACK:    WHITE:
			0 1 2         2 1 0     6 5 4
			7 * 3         3 * 7     7 * 3
			6 5 4         4 5 6     0 1 2
	*/
	for (j = 0; j < 8; j++)   // Look for pieces in all directions
	{
		fromRow = testRow;
		fromCol = testCol;
		for (i = 1; i < 8; i++) // Distance from the test square
		{
			fromRow += direction[j][0];
			fromCol += direction[j][1];
			if (isInBoard(fromRow, fromCol))
			{ // if square is in board..
				if (board[fromRow][fromCol] != 0)
				{ // We found the first piece in this direction
					if ((board[fromRow][fromCol] & BLACK) == myColor)
					{ // It is my piece
						if (isValidMove(fromRow, fromCol, testRow, testCol))
							return true;  // It can move and block the attack
					}
					break;    // No need to look further in this direction
				}
			}
			else
				break;  // We fell off the edge of the board
		}
	}
	return false; // The attack cannot be blocked
}

/* canBeCaptured returns true if the piece at testRow, testCol can be captured */
function canBeCaptured(testRow, testCol, epCol)
{
	var i;
	var tmpDir = -1;
	var enemyColor = BLACK;
	/* DESIGN NOTE: this function is designed only with CAPTURE checking in mind and should
		not be used for other purposes, e.g. if there is no piece (or a king) on the given square */
	/* Both normal captures and en passant captures are checked. The epCol parameter
		 should contain the column number of the en passant square or -1 if there is none.
		 If epCol >= 0 it indicates that we are replying to a pawn double advance move */

	if (board[testRow][testCol] & BLACK)
	{
		tmpDir = 1;
		enemyColor = WHITE;
	}

	var thePiece = getPieceName(board[testRow][testCol]);
	var atkSquare = getAttackers(testRow, testCol, enemyColor);  // Find all attackers

	for (i = 0; i < atkSquare.length; i++)  // Are the attackers pinned or can they capture?
		if(isValidMove(atkSquare[i][0], atkSquare[i][1], testRow, testCol))
			return true;  // The piece can be captured

	// If thePiece is a pawn can it by captured en passant?
	if (thePiece == 'pawn' && ((testRow == 3 && enemyColor == BLACK) || (testRow == 4 && enemyColor == WHITE)))
	{ // The pawn is on the correct row for a possible e.p. capture
		if (testCol > 0 && board[testRow][testCol-1] == (PAWN | enemyColor))
			if (board[testRow + tmpDir][testCol] == 0) // It's not a regular capture
					if (isValidMove(testRow, testCol-1, testRow + tmpDir, testCol, epCol))
						return true;  // En passant capture

		if (testCol < 7 && board[testRow][testCol+1] == (PAWN | enemyColor))
			if (board[testRow + tmpDir][testCol] == 0) // It's not a regular capture
					if (isValidMove(testRow, testCol+1, testRow + tmpDir, testCol. epCol))
						return true;  // En passant capture
	}
	return false; // The piece cannot be captured
}

/* Find all pieces of color atkColor that attack the given square */
/* Note: Even if a piece attacks a square it may not be able to move there */
/* Note: En passant captures are not considered by this function */
function getAttackers(toRow, toCol, atkColor)
{
	var i,j;
	var fromRow;
	var fromCol;
	var atkSquare = new Array( );

	/* check for knights first */
	for (i = 0; i < 8; i++) { // Check all eight possible knight moves
		fromRow = toRow + knightMove[i][0];
		fromCol = toCol + knightMove[i][1];
		if (isInBoard(fromRow, fromCol))
			if (board[fromRow][fromCol] == (KNIGHT | atkColor)) // Enemy knight found
					atkSquare[atkSquare.length] = [fromRow, fromCol];
	}
	/* tactic: start at test square and check all 8 directions for an attacking piece */
	/* directions:
		0 1 2
		7 * 3
		6 5 4
	*/

	for (j = 0; j < 8; j++)   // Look in all directions
	{
		fromRow = toRow;
		fromCol = toCol;
		for (i = 1; i < 8; i++) // Distance from thePiece
		{
			fromRow += direction[j][0];
			fromCol += direction[j][1];
			if (isInBoard(fromRow, fromCol))
			{
				if (board[fromRow][fromCol] != 0)
				{ // We found the first piece in this direction
					if((board[fromRow][fromCol] & BLACK) == atkColor) // It is an enemy piece
					{
						if(isAttacking(board[fromRow][fromCol], fromRow, fromCol, getPieceColor(board[fromRow][fromCol]), toRow, toCol))
							atkSquare[atkSquare.length] = [fromRow, fromCol]; // An attacker found
					}
					break;    // No need to look further in this direction
				}
			}
			else
				break;
		}
	}
	return atkSquare;
}

/* Is the given square attacked by a piece of color atkColor? */
function isAttacked(toRow, toCol, atkColor)
{
	return getAttackers(toRow, toCol, atkColor).length > 0;
}

/* Generate moves for a rook, bishop or queen placed at the from-square */
function genSlideMoves(fromRow, fromCol, moveDir)
{
	var i,j;
	var toRow;
	var toCol;
	var toSquare = new Array( ); // Store the generated moves
	var enemyColor = BLACK;
	if (board[fromRow][fromCol] & BLACK)
	{
		enemyColor = WHITE;
	}
	for (j = 0; j < moveDir.length; j++)  // Check all (valid) directions
	{
		toRow = fromRow;
		toCol = fromCol;
		for (i = 1; i < 8; i++) // Distance from the piece
		{
			toRow += moveDir[j][0];
			toCol += moveDir[j][1];
			if (isInBoard(toRow, toCol))
			{
				if (board[toRow][toCol] != 0)
				{ // We found the first piece in this direction
					if((board[toRow][toCol] & BLACK) == enemyColor)  // It's an enemy piece
					{
						if(isValidMove(fromRow, fromCol, toRow, toCol))
							toSquare[toSquare.length] = [toRow, toCol]; // A capture
					}
					break;    // No need to look further in this direction
				}
				else  // an empty square
				{
					if(isValidMove(fromRow, fromCol, toRow, toCol))
						toSquare[toSquare.length] = [toRow, toCol]; // Move to an empty square
				}
			}
			else
				break;
		}
	}
	return toSquare;
}

/* Generate all moves for the piece at the given square */
/* Currently this function is only used to test for stalemate.
	 Therefore castling moves are not checked as they are not relevant
	 for that purpose */
function genPieceMoves(fromRow, fromCol)
{
	var i;
	var thePiece;
	var toSquare;
	var forwardDir;
	var toRow;
	var toCol;
	var enemyColor = BLACK;
	if (board[fromRow][fromCol] & BLACK)
	{
		enemyColor = WHITE;
	}
	thePiece = board[fromRow][fromCol];

	toSquare = new Array( );

	switch(thePiece & COLOR_MASK)
	{
		case PAWN:
			forwardDir = 1;
			if (enemyColor == WHITE)
				forwardDir = -1;

			for (i = 0; i < 4; i++) {
				toRow = fromRow + pawnMove[i][0] * forwardDir;
				toCol = fromCol + pawnMove[i][1];
				if (isInBoard(toRow, toCol))
					if (board[toRow][toCol] == 0 || (board[toRow][toCol] & BLACK) == enemyColor)
						if(isValidMove(fromRow, fromCol, toRow, toCol))
							toSquare[toSquare.length] = [toRow, toCol];
			}
			break;

		case ROOK:
			toSquare = genSlideMoves(fromRow, fromCol, horzVertMove);
			break;

		case KNIGHT:
			for (i = 0; i < 8; i++) { // Check all eight possible knight moves
				toRow = fromRow + knightMove[i][0];
				toCol = fromCol + knightMove[i][1];
				if (isInBoard(toRow, toCol))
					if (board[toRow][toCol] == 0 || (board[toRow][toCol] & BLACK) == enemyColor)
						if(isValidMove(fromRow, fromCol, toRow, toCol))
							toSquare[toSquare.length] = [toRow, toCol];
			}
			break;

		case BISHOP:
			toSquare = genSlideMoves(fromRow, fromCol, diagonalMove);
			break;

		case QUEEN:
			toSquare = genSlideMoves(fromRow, fromCol, direction);
			break;

		case KING:
			for (i = 0; i < 8; i++) { // Check all eight possible king moves
				toRow = fromRow + direction[i][0];
				toCol = fromCol + direction[i][1];
				if (isInBoard(toRow, toCol))
					if (board[toRow][toCol] == 0 || (board[toRow][toCol] & BLACK) == enemyColor)
						if(isValidMove(fromRow, fromCol, toRow, toCol))
							toSquare[toSquare.length] = [toRow, toCol];
			}
			break;
	}

	return toSquare;
}

/* Generate all possible moves for the side indicated by the myColor parameter */
function genAllMoves(myColor)
{
	var i,j;
	var moves = new Array( );
	for (i = 0; i < 8; i++)     // For all board rows
	{
		for (j = 0; j < 8; j++)   // Check all columns
		{
			if(board[i][j] != 0 && ((board[i][j] & BLACK) == myColor))
			{
				if(typeof moves[i] == 'undefined') {
					moves[i] = new Array( );
				}

				moves[i][j] = genPieceMoves(i, j);
			}
		}
	}
	return moves;
}

/* Count how many different moves are possible in the current position for myColor */
function countMoves(myColor)
{
	var i,j;
	var moves = genAllMoves(myColor);
	var count = 0;
	for (i in moves)      // For all board rows
	{
		for (j in moves[i])   // Check all columns
		{
			count += moves[i][j].length;
		}
	}
	return count;
}

function isFiftyMoveDraw(FEN)
{ // Returns true if the game is drawn due to the fifty move draw rule (no captures or pawn moves)
	return FEN.split(' ')[4] >= 100;
}

function isThirdTimePosDraw(FEN)
{ // Returns true if this is the third time that the exact same position arises with the same side to move
	var i;
	var currentPos = FEN[FEN.length - 1].split(' ')[0];
	var count = 0;
	for (i = 0; i < FEN.length - 1; i++)
	{
		if(currentPos == FEN[i].split(' ')[0])
		{
			count++;
		}
	}
	return count >= 2;
}



function my_alert(thing)
{
	if (DEBUG)
	{
		alert(thing);
	}
}



Merci de bien vouloir m'aider à y voir plus clair dans cette enquête.







Configuration: Windows / Opera Next 36.0.2130.80
Afficher la suite 

Votre réponse

3 réponses

Messages postés
23537
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
7 décembre 2018
0
Merci
Bonjour,


une instruction qui ne se fait pas.
Celle ci dépend de la condition:
countMoves(myColor) qui doit être égal à zéro et de type numérique à mon avis.

Tu as déjà ta réponse.... ce n'est pas l'instruction "alert" qui ne se fait pas.... juste que ton IF n'entre jamais à cette ligne...

As tu vérifié que
countMoves(myColor)
retournait zéro ?
Pour ça, tu n'as qu'à placer un console.log ou un alert AVANT le IF avec ta variable pour le savoir....



Max747
Messages postés
74
Date d'inscription
vendredi 11 juillet 2014
Dernière intervention
9 décembre 2018
-
A la lecture de la console, countMoves(myColor) ne retourne rien apparemment.
D'ailleurs voici en image le résultat des consoles:



Je pense qu'il faille désormais s'orienter vers ligne 1347 du fichier validation.js.
Dont la variable count
var count = 0;

, si je ne me trompe, devrait obtenir la valeur zéro pour correspondre au fait qu' un des joueurs ne puissent plus jouer.Rendant ainsi la partie nulle ou pat en terme échiquéen.

Quelle recherche puis je entreprendre à partir de ce constat?
jordane45
Messages postés
23537
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
7 décembre 2018
-
Déjà... comment as tu testé la console ?
Tu n'as pas juste saisie la commande dedans mais bien placée dans ton code juste avant ton if hein ?? rassures moi...
Pourrais tu poster le code contenant ton "console.log" ?
Ca serait bien également de nous dire où sont déclarées (et comment.. avec quelles lignes de code...) les variables WHITE et BLACK ...

Sachant que, comme le montre ton imprime écran... tu as une jolie erreur concernant ta variable myColor ...
Tu peux également faire un console.log de cette variable...
Commenter la réponse de jordane45
Messages postés
74
Date d'inscription
vendredi 11 juillet 2014
Dernière intervention
9 décembre 2018
0
Merci
Déjà... comment as tu testé la console ?
Tu n'as pas juste saisie la commande dedans mais bien placée dans ton code juste avant ton if hein ??


Si j'ai placé le scrypt suivant dans la console:
consol.log(countMoves(myColor));

et non pas dans le fichier avant le if.
Je viens de le faire comme indiqué ci dessous mais c'est pire car aucune information n'est retournée.

Je ne demande pas mieux de te rassurer.Mais pour cela il faudrait que tu m'aides d'avantage en m'indiquant le code exact que je dois écrire avant le if (ligne 35 du fichier board.js).
Pour l'instant est ce cela en ligne 4 ci dessous?
function isGameDrawn( )
{
	var i,j;
consol.log(countMoves(myColor));
	// Stalemate?  // is all this needed, it is generated in php, so... - Pat est tout ce qui est nécessaire, il est généré en php, alors ...
	if (gameState == 'stalemate')
	{
		var myColor = WHITE;

		if (0 <= numMoves && 'b' == FEN[FEN.length - 1].split(' ')[1])
		{
			myColor = BLACK;
		}

		if (0 == countMoves(myColor))
		{
			alert('Nulle (pat)\nVous devriez offrir la nulle à votre adversaire.');
		}

		return "stalemate";
	}

	// Is the game drawn due to insufficient material to checkmate?
	var count = 0;
	var canCheckmate = false;

	for (i = 0; i < 8; i++)
	{
		for (j = 0; j < 8; j++)
		{
			if (board[i][j] != 0 && (board[i][j] & COLOR_MASK) != KING)
			{
				if ((board[i][j] & COLOR_MASK) != KNIGHT && (board[i][j] & COLOR_MASK) != BISHOP)
					canCheckmate = true;
				else
					count++;
			}
		}
	}
	if (count < 2 && ! canCheckmate)
	{
		alert('Nulle (materiel insuffisant pour mater)\nVous devriez offrir la nulle à votre adversaire.');
		return "material";
	}

	// Is the game drawn because this is the third time that the exact same position arises?
	if (numMoves >= 0 && isThirdTimePosDraw(FEN))
	{
		alert('Nulle (cette position a été rencontrée trois fois)\nVous devriez offrir la nulle à votre adversaire.');
		return "3";
	}

	// Draw because of no capture or pawn move for the last 50 moves?
	if (numMoves >= 0 && isFiftyMoveDraw(FEN[FEN.length-1]))
	{
		alert('Nulle (règle des 50 coups)\nVous devriez offrir la nulle à votre adversaire.');
		return "50";
	}

	return false;
}

A la lecture de la console sous Firefox, je ne le crois pas:

Car aucune information n'est présenté cette fois ci.
Si mon code est bon ligne 4, c'est que je ne sais pas me servir de la console alors!Ou utiliser le site pour lire le fichier Board.js.
En tout ca j' essaie de comprendre ce qui ne va pas à ce stade de la recherche.

Rassures moi aussi que je vais pouvoir arriver à résoudre ce problème avec ton aide si tu le veux bien.
Pour ma part, j'ai la volonté de le résoudre et prêt à y passer le temps qu'il faudra pour cela.A te présenter ce que tu me demandes (des images, les codes utilisés ou tout autres de tes demandes comme je me suis toujours efforcé à le faire).Et qui a toujours abouti à la résolution des problèmes!
Pour te rassurer, j' apprends beaucoup par ta lecture. Et je garde précieusement tes écrits.
Prenons notre temps.
Rien ne presse car ce n'est que du loisir finalement.

A demain matin pour la suite de cette "enquête" si tu veux bien.
Merci.
Max747
Messages postés
74
Date d'inscription
vendredi 11 juillet 2014
Dernière intervention
9 décembre 2018
-
Comme tu pourras le voir la partie est terminée par le pat du fait que le roi blanc bien que n'étant pas en échec, celui ci ne peut plus bouger.



gameState n'indique aucune valeur.
C'est néanmoins une fonction crée dans un fichier nommé chessgame.inc.php comme ceci:
function gamestate()
{
	empty($this->error) or trigger_error(_MD_CHESS_ERROR, E_USER_ERROR);
	return $this->gamestate;
}

Mais au paravent ici toujours dans le même fichier:
	var $gamestate;

Ainsi que dans beaucoup d'autres endroits.
jordane45
Messages postés
23537
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
7 décembre 2018
> Max747
Messages postés
74
Date d'inscription
vendredi 11 juillet 2014
Dernière intervention
9 décembre 2018
-
la fonction gameState que tu nous montres provient d'un fichier PHP.
et le var gameState .. c'est du Javascript....
A quel moment fais tu le lien entre les deux ??
Max747
Messages postés
74
Date d'inscription
vendredi 11 juillet 2014
Dernière intervention
9 décembre 2018
-
Je ne trouve pas le lien entre les deux.
Alors voici le fichier chessgame.inc.php où devrait se trouver ce lien d'après moi:
<?php
// ------------------------------------------------------------------------- //
//  This program is free software; you can redistribute it and/or modify     //
//  it under the terms of the GNU General Public License as published by     //
//  the Free Software Foundation; either version 2 of the License, or        //
//  (at your option) any later version.                                      //
//                                                                           //
//  You may not change or alter any portion of this comment or credits       //
//  of supporting developers from this source code or any supporting         //
//  source code which is considered copyrighted (c) material of the          //
//  original comment or credit authors.                                      //
//                                                                           //
//  This program is distributed in the hope that it will be useful,          //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of           //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            //
//  GNU General Public License for more details.                             //
//                                                                           //
//  You should have received a copy of the GNU General Public License        //
//  along with this program; if not, write to the Free Software              //
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA //
//  ------------------------------------------------------------------------ //
//  Author: Dave Lerner <http://Dave-L.com>                                  //
//  ------------------------------------------------------------------------ //
//  Adapted from Online Chess Club (OCC) version 1.0.10, which was written   //
//  by Michael Speck <http://lgames.sf.net> and published under the GNU      //
//  General Public License.                                                  //
//  ------------------------------------------------------------------------ //

/**
 * class ChessGame
 *
 * @package chess
 * @subpackage game
*/
define("gsRunning"   , 0);
define("gsMate"      , 1);
define("gsStalemate" , 2);
define("gsCheck"     , 3);


define('_MD_CHESS_ERROR',             'Error');
define('_MD_CHESS_FENBAD_LENGTH',          'invalid length');
define('_MD_CHESS_FENBAD_FIELD_COUNT',     'wrong number of fields');
define('_MD_CHESS_FENBAD_PP_INVALID',      'piece placement invalid');
define('_MD_CHESS_FENBAD_AC_INVALID',      'active color invalid');
define('_MD_CHESS_FENBAD_CA_INVALID',      'castling availability invalid');
define('_MD_CHESS_FENBAD_EP_INVALID',      'en passant target_square invalid');
define('_MD_CHESS_FENBAD_HC_INVALID',      'halfmove clock invalid');
define('_MD_CHESS_FENBAD_FN_INVALID',      'fullmove number invalid');
define('_MD_CHESS_FENBAD_MATERIAL',        'insufficient mating material');
define('_MD_CHESS_FENBAD_IN_CHECK',        'player to move cannot have opponent in check');
define('_MD_CHESS_FENBAD_CA_INCONSISTENT', 'castling availability inconsistent with piece placement');
define('_MD_CHESS_FENBAD_EP_COLOR',        'en passant target square wrong color');
define('_MD_CHESS_FENBAD_EP_NO_PAWN',      'en passant target square for nonexistent pawn');

/**
 * The purpose of this class is to handle chess moves.
 *
 * An instantiation of this class comprises the data essential for handling chess
 * moves in a specific game, and provides the requisite methods.
 *
 * - Input:      Game state and proposed move.
 * - Processing: Check the legality of the move, and update the game state if the move is legal.
 * - Output:     Indication of the move's legality, and the (possibly) updated game state.
 *
 * In addition to the above, there are utility methods for converting between Standard Algebraic
 * Notation (SAN) and a notation similar to Long Algebraic Notation.
 *
 * @package chess
 * @subpackage game
 */
class ChessGame {

	/**
		* Indicates whether object is valid.
		*
		* If empty string (''), indicates this is a valid object; otherwise contains an error message.
	 * Should be checked after creating an instance of this class.
		*
		* @var string $error
		*/
	var $error;

	 /**
		* gamestate
		*
	 * The game state is represented as an array with the following elements: - L'état du jeu est représenté sous forme de tableau avec les éléments suivants:
	 *
	 *  - 'fen_piece_placement'
	 *  - 'fen_active_color'
	 *  - 'fen_castling_availability'
	 *  - 'fen_en_passant_target_square'
	 *  - 'fen_halfmove_clock'
	 *  - 'fen_fullmove_number'
	 *  - 'pgn_result'
	 *  - 'pgn_fen'
	 *  - 'pgn_movetext'
	 *
	 * The elements prefixed with 'fen_' are standard Forsyth-Edwards Notation (FEN) elements,
	 * and the elements prefixed with 'pgn_' are standard Portable Game Notation (PGN) elements.
	 *
	 * Each element is a string.
		*
		* @var array $gamestate
		*/
	var $gamestate;

	 /**
		* board
		*
	 * A 64-element array, constructed from fen_piece_placement, is used for handling moves.
	 * Its indices are related to the standard tile coordinates as follows:
	 *
		* <pre>
	 * 8 | 56 57 58 59 60 61 62 63
	 * 7 | 48 49 50 51 52 53 54 55
	 * 6 | 40 41 42 43 44 45 46 47
	 * 5 | 32 33 34 35 36 37 38 39
	 * 4 | 24 25 26 27 28 29 30 31
	 * 3 | 16 17 18 19 20 21 22 23
	 * 2 |  8  9 10 11 12 13 14 15
	 * 1 |  0  1  2  3  4  5  6  7
	 *    ------------------------
	 *      a  b  c  d  e  f  g  h
		* </pre>
	 *
	 * For example, $board[17] is tile b3 and $board[55] is tile h7.
		*
		* @var array $board
		*/
	var $board;

	 /**
		* for auto-completion of moves
		* @var string $ac_move
		*/
	var $ac_move;

	 /**
		* array of white's pieces
		* @var array $w_figures
		*/
	var $w_figures;

	 /**
		* array of black's pieces
		* @var array $b_figures
		*/
	var $b_figures;


	 /**
	 * updated by handleMove, not used now but might be used in future
		* @var string $last_move
		*/
	var $last_move;

	 /**
	 * updated by handleMove, not used now but might be used in future
		* @var string $captured_piece
		*/
	var $captured_piece;

// --------------
// PUBLIC METHODS
// --------------

/**
 * constructor
 *
 * If a failure occurs, $this->error is set to a string containing an error message;
 * otherwise $this->error is set to an empty string.
 *
 * Example:
 * <pre>
 *    $chessgame = new ChessGame($fen);
 *    if (!empty($chessgame->error)) {
 *      echo "'$fen' invalid: $chessgame->error\n";
 *    }
 * </pre>
 *
 * @param mixed $param  If $param is an array, an existing game is loaded using $param as the nine-element gamestate array described above.
 * If $param is a non-empty string, a new game is created using $param as a FEN setup position.
 * Otherwise, a new game is created using the standard starting position.
 */
function __construct($param = null)
{
	// for now
	$this->browsing_mode  = 0;

	if (is_array($param)) {

		$this->gamestate = $param;
		$this->error     = '';

	} elseif (is_string($param) and !empty($param)) {

		$this->error = $this->init_gamestate($param);

	} else {

		$this->init_gamestate();
		$this->error = '';
	}
}

/**
 * Handle a move.
 *
 * @param string $move
 * @return array A two-element array:
 *  - $move_performed: true if the move was performed and the game state has been updated, false otherwise
 *  - $move_result_text: text message
 */
function move($move)
{
	empty($this->error) or trigger_error(_MD_CHESS_ERROR, E_USER_ERROR);
	return $this->handleMove($move);
}

/**
 * get game state
 *
 * @return array
 */
function gamestate()
{
	empty($this->error) or trigger_error(_MD_CHESS_ERROR, E_USER_ERROR);
	return $this->gamestate;
}

// ----------------------------------------------------------------
// PRIVATE METHODS - intended for use only by methods of this class
// ----------------------------------------------------------------

/**
 * Initialize gamestate for a new game.
 *
 * If a non-empty string $fen is provided, the game is initialized using $fen as a FEN setup position.
 * Otherwise the game is initialized using the standard starting position.
 *
 * @param  string  $fen
 * @return string  empty string on success, or error message on failure
 *
 * @access private
 */
function init_gamestate($fen = null)
{
	$this->gamestate = array();

	if (!empty($fen)) {
		$setup = true;
	} else {
		$setup = false;
		$fen   = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';
	}

	// check that data is not unreasonably short or long
	if (strlen($fen) < 23 or strlen($fen) > 100) {
		return _MD_CHESS_FENBAD_LENGTH; // invalid length
	}

	$fen_data = explode(' ', $fen);

	if (count($fen_data) != 6) {
		return _MD_CHESS_FENBAD_FIELD_COUNT; // wrong number of fields
	}

	$this->gamestate['fen_piece_placement']          = $fen_data[0];
	$this->gamestate['fen_active_color']             = $fen_data[1];
	$this->gamestate['fen_castling_availability']    = $fen_data[2];
	$this->gamestate['fen_en_passant_target_square'] = $fen_data[3];
	$this->gamestate['fen_halfmove_clock']           = $fen_data[4];
	$this->gamestate['fen_fullmove_number']          = $fen_data[5];
	$this->gamestate['pgn_fen']                      = $setup ? $fen : null;
	$this->gamestate['pgn_result']                   = '*';
	$this->gamestate['pgn_movetext']                 = '*';

	if (!$this->fen_piece_placement_to_board())
	{
		return _MD_CHESS_FENBAD_PP_INVALID; // piece_placement invalid
	}
	elseif ($this->gamestate['fen_active_color'] != 'w' and $this->gamestate['fen_active_color'] != 'b')
	{
		return _MD_CHESS_FENBAD_AC_INVALID; // active_color invalid
	}
	// Since fen_piece_placement_to_board() checked $fen for the correct number of fields above, $castling_availability is non-empty.
	elseif ($this->gamestate['fen_castling_availability'] != '-' and !preg_match('/^(?:K\w?)?(?:Q\w?)?(?:k\w?)?(?:q\w?)?$/', $this->gamestate['fen_castling_availability']))
	{
		return _MD_CHESS_FENBAD_CA_INVALID; // castling_availability invalid
	}
	elseif ($this->gamestate['fen_en_passant_target_square'] != '-' and !preg_match('/^[a-h][36]$/', $this->gamestate['fen_en_passant_target_square']))
	{
		return _MD_CHESS_FENBAD_EP_INVALID; // en_passant_target_square invalid
	}
	elseif (!preg_match('/^\d{0,4}$/', $this->gamestate['fen_halfmove_clock']))
	{
		return _MD_CHESS_FENBAD_HC_INVALID; // halfmove_clock invalid
	}
	elseif (!preg_match('/^\d{0,4}$/', $this->gamestate['fen_fullmove_number']) or $this->gamestate['fen_fullmove_number'] < 1)
	{
		return _MD_CHESS_FENBAD_FN_INVALID; // fullmove_number invalid
	}
	elseif ($this->insufficient_mating_material())
	{
		return _MD_CHESS_FENBAD_MATERIAL; // insufficient mating material
	}
	elseif (($this->gamestate['fen_active_color'] == 'w' and $this->kingIsUnderAttack('b', 'w'))
		or   ($this->gamestate['fen_active_color'] == 'b' and $this->kingIsUnderAttack('w', 'b')))
	{
		return _MD_CHESS_FENBAD_IN_CHECK; // player to move cannot have opponent in check
	}
	elseif ((strstr($this->gamestate['fen_castling_availability'], 'K') and ($this->board[ 4] != 'wK' or $this->board[ 7] != 'wR'))
		or   (strstr($this->gamestate['fen_castling_availability'], 'Q') and ($this->board[ 4] != 'wK' or $this->board[ 0] != 'wR'))
		or   (strstr($this->gamestate['fen_castling_availability'], 'k') and ($this->board[60] != 'bK' or $this->board[63] != 'bR'))
		or   (strstr($this->gamestate['fen_castling_availability'], 'q') and ($this->board[60] != 'bK' or $this->board[56] != 'bR')))
	{
		return _MD_CHESS_FENBAD_CA_INCONSISTENT; // castling availability inconsistent with piece placement
	}
	elseif (($this->gamestate['fen_en_passant_target_square'] != '-' and $this->gamestate['fen_en_passant_target_square']{1} == 3 and $this->gamestate['fen_active_color'] != 'b')
		or   ($this->gamestate['fen_en_passant_target_square'] != '-' and $this->gamestate['fen_en_passant_target_square']{1} == 6 and $this->gamestate['fen_active_color'] != 'w'))
	{
		return _MD_CHESS_FENBAD_EP_COLOR; // en passant target square wrong color
	}
	elseif ($this->gamestate['fen_en_passant_target_square'] != '-' and $this->gamestate['fen_en_passant_target_square']{1} == 3
		and $this->board[$this->boardCoordToIndex($this->gamestate['fen_en_passant_target_square']{0} . '4')] != 'wP')
	{
		return _MD_CHESS_FENBAD_EP_NO_PAWN; // en passant target square for nonexistent pawn
	}
	elseif ($this->gamestate['fen_en_passant_target_square'] != '-' and $this->gamestate['fen_en_passant_target_square']{1} == 6
		and $this->board[$this->boardCoordToIndex($this->gamestate['fen_en_passant_target_square']{0} . '5')] != 'bP')
	{
		return _MD_CHESS_FENBAD_EP_NO_PAWN; // en passant target square for nonexistent pawn
	}

	#echo "In " . __CLASS__ . '::' . __FUNCTION__ . "\n";#*#DEBUG#
	#var_dump('gamestate', $this->gamestate);#*#DEBUG#

	// save the current FEN to the board
	$this->fen_piece_placement_to_board( );
	return ''; // successful
}

/**
 * Check whether a path is blocked.
 *
 * check a series of tiles given a start, an end tile
 * which is not included to the check and a position
 * change for each iteration. return true if not blocked.
 * all values are given for 1dim board.
 *
 * @param int $start
 * @param int $end
 * @param int $change
 * @return bool
 *
 * @access private
 */
function pathIsNotBlocked($start, $end, $change)
{
	for ($pos = $start; $pos != $end; $pos += $change) {

		#echo "path: $pos: '$this->board[$pos]' "; #*#DEBUG#

		if (!$this->is_empty_tile($pos))
			return false;
	}

	return true;
}

/**
 * Get path.
 *
 * get the empty tiles between start and end as an 1dim array.
 * whether the path is clear is not checked.
 *
 * @param int $start
 * @param int $end
 * @param int $change
 * @return array
 *
 * @access private
 */
function getPath($start, $end, $change)
{
	$path = array();
	for ($pos = $start; $pos != $end; $pos += $change) {
		$path[] = $pos;
	}

	return $path;
}

/**
 * get path change
 *
 * get the change value that must be added to create
 * the 1dim path for figure moving from fig_pos to
 * dest_pos. it is assumed that the movement is valid!
 * no additional checks as in tileIsReachable are
 * performed. rook, queen and bishop are the only
 * units that can have empty tiles in between.
 *
 * @param string $fig
 * @param int $fig_pos
 * @param int $dest_pos
 * @return int
 *
 * @access private
 */
function getPathChange($fig, $fig_pos, $dest_pos)
{
	$change = 0;

	$fy = floor($fig_pos / 8);
	$fx = $fig_pos % 8;
	$dx = $dest_pos % 8;
	$dy = floor($dest_pos / 8);

	switch ( $fig ) {

		/* bishop */
		case 'B':
			$change =  ($dy < $fy) ? -8 : 8;
			$change += ($dx < $fx) ? -1 : 1;
			break;

		/* rook */
		case 'R':
			if ($fx == $dx) {
				$change = ($dy < $fy) ? -8 : 8;
			} else {
				$change = ($dx < $fx) ? -1 : 1;
			}
			break;

		/* queen */
		case 'Q':
			if (abs($fx - $dx) == abs($fy - $dy)) {
				$change =  ($dy < $fy) ? -8 : 8;
				$change += ($dx < $fx) ? -1 : 1;
			} elseif ($fx == $dx) {
				$change = ($dy < $fy) ? -8 : 8;
			}
			else {
				$change = ($dx < $fx) ? -1 : 1;
			}
			break;
	}

	return $change;
}

/**
 * Check whether a tile is reachable.
 *
 * check whether dest_pos is in reach for unit of fig_type
 * at tile fig_pos. it is not checked whether the tile
 * itself is occupied but only the tiles in between.
 * this function does not check pawns.
 *
 * @param string $fig
 * @param int $fig_pos
 * @param int $dest_pos
 * @return bool
 *
 * @access private
 */
function tileIsReachable($fig, $fig_pos, $dest_pos)
{
	if ( $fig_pos==$dest_pos) return;
	$result = 0;
	$fy = floor($fig_pos/8); $fx = $fig_pos%8;
	$dy = floor($dest_pos/8); $dx = $dest_pos%8;
	/* DEBUG:  echo "$fx,$fy --> $dx,$dy: "; */
	switch ( $fig )
	{
		/* knight */
		case 'N':
			if ( abs($fx-$dx)==1 && abs($fy-$dy)==2 )
				$result = 1;
			if ( abs($fy-$dy)==1 && abs($fx-$dx)==2 )
				$result = 1;
			break;
		/* bishop */
		case 'B':
			if ( abs($fx-$dx) != abs($fy-$dy) )
				break;
			if ( $dy < $fy ) $change = -8; else $change =  8;
			if ( $dx < $fx ) $change -= 1; else $change += 1;
			if ( $this->pathIsNotBlocked( $fig_pos+$change, $dest_pos, $change ) )
				$result = 1;
			break;
		/* rook */
		case 'R':
			if ( $fx!=$dx && $fy!=$dy )
				break;
			if ( $fx==$dx )
			{
				if ( $dy<$fy ) $change = -8; else $change = 8;
			}
			else {
				if ( $dx<$fx ) $change = -1; else $change = 1;
			}
			if ( $this->pathIsNotBlocked( $fig_pos+$change, $dest_pos, $change ) )
				$result = 1;
			break;
		/* queen */
		case 'Q':
			if ( abs($fx-$dx) != abs($fy-$dy) && $fx!=$dx && $fy!=$dy )
				break;
			if ( abs($fx-$dx) == abs($fy-$dy) )
			{
				if ( $dy < $fy ) $change = -8; else $change =  8;
				if ( $dx < $fx ) $change -= 1; else $change += 1;
			}
			else if ( $fx==$dx ) {
				if ( $dy<$fy ) $change = -8; else $change = 8;
			}
			else
			{
				if ( $dx<$fx ) $change = -1; else $change = 1;
			}
			if ( $this->pathIsNotBlocked( $fig_pos+$change, $dest_pos, $change ) )
				$result = 1;
			break;
		/* king */
		case 'K':
			if ( abs($fx-$dx) > 1 || abs($fy-$dy) > 1 ) break;
			$kings = 0;
			$adj_tiles = $this->getAdjTiles( $dest_pos );
			foreach( $adj_tiles as $tile )
				if ($this->board[$tile]{1} == 'K' ) $kings++;
			if ( $kings == 2 ) break;
			$result = 1;
			break;
	}

	/* DEBUG: echo " $result<BR>"; */
	return $result;
}

/**
 * Check whether a pawn can attack a tile.
 *
 * @param int $fig_pos Position of pawn
 * @param int $dest_pos Tile to check
 * @return bool True if pawn can attack
 *
 * @access private
 */
function checkPawnAttack($fig_pos, $dest_pos)
{
	if ( $this->board[$fig_pos]{0} == 'w' )
	{
		if ( ($fig_pos % 8) > 0 && $dest_pos == $fig_pos+7 )
			return true;
		if ( ($fig_pos % 8) < 7 && $dest_pos == $fig_pos+9 )
			return true;
	}
	else if ( $this->board[$fig_pos]{0} == 'b' )
	{
		if ( ($fig_pos % 8) < 7 && $dest_pos == $fig_pos-7 )
			return true;
		if ( ($fig_pos % 8) > 0 && $dest_pos == $fig_pos-9 )
			return true;
	}
	return false;
}

/**
 * Check whether a pawn move is legal.
 *
 * check whether pawn at figpos may move to destpos.
 * first move may be two tiles instead of just one.
 * again the last tile is not checked but just the path
 * in between.
 *
 * @param int $fig_pos  Position of pawn.
 * @param int $dest_pos  Destination tile.
 * @return bool True if move is legal
 *
 * @access private
 */
function checkPawnMove($fig_pos, $dest_pos)
{
	$first_move = 0;

	if ( $this->board[$fig_pos]{0} == 'w' )
	{
		if ( $fig_pos >= 8 && $fig_pos <= 15 )
			$first_move = 1;
		if ( $dest_pos==$fig_pos+8 )
			return true;
		if ( $first_move && ( $dest_pos==$fig_pos+16 ) )
		if ($this->is_empty_tile($fig_pos + 8))
			return true;
	}
	else if ($this->board[$fig_pos]{0} == 'b' )
	{
		if ( $fig_pos >= 48 && $fig_pos <= 55 )
			$first_move = 1;
		if ( $dest_pos==$fig_pos-8 )
			return true;
		if ( $first_move && ( $dest_pos==$fig_pos-16 ) )
		if ($this->is_empty_tile($fig_pos - 8))
			return true;
	}
	return false;
}

/**
 * Check whether a tile is under attack by the specified player.
 *
 * @param string $opp  Attacking color ('w' or 'b')
 * @param int $dest_pos  Tile to check
 * @return bool
 *
 * @access private
 */
function tileIsUnderAttack($opp, $dest_pos)
{
#var_dump('tileIsUnderAttack, opp', $opp, 'dest_pos', $dest_pos, 'board', $board);#*#DEBUG#
	for ( $i = 0; $i < 64; $i++ )
		if ($this->board[$i]{0} == $opp )
		{
			if ( ($this->board[$i]{1}=='P' && $this->checkPawnAttack($i,$dest_pos)) ||
					 ($this->board[$i]{1}!='P' &&
								$this->tileIsReachable($this->board[$i]{1},$i,$dest_pos)) )
			{
				/*DEBUG: echo "attack test: $i: ",$opp,"P<BR>"; */
				return true;
			}
		}
	return false;
}

/**
 * Check whether a player's king can be attacked by his opponent.
 *
 * @param string $player  Player's color ('w' or 'b')
 * @param string $opp     Opponent's color ('w' or 'b')
 * @return bool
 *
 * @access private
 */
function kingIsUnderAttack($player, $opp)
{
	#var_dump('kingIsUnderAttack, player', $player, 'opp', $opp, 'board', $this->board);#*#DEBUG#

	for ( $i = 0; $i < 64; $i++ )
		if ($this->board[$i]{0} == $player && $this->board[$i]{1} == 'K' )
		{
			$king_pos = $i;
			break;
		}
	#echo "$player king is at $king_pos<BR>";#*#DEBUG#

	return $this->tileIsUnderAttack( $opp, $king_pos );
}

/**
 * Check whether player's king is checkmated by his opponent.
 *
 * @param string $player  Player's color ('w' or 'b')
 * @param string $opp     Opponent's color ('w' or 'b')
 * @return bool
 *
 * @access private
 */
function isCheckMate($player, $opp)
{
	for ( $i = 0; $i < 64; $i++ )
		if ($this->board[$i]{0} == $player && $this->board[$i]{1} == 'K' )
		{
			$king_pos = $i;
			$king_x = $i % 8;
			$king_y = floor($i/8);
			break;
		}

	/* test adjacent tiles while king is temporarly removed */
	$adj_tiles = $this->getAdjTiles( $king_pos );
	$contents = $this->board[$king_pos]; $this->clear_tile($king_pos);
	foreach ( $adj_tiles as $dest_pos )
	{
		if ($this->board[$dest_pos]{0} == $player ) continue;
		if ( $this->tileIsUnderAttack($opp,$dest_pos) ) continue;
		$this->board[$king_pos] = $contents;
		return false;
	}
	$this->board[$king_pos] = $contents;

	/* DEBUG:  echo "King cannot escape by itself! "; */

	/* get all figures that attack the king */
	$attackers = array(); $count = 0;
	for ( $i = 0; $i < 64; $i++ )
		if ( $this->board[$i]{0} == $opp )
		{
			if ( ($this->board[$i]{1}=='P' && $this->checkPawnAttack($i,$king_pos)) ||
					 ($this->board[$i]{1}!='P' &&
								$this->tileIsReachable($this->board[$i]{1},$i,$king_pos)) )
			{
					$attackers[$count++] = $i;
			}
		}
	/* DEBUG:
	for( $i = 0; $i < $count; $i++ )
		echo "Attacker: $attackers[$i] ";
	echo "Attackercount: ",count($attackers), " "; */

	/* if there are no atackers, it is not checkmate */
	if ( 0 == $count ) return false;

	/* if more than one there is no chance to escape */
	if ( $count > 1 ) return true;

	/* check whether attacker can be killed by own figure */
	$dest_pos = $attackers[0];
	for ( $i = 0; $i < 64; $i++ )
		if ( $this->board[$i]{0} == $player )
		{
			if ( ($this->board[$i]{1}=='P' && $this->checkPawnAttack($i,$dest_pos)) ||
					 ($this->board[$i]{1}!='P' && $this->board[$i]{1}!='K' &&
							$this->tileIsReachable($this->board[$i]{1},$i,$dest_pos)) ||
					 ($this->board[$i]{1}=='K' &&
							$this->tileIsReachable($this->board[$i]{1},$i,$dest_pos) &&
							!$this->tileIsUnderAttack($opp,$dest_pos)) )
			{
				/* DEBUG: echo "candidate: $i "; */
				$can_kill_atk = 0;
				$contents_def = $this->board[$i];
				$contents_atk = $this->board[$dest_pos];
				$this->board[$dest_pos] = $this->board[$i];
				$this->clear_tile($i);
				if ( !$this->tileIsUnderAttack($opp,$king_pos) )
					$can_kill_atk = 1;
				$this->board[$i] = $contents_def;
				$this->board[$dest_pos] = $contents_atk;
				if ( $can_kill_atk )
				{
					/* DEBUG: echo "$i can kill attacker"; */
					return false;
				}
			}
		}

	/* check whether own unit can block the way */

	/* if attacking unit is a knight there
	 * is no way to block the path */
	if ( $this->board[$dest_pos]{1} == 'N' ) return true;

	/* if enemy is adjacent to king there is no
	 * way either */
	$dest_x = $dest_pos % 8;
	$dest_y = floor($dest_pos/8);
	if ( abs($dest_x-$king_x)<=1 && abs($dest_y-$king_y)<=1 )
		return true;

	/* get the list of tiles between king and attacking
	 * unit that can be blocked to stop the attack */
	$change = $this->getPathChange($this->board[$dest_pos]{1},$dest_pos,$king_pos);
	/* DEBUG:  echo "path change: $change "; */
	$path = $this->getPath($dest_pos+$change,$king_pos,$change);
	/* DEBUG: foreach( $path as $tile ) echo "tile: $tile "; */
	foreach( $path as $pos )
	{
		for ( $i = 0; $i < 64; $i++ )
			if ( $this->board[$i]{0} == $player )
			{
				if ( ($this->board[$i]{1}=='P' && $this->checkPawnMove($i,$pos)) ||
						 ($this->board[$i]{1}!='P' && $this->board[$i]{1}!='K' &&
									$this->tileIsReachable($this->board[$i]{1},$i,$pos)) )
				{
						/* DEBUG: echo "$i can block "; */
						return false;
				}
			}
	}
	return true;
}

/**
 * Check whether player is stalemated. - Vérifiez si le joueur est pat.
 *
 * @param string $player  Color of player who has the move ('w' or 'b')
 * @param string $opp     Opponent's color ('w' or 'b')
 * @return bool
 *
 * @todo recognize when move is not possible because of check
 *
 * @access private
 */
function isStaleMate($player, $opp)
{
	/* if there is more than one piece for the player, it is not stalemate - s'il y a plus d'une pièce pour le joueur, ce n'est pas une impasse*/
	if (1 < eval("count(\$this->".$player."_figures);"))
		return false;

	for ( $i = 0; $i < 64; $i++ )
		if ($this->board[$i]{0} == $player )
			switch ($this->board[$i]{1} )
			{
				case 'K':
					$adj_tiles = $this->getAdjTiles( $i );
					foreach ( $adj_tiles as $pos )
					{
						if ( $this->board[$pos]{0} == $player ) continue;
						if ( $this->tileIsUnderAttack($opp,$pos) ) continue;
						return false;
					}
					/* DEBUG:  echo "King cannot escape by itself! - Roi ne peut pas s'échapper par lui-même! "; */
					break;
				case 'P':
					if ( $player == 'w' )
					{
						if ($this->is_empty_tile($i + 8)) return false;
						if ( ($i%8) > 0 && $this->board[$i+7]{0} != $player ) return false;
						if ( ($i%8) < 7 && $this->board[$i+9]{0} != $player ) return false;
					}
					else
					{
						if ($this->is_empty_tile($i - 8)) return false;
						if ( ($i%8) > 0 && $this->board[$i-9]{0} != $player ) return false;
						if ( ($i%8) < 7 && $this->board[$i-7]{0} != $player ) return false;
					}
					break;
				case 'B':
					if ( $i-9 >= 0  && $this->board[$i-9]{0} != $player ) return false;
					if ( $i-7 >= 0  && $this->board[$i-7]{0} != $player ) return false;
					if ( $i+9 <= 63 && $this->board[$i+9]{0} != $player ) return false;
					if ( $i+7 <= 63 && $this->board[$i+7]{0} != $player ) return false;
					break;
				case 'R':
					if ( $i-8 >= 0  && $this->board[$i-8]{0} != $player ) return false;
					if ( $i-1 >= 0  && $this->board[$i-1]{0} != $player ) return false;
					if ( $i+8 <= 63 && $this->board[$i+8]{0} != $player ) return false;
					if ( $i+1 <= 63 && $this->board[$i+1]{0} != $player ) return false;
					break;
				case 'Q':
					$adj_tiles = $this->getAdjTiles( $i );
					foreach ( $adj_tiles as $pos )
						if ( $this->board[$pos]{0} != $player )
							return false;
					break;
				case 'N':
					if ( $i-17 >= 0  && $this->board[$i-17]{0} != $player ) return false;
					if ( $i-15 >= 0  && $this->board[$i-15]{0} != $player ) return false;
					if ( $i-6  >= 0  && $this->board[$i-6]{0}  != $player ) return false;
					if ( $i+10 <= 63 && $this->board[$i+10]{0} != $player ) return false;
					if ( $i+17 <= 63 && $this->board[$i+17]{0} != $player ) return false;
					if ( $i+15 <= 63 && $this->board[$i+15]{0} != $player ) return false;
					if ( $i+6  <= 63 && $this->board[$i+6]{0}  != $player ) return false;
					if ( $i-10 >= 0  && $this->board[$i-10]{0} != $player ) return false;
					break;
			}

	return true;
}

/**
 * Generate informational text message with parameters. - Générer un message texte d'information avec des paramètres.
 *
 * Example:
 * <pre>
 *   echo move_msg('cannot find {$param[1]} pawn in column {$param[2]}', 'b', 'e');
 *    - prints: "cannot find b pawn in column e - ne peut pas trouver pion b dans la colonne e"
 * </pre>
 *
 * @param string $text
 * @param string $param,...  Unlimited number of parameters referenced by $text
 * @return string
 *
 * @access private
 */
function move_msg($text)
{
	$param = func_get_args();
	#var_dump('move_msg, text', $text, 'param', $param);#*#DEBUG#
	return eval("return \"$text\";");
}

/**
 * Translate Standard Algebraic Notation (SAN) into a full move description.
 *
 * The completed move is placed in $this->ac_move.
 *
 * @param string $player 'w' or 'b'
 * @param string $move
 * <pre>
 *   [a-h][1-8|a-h][RNBQK]              pawn move/attack
 *   [PRNBQK][a-h][1-8]                 figure move
 *   [PRNBQK][:x][a-h][1-8]             figure attack
 *   [PRNBQK][1-8|a-h][a-h][1-8]        ambigous figure move
 *   [a-h][:x][a-h][1-8][[RNBQK]        ambigous pawn attack
 *   [PRNBQK][1-8|a-h][:x][a-h][1-8]    ambigous figure attack
 * </pre>
 * @return string  Empty string if successful, otherwise error message
 *
 * @access private
 */
function completeMove($player, $move)
{
	/*
	 * [a-h][1-8|a-h][RNBQK]              pawn move/attack
	 * [PRNBQK][a-h][1-8]                 figure move
	 * [PRNBQK][:x][a-h][1-8]             figure attack
	 * [PRNBQK][1-8|a-h][a-h][1-8]        ambigous figure move
	 * [a-h][:x][a-h][1-8][[RNBQK]        ambigous pawn attack
	 * [PRNBQK][1-8|a-h][:x][a-h][1-8]    ambigous figure attack
	 */
	$error = _MD_CHESS_MOVE_UNKNOWN; // "format is totally unknown!"

	$this->ac_move = $move;

	if ( strlen($move)>=6 )
	{
		/* full move: a pawn requires a ? in the end
		 * to automatically choose a queen on last line */
		if ( $move[0] == 'P' )
		if ( $move[strlen($move)-1]<'A' || $move[strlen($move)-1]>'Z' )
			$this->ac_move = "$move?";
		return "";
	}

	/* allow last letter to be a capital one indicating
	 * the chessmen a pawn is supposed to transform into,
	 * when entering the last file. we split this character
	 * to keep the autocompletion process the same. */
	$pawn_upg = "?";
	if ( $move[strlen($move)-1]>='A' && $move[strlen($move)-1]<='Z' )
	{
		$pawn_upg = $move[strlen($move)-1];
		$move = substr( $move, 0, strlen($move)-1 );
	}
	// remove trailing '=', if present
	if ($move{strlen($move)-1} == '=') {
		$move = substr($move, 0, strlen($move)-1);
	}
	if ( $pawn_upg == "P" || $pawn_upg == "K" )
		return _MD_CHESS_MOVE_PAWN_MAY_BECOME; // "A pawn may only become either a knight, a bishop, a rook or a queen!"

	if ( $move[0]>='a' && $move[0]<='h' )
	{
		/* pawn move. either it's 2 or for characters as
		 * listed above */
		if ( strlen($move) == 4 )
		{
			if ( $move[1] != 'x' )
				return _MD_CHESS_MOVE_USE_X; // "use x to indicate an attack"
			$dest_x = $move[2];
			$dest_y = $move[3];
			$src_x  = $move[0];
			if ( $player == 'w' )
				$src_y  = $dest_y-1;
			else
				$src_y  = $dest_y+1;
			$this->ac_move = sprintf( "P%s%dx%s%d%s",
													$src_x,$src_y,$dest_x,$dest_y,
													$pawn_upg );
			return "";
		}
		else
		if (strlen($move) == 2 )
		{
			$fig = sprintf( "%sP", $player );
			if ( $move[1] >= '1' && $move[1] <= '8' )
			{
				/* pawn move */
				$pos = $this->boardCoordToIndex( $move );
				if ( $pos == 64 ) return $this->move_msg(_MD_CHESS_MOVE_COORD_INVALID, $move); // "coordinate $move is invalid"
				if ( $player == 'w' )
				{
					while( $pos >= 0 && $this->board[$pos] != $fig ) $pos -= 8;
					if ( $pos < 0 ) $not_found = 1;
				}
				else
				{
					while( $pos <= 63 && $this->board[$pos] != $fig ) $pos += 8;
					if ( $pos > 63 ) $not_found = 1;
				}
				$pos = $this->boardIndexToCoord( $pos );
				if ( (isset($not_found) && $not_found) || $pos == "" ) {
					return $this->move_msg(_MD_CHESS_MOVE_CANNOT_FIND_PAWN, $player, $move[0]); // "cannot find $player pawn in column $move[0]"
				} else {
					$this->ac_move = sprintf( "P%s-%s%s", $pos, $move, $pawn_upg );
					return "";
				}
			}
			else
			{
				/* notation: [a-h][a-h] for pawn attack no longer allowed
				 * except for history browser */
				if ( $this->browsing_mode == 0 )
						return _MD_CHESS_MOVE_USE_NOTATION; // "please use denotation [a-h]x[a-h][1-8] for pawn attacks (see help for more information)"
				/* pawn attack must be only one pawn in column! */
				$pawns = 0;
				$start = $this->boardCoordToIndex( sprintf( "%s1", $move[0] ) );
				if ( $start == 64 ) return $this->move_msg(_MD_CHESS_MOVE_COORD_INVALID, $move[0]); // "coordinate $move[0] is invalid"
				for ( $i = 1; $i <= 8; $i++, $start+=8 )
					if ( $this->board[$start] == $fig )
					{
						$pawns++;
						$pawn_line = $i;
					}
				if ( $pawns == 0 )
					return $this->move_msg(_MD_CHESS_MOVE_NO_PAWN, $move[0]); // "there is no pawn in column $move[0]"
				else if ( $pawns > 1 )
					return $this->move_msg(_MD_CHESS_MOVE_TWO_PAWNS, $move[0]); // "there is more than one pawn in column $move[0]"
				else
				{
					if ( $player == 'w' )
						$dest_line = $pawn_line+1;
					else
						$dest_line = $pawn_line-1;
					$this->ac_move = sprintf( "P%s%dx%s%d",
														$move[0],$pawn_line,$move[1],$dest_line );
					return "";
				}
			}
		}
	}
	else
	{
		/* figure move */
		$dest_coord = substr( $move, strlen($move)-2, 2 );
		$action = $move[strlen($move)-3];
		if ( $action != 'x' ) $action = '-';
		if ( $player == 'w' )
			$figures = $this->w_figures;
		else
			$figures = $this->b_figures;
		$fig_count = 0;
		foreach( $figures as $figure )
			if ( $figure[0] == $move[0] )
			{
				$fig_count++;
				if ( $fig_count == 1 )
					$pos1 = substr( $figure, 1, 2 );
				else
					$pos2 = substr( $figure, 1, 2 );
			}
		if ( $fig_count == 0 )
			return $this->move_msg(_MD_CHESS_MOVE_NO_FIGURE, $move[0], $this->getFullFigureName($move[0])); // sprintf("there is no figure %s = %s", $move[0], $this->getFullFigureName($move[0]))
		else
		if ( $fig_count == 1 )
		{
			 $this->ac_move = sprintf( "%s%s%s%s",
											$move[0], $pos1, $action, $dest_coord );
			 return "";
		}
		else
		{
			/* two figures which may cause ambiguity */
			$dest_pos = $this->boardCoordToIndex( $dest_coord );
			if ( $dest_pos == 64 )
				return $this->move_msg(_MD_CHESS_MOVE_COORD_INVALID, $dest_coord); // "coordinate $dest_coord is invalid"
			$fig1_can_reach = $this->tileIsReachable( $move[0],
														$this->boardCoordToIndex($pos1), $dest_pos );
			$fig2_can_reach = $this->tileIsReachable( $move[0],
														$this->boardCoordToIndex($pos2), $dest_pos );
			if ( !$fig1_can_reach && !$fig2_can_reach )
				return $this->move_msg(_MD_CHESS_MOVE_NEITHER_CAN_REACH, $move[0], $this->getFullFigureName($move[0]), $dest_coord); // sprintf("neither of the %s = %s can reach %s", $move[0], $this->getFullFigureName($move[0]), $dest_coord)
			else
			if ( $fig1_can_reach && $fig2_can_reach )
			{
				/* ambiguity - check whether a hint is given */
				if ( ($action=='-' && strlen($move)==4) ||
						 ($action=='x' && strlen($move)==5) )
					$hint = $move[1];
				if ( empty($hint) )
					return $this->move_msg(_MD_CHESS_MOVE_BOTH_CAN_REACH, $move[0], $this->getFullFigureName($move[0]), $dest_coord); // sprintf("both of the %s = %s can reach %s", $move[0], $this->getFullFigureName($move[0]), $dest_coord)
				else
				{
					$move_fig1 = 0;
					$move_fig2 = 0;
					if ( $hint>='1' && $hint<='8' )
					{
						if ( $pos1[1]==$hint && $pos2[1]!=$hint )
							$move_fig1 = 1;
						if ( $pos2[1]==$hint && $pos1[1]!=$hint )
							$move_fig2 = 1;
					}
					else
					{
						if ( $pos1[0]==$hint && $pos2[0]!=$hint )
							$move_fig1 = 1;
						if ( $pos2[0]==$hint && $pos1[0]!=$hint )
							$move_fig2 = 1;
					}
					if ( !$move_fig1 && !$move_fig2 )
						return _MD_CHESS_MOVE_AMBIGUOUS; // "ambiguity is not properly resolved"
					if ( $move_fig1 )
						$this->ac_move = sprintf( "%s%s%s%s",
													$move[0], $pos1, $action, $dest_coord );
					else
						$this->ac_move = sprintf( "%s%s%s%s",
													$move[0], $pos2, $action, $dest_coord );
					return;
				}
			}
			else
			{
				if ( $fig1_can_reach )
					$this->ac_move = sprintf( "%s%s%s%s",
												$move[0], $pos1, $action, $dest_coord );
				else
					$this->ac_move = sprintf( "%s%s%s%s",
												$move[0], $pos2, $action, $dest_coord );
				return "";
			}
		}
	}

	return $error;
}

/**
 * A hacky function that uses autocomplete to short
 * a full move. if this fails there is no warning
 * but the move is kept unchanged.
 *
 * @param string $player  'w' or 'b'
 * @param string $move
 * @return string  new move
 *
 * @access private
 */
function convertFullToChessNotation($player, $move)
{
	$new_move = $move;

	$old_ac_move = $this->ac_move; /* backup required as autocomplete
															will overwrite it */

	/* valid pawn moves are always non-ambigious */
	if ( $move[0] == 'P' )
	{
		/* skip P anycase. for attacks skip source digit
			 and for moves skip source pos and - */
		if ( $move[3] == '-' )
			$new_move = substr( $move, 4 );
		else
		if ( $move[3] == 'x' )
			$new_move = sprintf("%s%s", $move[1], substr( $move, 3 ) );
	}
	else
	{
		/* try to remove the source position and check whether it
		 * is a non-ambigious move. if it is add one of the components
		 * and check again */
		if ( $move[3] == '-' )
			$dest = substr( $move, 4 );
		else
		if ( $move[3] == 'x' )
			$dest = substr( $move, 3 );
		$new_move = sprintf("%s%s", $move[0], $dest );
		if ( $this->completeMove($player,$new_move) != "" )
		{
			/* add a component */
			$new_move = sprintf("%s%s%s", $move[0], $move[1], $dest );
			if ( $this->completeMove($player,$new_move) != "" )
			{
				/* add other component */
				$new_move = sprintf("%s%s%s", $move[0], $move[2], $dest );
				if ( $this->completeMove($player,$new_move) != "" )
					 $new_move = $move; /* give up */
			}
		}
	}

	$this->ac_move = $old_ac_move;
	return $new_move;
}

/**
 * Handle a move.
 *
 * check whether it is user's turn and the move is valid.
 * if the move is okay update the game file.
 *
 * @param string $move
 * @return array A two-element array:
 *  - $move_performed: true if the move was performed and the game state has been updated, false otherwise
 *  - $move_result_text: text message
 *
 * @access private
 */
function handleMove($move)
{
	/* DEBUG: echo "HANDLE: $move, $comment<BR>"; */

	$result = _MD_CHESS_MOVE_UNDEFINED;
	$move_handled = 0;

	// Use $this->gamestate['fen_piece_placement'] to initialize $this->board, $this->w_figures and $this->b_figures.
	$this->fen_piece_placement_to_board() or trigger_error('handleMove, piece_placement invalid', E_USER_ERROR);

	// get color of current player
	$cur_player = $this->gamestate['fen_active_color']; /* b or w */

	if ($cur_player != 'w' and $cur_player != 'b') {
		return(array(false, "handleMove, internal error: player='$cur_player'"));
	}

	$cur_opp = ($cur_player == 'w') ? 'b' : 'w';

	if ($this->gamestate['pgn_result'] != '*')
	{
		return(array(false, _MD_CHESS_MOVE_GAME_OVER));
	}

	// get castling availability flags
	$white_may_castle_short = strstr($this->gamestate['fen_castling_availability'], 'K') ? true : false;
	$white_may_castle_long  = strstr($this->gamestate['fen_castling_availability'], 'Q') ? true : false;
	$black_may_castle_short = strstr($this->gamestate['fen_castling_availability'], 'k') ? true : false;
	$black_may_castle_long  = strstr($this->gamestate['fen_castling_availability'], 'q') ? true : false;

	// Castling is supposed to use ohs, not zeros.  Allow zeros on input anyway.
	if ($move == '0-0') {
		$move = 'O-O';
	} elseif ($move == '0-0-0') {
		$move = 'O-O-O';
	}

	// allow two-step of king to indicate castling
	if ($cur_player == 'w' && $move == 'Ke1-g1') {
		$move = 'O-O';
	} elseif ($cur_player == 'w' && $move == 'Ke1-c1') {
		$move = 'O-O-O';
	} elseif ($cur_player == 'b' && $move == 'Ke8-g8') {
		$move = 'O-O';
	} elseif ($cur_player == 'b' && $move == 'Ke8-c8') {
		$move = 'O-O-O';
	}

	/* backup full move input for game history before
	 * splitting figure type apart */
	$history_move = $move;

	/* clear last move - won't be saved yet if anything
		 goes wrong */
	$this->last_move = "x";
	$this->piece_captured = 'x';

	/* HANDLE MOVES:
	 * ---                               surrender
	 * O-O                               short castling
	 * O-O-O                             long castling
	 * [PRNBQK][a-h][1-8][-:x][a-h][1-8] unshortened move
	 */
	if ($move == 'O-O') {

		/* short castling */

		if ($cur_player=="b") {

			if (!$black_may_castle_short) {
				return(array(false, _MD_CHESS_MOVE_NO_CASTLE)); // You cannot castle short any longer!
			}
			if (!$this->is_empty_tile(61) or !$this->is_empty_tile(62)) {
				return(array(false, _MD_CHESS_MOVE_NO_CASTLE)); // Cannot castle short because the way is blocked!
			}
			if ($this->kingIsUnderAttack( "b", "w" )) {
				return(array(false, _MD_CHESS_MOVE_NO_CASTLE)); // You cannot escape check by castling!
			}
			if ( $this->tileIsUnderAttack( "w", 62 ) || $this->tileIsUnderAttack( "w", 61 ) ) {
				return(array(false, _MD_CHESS_MOVE_NO_CASTLE)); // A tile the king passes over or into would be under attack after short castling!
			}
			$this->clear_tile(60);
			$this->board[62] = "bK";
			$this->board[61] = "bR";
			$this->clear_tile(63);
			$black_may_castle_short = false;
			$black_may_castle_long  = false;

		} else {

			if (!$white_may_castle_short) {
				return(array(false, _MD_CHESS_MOVE_NO_CASTLE)); // You cannot castle short any longer!
			}
			if (!$this->is_empty_tile(5) or !$this->is_empty_tile(6)) {
				return(array(false, _MD_CHESS_MOVE_NO_CASTLE)); // Cannot castle short because the way is blocked!
			}
			if ( $this->kingIsUnderAttack( "w", "b" ) ) {
				return(array(false, _MD_CHESS_MOVE_NO_CASTLE)); // You cannot escape check by castling!
			}
			if ( $this->tileIsUnderAttack( "b", 5 ) || $this->tileIsUnderAttack( "b", 6 ) ) {
				return(array(false, _MD_CHESS_MOVE_NO_CASTLE)); // A tile the king passes over or into would be under attack after short castling!
			}
			$this->clear_tile(4);
			$this->board[6] = "wK";
			$this->board[5] = "wR";
			$this->clear_tile(7);
			$white_may_castle_short = false;
			$white_may_castle_long  = false;
		}
		$result = _MD_CHESS_MOVE_CASTLED_SHORT;
		$move_handled = 1;
		$this->last_move = "O-O";

	} elseif ($move == 'O-O-O') {

		/* long castling */

		if ($cur_player=="b") {

			if (!$black_may_castle_long) {
				return(array(false, _MD_CHESS_MOVE_NO_CASTLE)); // You cannot castle long any longer!
			}
			if (!$this->is_empty_tile(57) or !$this->is_empty_tile(58) or !$this->is_empty_tile(59)) {
				return(array(false, _MD_CHESS_MOVE_NO_CASTLE)); // Cannot castle long because the way is blocked!
			}
			if ( $this->kingIsUnderAttack( "b", "w" ) ) {
				return(array(false, _MD_CHESS_MOVE_NO_CASTLE)); // You cannot escape check by castling!
			}
			if ( $this->tileIsUnderAttack( "w", 58 ) || $this->tileIsUnderAttack( "w", 59 ) ) {
				return(array(false, _MD_CHESS_MOVE_NO_CASTLE)); // A tile the king passes over or into would be under attack after short castling!
			}
			$this->clear_tile(56);
			$this->board[58] = "bK";
			$this->board[59] = "bR";
			$this->clear_tile(60);
			$black_may_castle_short = false;
			$black_may_castle_long  = false;

		} else {

			if (!$white_may_castle_long) {
				return(array(false, _MD_CHESS_MOVE_NO_CASTLE)); // You cannot castle long any longer!
			}
			if (!$this->is_empty_tile(1) or !$this->is_empty_tile(2) or !$this->is_empty_tile(3)) {
				return(array(false, _MD_CHESS_MOVE_NO_CASTLE)); // Cannot castle long because the way is blocked!
			}
			if ($this->kingIsUnderAttack( "w", "b" )) {
				return(array(false, _MD_CHESS_MOVE_NO_CASTLE)); // You cannot escape check by castling!
			}
			if ( $this->tileIsUnderAttack( "b", 2 ) || $this->tileIsUnderAttack( "b", 3 ) ) {
				return(array(false, _MD_CHESS_MOVE_NO_CASTLE)); // A tile the king passes over or into would be under attack after short castling!
			}
			$this->clear_tile(0);
			$this->board[2] = "wK";
			$this->board[3] = "wR";
			$this->clear_tile(4);
			$white_may_castle_short = false;
			$white_may_castle_long  = false;
		}
		$result = _MD_CHESS_MOVE_CASTLED_LONG;
		$move_handled = 1;
		$this->last_move = "O-O-O";
	}

	else
	{
		/* [PRNBQK][a-h][1-8][-:x][a-h][1-8][RNBQK] full move */

		/* allow short move description by autocompleting to
		 * full description */
		$ac_error = $this->completeMove( $cur_player, trim($move) );
		if ( $ac_error != "" )
			return(array(false, $ac_error)); // "ERROR: autocomplete: $ac_error"
		else
			$move = $this->ac_move;
		$this->last_move = str_replace( "?", "", $move );

		/* a final captial letter may only be N,B,R,Q for the
		 * appropiate chessman */
		$c = $move[strlen($move)-1];
		if ( $c >= 'A' && $c <= 'Z' )
		if ( $c != 'N' && $c != 'B' && $c != 'R' && $c != 'Q' )
			return(array(false, _MD_CHESS_MOVE_INVALID_PIECE)); // "ERROR: only N (knight), B (bishop), R (rook) and Q (queen) are valid chessman identifiers"

		/* if it is a full move, try to shorten the history move */
		if ( strlen( $history_move ) >= 6 )
			$history_move =
					$this->convertFullToChessNotation($cur_player,$history_move);
		/* DEBUG: echo "Move: $move ($history_move)<BR>"; */

		/* validate figure and position */
		$fig_type = $move[0];
		$fig_name = $this->getFullFigureName( $fig_type );
		if ( $fig_name == "empty" )
			return(array(false, $this->move_msg(_MD_CHESS_MOVE_UNKNOWN_FIGURE, $fig_type))); // "ERROR: Figure $fig_type is unknown!"
		$fig_coord = substr($move,1,2);
		$fig_pos = $this->boardCoordToIndex( $fig_coord );
		if ( $fig_pos == 64 ) return(array(false, $this->move_msg(_MD_CHESS_MOVE_COORD_INVALID, $fig_coord))); // "ERROR: $fig_coord is invalid!"
		/* DEBUG  echo "fig_type: $fig_type, fig_pos: $fig_pos<BR>"; */
		if ($this->is_empty_tile($fig_pos))
			return(array(false, $this->move_msg(_MD_CHESS_MOVE_TILE_EMPTY, $fig_coord))); // "ERROR: Tile $fig_coord is empty."
		if ( $this->board[$fig_pos]{0} != $cur_player )
			return(array(false, _MD_CHESS_MOVE_NOT_YOUR_PIECE)); // "ERROR: Figure does not belong to you!"
		if ( $this->board[$fig_pos]{1} != $fig_type )
			return(array(false, _MD_CHESS_MOVE_NOEXIST_FIGURE)); // "ERROR: Figure does not exist!"

		/* get target index */
		$dest_coord = substr($move,4,2);
		$dest_pos = $this->boardCoordToIndex( $dest_coord );
		if ( $dest_pos == 64 )
			return(array(false, $this->move_msg(_MD_CHESS_MOVE_COORD_INVALID, $dest_coord))); // "ERROR: $dest_coord is invalid!"
		if ( $dest_pos == $fig_pos )
			return(array(false, _MD_CHESS_MOVE_START_END_SAME));
		/* DEBUG  echo "dest_pos: $dest_pos<BR>"; */

		/* get action */
		$action = $move[3];
		if ( $move[3] == "-" )
			$action = 'M'; /* move */
		else if ( $move[3] == 'x' )
			$action = 'A'; /* attack */
		else
			return(array(false, $this->move_msg(_MD_CHESS_MOVE_UNKNOWN_ACTION, $action))); // "ERROR: $action is unknown! Please use \"-\" for a move and \"x\" for an attack."

		/* if attack an enemy unit must be present on tile
		 * and if move then tile must be empty. in both cases
		 * the king must not be checked after moving. */

		/* check whether the move is along a valid path and
		 * whether all tiles in between are empty thus the path
		 * is not blocked. the final destination tile is not
		 * checked here. */
		if ( $fig_type != 'P' )
		{
				if ( !$this->tileIsReachable( $fig_type, $fig_pos, $dest_pos ) )
					return(array(false, $this->move_msg(_MD_CHESS_MOVE_OUT_OF_RANGE, $dest_coord, $fig_name, $fig_coord))); // "ERROR: Tile $dest_coord is out of moving range for $fig_name at $fig_coord!"
		}
		else {
			if ( $action == 'M' && !$this->checkPawnMove( $fig_pos, $dest_pos ) )
					return(array(false, $this->move_msg(_MD_CHESS_MOVE_OUT_OF_RANGE, $dest_coord, $fig_name, $fig_coord))); // "ERROR: Tile $dest_coord is out of moving range for $fig_name at $fig_coord!"
			if ( $action == 'A' && !$this->checkPawnAttack( $fig_pos, $dest_pos ) )
					return(array(false, $this->move_msg(_MD_CHESS_MOVE_OUT_OF_RANGE, $dest_coord, $fig_name, $fig_coord))); // "ERROR: Tile $dest_coord is out of attacking range for $fig_name at $fig_coord!"
		}

	$en_passant_capture_performed = 0; // 1 if en passant captured occurred, else 0
	/* check action */
	if ( $action == 'M' && !$this->is_empty_tile($dest_pos)) {
		return(array(false, $this->move_msg(_MD_CHESS_MOVE_OCCUPIED, $dest_coord))); // "ERROR: Tile $dest_coord is occupied. You cannot move there."
	}
	if ( $action == 'A' && $this->is_empty_tile($dest_pos)) {
		/* en passant of pawn? */
		if ( $fig_type == 'P' ) {
			if ($this->boardIndexToCoord($dest_pos) == $this->gamestate['fen_en_passant_target_square']) {
				$en_passant_capture_performed = 1;
			}
			if ($en_passant_capture_performed == 0) {
				return(array(false, _MD_CHESS_MOVE_NO_EN_PASSANT)); // "ERROR: en-passant no longer possible!"
			}
		} else {
			return(array(false, $this->move_msg(_MD_CHESS_MOVE_ATTACK_EMPTY, $dest_coord))); // "ERROR: Tile $dest_coord is empty. You cannot attack it."
		}
	}
	if ( $action == 'A' && $this->board[$dest_pos]{0} == $cur_player ) {
		return(array(false, $this->move_msg(_MD_CHESS_MOVE_ATTACK_SELF, $dest_coord))); // "ERROR: You cannot attack own unit at $dest_coord."
	}

		/* backup affected tiles */
		$old_fig_tile = $this->board[$fig_pos];
		$old_dest_tile = $this->board[$dest_pos];

		/* perform move */
		$this->clear_tile($fig_pos);
		if (!$this->is_empty_tile($dest_pos))
			$this->piece_captured = sprintf("%s%s",$this->board[$dest_pos],$dest_pos);
		$this->board[$dest_pos] = "$cur_player$fig_type";
		if ( $en_passant_capture_performed ) {
			/* kill pawn */
			if ( $cur_player == 'w' )
			{
				$this->clear_tile($dest_pos - 8);
				$this->piece_captured = sprintf("bP%s",$dest_pos-8);
			}
			else
			{
				$this->clear_tile($dest_pos + 8);
				$this->piece_captured = sprintf("wP%s",$dest_pos+8);
			}
		}

		/* check check :) */
		if ( $this->kingIsUnderAttack( $cur_player, $cur_opp ) )
		{
			$this->board[$fig_pos] = $old_fig_tile;
			$this->board[$dest_pos] = $old_dest_tile;
			if ( $en_passant_capture_performed ) {
			 // restore pawn that was captured above, since that move is invalid
				if ( $cur_player == 'w' )
					$this->board[$dest_pos-8] = "bP";
				else
					$this->board[$dest_pos+8] = "wP";
			}
			return(array(false, _MD_CHESS_MOVE_IN_CHECK)); // "ERROR: Move is invalid because king would be under attack then."
		}

	// check whether this forbids any castling
	if ($fig_type == 'K') {
		if ($cur_player == 'w') {
			$white_may_castle_short = false;
			$white_may_castle_long  = false;
		} else {
			$black_may_castle_short = false;
			$black_may_castle_long  = false;
		}
	}

	if ($fig_type == 'R') {
		if ($cur_player == 'w') {
			if ($fig_pos == 7) {
				$white_may_castle_short = false;
			} elseif ($fig_pos == 0) {
				$white_may_castle_long = false;
			}
		} else {
			if ($fig_pos == 63) {
				$black_may_castle_short = false;
			} elseif ($fig_pos == 56) {
				$black_may_castle_long = false;
			}
		}
	}

	// if a pawn moved two tiles, this will allow 'en passant' on next move
	if ($fig_type == 'P' and abs($fig_pos - $dest_pos) == 16) {
		$file_chars = 'abcdefgh';
		$this->gamestate['fen_en_passant_target_square'] = $file_chars{$fig_pos % 8} . ($cur_player == 'w' ? '3' : '6');
	} else {
		// clear 'en passant'
		$this->gamestate['fen_en_passant_target_square'] = '-';
	}

		if ($action == 'M' )
			$result = $this->move_msg(_MD_CHESS_MOVE_MOVED, $fig_name, $fig_coord, $dest_coord);
		else
			$result = $this->move_msg(_MD_CHESS_MOVE_CAPTURED, $fig_name, $dest_coord, $fig_coord);

		/* if pawn reached last line convert into a queen */
		if ( $fig_type == 'P' )
		{
			if ( ($cur_player=='w' && $dest_pos>= 56) ||
					 ($cur_player=='b' && $dest_pos<= 7 ) )
			{
				$pawn_upg = $move[strlen($move)-1];
				if ( $pawn_upg == '?' )
				{
					$pawn_upg = 'Q';
					$history_move = sprintf( "%sQ", $history_move );
				}
				$this->board[$dest_pos] = "$cur_player$pawn_upg";
				$result .= ' ... ' . $this->move_msg(_MD_CHESS_MOVE_PROMOTED, $this->getFullFigureName($pawn_upg));
			}
		}

		$move_handled = 1;
	}

	/* if a legal move was performed test whether you
	 * check the opponent or even check-mate him. then
	 * update castling and en-passant flags, select the
	 * next player and add the move to the history. */

	if ($move_handled) {

		// Use $this->board to update $this->gamestate['fen_piece_placement'].
		$this->board_to_fen_piece_placement();

		// handle check, checkmate and stalemate - gére l'échec, l'échec et mat et le pat
		$comment = '';
		if ($this->kingIsUnderAttack( $cur_opp, $cur_player)) {
			// if this is check mate finish the game, otherwise if not just add a + to the move
			if ($this->isCheckMate($cur_opp, $cur_player)) {
				$this->gamestate['pgn_result'] = $cur_player == 'w' ? '1-0' : '0-1';
				$history_move .= '#';
				$result .= ' ... ' . _MD_CHESS_MOVE_CHECKMATE;
			} else {
				$history_move .= '+';
			}
		} elseif ($this->isStaleMate($cur_opp, $cur_player)) {
			$this->gamestate['pgn_result'] = '1/2-1/2';
			$result .= ' ... ' . _MD_CHESS_MOVE_STALEMATE;
			$comment = _MD_CHESS_DRAW_STALEMATE;
		} elseif ($this->insufficient_mating_material()) {
			$this->gamestate['pgn_result'] = '1/2-1/2';
			$result .= ' ... ' . _MD_CHESS_MOVE_MATERIAL;
			$comment = _MD_CHESS_DRAW_NO_MATE;
		}

		// store possible castling-availability modification
		$KQkq = ($white_may_castle_short ? 'K' : '') . ($white_may_castle_long ? 'Q' : '')
				. ($black_may_castle_short ? 'k' : '') . ($black_may_castle_long ? 'q' : '');
		$this->gamestate['fen_castling_availability'] = !empty($KQkq) ? $KQkq : '-';

		// strip old result-string from end of movetext
		// It's assumed that the movetext for a game in play is terminated by a '*', possibly preceded by whitespace.
		// (The whitespace will be present unless there are no moves in the game yet.)
		$this->gamestate['pgn_movetext'] = preg_replace('/\s*\*$/', '', $this->gamestate['pgn_movetext']);

		// if white move, output move-number
		if ($this->gamestate['fen_active_color'] == 'w') {
			if (!empty($this->gamestate['pgn_movetext'])) {
				$this->gamestate['pgn_movetext'] .= ' ';
			}
			$this->gamestate['pgn_movetext'] .= $this->gamestate['fen_fullmove_number'] . '.';

		// if black move, no moves yet, and game is setup, output move number with special '...' terminator
		} elseif (empty($this->gamestate['pgn_movetext']) and !empty($this->gamestate['pgn_fen'])) {
			$this->gamestate['pgn_movetext'] .= $this->gamestate['fen_fullmove_number'] . '...';
		}

		// update movetext
		// comment is added only for a concluded game
		$this->gamestate['pgn_movetext'] .= ' ' . $history_move . ' ' . $this->gamestate['pgn_result'];
		if (!empty($comment)) {
			$this->gamestate['pgn_movetext'] .= ' {' . $comment . '}';
		}

		// if black move, increment move-number
		if ($this->gamestate['fen_active_color'] == 'b') {
			++$this->gamestate['fen_fullmove_number'];
		}

		// If pawn advance or capturing move, reset the halfmove clock. Otherwise increment it.
		if ($move != 'O-O' and $move != 'O-O-O' and ($move{0} == 'P' or $move{3} == 'x')) {
			$this->gamestate['fen_halfmove_clock'] = 0;
		} else {
			++$this->gamestate['fen_halfmove_clock'];
		}

		// set next player
		$this->gamestate['fen_active_color'] = $this->gamestate['fen_active_color'] == 'w' ? 'b' : 'w';
	}

	return array($move_handled, $result);
}

/**
 * Check whether a tile is empty.
 *
 * @param int $position
 * @return bool
 *
 * @access private
 */
function is_empty_tile($position)
{
	return $this->board[$position] == '00';
}

/**
 * Clear a tile.
 *
 * @param int $position  Position of tile
*
 * @access private
 */
function clear_tile($position)
{
	$this->board[$position] = '00';
}

/**
 * Convert FEN piece placement field to array.
 *
 * Use $this->gamestate['fen_piece_placement'] to initialize $this->board, $this->w_figures and $this->b_figures.
 *
 * @return bool True if piece placement is valid, otherwise false.
 *
 * @access private
 */
function fen_piece_placement_to_board()
{
	if (empty($this->gamestate['fen_piece_placement']) or strlen($this->gamestate['fen_piece_placement']) > 71) {
		#trigger_error('piece placement empty or length invalid', E_USER_WARNING); #*#DEBUG#
		return false; // invalid length
	}

	$this->board = array();
	$piece_map = array(
		'K' => 'wK', 'Q' => 'wQ', 'R' => 'wR', 'B' => 'wB', 'N' => 'wN', 'P' => 'wP',
		'k' => 'bK', 'q' => 'bQ', 'r' => 'bR', 'b' => 'bB', 'n' => 'bN', 'p' => 'bP',
	);
	$tiles = implode('', array_reverse(explode('/', $this->gamestate['fen_piece_placement'])));
	for ($i = 0; $i < strlen($tiles); ++$i) {
		$tile = $tiles{$i};
		if (isset($piece_map[$tile])) {
			$this->board[] = $piece_map[$tile];
		} elseif (is_numeric($tile) and $tile >= 1 and $tile <= 8) {
			for ($j = 0; $j < $tile; ++$j) {
				$this->board[] = '00';
			}
		} else {
			#trigger_error("tile='$tile'", E_USER_WARNING); #*#DEBUG#
			return false; // unexpected character in piece_placement
		}
	}
	if (count($this->board) != 64) {
		#trigger_error('count(board)=' . count($this->board), E_USER_WARNING); #*#DEBUG#
		return false; // piece_placement has incorrect number of tiles
	}

	$this->w_figures = array();
	$this->b_figures = array();
	for ($i = 0; $i < 64; ++$i) {
		$tile = $this->board[$i];
		$coordinates = $this->boardIndexToCoord($i);
		if ($tile{0} == 'w') {
			$this->w_figures[] = $tile{1} . $coordinates;
		} elseif ($tile{0} == 'b') {
			$this->b_figures[] = $tile{1} . $coordinates;
		}
	}

	return true;
}

/**
 * Convert array to FEN piece placement field.
 *
 * Use $this->board to initialize $this->gamestate['fen_piece_placement'].
 *
 * @access private
 */
function board_to_fen_piece_placement()
{
	$rows = array();
	for ($rank = 7; $rank >= 0; --$rank) {
		$row = '';
		for ($file = 0; $file < 8; ++$file) {
			$index = 8 * $rank + $file;
			if (!$this->is_empty_tile($index)) {
				$tile = $this->board[$index];
				$piece = ($tile[0] == 'w') ? $tile[1] : strtolower($tile[1]); // 'K','Q','R','B','N' or 'P' (uppercase for white, lowercase for black)
			} else {
				$piece = 'x'; // temporarily mark each empty tile with 'x'
			}
			$row .= $piece; // append piece symbol to row-string
		}
		$rows[] = $row;
	}
	// Concatenate the eight row-strings with the separator '/'.
	// Then replace each string of x's with the string length.
	$this->gamestate['fen_piece_placement'] = preg_replace_callback('/(x+)/', create_function('$matches','return strlen($matches[1]);'), implode('/', $rows));
}

/**
 * Determine whether there is insufficient material to mate.
 *
 * @return bool  True if only the following pieces remain: K vs. K, K vs. K+B or K vs. K+N; otherwise false.
 *
 * @access private
 */
function insufficient_mating_material()
{
	$pieces      = strtoupper($this->gamestate['fen_piece_placement']);
	$counts      = count_chars($pieces, 1);
	$num_queens  = intval(@$counts[ord('Q')]);
	$num_rooks   = intval(@$counts[ord('R')]);
	$num_bishops = intval(@$counts[ord('B')]);
	$num_knights = intval(@$counts[ord('N')]);
	$num_pawns   = intval(@$counts[ord('P')]);
	return ($num_queens == 0 and $num_rooks == 0 and ($num_bishops + $num_knights) <= 1 and $num_pawns == 0);
}


/**
 * Returns a number based on current status of the game - Renvoie un nombre basé sur le statut actuel du jeu.
 *
 * @param string Players color ('w' or 'b')
 * @return int  0 = Normal; 1 = Mate; 2 = Stalemate; 3 = Check - 0 = Normal; 1 = échec et mat; 2 = Pat; 3 = échec
 *
 * @access private
 */
function get_status($player)
{
	$opp = ('w' == $player) ? 'b' : 'w';

	$status = 0;

	if ($this->kingIsUnderAttack($player, $opp))
	{
		$status = 3;

		if ($this->isCheckMate($player, $opp))
		{
			$status = 1;
		}
	}
	else if ($this->isStaleMate($player, $opp))
	{
		$status = 2;
	}

	return $status;
}


function get_status_string($player)
{
	$i = $this->get_status($player);

	switch ($i)
	{
		case gsMate      : return 'Mate';
		case gsStalemate : return 'Stalemate';
		case gsCheck     : return 'Check';
		default          : return '';
	}
}


// --------------------------
// INCIDENTAL PRIVATE METHODS
// --------------------------
// These functions don't really need to be class methods, since they don't access class properties.
// They're placed within the class only for name-scoping.

/**
 * Convert board coordinates [a-h][1-8] to board index [0..63]
 *
 * @param string $coord  Example: 'b3'
 * @return int  Example: 17
 *
 * @access private
 */
function boardCoordToIndex( $coord )
{
	//echo $coord," --> ";
	switch ( $coord[0] )
	{
		case 'a': $x = 0; break;
		case 'b': $x = 1; break;
		case 'c': $x = 2; break;
		case 'd': $x = 3; break;
		case 'e': $x = 4; break;
		case 'f': $x = 5; break;
		case 'g': $x = 6; break;
		case 'h': $x = 7; break;
		default: return 64; /* erronous coord */
	}
	$y = $coord[1]-1;
	if ( $y < 0 || $y > 7 )
		return 64; /* erronous coord */
	$index = $y * 8 + $x;
	//echo "$index | ";
	return $index;
}

/**
 * Convert board index [0..63] to board coordinates [a-h][1-8].
 *
 * @param int $index  Example: 17
 * @return string  Example: 'b3'
 *
 * @access private
 */
function boardIndexToCoord( $index )
{
	//echo $index," --> ";
	if ( $index < 0 || $index > 63 )
		return "";
	$y = floor($index/8)+1;
	$x = chr( ($index%8)+97 );
	$coord = "$x$y";
	//echo "$coord | ";
	return $coord;
}

/**
 * Get piece name from piece symbol.
 *
 * @param string $short  Piece symbol
 * @return string        Piece name
 *
 * @access private
 */
function getFullFigureName( $short )
{
	static $names = array(
		'K' => _MD_CHESS_MOVE_KING,
		'Q' => _MD_CHESS_MOVE_QUEEN,
		'R' => _MD_CHESS_MOVE_ROOK,
		'B' => _MD_CHESS_MOVE_BISHOP,
		'N' => _MD_CHESS_MOVE_KNIGHT,
		'P' => _MD_CHESS_MOVE_PAWN
	);
	return isset($names[$short]) ? $names[$short] : _MD_CHESS_MOVE_EMPTY;
}

/**
 * Get tiles adjacent to specified tile.
 *
 * @param int $fig_pos
 * @return array
 *
 * @access private
 */
function getAdjTiles( $fig_pos )
{
	$adj_tiles = array(); $i = 0;

	$x = $fig_pos % 8; $y = floor( $fig_pos / 8 );

	if ( $x > 0 && $y > 0 ) $adj_tiles[$i++] = $fig_pos-9;
	if (           $y > 0 ) $adj_tiles[$i++] = $fig_pos-8;
	if ( $x < 7 && $y > 0 ) $adj_tiles[$i++] = $fig_pos-7;
	if ( $x < 7           ) $adj_tiles[$i++] = $fig_pos+1;
	if ( $x < 7 && $y < 7 ) $adj_tiles[$i++] = $fig_pos+9;
	if (           $y < 7 ) $adj_tiles[$i++] = $fig_pos+8;
	if ( $x > 0 && $y < 7 ) $adj_tiles[$i++] = $fig_pos+7;
	if ( $x > 0           ) $adj_tiles[$i++] = $fig_pos-1;

	/* DEBUG:  foreach( $adj_tiles as $tile )
		echo "adj: $tile "; */

	return $adj_tiles;
}

} // class ChessGame


Ne l'ayant pas trouvé, je ne puis être sur qu'il s'y trouve hélas.
Voir les lignes suivantes:
106, 193, 226; 229, 249, 269 à 277, 253, 288, 292, 296, 300, 308, 309, 313 à 316, 320, 321, 326, 330, 331, 337, 1203, 1211, 1217 à 1220, 1444, 1523, 1529, 1564, 1572, 1579, 1583, 191, 1596, 1599, 1600, 1601, 1603, 1606, 1607, 1612, 1614, 1618, 1619, 1624, 1626, 1630, 1672, 1682, 1719, 1742 et 1754.
jordane45
Messages postés
23537
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
7 décembre 2018
> Max747
Messages postés
74
Date d'inscription
vendredi 11 juillet 2014
Dernière intervention
9 décembre 2018
-
Le code que tu nous montres est celui de la class ChessGame
Ca serait plutôt le code qui fait appel à cette class qui pourrait nous interesser.
Quoi qu'il en soit... je ne vais pas reluquer tous tes fichiers....
Je t'ai donné des "méthodes" pour debuguer ton code et essayer de suivre le cheminement logique de celui-ci.
Je ne sais pas où tu as trouvé ce code ni ce que tu cherches réellement à en faire mais le mieux serait de contacter le développeur directement... on gagnera du temps.
Moi je m'arrête là.
Bonne continuation.
Max747
Messages postés
74
Date d'inscription
vendredi 11 juillet 2014
Dernière intervention
9 décembre 2018
-
Ce que j'essaie de faire ?
Résoudre le problème de l'absence d'alerte quand le jeu est pat aux échecs.
Ce site de jeu fût mis à disposition gratuitement il y a plusieurs années déjà sur internet.
Je suis convaincu que lorsque j'aurai trouvé le développeur (si je remonte jusqu' à lui), celui ci ne me répondra pas.Car en libre accès les fichiers sont modifiés et archi modifiés.Alors cela se comprends très bien que celui qui est à l'origine de ce site ne veuille plus y revenir!
Enfin, au sujet des développeurs, je suis toujours surpris de n'avoir à chaque fois que toi comme seul interlocuteur.
Alors que parfois tu écris au pluriel (Ca serait bien également de nous dire où sont déclarées (et comment.. avec quelles lignes de code...) les variables WHITE et BLACK ... ).Mais où sont les autres qui ne participent jamais?
Savez vous que pour résoudre un simple problème de présentation de message d'alerte comme celui qui me concerne, les développeurs patentés demandent au minimum 100 euros pour se service?
D'ailleurs chez eux les tarifs peuvent généralement varier du simple au triple. Un peu comme les plombiers ou les serruriers.Et je ne fais pas référence au garagistes!
Ceci dit, je n'ai donc plus l'espoir de trouver une aide sur internet à partir du moment où même quand cela fait parti du loisir, personne ne prend le temps qu'il faut pour aider des gens qui comme moi se consacrent par le jeu aux loisirs des autres.
On n'est jamais si seul que dans la foule!!!
Enfin, je te remercie quand même, bien évidemment, pour avoir tenter de m'apprendre des notions en programmation de sites.
Celles ci me furent et me seront encore utiles.Mais j'ai du y mettre du mieux comme on dit.Car ce ne fut pas facile de découvrir ces nouveautés uniquement que par tes écrits!
Merci encore pour tes interventions.
Un passionné qui croit toujours au père Noël.
Commenter la réponse de Max747
Messages postés
23537
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
7 décembre 2018
0
Merci
Bonjour,
Après avoir rapidement regardé les fichiers de ton site...


La variable gameState est générée dans le fichier "echecs\includes\gui.inc.php"
dans la fonction getStatus()
Fonction appellée elle même dans le fichier "echecs\chess.php" à la ligne 337
$head_extra .= getStatus( ); // writes 'whosMove', 'gameState', and 'statusMsg' (gui.inc.php)


Donc ce qui semble indiquer que cette variable s'actualise lorsque l'on recharge la page en question.


Je te propose de modifier (dans le fichier chess.php) la ligne 337 en la remplaçant par :
$head_extra .= "console.log('head_moves',moves);";
$h_status = getStatus();
$head_extra .= "console.log('head_status',".$h_status.");";
$head_extra .= $h_status; // writes 'whosMove', 'gameState', and 'statusMsg' (gui.inc.php)


Puis de dérouler une partie jusqu'au PAT afin de voir, dans la console, ce qui s'affiche.
(l'idéal étant d'avoir coché, dans la console, la case "conserver les journaux" afin de garder dans la console tout ce qui se passe même après le rechargement de la page)


jordane45
Messages postés
23537
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
7 décembre 2018
-
Tu peux virer cette ligne
$head_extra .= "console.log('head_status',".$h_status.");";

elle génère des erreurs en effet
Max747
Messages postés
74
Date d'inscription
vendredi 11 juillet 2014
Dernière intervention
9 décembre 2018
-
Les parties ne sont plus accessibles lorsque la modif est en service.
Regarde l'image de la page d'une partie parmi tant d'autres:

C'est ainsi que je suis obligé d'annuler la modif pour le test maintenant pour que les gens puissent jouer.

Je dois m'absenter et serai de retour ce soir.

Je compte sur toi.
jordane45
Messages postés
23537
Date d'inscription
mercredi 22 octobre 2003
Statut
Modérateur
Dernière intervention
7 décembre 2018
-
Avant de partir...
Vire la ligne $head_extra .= "console.log('head_status',".$h_status.");";
Max747
Messages postés
74
Date d'inscription
vendredi 11 juillet 2014
Dernière intervention
9 décembre 2018
-
Voilà c'est fait.
Les parties sont désormais accessibles.
Avec toutes mes excuses pour cette absence.Mais je ne pouvais plus rester 5 minutes de plus.
Merci pour tes recherches.
J'attends tes nouvelles instructions que je pourrai mettre en oeuvre demain matin au plus tard.
Max747
Messages postés
74
Date d'inscription
vendredi 11 juillet 2014
Dernière intervention
9 décembre 2018
-
A tout hasard:
Commenter la réponse de jordane45
Wondershare PDFelement Pro 6.7.11 | Manto 2018 Hindi 720p WEB-DL x264 ESub [MW] | Thám Tử Lừng Danh Conan chap 455