Tutoriais

Tutorial Programando Jogo de Xadrez

Esse tutorial é indicado para programadores com conhecimento avançado em javascript.
O tutorial mostra como programar um jogo de xadrez.
O foco do tutorial é escrita de código.

O tutorial apresenta duas dicas que podem escapar ao programador iniciante:
  • Maiúsculas/Minúsculas.
  • A lista de jogadas deve existir antes do user click.
  • Desenhando o Tabuleiro

    Em um arquivo chamado jogo.htm vai o todo o código-fonte.
    Código HTML css js
    Tudo em um só arquivo.

    A tag <table> é o esqueleto desse tutorial.
    table tr td

    Serão 8 <tr> cada um contendo 8 <td>

    Em javascript uma variável armazena uma grande HTMString que o comando innerHTML atribui à página.
    <!doctype html>
    <html>
    <meta charset=utf-8>
    <meta name=viewport content='width=device-width'>
    <body style='background-color:#808080; margin:0px; height:100vh; display:flex; justify-content:center; align-items:center;'></body>
    <script>
    function renderSquare(s){
    	if((s+parseInt(s/8))%2) //background do quadrado
    		bgtdcolor="404040"; //cinza escuro
    	else
    		bgtdcolor="c0c0c0"; //cinza claro
    
    	htm+="<td style='width:42px; height:42px; background-color:#"+bgtdcolor+";'>"; //o quadrado
    	htm+="<div onclick='pickSquare("+s+");' style='width:32px; height:32px; margin:0px auto; text-align:center; font-size:22px; border-radius:50%; border:2px solid transparent;'>&nbsp;</div>"; //um circulo transparente dentro do quadrado
    	htm+="</td>"; //o quadrado
    }
    
    htm="<table cellpadding=0 cellspacing=0 style='margin:30px;'>";
    for(x=0;x<8;x++){
    	htm+="<tr>";
    	for(y=0;y<8;y++)renderSquare((x*8)+y);
    	htm+="</tr>";
    }
    document.body.innerHTML=htm+"</table>";
    </script>
    </html>

    Desenhando as Peças

    Em uma variável (array) ficam as posições das peças.
    board=[ //variável array que armazena o jogo! as brancas são as maiúsculas
    'r','n','b','q','k','b','n','r',
    'p','p','p','p','p','p','p','p',
    ' ',' ',' ',' ',' ',' ',' ',' ',
    ' ',' ',' ',' ',' ',' ',' ',' ',
    ' ',' ',' ',' ',' ',' ',' ',' ',
    ' ',' ',' ',' ',' ',' ',' ',' ',
    'P','P','P','P','P','P','P','P',
    'R','N','B','Q','K','B','N','R'
    ];
    Existe a possibilidade de se usar imagens para as peças, mas nesse tutorial usa-se Unicode Chars

    Abaixo vai o código que desenha o tabuleiro e coloca o Unicode-Char na posição devida.
    <!doctype html>
    <html>
    <meta charset=utf-8>
    <meta name=viewport content='width=device-width'>
    <body style='background-color:#808080; margin:0px; height:100vh; display:flex; justify-content:center; align-items:center;'></body>
    <script>
    board=[ //variável array que armazena o jogo! as brancas são as maiúsculas
    'r','n','b','q','k','b','n','r',
    'p','p','p','p','p','p','p','p',
    ' ',' ',' ',' ',' ',' ',' ',' ',
    ' ',' ',' ',' ',' ',' ',' ',' ',
    ' ',' ',' ',' ',' ',' ',' ',' ',
    ' ',' ',' ',' ',' ',' ',' ',' ',
    'P','P','P','P','P','P','P','P',
    'R','N','B','Q','K','B','N','R'
    ];
    
    function renderSquare(s){
    	if((s+parseInt(s/8))%2) //background do quadrado
    		bgtdcolor="404040"; //cinza escuro
    	else
    		bgtdcolor="c0c0c0"; //cinza claro
    
    	htm+="<td style='width:42px; height:42px; background-color:#"+bgtdcolor+";'>"; //o quadrado
    
    	htm+="<div onclick='pickSquare("+s+");' style='width:32px; height:32px; margin:0px auto; text-align:center; font-size:22px; border-radius:50%; border:2px solid "; //o circulo dentro do quadrado
    
    	if(board[s]!=' '){
    		htm+="#808080; background-color:#808080;'>"; //cor da borda do círculo igual a cor de dentro do círculo
    
    		switch(board[s]){
    			case 'p':htm+="&#9823;";break; // ♟ peao preto
    			case 'n':htm+="&#9822;";break; // ♞ cavalo preto
    			case 'b':htm+="&#9821;";break; // ♝ bispo preto
    			case 'r':htm+="&#9820;";break; // ♜ torre preto
    			case 'q':htm+="&#9819;";break; // ♛ rainha preto
    			case 'k':htm+="&#9818;";break; // ♚ rei preto
    			case 'P':htm+="&#9817;";break; // ♙ peao branco
    			case 'N':htm+="&#9816;";break; // ♘ cavalo branco
    			case 'B':htm+="&#9815;";break; // ♗ bispo branco
    			case 'R':htm+="&#9814;";break; // ♖ torre branco
    			case 'Q':htm+="&#9813;";break; // ♕ rainha branco
    			case 'K':htm+="&#9812;";break; // ♔ rei branco
    		}
    	}
    	else htm+="transparent;'>&nbsp;"; //quadrado vazio
    
    	htm+="</div>"; //o circulo dentro do quadrado
    
    	htm+="</td>"; //o quadrado
    }
    
    htm="<table cellpadding=0 cellspacing=0 style='margin:30px;'>";
    for(x=0;x<8;x++){ //se o player joga com as brancas o board é exibido com as brancas embaixo
    	htm+="<tr>";
    	for(y=0;y<8;y++)renderSquare((x*8)+y);
    	htm+="</tr>";
    }
    document.body.innerHTML=htm+"</table>";
    </script>
    </html>

    Fazendo a Peça Mudar de Posição

    Para implementar a mudança de posição das peças é necessário uma variável que armazena qual peça está para mudar.
    function pickSquare(square){ //função que é executada quando o user seleciona (click) algum quadrado
    	if(whiteTurn&&(board[square]=='P'||board[square]=='N'||board[square]=='B'||board[square]=='R'||board[square]=='Q'||board[square]=='K'))selected=square;
    	if(!whiteTurn&&(board[square]=='p'||board[square]=='n'||board[square]=='b'||board[square]=='r'||board[square]=='q'||board[square]=='k'))selected=square;
    
    	for(x=0;x<movesList.length;x++) //percorrendo a 'lista de jogadas válidas'
    		if(movesList[x][0]==selected&&movesList[x][1]==square){ //se o user clicou em um quadrado de uma jogada válida
    		move(selected,square);
    		selected=-1;
    		whiteTurn=!whiteTurn;
    	}
    
    	main(); //redesenha o tabuleiro
    }

    Uma lista de Jogadas

    Pode parecer uma ideia legal calcular a lista de jogadas válidas no momento que o user seleciona a peça.
    Mas não é uma boa ideia.
    Minha experiência indica que essa lista deve ser gerada antes.

    No momento da seleção da peça já deve estar armazenada na memória uma lista de peças selecionáveis e posições ocupáveis.

    Ter a lista também é importante na hora de selecionar uma jogada válida aleatória para o jogador.
    <!doctype html>
    <html>
    <meta charset=utf-8>
    <meta name=viewport content='width=device-width'>
    <style>
    @keyframes slide{
    	from{right:1006px;}
    	to{right:6px;}
    }
    </style>
    <body style='background-color:#808080; margin:0px; height:100vh; display:flex; justify-content:center; align-items:center;'></body>
    <script>
    selected=-1; //nenhuma peça selecionada
    humanPlayWhite=parseInt(Math.random()*2); //sorteia se o jogador comanda as peças brancas
    whiteTurn=true; //sempre são as brancas que começam
    
    board=[ //variável array que armazena o jogo! as brancas são as maiúsculas
    'r','n','b','q','k','b','n','r',
    'p','p','p','p','p','p','p','p',
    ' ',' ',' ',' ',' ',' ',' ',' ',
    ' ',' ',' ',' ',' ',' ',' ',' ',
    ' ',' ',' ',' ',' ',' ',' ',' ',
    ' ',' ',' ',' ',' ',' ',' ',' ',
    'P','P','P','P','P','P','P','P',
    'R','N','B','Q','K','B','N','R'
    ];
    
    function isEmpty(o){return board[o]==' ';} //função que indica se o quadrado está vazio
    
    function isCapturable(o){ //função que indica se o quadrado contém uma peça que pode ser capturada
    	if(whiteTurn)return board[o]=='p'||board[o]=='n'||board[o]=='b'||board[o]=='r'||board[o]=='q';
    	if(!whiteTurn)return board[o]=='P'||board[o]=='N'||board[o]=='B'||board[o]=='R'||board[o]=='Q';
    }
    
    function promotePawns(){ //os peões que chegam do outro lado são promovidos
    	for(x=0;x<8;x++) //quadrados da primeira linha
    		if(board[x]=='P') //se tem um peão branco na primeira linha
    			board[x]='Q'; //promovido a rainha
    	for(x=56;x<64;x++) //quadrados da última linha
    		if(board[x]=='p') //se tem um peão preto na primeira linha
    			board[x]='q'; //promovido a rainha
    }
    
    function move(from,to){
    	board[to]=board[from];
    	board[from]=' ';
    
    	promotePawns(); //os peões que chegam do outro lado são promovidos
    }
    
    function pickSquare(square){ //função que é executada quando o user seleciona (click) algum quadrado
    	if(whiteTurn&&(board[square]=='P'||board[square]=='N'||board[square]=='B'||board[square]=='R'||board[square]=='Q'||board[square]=='K'))selected=square;
    	if(!whiteTurn&&(board[square]=='p'||board[square]=='n'||board[square]=='b'||board[square]=='r'||board[square]=='q'||board[square]=='k'))selected=square;
    
    	for(x=0;x<movesList.length;x++) //percorrendo a 'lista de jogadas válidas'
    		if(movesList[x][0]==selected&&movesList[x][1]==square){ //se o user clicou em um quadrado de uma jogada válida
    		move(selected,square);
    		selected=-1;
    		whiteTurn=!whiteTurn;
    	}
    
    	main(); //redesenha o tabuleiro
    }
    
    function computerMove(){
    	oponentMove=movesList[parseInt(Math.random()*movesList.length)];
    
    	for(x=movesList.length-1;x>-1;x--) //percorrendo a 'lista de jogadas válidas'
    		if(!isEmpty(movesList[x][1])) //se tem peça adversária no quadrado destino
    			oponentMove=movesList[x]; //esse movimento é selecionado
    
    	move(oponentMove[0],oponentMove[1]);
    	whiteTurn=!whiteTurn;
    	main();
    }
    
    function addPawnsMoves(){
    	if(whiteTurn){ //jogadas peões brancos
    		for(x=8;x<64;x++) //para todos quadrados
    			if(board[x]=='P'&&isEmpty(x-8)) //se está ocupado por um peão branco e o quadrado adiante está vazio
    				movesList.push([x,x-8]); //insere a jogada de andar um pra frente
    		for(x=48;x<56;x++) //para os quadrados na linha inicial de peões
    			if(board[x]=='P'&&isEmpty(x-8)&&isEmpty(x-16)) //se a casa está ocupada por um peão branco e os dois quadrados adiante estão vazios
    				movesList.push([x,x-16]); //insere a jogada de andar dois para frente
    		for(x=8;x<56;x++)
    			if(board[x]=='P'&&x%8!=7&&isCapturable(x-7)) //se tem alguma peça que o peão pode capturar na diagonal direita
    				movesList.push([x,x-7]); //insere a jogada de capturar à direita
    		for(x=8;x<56;x++)
    			if(board[x]=='P'&&x%8!=0&&isCapturable(x-9)) //se tem alguma peça que o peão pode capturar na diagonal esquerda
    				movesList.push([x,x-9]); //insere a jogada de capturar à esquerda
    	}
    	else{
    		//jogadas peões pretos
    		for(x=0;x<56;x++)
    			if(board[x]=='p'&&isEmpty(x+8))
    				movesList.push([x,x+8]);
    		for(x=8;x<16;x++)
    			if(board[x]=='p'&&isEmpty(x+8)&&isEmpty(x+16))
    				movesList.push([x,x+16]);
    		for(x=8;x<56;x++)
    			if(board[x]=='p'&&x%8!=0&&isCapturable(x+7))
    				movesList.push([x,x+7]);
    		for(x=8;x<56;x++)
    			if(board[x]=='p'&&x%8!=7&&isCapturable(x+9))
    				movesList.push([x,x+9]);
    	}
    }
    
    function addHorsesMoves(){
    	//jogadas cavalo
    	for(x=0;x<64;x++) //para todos quadrados
    		if((whiteTurn&&board[x]=='N')||(!whiteTurn&&board[x]=='n')){ //se o quadrado contém um cavalo
    			if(x>15&&x%8>0&&(isCapturable(x-17)||isEmpty(x-17))) //-17 é duas linhas pra cima e um quadrado à esquerda
    				movesList.push([x,x-17]); //insere na lista de jogadas
    			if(x>15&&x%8<7&&(isCapturable(x-15)||isEmpty(x-15))) //-15 é duas linhas pra cima e um quadrado à direita
    				movesList.push([x,x-15]);
    			if(x>7&&x%8>1&&(isCapturable(x-10)||isEmpty(x-10))) //-10 é uma linha acima e dois quadrados à esquerda
    				movesList.push([x,x-10]);
    			if(x>7&&x%8<6&&(isCapturable(x-6)||isEmpty(x-6)))  //-6 é uma linha acima e dois quadrados à direita
    				movesList.push([x,x-6]);
    			if(x<56&&x%8>1&&(isCapturable(x+6)||isEmpty(x+6)))  //6 é uma linha acima e dois quadrados à direita
    				movesList.push([x,x+6]);
    			if(x<56&&x%8<6&&(isCapturable(x+10)||isEmpty(x+10))) //10 é uma linha acima e dois quadrados à esquerda
    				movesList.push([x,x+10]);
    			if(x<48&&x%8>0&&(isCapturable(x+15)||isEmpty(x+15))) //15 é duas linhas pra cima e um quadrado à direita
    				movesList.push([x,x+15]);
    			if(x<48&&x%8<7&&(isCapturable(x+17)||isEmpty(x+17))) //17 é duas linhas pra cima e um quadrado à esquerda
    				movesList.push([x,x+17]);
    		}
    }
    
    function addBishopsMoves(){
    	//jogadas bispo/rainha
    	for(x=0;x<64;x++) //para todos quadrados
    		if((whiteTurn&&(board[x]=='B'||board[x]=='Q'))||(!whiteTurn&&(board[x]=='b'||board[x]=='q'))){ //se o quadrado contém um bispo ou uma rainha
    			for(t=x-9;t>-1&&t%8!=7&&(isEmpty(t)||isCapturable(t));t-=9){ //percorre a diagonal enquanto o quadrado for vazio ou contiver alguma peça capturável
    				movesList.push([x,t]); //insere na lista de jogadas
    				if(!isEmpty(t))break; //se o quadrado contém alguma peça, interrompe a procura nessa diagonal
    			}
    			for(t=x-7;t>-1&&t%8!=0&&(isEmpty(t)||isCapturable(t));t-=7){ //percorre a diagonal enquanto o quadrado for vazio ou contiver alguma peça capturável
    				movesList.push([x,t]);
    				if(!isEmpty(t))break;
    			}
    			for(t=x+7;t<64&&t%8!=7&&(isEmpty(t)||isCapturable(t));t+=7){
    				movesList.push([x,t]); //insere na lista de jogadas
    				if(!isEmpty(t))break;
    			}
    			for(t=x+9;t<64&&t%8!=0&&(isEmpty(t)||isCapturable(t));t+=9){
    				movesList.push([x,t]);
    				if(!isEmpty(t))break; //se o quadrado contém alguma peça, interrompe a procura nessa diagonal
    			}
    		}
    }
    
    function addRooksMoves(){
    	//jogadas torre/rainha
    	for(x=0;x<64;x++) //para todos quadrados
    		if((whiteTurn&&(board[x]=='R'||board[x]=='Q'))||(!whiteTurn&&(board[x]=='r'||board[x]=='q'))){ //se o quadrado contém uma torre ou uma rainha
    			for(t=x-1;t%8!=7&&(isEmpty(t)||isCapturable(t));t-=1){ //percorre a linha enquanto o quadrado for vazio ou contiver alguma peça capturável
    				movesList.push([x,t]); //insere na lista de jogadas
    				if(!isEmpty(t))break; //se o quadrado contém alguma peça, interrompe a procura nessa linha
    			}
    			for(t=x+1;t%8!=0&&(isEmpty(t)||isCapturable(t));t+=1){
    				movesList.push([x,t]); //insere na lista de jogadas
    				if(!isEmpty(t))break;
    			}
    			for(t=x-8;t>-1&&(isEmpty(t)||isCapturable(t));t-=8){ //percorre a coluna enquanto o quadrado for vazio ou contiver alguma peça capturável
    				movesList.push([x,t]);
    				if(!isEmpty(t))break;
    			}
    			for(t=x+8;t<64&&(isEmpty(t)||isCapturable(t));t+=8){
    				movesList.push([x,t]);
    				if(!isEmpty(t))break; //se o quadrado contém alguma peça, interrompe a procura nessa coluna
    			}
    		}
    }
    
    function addKingsMoves(){
    	//jogadas rei
    	for(x=0;x<64;x++) //para todos quadrados
    		if((whiteTurn&&board[x]=='K')||(!whiteTurn&&board[x]=='k')){ //se o quadrado contém o rei
    			if(x>7&&x%8>0&&(isCapturable(x-9)||isEmpty(x-9)))
    				movesList.push([x,x-9]); //rei na diagonal 1
    			if(x>7&&(isCapturable(x-8)||isEmpty(x-8)))
    				movesList.push([x,x-8]); //rei indo para frente
    			if(x>7&&x%8<7&&(isCapturable(x-7)||isEmpty(x-7)))
    				movesList.push([x,x-7]); //rei na diagonal 2
    			if(x%8>0&&(isCapturable(x-1)||isEmpty(x-1)))
    				movesList.push([x,x-1]); //rei indo para a esquerda
    			if(x%8<7&&(isCapturable(x+1)||isEmpty(x+1)))
    				movesList.push([x,x+1]); //rei indo parra a direita
    			if(x<56&&x%8>0&&(isCapturable(x+7)||isEmpty(x+7)))
    				movesList.push([x,x+7]); //rei na diagonal 3
    			if(x<56&&(isCapturable(x+8)||isEmpty(x+8)))
    				movesList.push([x,x+8]); //rei indo para trás
    			if(x<56&&x%8<7&&(isCapturable(x+9)||isEmpty(x+9)))
    				movesList.push([x,x+9]); //rei na diagonal 4
    		}
    }
    
    function discardInvalidMoves(){
    	backupBoard=[]; //é necessário criar uma cópia do tabuleiro para calcular as jogadas que deixam o rei em xeque
    	for(x=0;x<64;x++) //para todos quadrados
    		backupBoard[x]=board[x];
    
    	discardXeques=[]; //variável para desabilitar jogadas que deixariam o rei em xeque
    
    	for(m=0;m<movesList.length;m++){ //para todos movimentos na lista de jogadas
    		discardXeques[m]=movesList[m]; //uma por uma são testadas para verificar se é uma jogada válida
    
    		board=[]; //volta o tabuleiro para verificar se essa jogada deixa o rei em xeque
    		for(x=0;x<64;x++)
    			board[x]=backupBoard[x];
    
    		move(movesList[m][0],movesList[m][1]); //muda a posição das peças para calcular se essa configuração deixa o rei em xeque
    
    		if(whiteTurn){
    			for(x=0;x<64;x++)if(board[x]=='K')king=x; //essa variável pega a posição do rei para calcular se ele fica em xeque
    
    			//procura por torre ou rainha em posição de atacar o rei
    			for(x=king-8;x>-1;x-=8){
    				if(board[x]=='q'||board[x]=='r')discardXeques[m]=-1;
    				if(!isEmpty(x))break;
    			}
    			for(x=king+8;x<64;x+=8){
    				if(board[x]=='q'||board[x]=='r')discardXeques[m]=-1;
    				if(!isEmpty(x))break;
    			}
    			for(x=king-1;x>-1&&x%8!=7;x-=1){
    				if(board[x]=='q'||board[x]=='r')discardXeques[m]=-1;
    				if(!isEmpty(x))break;
    			}
    			for(x=king+1;x<64&&x%8!=0;x+=1){
    				if(board[x]=='q'||board[x]=='r')discardXeques[m]=-1;
    				if(!isEmpty(x))break;
    			}
    
    			//procura por bispo ou rainha em posição de atacar o rei
    			for(x=king-9;x>-1&&x%8!=7;x-=9){
    				if(board[x]=='q'||board[x]=='b')discardXeques[m]=-1;
    				if(!isEmpty(x))break;
    			}
    			for(x=king-7;x>-1&&x%8!=0;x-=7){
    				if(board[x]=='q'||board[x]=='b')discardXeques[m]=-1;
    				if(!isEmpty(x))break;
    			}
    			for(x=king+7;x<64&&x%8!=7;x+=7){
    				if(board[x]=='q'||board[x]=='b')discardXeques[m]=-1;
    				if(!isEmpty(x))break;
    			}
    			for(x=king+9;x<64&&x%8!=0;x+=9){
    				if(board[x]=='q'||board[x]=='b')discardXeques[m]=-1;
    				if(!isEmpty(x))break;
    			}
    
    			//procura por rei adversário em posição de atacar o rei
    			if(king>7&&king%8>0&&board[king-9]=='k')discardXeques[m]=-1;
    			if(king>7&&board[king-8]=='k')discardXeques[m]=-1;
    			if(king>7&&king%8<7&&board[king-7]=='k')discardXeques[m]=-1;
    			if(king%8>0&&board[king-1]=='k')discardXeques[m]=-1;
    			if(king%8<7&&board[king+1]=='k')discardXeques[m]=-1;
    			if(king<56&&king%8>0&&board[king+7]=='k')discardXeques[m]=-1;
    			if(king<56&&board[king+8]=='k')discardXeques[m]=-1;
    			if(king<56&&king%8<7&&board[king+9]=='k')discardXeques[m]=-1;
    
    			//procura por cavalo adversário em posição de atacar o rei
    			if(king>15&&king%8>0&&board[king-17]=='n')discardXeques[m]=-1;
    			if(king>15&&king%8<7&&board[king-15]=='n')discardXeques[m]=-1;
    			if(king>7&&king%8>1&&board[king-10]=='n')discardXeques[m]=-1;
    			if(king>7&&king%8<6&&board[king-6]=='n')discardXeques[m]=-1;
    			if(king<56&&king%8>1&&board[king+6]=='n')discardXeques[m]=-1;
    			if(king<56&&king%8<6&&board[king+10]=='n')discardXeques[m]=-1;
    			if(king<48&&king%8>0&&board[king+15]=='n')discardXeques[m]=-1;
    			if(king<48&&king%8<7&&board[king+17]=='n')discardXeques[m]=-1;
    
    			//procura por peão adversário em posição de atacar o rei
    			if(king>7&&king%8>0&&board[king-9]=='p')discardXeques[m]=-1;
    			if(king>7&&king%8<7&&board[king-7]=='p')discardXeques[m]=-1;
    		}
    		if(!whiteTurn){
    			for(x=0;x<64;x++)if(board[x]=='k')king=x; //essa variável pega a posição do rei para calcular se ele fica em xeque
    
    			//procura por torre ou rainha em posição de atacar o rei
    			for(x=king-8;x>-1;x-=8){
    				if(board[x]=='Q'||board[x]=='R')discardXeques[m]=-1;
    				if(!isEmpty(x))break;
    			}
    			for(x=king+8;x<64;x+=8){
    				if(board[x]=='Q'||board[x]=='R')discardXeques[m]=-1;
    				if(!isEmpty(x))break;
    			}
    			for(x=king-1;x>-1&&x%8!=7;x-=1){
    				if(board[x]=='Q'||board[x]=='R')discardXeques[m]=-1;
    				if(!isEmpty(x))break;
    			}
    			for(x=king+1;x<64&&x%8!=0;x+=1){
    				if(board[x]=='Q'||board[x]=='R')discardXeques[m]=-1;
    				if(!isEmpty(x))break;
    			}
    
    			//procura por bispo ou rainha em posição de atacar o rei
    			for(x=king-9;x>-1&&x%8!=7;x-=9){
    				if(board[x]=='Q'||board[x]=='B')discardXeques[m]=-1;
    				if(!isEmpty(x))break;
    			}
    			for(x=king-7;x>-1&&x%8!=0;x-=7){
    				if(board[x]=='Q'||board[x]=='B')discardXeques[m]=-1;
    				if(!isEmpty(x))break;
    			}
    			for(x=king+7;x<64&&x%8!=7;x+=7){
    				if(board[x]=='Q'||board[x]=='B')discardXeques[m]=-1;
    				if(!isEmpty(x))break;
    			}
    			for(x=king+9;x<64&&x%8!=0;x+=9){
    				if(board[x]=='Q'||board[x]=='B')discardXeques[m]=-1;
    				if(!isEmpty(x))break;
    			}
    
    			//procura por rei adversário em posição de atacar o rei
    			if(king>7&&king%8>0&&board[king-9]=='K')discardXeques[m]=-1;
    			if(king>7&&board[king-8]=='K')discardXeques[m]=-1;
    			if(king>7&&king%8<7&&board[king-7]=='K')discardXeques[m]=-1;
    			if(king%8>0&&board[king-1]=='K')discardXeques[m]=-1;
    			if(king%8<7&&board[king+1]=='K')discardXeques[m]=-1;
    			if(king<56&&king%8>0&&board[king+7]=='K')discardXeques[m]=-1;
    			if(king<56&&board[king+8]=='K')discardXeques[m]=-1;
    			if(king<56&&king%8<7&&board[king+9]=='K')discardXeques[m]=-1;
    
    			//procura por cavalo adversário em posição de atacar o rei
    			if(king>15&&king%8>0&&board[king-17]=='N')discardXeques[m]=-1;
    			if(king>15&&king%8<7&&board[king-15]=='N')discardXeques[m]=-1;
    			if(king>7&&king%8>1&&board[king-10]=='N')discardXeques[m]=-1;
    			if(king>7&&king%8<6&&board[king-6]=='N')discardXeques[m]=-1;
    			if(king<56&&king%8>1&&board[king+6]=='N')discardXeques[m]=-1;
    			if(king<56&&king%8<6&&board[king+10]=='N')discardXeques[m]=-1;
    			if(king<48&&king%8>0&&board[king+15]=='N')discardXeques[m]=-1;
    			if(king<48&&king%8<7&&board[king+17]=='N')discardXeques[m]=-1;
    
    			//procura por peão adversário em posição de atacar o rei
    			if(king<56&&king%8>0&&board[king+7]=='P')discardXeques[m]=-1;
    			if(king<56&&king%8<7&&board[king+9]=='P')discardXeques[m]=-1;
    		}
    	}
    
    	board=[];
    	for(x=0;x<64;x++) //agora que as jogadas que deixam o rei em xeque foram demarcadas com -1, volta o tabuleiro como estava antes
    		board[x]=backupBoard[x];
    
    	movesList=[]; //re-cria a lista de jogadas
    	for(m=0;m<discardXeques.length;m++) //percorre a lista de testados
    		if(discardXeques[m]!=-1) //se não foi marcada como inválida
    			movesList.push(discardXeques[m]); //adiciona a jogada à lista
    }
    
    function renderSquare(s){
    	if((s+parseInt(s/8))%2) //background do quadrado
    		bgtdcolor="404040"; //cinza escuro
    	else
    		bgtdcolor="c0c0c0"; //cinza claro
    
    	for(m=0;m<movesList.length;m++) //procurando na lista de jogadas válidas
    		if(selected==movesList[m][0]&&s==movesList[m][1]) //se o quadrado é um local válido  de concluir o movimento
    			bgtdcolor="1a73e8"; //azul escuro
    
    	htm+="<td style='width:42px; height:42px; background-color:#"+bgtdcolor+";'>"; //o quadrado
    	htm+="<div onclick='pickSquare("+s+");' style='width:32px; height:32px; margin:0px auto; text-align:center; font-size:22px; border-radius:50%; border:2px solid "; //o circulo dentro do quadrado
    
    	if(board[s]!=' '){
    		if(selected==s) //quadrado selecionado
    			htm+="#40ff40; background-color:#808080;'>"; //cor da borda do círculo verde
    		else
    			htm+="#808080; background-color:#808080;'>"; //cor da borda do círculo igual a cor de dentro do círculo
    
    		switch(board[s]){
    			case 'p':htm+="&#9823;";break; // ♟ peao preto
    			case 'n':htm+="&#9822;";break; // ♞ cavalo preto
    			case 'b':htm+="&#9821;";break; // ♝ bispo preto
    			case 'r':htm+="&#9820;";break; // ♜ torre preto
    			case 'q':htm+="&#9819;";break; // ♛ rainha preto
    			case 'k':htm+="&#9818;";break; // ♚ rei preto
    			case 'P':htm+="&#9817;";break; // ♙ peao branco
    			case 'N':htm+="&#9816;";break; // ♘ cavalo branco
    			case 'B':htm+="&#9815;";break; // ♗ bispo branco
    			case 'R':htm+="&#9814;";break; // ♖ torre branco
    			case 'Q':htm+="&#9813;";break; // ♕ rainha branco
    			case 'K':htm+="&#9812;";break; // ♔ rei branco
    		}
    	}
    	else htm+="transparent;'>&nbsp;"; //quadrado vazio
    
    	htm+="</div>"; //o circulo dentro do quadrado
    	htm+="</td>"; //o quadrado
    }
    
    function boardWhiteAbove(){
    	htm="<table cellpadding=0 cellspacing=0 style='margin:30px;'>";
    	for(x=0;x<8;x++){ //se o player joga com as brancas o board é exibido com as brancas embaixo
    		htm+="<tr>";
    		for(y=0;y<8;y++)renderSquare((x*8)+y);
    		htm+="</tr>";
    	}
    	document.body.innerHTML=htm+"</table>";
    }
    
    function boardBlackAbove(){
    	htm="<table cellpadding=0 cellspacing=0 style='margin:30px;'>";
    	for(x=7;x>-1;x--){ //se o player joga com as brancas o board é exibido com as brancas embaixo
    		htm+="<tr>";
    		for(y=7;y>-1;y--)renderSquare((x*8)+y);
    		htm+="</tr>";
    	}
    	document.body.innerHTML=htm+"</table>";
    }
    
    function render(){
    	if(humanPlayWhite)
    		boardWhiteAbove(); //se o player joga com as brancas o board é exibido com as brancas embaixo
    	else
    		boardBlackAbove(); //se o player joga com as pretas o board é exibido com as pretas embaixo
    
    	if(movesList.length==0)document.body.innerHTML+="<button style='padding:10px; width:84px; position:absolute; bottom:6px; right:6px; animation:slide 1s;' onclick='location.reload();'>restart</button>";
    }
    
    function main(){
    	movesList=[]; //lista de jogadas possíveis
    	//a variável movesList é um array
    	//o comando push insere/adiciona algo no array
    
    	addPawnsMoves(); //adiciona as jogadas dos peões à 'lista de jogadas válidas'
    	addHorsesMoves(); //adiciona as jogadas dos cavalos à 'lista de jogadas válidas'
    	addBishopsMoves(); //adiciona as jogadas em diagonal à 'lista de jogadas válidas'
    	addRooksMoves(); //adiciona as jogadas (em linha e em coluna) à 'lista de jogadas válidas'
    	addKingsMoves(); //adiciona as jogadas do rei 'lista de jogadas válidas'
    
    	discardInvalidMoves();
    
    	if(humanPlayWhite!=whiteTurn&&movesList.length>0)
    		setTimeout(computerMove,500); //jogada aleatória daqui meio segundo
    
    	render();
    }
    
    main();
    </script>
    </html>

    Página-Game

    Experimente o jogo