Jogo de Xadrez em WLanguage e oop com iA
Iniciado por Boller, 17,mar. 2025 18:05 - No hay respuesta
Miembro registrado 3.855 mensajes
Publicado el 17,marzo 2025 - 18:05
Boa tarde Vou criar um exemplo de código em WLanguage (linguagem da plataforma WinDev) para um jogo de xadrez usando programação orientada a objetos (OOP). Incluirei as principais classes, lógica de movimento das peças e um recurso básico para sugerir as próximas 5 jogadas possíveis do oponente. Vou estruturar o código em várias partes para clareza. // Classe base para Peça de Xadrez CLASS Peça PUBLIC sCor IS string // "Branco" ou "Preto" nLinha IS int nColuna IS int bAtiva IS boolean PROCEDURE Construtor(sCorPeça IS string, nLin IS int, nCol IS int) sCor = sCorPeça nLinha = nLin nColuna = nCol bAtiva = True PROCEDURE VIRTUAL MovimentosPossíveis() RETURNS array of string RETURN [] END // Classe derivada para Peão CLASS Peão INHERITS Peça PROCEDURE MovimentosPossíveis() RETURNS array of string aMovimentos IS array of string nDireção IS int = IIF(sCor = "Branco", 1, -1) // Movimento básico para frente IF Tabuleiro::PosicaoLivre(nLinha + nDireção, nColuna) THEN ArrayAdd(aMovimentos, NumToString(nLinha + nDireção) + NumToString(nColuna)) END // Movimento duplo no início IF (sCor = "Branco" AND nLinha = 2) OR (sCor = "Preto" AND nLinha = 7) THEN IF Tabuleiro::PosicaoLivre(nLinha + 2*nDireção, nColuna) THEN ArrayAdd(aMovimentos, NumToString(nLinha + 2*nDireção) + NumToString(nColuna)) END END RETURN aMovimentos END // Classe Tabuleiro CLASS Tabuleiro PUBLIC aPeças IS array of Peça sJogadorAtual IS string = "Branco" PROCEDURE Inicializar() // Adiciona peões brancos FOR i = 1 TO 8 ArrayAdd(aPeças, Peão("Branco", 2, i)) END // Adiciona peões pretos FOR i = 1 TO 8 ArrayAdd(aPeças, Peão("Preto", 7, i)) END // Aqui adicionaria outras peças (torre, cavalo, etc.) PROCEDURE PosicaoLivre(nLin IS int, nCol IS int) RETURNS boolean IF nLin < 1 OR nLin > 8 OR nCol < 1 OR nCol > 8 THEN RETURN False END FOR EACH p OF aPeças IF p::nLinha = nLin AND p::nColuna = nCol AND p::bAtiva THEN RETURN False END END RETURN True PROCEDURE MoverPeça(pPeça IS Peça, nNovaLinha IS int, nNovaColuna IS int) RETURNS boolean aMovimentos IS array of string = pPeça::MovimentosPossíveis() sDestino IS string = NumToString(nNovaLinha) + NumToString(nNovaColuna) IF ArraySearch(aMovimentos, sDestino) >= 0 THEN pPeça::nLinha = nNovaLinha pPeça::nColuna = nNovaColuna sJogadorAtual = IIF(sJogadorAtual = "Branco", "Preto", "Branco") RETURN True END RETURN False PROCEDURE ProximasJogadasOponente(nQuantidade IS int = 5) RETURNS array of string aJogadas IS array of string nContador IS int = 0 FOR EACH p OF aPeças IF p::sCor <> sJogadorAtual AND p::bAtiva THEN aMovimentos IS array of string = p::MovimentosPossíveis() FOR EACH sMov OF aMovimentos IF nContador < nQuantidade THEN ArrayAdd(aJogadas, p::ClassName() + " de " + NumToString(p::nLinha) + NumToString(p::nColuna) + " para " + sMov) nContador++ END END END END RETURN aJogadas END // Janela principal WINDOW JogoXadrez Tab IS Tabuleiro PROCEDURE GLOBAL InicializarJogo() Tab = Tabuleiro() Tab::Inicializar() // Configuração da interface gráfica GRD_Tabuleiro IS Grid GRD_Tabuleiro..Rows = 8 GRD_Tabuleiro..Columns = 8 // Desenha o tabuleiro inicial AtualizarTabuleiro() PROCEDURE AtualizarTabuleiro() FOR i = 1 TO 8 FOR j = 1 TO 8 GRD_Tabuleiro[i,j] = "" END END FOR EACH p OF Tab::aPeças IF p::bAtiva THEN GRD_Tabuleiro[p::nLinha, p::nColuna] = Left(p::ClassName(), 1) + IIF(p::sCor = "Branco", "B", "P") END END PROCEDURE BTN_MostrarJogadas..Clicked() aJogadas IS array of string = Tab::ProximasJogadasOponente(5) sTexto IS string = "Próximas 5 jogadas possíveis do oponente:" + CRLF FOR EACH jogada OF aJogadas sTexto += jogada + CRLF END Info(sTexto) END // Tratamento de clique no tabuleiro PROCEDURE GRD_Tabuleiro..Clicked() STATIC pSelecionada IS Peça nLin IS int = GRD_Tabuleiro..ClickedRow nCol IS int = GRD_Tabuleiro..ClickedColumn IF pSelecionada = Null THEN // Seleciona peça FOR EACH p OF Tab::aPeças IF p::nLinha = nLin AND p::nColuna = nCol AND p::sCor = Tab::sJogadorAtual THEN pSelecionada = p BREAK END END ELSE // Tenta mover IF Tab::MoverPeça(pSelecionada, nLin, nCol) THEN AtualizarTabuleiro() END pSelecionada = Null END END Este código implementa: 1 Estrutura OOP: ◦ Classe base Peça com propriedades básicas ◦ Classe derivada Peão com regras de movimento específicas ◦ Classe Tabuleiro para gerenciar o jogo 2 Funcionalidades principais: ◦ Inicialização do tabuleiro ◦ Movimento de peças com validação ◦ Alternância de jogadores ◦ Cálculo das próximas 5 jogadas possíveis do oponente 3 Interface gráfica: ◦ Grid para representar o tabuleiro ◦ Botão para mostrar jogadas possíveis ◦ Tratamento de cliques para seleção e movimento 4 Recursos da WLanguage: ◦ Uso de arrays dinâmicos ◦ Herança de classes ◦ Procedimentos virtuais ◦ Controles gráficos nativos ◦ Tratamento de eventos Para completar o jogo, seria necessário: 1 Implementar as outras peças (Torre, Cavalo, Bispo, Rainha, Rei) 2 Adicionar regras especiais (roque, en passant, promoção) 3 Implementar verificação de xeque e xeque-mate 4 Adicionar gráficos para as peças 5 Melhorar a IA para seleção de melhores jogadas O código atual fornece uma base sólida que pode ser expandida. A função ProximasJogadasOponente() lista movimentos possíveis aleatórios do oponente até atingir o limite de 5, mas poderia ser aprimorada com uma heurística para selecionar as melhores jogadas. Para executar, você precisaria: 1 Criar uma janela no WinDev 2 Adicionar um controle Grid (GRD_Tabuleiro) 3 Adicionar um botão (BTN_MostrarJogadas) 4 Associar os eventos correspondentes Para aprimorar o jogo de xadrez em WLanguage que desenvolvi, há várias melhorias e funcionalidades adicionais que podem ser implementadas. Vou listar as principais possibilidades de expansão e detalhar algumas delas, mantendo o foco nas capacidades da linguagem e nas necessidades de um jogo de xadrez completo: --- ### 1. Implementação de Todas as Peças Atualmente, apenas o Peão está implementado. Adicionar as outras peças é essencial: - **Torre**: Movimentos horizontais e verticais ilimitados. - **Cavalo**: Movimentos em "L" (2+1 ou 1+2). - **Bispo**: Movimentos diagonais ilimitados. - **Rainha**: Combinação de Torre e Bispo. - **Rei**: Movimento de uma casa em qualquer direção. Exemplo para a Torre: ```windev CLASS Torre INHERITS Peça PROCEDURE MovimentosPossíveis() RETURNS array of string aMovimentos IS array of string // Horizontal direita FOR i = nColuna + 1 TO 8 IF Tabuleiro::PosicaoLivre(nLinha, i) THEN ArrayAdd(aMovimentos, NumToString(nLinha) + NumToString(i)) ELSE BREAK END END // Adicionar outras direções (esquerda, cima, baixo) de forma similar RETURN aMovimentos END ``` --- ### 2. Regras Especiais do Xadrez Adicionar regras específicas para tornar o jogo completo: - **Roque**: Movimento especial envolvendo Rei e Torre. - **En passant**: Captura especial de peão. - **Promoção**: Transformação de peão ao chegar na última linha. - **Xeque e Xeque-mate**: Verificação de ameaça ao Rei e fim de jogo. Exemplo de verificação de xeque: ```windev PROCEDURE Tabuleiro::EstaEmXeque(sCorRei IS string) RETURNS boolean pRei IS Peça FOR EACH p OF aPeças IF p::ClassName() = "Rei" AND p::sCor = sCorRei THEN pRei = p BREAK END END FOR EACH p OF aPeças IF p::sCor <> sCorRei THEN aMov IS array of string = p::MovimentosPossíveis() IF ArraySearch(aMov, NumToString(pRei::nLinha) + NumToString(pRei::nColuna)) >= 0 THEN RETURN True END END END RETURN False END ``` --- ### 3. Interface Gráfica Aprimorada - **Imagens das Peças**: Usar `Image` controls ou sprites para representar as peças visualmente. - **Animação de Movimentos**: Utilizar as funções de animação do WinDev (`Animate`). - **Destacar Movimentos Possíveis**: Colorir as células do grid quando uma peça é selecionada. - **Histórico de Jogadas**: Adicionar um controle `List Box` para mostrar movimentos anteriores. Exemplo de destaque de movimentos: ```windev PROCEDURE DestacarMovimentos(pPeça IS Peça) aMov IS array of string = pPeça::MovimentosPossíveis() FOR EACH sPos OF aMov nLin IS int = Val(Left(sPos, 1)) nCol IS int = Val(Right(sPos, 1)) GRD_Tabuleiro[nLin, nCol]..BackgroundColor = LightYellow END END ``` --- ### 4. Inteligência Artificial (IA) Melhorar o recurso de "próximas 5 jogadas" com uma IA básica: - **Avaliação de Posição**: Criar uma função que pontue a posição (material, controle do centro, segurança do rei). - **Minimax**: Implementar um algoritmo simples de busca em árvore para escolher as melhores jogadas. Exemplo básico de avaliação: ```windev PROCEDURE AvaliarPosicao() RETURNS int nPontos IS int = 0 FOR EACH p OF aPeças IF p::bAtiva THEN nValor IS int = SWITCH p::ClassName() CASE "Peão": 1 CASE "Cavalo", "Bispo": 3 CASE "Torre": 5 CASE "Rainha": 9 CASE "Rei": 100 OTHER CASE: 0 END nPontos += IIF(p::sCor = "Branco", nValor, -nValor) END END RETURN nPontos END ``` --- ### 5. Recursos Multiplayer - **Jogo em Rede**: Usar sockets (`SocketConnect`) ou o recurso de comunicação em tempo real do WinDev para permitir partidas online. - **Salvar/Carregar Partida**: Implementar serialização do estado do jogo em arquivo ou banco de dados HFSQL. Exemplo de salvar jogo: ```windev PROCEDURE SalvarJogo(sArquivo IS string) f IS File f = fCreate(sArquivo) FOR EACH p OF aPeças fWriteLine(f, p::ClassName() + ";" + p::sCor + ";" + NumToString(p::nLinha) + ";" + NumToString(p::nColuna)) END fClose(f) END ``` --- ### 6. Experiência do Usuário - **Som**: Adicionar efeitos sonoros para movimentos e capturas usando `SoundPlay`. - **Temporizador**: Implementar controle de tempo por jogador com `Timer`. - **Modo Treino**: Sugerir jogadas para o jogador atual, além do oponente. Exemplo de temporizador: ```windev PROCEDURE IniciarTemporizador() nTempoBranco IS int = 600 // 10 minutos em segundos nTempoPreto IS int = 600 TimerSys(1000, "AtualizarTempo") END PROCEDURE AtualizarTempo() IF Tab::sJogadorAtual = "Branco" THEN nTempoBranco-- EDT_TempoBranco = FormatTime(nTempoBranco) ELSE nTempoPreto-- EDT_TempoPreto = FormatTime(nTempoPreto) END END ``` --- ### 7. Testes e Depuração - **Log de Movimentos**: Adicionar um sistema de log usando `Trace` para debug. - **Testes Automáticos**: Criar procedimentos para testar movimentos válidos e inválidos. --- ### Implementação Sugerida Para começar, eu recomendaria: 1. Completar as classes das peças (Torre, Cavalo, etc.). 2. Adicionar regras de xeque e xeque-mate. 3. Melhorar a interface com imagens e destaque de movimentos. 4. Implementar uma IA básica com avaliação de posição. Certamente! Há ainda mais funcionalidades e melhorias que podem ser implementadas no jogo de xadrez em WLanguage para torná-lo mais robusto, interativo e profissional. Vou listar ideias adicionais que vão além do que já mencionei, explorando recursos avançados da linguagem e possibilidades criativas: --- ### 1. Sistema de Pontuação e Ranking - **Pontuação por Partida**: Registrar pontos baseados em vitórias, empates e desempenho (ex.: tempo restante, número de movimentos). - **Ranking de Jogadores**: Usar o banco de dados HFSQL nativo do WinDev para criar um sistema de classificação persistente. Exemplo: ```windev PROCEDURE SalvarResultado(sJogador IS string, nPontos IS int) HOpenConnection("XadrezDB") Jogador IS Record HReadSeekFirst(Jogador, Nome, sJogador) IF HFound() THEN Jogador.Pontuacao += nPontos HModify(Jogador) ELSE Jogador.Nome = sJogador Jogador.Pontuacao = nPontos HAdd(Jogador) END HCloseConnection() END ``` --- ### 2. Modos de Jogo Alternativos - **Xadrez 960 (Fischer Random)**: Randomizar a posição inicial das peças na primeira e oitava linhas, respeitando as regras do Xadrez 960. - **Modo Puzzle**: Apresentar posições predefinidas para o jogador resolver (ex.: xeque-mate em 2 jogadas). - **Xadrez por Correspondência**: Permitir jogadas assíncronas salvando o estado do jogo. Exemplo de randomização para Xadrez 960: ```windev PROCEDURE InicializarXadrez960() aPosicoes IS array of string = ["T", "C", "B", "Q", "K", "B", "C", "T"] ArrayShuffle(aPosicoes) FOR i = 1 TO 8 sTipo IS string = aPosicoes[i] ArrayAdd(Tab::aPeças, SWITCH sTipo CASE "T": Torre("Branco", 1, i) CASE "C": Cavalo("Branco", 1, i) CASE "B": Bispo("Branco", 1, i) CASE "Q": Rainha("Branco", 1, i) CASE "K": Rei("Branco", 1, i) END) END // Adicionar peões e peças pretas END ``` --- ### 3. Análise de Partidas - **Replay de Partidas**: Gravar todos os movimentos em uma estrutura (ex.: array ou arquivo) e permitir replay passo a passo. - **Exportação em PGN**: Implementar exportação no formato Portable Game Notation, padrão para xadrez. - **Estatísticas**: Mostrar métricas como número de capturas, tempo médio por jogada, etc. Exemplo de gravação de movimentos: ```windev PROCEDURE Tabuleiro::MoverPeça(pPeça IS Peça, nNovaLinha IS int, nNovaColuna IS int) RETURNS boolean IF Super::MoverPeça(pPeça, nNovaLinha, nNovaColuna) THEN sMovimento IS string = pPeça::ClassName() + " " + NumToString(pPeça::nLinha) + NumToString(pPeça::nColuna) + "-" + NumToString(nNovaLinha) + NumToString(nNovaColuna) ArrayAdd(aHistoricoMovimentos, sMovimento) RETURN True END RETURN False END ``` --- ### 4. Integração com Tecnologias Externas - **IA Avançada**: Integrar uma engine de xadrez como Stockfish via chamadas externas (`ExecuteProcess`) para níveis de dificuldade realistas. - **API Online**: Conectar-se a plataformas como Lichess ou Chess.com para buscar posições ou jogar online. - **Reconhecimento de Voz**: Usar `SpeechRecognition` do WinDev para permitir comandos como "Peão para E4". Exemplo com Stockfish: ```windev PROCEDURE ConsultarStockfish(sPosicaoFEN IS string) RETURNS string sComando IS string = "stockfish.exe position fen " + sPosicaoFEN + " go depth 10" sResultado IS string = ExecuteProcess(sComando, execWait) RETURN ExtractString(sResultado, "bestmove", " ") END ``` --- ### 5. Personalização - **Temas Visuais**: Permitir troca de cores do tabuleiro e estilos de peças usando `SkinTemplate`. - **Configuração de IA**: Ajustar dificuldade (profundidade de busca, tempo de cálculo). - **Peças Customizadas**: Permitir upload de imagens pelo usuário para personalizar as peças. Exemplo de troca de tema: ```windev PROCEDURE MudarTema(sTema IS string) SWITCH sTema CASE "Clássico" GRD_Tabuleiro..BackgroundColor = LightGray GRD_Tabuleiro..AlternateColor = White CASE "Madeira" GRD_Tabuleiro..BackgroundColor = Brown GRD_Tabuleiro..AlternateColor = LightBrown END END ``` --- ### 6. Ferramentas de Aprendizado - **Dicas Contextuais**: Mostrar explicações sobre por que uma jogada é boa ou ruim. - **Treinamento de Aberturas**: Implementar um banco de aberturas famosas (ex.: Ruy Lopez, Defesa Siciliana). - **Modo Análise**: Permitir que o jogador experimente variações sem afetar o jogo principal. Exemplo de dica: ```windev PROCEDURE MostrarDica(pPeça IS Peça) aMov IS array of string = pPeça::MovimentosPossíveis() IF ArrayCount(aMov) > 0 THEN Info("Você pode mover " + pPeça::ClassName() + " para " + aMov[1] + ". Isso controla o centro do tabuleiro!") END END ``` --- ### 7. Otimização e Performance - **Cache de Movimentos**: Armazenar movimentos possíveis calculados para evitar recálculos. - **Multithreading**: Usar `ThreadExecute` para calcular jogadas da IA em segundo plano. - **Compressão de Dados**: Compactar o histórico de partidas para economizar espaço. Exemplo de thread para IA: ```windev PROCEDURE CalcularJogadaIA() ThreadExecute("CalculoIA", ThreadNormal, "CalcularMelhorJogada") END PROCEDURE CalcularMelhorJogada() aJogadas IS array of string = Tab::ProximasJogadasOponente(5) // Lógica de escolha da melhor jogada ThreadSendSignal("JogadaCalculada", aJogadas[1]) END ``` --- ### 8. Recursos Sociais - **Chat**: Adicionar um controle de chat para partidas multiplayer. - **Compartilhamento**: Permitir compartilhar posições ou partidas via redes sociais ou e-mail. - **Torneios**: Criar um sistema de torneio interno com múltiplos jogadores. Exemplo de chat simples: ```windev PROCEDURE EnviarMensagem() EDT_Chat..AddLine = EDT_Mensagem IF bMultiplayer THEN SocketWrite(sSessao, EDT_Mensagem) END EDT_Mensagem = "" END ``` --- ### Próximos Passos Se quiser avançar, sugiro começar com: 1. Integração com Stockfish para uma IA competitiva. 2. Sistema de replay e exportação PGN para análise. 3. Modo Xadrez 960 para variedade. Ao revisar o desenvolvimento do jogo de xadrez em WLanguage até agora, percebo que cobrimos muitas funcionalidades importantes, mas ainda há aspectos que podem estar sendo negligenciados ou que não exploramos completamente. Vou destacar o que pode estar faltando ou mereça mais atenção para garantir que o jogo esteja completo, funcional e alinhado com as expectativas de um projeto robusto. Aqui estão os pontos que estamos "esquecendo" ou que poderiam ser refinados: --- ### 1. Validação Completa das Regras do Xadrez Embora tenhamos mencionado algumas regras especiais, ainda falta implementá-las completamente e garantir que todas as regras oficiais sejam respeitadas: - **Impedir Movimentos que Deixem o Rei em Xeque**: Atualmente, os movimentos são validados apenas pela peça, mas não verificamos se o movimento coloca o próprio rei em xeque. - **Empate por Repetição**: Detectar quando uma posição se repete três vezes. - **Regra dos 50 Movimentos**: Terminar o jogo em empate se não houver capturas ou movimentos de peão em 50 jogadas. - **Rei Afogado (Stalemate)**: Identificar quando um jogador não tem movimentos legais, mas não está em xeque. Exemplo de validação de xeque após movimento: ```windev PROCEDURE Tabuleiro::MoverPeça(pPeça IS Peça, nNovaLinha IS int, nNovaColuna IS int) RETURNS boolean nLinAntiga IS int = pPeça::nLinha nColAntiga IS int = pPeça::nColuna IF Super::MoverPeça(pPeça, nNovaLinha, nNovaColuna) THEN IF EstaEmXeque(sJogadorAtual) THEN // Desfaz o movimento pPeça::nLinha = nLinAntiga pPeça::nColuna = nColAntiga RETURN False END RETURN True END RETURN False END ``` --- ### 2. Tratamento de Capturas - **Captura de Peças**: Não implementamos a lógica para remover peças capturadas do tabuleiro. Atualmente, o código apenas move peças, mas não verifica se há uma peça adversária na posição de destino. - **Atualização Visual**: Garantir que a peça capturada desapareça da interface. Exemplo: ```windev PROCEDURE Tabuleiro::CapturarPeça(nLin IS int, nCol IS int) FOR EACH p OF aPeças IF p::nLinha = nLin AND p::nColuna = nCol AND p::bAtiva THEN p::bAtiva = False BREAK END END END PROCEDURE Tabuleiro::MoverPeça(pPeça IS Peça, nNovaLinha IS int, nNovaColuna IS int) RETURNS boolean IF NOT PosicaoLivre(nNovaLinha, nNovaColuna) THEN CapturarPeça(nNovaLinha, nNovaColuna) END RETURN Super::MoverPeça(pPeça, nNovaLinha, nNovaColuna) END ``` --- ### 3. Sistema de Fim de Jogo - **Condições de Vitória**: Falta uma função clara para declarar o vencedor (xeque-mate) ou empate. - **Notificação**: Mostrar uma mensagem ou tela de fim de jogo. Exemplo: ```windev PROCEDURE Tabuleiro::VerificarFimJogo() RETURNS string IF EstaEmXeque(sJogadorAtual) THEN bTemMovimentos IS boolean = False FOR EACH p OF aPeças IF p::sCor = sJogadorAtual AND p::bAtiva THEN IF ArrayCount(p::MovimentosPossíveis()) > 0 THEN bTemMovimentos = True BREAK END END END IF NOT bTemMovimentos THEN RETURN "Xeque-mate! " + IIF(sJogadorAtual = "Branco", "Pretas vencem", "Brancas vencem") END ELSE bTemMovimentos IS boolean = False FOR EACH p OF aPeças IF p::sCor = sJogadorAtual AND p::bAtiva THEN IF ArrayCount(p::MovimentosPossíveis()) > 0 THEN bTemMovimentos = True BREAK END END END IF NOT bTemMovimentos THEN RETURN "Empate por afogamento" END END RETURN "" END ``` --- ### 4. Feedback ao Jogador - **Indicação de Xeque**: Mostrar visualmente ou por mensagem quando o rei está em xeque. - **Movimentos Inválidos**: Informar por que um movimento não foi aceito (ex.: "Movimento ilegal" ou "Coloca o rei em xeque"). - **Turno Atual**: Exibir claramente de quem é a vez. Exemplo: ```windev PROCEDURE AtualizarInterface() AtualizarTabuleiro() IF Tab::EstaEmXeque(Tab::sJogadorAtual) THEN Info("Xeque!") END EDT_Turno = "Vez de: " + Tab::sJogadorAtual END ``` --- ### 5. Robustez e Tratamento de Erros - **Validação de Entrada**: Garantir que cliques fora do tabuleiro ou ações inválidas não quebrem o jogo. - **Desfazer Movimentos**: Permitir voltar um movimento em caso de erro (útil para testes ou modo casual). - **Exceções**: Tratar possíveis erros, como tentativa de mover uma peça inexistente. Exemplo de desfazer: ```windev PROCEDURE Tabuleiro::DesfazerUltimoMovimento() IF ArrayCount(aHistoricoMovimentos) > 0 THEN sUltimoMov IS string = aHistoricoMovimentos[ArrayCount(aHistoricoMovimentos)] ArrayDelete(aHistoricoMovimentos, ArrayCount(aHistoricoMovimentos)) // Parse do movimento (ex.: "Peão 22-24") sPeça IS string = ExtractString(sUltimoMov, 1, " ") sOrigem IS string = ExtractString(sUltimoMov, 2, " ") sDestino IS string = ExtractString(sUltimoMov, 3, " ") FOR EACH p OF aPeças IF p::ClassName() = sPeça AND p::nLinha = Val(Left(sDestino, 1)) THEN p::nLinha = Val(Left(sOrigem, 1)) p::nColuna = Val(Right(sOrigem, 1)) BREAK END END sJogadorAtual = IIF(sJogadorAtual = "Branco", "Preto", "Branco") END END ``` --- ### 6. Testes de Compatibilidade - **Multiplataforma**: Garantir que o jogo funcione em WinDev Mobile ou WebDev, ajustando a interface para telas menores ou navegadores. - **Resolução**: Testar o layout em diferentes tamanhos de tela. --- ### 7. Documentação e Acessibilidade - **Ajuda no Jogo**: Incluir um manual ou dicas interativas (ex.: "Como jogar" ou "Regras do xadrez"). - **Acessibilidade**: Adicionar suporte a leitores de tela ou comandos por teclado. Exemplo de ajuda: ```windev PROCEDURE MostrarAjuda() WindowOpen("WND_Ajuda") WND_Ajuda::EDT_Conteudo = "Regras do Xadrez:" + CRLF + "1. O Rei move-se uma casa em qualquer direção." + CRLF + "2. A Rainha move-se em qualquer direção, quantas casas quiser." END ``` --- ### 8. Balanceamento da IA - **Dificuldade Ajustável**: O cálculo das "próximas 5 jogadas" é básico e aleatório. Falta uma IA que varie entre fácil (jogadas simples) e difícil (minimax com profundidade maior). - **Simulação de Erros**: Para modo fácil, a IA poderia cometer erros intencionais. --- ### O Que Estamos Realmente Esquecendo? Refletindo sobre o escopo, o principal que estamos esquecendo é **tornar o jogo "jogável" como um produto final**. Isso significa: - Garantir que todas as regras estejam implementadas e testadas. - Criar um fluxo completo de jogo (início, meio e fim). - Polir a experiência do usuário com feedback claro e uma interface intuitiva. ### Próximo Passo Sugerido Eu sugiro focar em: 1. Implementar a captura de peças e a validação de xeque completo. 2. Adicionar o sistema de fim de jogo (xeque-mate e empates). 3. Testar o jogo com uma partida completa para identificar falhas. Para enriquecer a lógica e a inteligência artificial (IA) do jogo de xadrez em WLanguage, podemos adicionar camadas de complexidade que tornem o jogo mais estratégico, realista e desafiador. Vou detalhar ideias para melhorar a lógica geral do jogo e implementar uma IA mais sofisticada, aproveitando as capacidades da linguagem e conceitos de xadrez computacional. --- ### Melhorias na Lógica do Jogo #### 1. Controle de Estado Avançado - **Histórico Completo**: Além de registrar movimentos, armazenar o estado completo do tabuleiro em cada turno (posição de todas as peças) para suportar análise e desfazer movimentos com capturas. - **Detecção de Padrões**: Identificar situações como "rei e rainha contra rei" ou "insuficiência de material" para declarar empates automaticamente. Exemplo de estado do tabuleiro: ```windev PROCEDURE Tabuleiro::SalvarEstado() sEstado IS string FOR EACH p OF aPeças IF p::bAtiva THEN sEstado += p::ClassName() + ";" + p::sCor + ";" + NumToString(p::nLinha) + ";" + NumToString(p::nColuna) + "|" END END ArrayAdd(aEstados, sEstado) END ``` #### 2. Validação de Movimentos Avançada - **Cálculo de Caminho Livre**: Para peças como Torre, Bispo e Rainha, verificar se o caminho até o destino está desobstruído. - **Simulação de Movimentos**: Antes de executar um movimento, simular seus efeitos para garantir que ele seja legal (ex.: não deixar o rei em xeque). Exemplo de caminho livre para Torre: ```windev PROCEDURE Torre::CaminhoLivre(nLinDest IS int, nColDest IS int) RETURNS boolean IF nLinha = nLinDest THEN nInicio IS int = Min(nColuna, nColDest) + 1 nFim IS int = Max(nColuna, nColDest) - 1 FOR i = nInicio TO nFim IF NOT Tabuleiro::PosicaoLivre(nLinha, i) THEN RETURN False END END ELSE IF nColuna = nColDest THEN // Similar para vertical END RETURN True END ``` #### 3. Heurísticas de Jogo - **Controle do Centro**: Priorizar movimentos que controlem as casas centrais (E4, E5, D4, D5). - **Desenvolvimento de Peças**: Incentivar mover peças menores antes das maiores (ex.: cavalos e bispos antes da rainha). --- ### Inteligência Artificial Avançada #### 1. Algoritmo Minimax O Minimax é o coração de muitas IAs de xadrez. Ele simula jogadas futuras para escolher a melhor opção: - **Maximizar**: O jogador atual tenta maximizar sua pontuação. - **Minimizar**: O oponente tenta minimizar essa pontuação. - **Profundidade**: Limitar a busca a X turnos para balancear desempenho e qualidade. Exemplo básico de Minimax: ```windev PROCEDURE Minimax(nProfundidade IS int, bMaximizando IS boolean) RETURNS int IF nProfundidade = 0 OR Tab::VerificarFimJogo() <> "" THEN RETURN AvaliarPosicao() END IF bMaximizando THEN nMelhorValor IS int = -Infinity FOR EACH p OF aPeças IF p::sCor = sJogadorAtual AND p::bAtiva THEN aMov IS array of string = p::MovimentosPossíveis() FOR EACH sMov OF aMov nLin IS int = Val(Left(sMov, 1)) nCol IS int = Val(Right(sMov, 1)) SalvarEstado() MoverPeça(p, nLin, nCol) nValor IS int = Minimax(nProfundidade - 1, False) RestaurarEstado() nMelhorValor = Max(nMelhorValor, nValor) END END END RETURN nMelhorValor ELSE nMelhorValor IS int = Infinity // Similar, mas minimizando para o oponente END END ``` #### 2. Função de Avaliação Refinada A função `AvaliarPosicao()` pode ser expandida para considerar: - **Valor Material**: Peão = 1, Cavalo/Bispo = 3, Torre = 5, Rainha = 9, Rei = 100. - **Mobilidade**: Número de movimentos legais disponíveis. - **Segurança do Rei**: Penalizar reis expostos ou cercados. - **Estrutura de Peões**: Bonificar peões conectados, penalizar peões dobrados. Exemplo aprimorado: ```windev PROCEDURE AvaliarPosicao() RETURNS int nPontos IS int = 0 FOR EACH p OF aPeças IF p::bAtiva THEN nValor IS int = SWITCH p::ClassName() CASE "Peão": 1 CASE "Cavalo", "Bispo": 3 CASE "Torre": 5 CASE "Rainha": 9 CASE "Rei": 100 END nPontos += IIF(p::sCor = "Branco", nValor, -nValor) // Bônus por mobilidade nPontos += IIF(p::sCor = "Branco", 0.1, -0.1) * ArrayCount(p::MovimentosPossíveis()) END END // Bônus por controle do centro IF NOT PosicaoLivre(4, 4) THEN nPontos += IIF(sJogadorAtual = "Branco", 0.5, -0.5) RETURN nPontos END ``` #### 3. Poda Alfa-Beta Para otimizar o Minimax, podemos usar a poda Alfa-Beta, que elimina ramos da árvore de busca que não afetarão o resultado final. Exemplo: ```windev PROCEDURE AlfaBeta(nProfundidade IS int, nAlfa IS int, nBeta IS int, bMaximizando IS boolean) RETURNS int IF nProfundidade = 0 OR Tab::VerificarFimJogo() <> "" THEN RETURN AvaliarPosicao() END IF bMaximizando THEN nValor IS int = -Infinity FOR EACH p OF aPeças IF p::sCor = sJogadorAtual AND p::bAtiva THEN aMov IS array of string = p::MovimentosPossíveis() FOR EACH sMov OF aMov nLin IS int = Val(Left(sMov, 1)) nCol IS int = Val(Right(sMov, 1)) SalvarEstado() MoverPeça(p, nLin, nCol) nValor = Max(nValor, AlfaBeta(nProfundidade - 1, nAlfa, nBeta, False)) RestaurarEstado() nAlfa = Max(nAlfa, nValor) IF nBeta <= nAlfa THEN BREAK END END END RETURN nValor ELSE // Similar, mas minimizando END END ``` #### 4. Livro de Aberturas - **Pré-carregar Aberturas**: Incluir um banco de dados com aberturas populares (ex.: Gambito da Rainha, Defesa Siciliana) para a IA jogar como um humano nos primeiros turnos. - **Formato Simples**: Usar um array ou arquivo HFSQL com sequências de movimentos. Exemplo: ```windev PROCEDURE ConsultarAbertura() RETURNS string aAberturas IS array of string ArrayAdd(aAberturas, "E2E4;E7E5") // 1. e4 e5 ArrayAdd(aAberturas, "E2E4;C7C5") // 1. e4 c5 (Siciliana) sHistorico IS string = StringBuild("%1", aHistoricoMovimentos) FOR EACH sAbertura OF aAberturas IF Left(sHistorico, Length(sAbertura)) = sAbertura THEN RETURN ExtractString(sAbertura, ArrayCount(aHistoricoMovimentos) + 1, ";") END END RETURN "" END ``` #### 5. Dificuldade Ajustável - **Profundidade Variável**: Ajustar a profundidade do Minimax (ex.: 2 para fácil, 4 para médio, 6 para difícil). - **Erro Intencional**: Em níveis fáceis, escolher uma jogada subótima aleatoriamente com certa probabilidade. Exemplo: ```windev PROCEDURE JogadaIA(nNivel IS int) RETURNS string IF nNivel = 1 AND Random(1, 100) < 30 THEN aMovimentos IS array of string = ProximasJogadasOponente() RETURN aMovimentos[Random(1, ArrayCount(aMovimentos))] END RETURN CalcularMelhorJogada(nNivel) END ``` #### 6. Paralelismo - **Multithreading**: Usar `ThreadExecute` para calcular jogadas em paralelo, especialmente em máquinas multicore. - **Pré-cálculo**: Calcular a próxima jogada enquanto o jogador pensa. Exemplo: ```windev PROCEDURE PreCalcularIA() ThreadExecute("IA", ThreadNormal, "CalcularMelhorJogada", 4) END PROCEDURE CalcularMelhorJogada(nProfundidade IS int) sMelhorJogada IS string nMelhorValor IS int = -Infinity FOR EACH p OF aPeças IF p::sCor = sJogadorAtual AND p::bAtiva THEN aMov IS array of string = p::MovimentosPossíveis() FOR EACH sMov OF aMov SalvarEstado() MoverPeça(p, Val(Left(sMov, 1)), Val(Right(sMov, 1))) nValor IS int = AlfaBeta(nProfundidade - 1, -Infinity, Infinity, False) IF nValor > nMelhorValor THEN nMelhorValor = nValor sMelhorJogada = sMov END RestaurarEstado() END END END ThreadSendSignal("JogadaPronta", sMelhorJogada) END ``` --- ### Integração no Jogo Para usar essas melhorias: 1. Substituir `ProximasJogadasOponente()` por uma chamada ao Alfa-Beta com profundidade ajustável. 2. Adicionar um controle na interface para escolher o nível de dificuldade. 3. Implementar o livro de aberturas como fallback inicial. Exemplo de uso: ```windev PROCEDURE BTN_JogadaIA..Clicked() sJogada IS string = JogadaIA(EDT_Dificuldade) IF sJogada <> "" THEN pPeça IS Peça = // Encontrar peça correspondente Tab::MoverPeça(pPeça, Val(Left(sJogada, 1)), Val(Right(sJogada, 1))) AtualizarTabuleiro() END END ``` --- ### O Que Focar? Sugiro começar com: 1. Função de avaliação refinada (material + mobilidade). 2. Minimax com poda Alfa-Beta (profundidade 4). 3. Livro de aberturas básico. Parece que você quis dizer "Algo mais?"! Vou assumir que está perguntando o que mais podemos adicionar de lógica e inteligência artificial ao jogo de xadrez em WLanguage. Vou explorar ideias adicionais que ainda não abordamos, focando em aspectos avançados de lógica e IA, bem como algumas inovações que podem tornar o jogo único e mais sofisticado. --- ### Lógica Adicional #### 1. Sistema de Prioridade de Movimentos - **Ordenação de Jogadas**: Antes de avaliar movimentos no Minimax, ordená-los por prioridade (ex.: capturas primeiro, depois cheques, depois movimentos normais) para melhorar a eficiência da poda Alfa-Beta. - **Heurística de Ameaças**: Detectar e priorizar movimentos que criam ameaças múltiplas (forks) ou defendem peças sob ataque. Exemplo: ```windev PROCEDURE OrdenarMovimentos(aMovimentos IS array of string, pPeça IS Peça) RETURNS array of string aPrioridades IS array of int FOR EACH sMov OF aMovimentos nLin IS int = Val(Left(sMov, 1)) nCol IS int = Val(Right(sMov, 1)) nPrioridade IS int = 0 IF NOT Tabuleiro::PosicaoLivre(nLin, nCol) THEN nPrioridade += 10 // Captura END IF Tabuleiro::CausaXeque(pPeça, nLin, nCol) THEN nPrioridade += 5 // Xeque END ArrayAdd(aPrioridades, nPrioridade) END ArraySort(aMovimentos, aPrioridades, sortDescending) RETURN aMovimentos END ``` #### 2. Detecção de Padrões Estratégicos - **Pin (Pregadura)**: Identificar quando uma peça está imobilizada por proteger uma peça mais valiosa (ex.: torre pregando um cavalo contra o rei). - **Discovered Attack**: Reconhecer ataques descobertos (ex.: mover um peão para revelar um ataque de bispo). - **Battery**: Detectar alinhamentos de peças (ex.: duas torres na mesma coluna). Exemplo de detecção de pin: ```windev PROCEDURE Tabuleiro::EstaPresa(pPeça IS Peça) RETURNS boolean FOR EACH pAtacante OF aPeças IF pAtacante::sCor <> pPeça::sCor AND pAtacante::bAtiva THEN aMov IS array of string = pAtacante::MovimentosPossíveis() IF ArraySearch(aMov, NumToString(pPeça::nLinha) + NumToString(pPeça::nColuna)) >= 0 THEN // Verifica se há uma peça mais valiosa atrás FOR EACH pDefensor OF aPeças IF pDefensor::sCor = pPeça::sCor AND pDefensor <> pPeça AND EstaAlinhado(pAtacante, pPeça, pDefensor) THEN RETURN True END END END END END RETURN False END ``` #### 3. Simulação de Final de Jogo - **Regras Específicas**: Implementar lógica para finais comuns (ex.: rei e rainha vs. rei, rei e torre vs. rei) com estratégias pré-programadas. - **Tabela de Posições**: Usar uma pequena base de dados (HFSQL) com posições conhecidas de xeque-mate em 1 ou 2 jogadas. --- ### Inteligência Artificial Avançada #### 1. Aprendizado por Reforço Simples - **Memória de Partidas**: Armazenar resultados de jogadas anteriores e ajustar pesos na função de avaliação com base em vitórias/derrotas. - **Exploração vs. Exploração**: Balancear entre tentar jogadas conhecidas e explorar novas possibilidades. Exemplo básico: ```windev PROCEDURE AtualizarPesoJogada(sJogada IS string, bVitoria IS boolean) HOpenConnection("XadrezDB") Jogada IS Record HReadSeekFirst(Jogada, Movimento, sJogada) IF HFound() THEN Jogada.Peso += IIF(bVitoria, 0.1, -0.1) HModify(Jogada) ELSE Jogada.Movimento = sJogada Jogada.Peso = IIF(bVitoria, 0.1, -0.1) HAdd(Jogada) END HCloseConnection() END ``` #### 2. Monte Carlo Tree Search (MCTS) O MCTS é uma alternativa ao Minimax, usada em jogos como Go e xadrez moderno: - **Simulação**: Executar várias simulações aleatórias a partir de uma posição. - **Seleção**: Escolher os ramos mais promissores com base em uma fórmula (ex.: UCT - Upper Confidence Bound). Exemplo simplificado: ```windev PROCEDURE MCTS(nSimulacoes IS int) RETURNS string aNos IS array of Node FOR EACH p OF aPeças IF p::sCor = sJogadorAtual AND p::bAtiva THEN aMov IS array of string = p::MovimentosPossíveis() FOR EACH sMov OF aMov n IS Node n.Movimento = sMov n.Visitas = 0 n.Vitorias = 0 ArrayAdd(aNos, n) END END END FOR i = 1 TO nSimulacoes nSelecionado IS Node = SelecionarNo(aNos) // Usa UCT SalvarEstado() ExecutarMovimento(nSelecionado.Movimento) nResultado IS int = SimularJogoAleatorio() RestaurarEstado() nSelecionado.Visitas++ nSelecionado.Vitorias += nResultado END RETURN MelhorNo(aNos).Movimento END ``` #### 3. Redes Neurais Simples (Simulação) Embora WLanguage não tenha suporte nativo a redes neurais, podemos simular uma rede simples com pesos ajustáveis para avaliar posições: - **Entradas**: Número de peças, mobilidade, segurança do rei, etc. - **Saída**: Pontuação estimada. Exemplo: ```windev PROCEDURE AvaliarComRede(nPeçasBrancas IS int, nPeçasPretas IS int, nMobilidade IS int) RETURNS float aPesos IS array of float = [0.5, -0.5, 0.1] // Ajustáveis nSaida IS float = (nPeçasBrancas * aPesos[1]) + (nPeçasPretas * aPesos[2]) + (nMobilidade * aPesos[3]) RETURN nSaida END ``` #### 4. Adaptação ao Jogador - **Análise de Estilo**: Observar padrões do jogador (agressivo, defensivo) e ajustar a IA (ex.: contra jogadores agressivos, focar em contra-ataques). - **Nível Dinâmico**: Aumentar ou diminuir a profundidade da IA com base no desempenho do jogador. Exemplo: ```windev PROCEDURE AjustarDificuldade() IF nVitoriasJogador > nVitoriasIA + 2 THEN nProfundidadeIA++ ELSE IF nVitoriasIA > nVitoriasJogador + 2 THEN nProfundidadeIA-- END END ``` #### 5. Previsão de Longo Prazo - **Planejamento Estratégico**: Implementar metas de longo prazo, como avançar um peão para promoção ou criar uma bateria de torres. - **Horizonte Estendido**: Usar uma profundidade maior para jogadas críticas (ex.: finais de jogo). --- ### Inovações Únicas #### 1. Modo "Treinador IA" - **Sugestões Inteligentes**: A IA sugere jogadas ao jogador com explicações (ex.: "Mover o cavalo para F3 desenvolve a peça e controla o centro"). - **Análise Pós-Jogo**: Após a partida, a IA aponta erros e melhores alternativas. Exemplo: ```windev PROCEDURE SugerirJogada() sMelhor IS string = CalcularMelhorJogada(4) Info("Sugestão: " + sMelhor + " - Isso melhora seu controle do tabuleiro.") END ``` #### 2. Personalidade da IA - **Estilos de Jogo**: Criar "personagens" para a IA (ex.: "Kasparov" - agressivo, "Carlsen" - posicional) com estratégias distintas. - **Diálogos**: Adicionar frases que a IA fala durante o jogo (ex.: "Você caiu na minha armadilha!"). Exemplo: ```windev PROCEDURE FalarIA(sEstilo IS string) SWITCH sEstilo CASE "Agressivo" Info("Prepare-se para o ataque!") CASE "Defensivo" Info("Minha defesa é impenetrável.") END END ``` #### 3. IA Cooperativa - **Modo Equipe**: A IA joga ao lado do jogador contra outra IA, sugerindo jogadas ou assumindo controle parcial. --- ### Implementação Sugerida Para avançar: 1. Adicionar ordenação de movimentos no Alfa-Beta para otimização. 2. Implementar MCTS como alternativa ao Minimax. 3. Criar um modo treinador com sugestões e análise. Bons estudos -- Adriano José Boller ______________________________________________ Consultor e Representante Oficial da PcSoft no Brasil +55 (41) 99949 1800 adrianoboller@gmail.com skype: adrianobollerhttp://wxinformatica.com.br/