💻 Exemplos: Capítulo 19: Projeto Integrador I: Motor Completo de Jogo de Xadrez em Python POO Pura
Especialização em Sistemas com Python 3.12+ • Capítulo 19
🎯 Demonstração Prática: Mini Motor de Xadrez POO com Torre, Rei e Renderização Unicode
O exemplo abaixo implementa um núcleo funcional do motor de xadrez em Python orientado a objetos:
- Conversão bidirecional entre notação algébrica internacional (
a1ah8) e matriz $8 \times 8$. - Tabuleiro gerenciando posições e peças com encapsulamento estrito.
- Hierarquia polimórfica com classe abstrata
Peca, especializando aTorre(peça deslizante) e oRei(peça de passo). - Renderização visual no console utilizando símbolos Unicode autênticos (
♔,♚,♖,♜).
"""
demonstracao_motor_xadrez.py
Motor de Xadrez Orientado a Objetos Puro com Tabuleiro 8x8, Torre, Rei e Notação Algébrica.
Compatível com Python 3.12+.
"""
from __future__ import annotations
from abc import ABC, abstractmethod
from dataclasses import dataclass
from enum import Enum, auto
from typing import Final
# ==============================================================================
# 1. ENUMERAÇÕES E COORDENADAS
# ==============================================================================
class Cor(Enum):
BRANCA = auto()
PRETA = auto()
@dataclass(frozen=True, slots=True)
class Posicao:
linha: int
coluna: int
def __str__(self) -> str:
return f"[{self.linha}, {self.coluna}]"
@dataclass(frozen=True, slots=True)
class PosicaoXadrez:
coluna: str # 'a' a 'h'
linha: int # 1 a 8
def para_posicao_matriz(self) -> Posicao:
r = 8 - self.linha
c = ord(self.coluna.lower()) - ord('a')
return Posicao(r, c)
@classmethod
def de_posicao_matriz(cls, pos: Posicao) -> PosicaoXadrez:
col = chr(ord('a') + pos.coluna)
lin = 8 - pos.linha
return cls(coluna=col, linha=lin)
def __str__(self) -> str:
return f"{self.coluna}{self.linha}"
# ==============================================================================
# 2. HIERARQUIA DE PEÇAS POLIMÓRFICAS
# ==============================================================================
class Peca(ABC):
def __init__(self, tabuleiro: Tabuleiro, cor: Cor) -> None:
self.tabuleiro: Tabuleiro = tabuleiro
self.cor: Cor = cor
@abstractmethod
def simbolo(self) -> str:
...
@abstractmethod
def movimentos_possiveis(self, pos_atual: Posicao) -> list[Posicao]:
...
class Torre(Peca):
def simbolo(self) -> str:
return "♖" if self.cor == Cor.BRANCA else "♜"
def movimentos_possiveis(self, pos_atual: Posicao) -> list[Posicao]:
movs: list[Posicao] = []
# Direções retas ortogonais: Cima, Baixo, Esquerda, Direita
direcoes = [(-1, 0), (1, 0), (0, -1), (0, 1)]
for dr, dc in direcoes:
r, c = pos_atual.linha + dr, pos_atual.coluna + dc
while 0 <= r < 8 and 0 <= c < 8:
destino = Posicao(r, c)
peca_alvo = self.tabuleiro.obter_peca(destino)
if peca_alvo is None:
movs.append(destino)
elif peca_alvo.cor != self.cor:
movs.append(destino) # Captura permitida
break
else:
break # Bloqueada por peça amiga
r += dr
c += dc
return movs
class Rei(Peca):
def simbolo(self) -> str:
return "♔" if self.cor == Cor.BRANCA else "♚"
def movimentos_possiveis(self, pos_atual: Posicao) -> list[Posicao]:
movs: list[Posicao] = []
# Vizinhança direta de 8 casas
deltas = [(-1,-1), (-1,0), (-1,1), (0,-1), (0,1), (1,-1), (1,0), (1,1)]
for dr, dc in deltas:
r, c = pos_atual.linha + dr, pos_atual.coluna + dc
if 0 <= r < 8 and 0 <= c < 8:
destino = Posicao(r, c)
alvo = self.tabuleiro.obter_peca(destino)
if alvo is None or alvo.cor != self.cor:
movs.append(destino)
return movs
# ==============================================================================
# 3. TABULEIRO 8x8 E ORQUESTRADOR
# ==============================================================================
class Tabuleiro:
def __init__(self) -> None:
# Matriz 8x8 contendo ponteiros para Peca ou None
self._grade: list[list[Peca | None]] = [[None for _ in range(8)] for _ in range(8)]
def obter_peca(self, pos: Posicao) -> Peca | None:
return self._grade[pos.linha][pos.coluna]
def posicionar_peca(self, peca: Peca, pos: Posicao) -> None:
self._grade[pos.linha][pos.coluna] = peca
def remover_peca(self, pos: Posicao) -> Peca | None:
peca = self.obter_peca(pos)
self._grade[pos.linha][pos.coluna] = None
return peca
def exibir(self) -> None:
print("\n a b c d e f g h")
print(" +-----------------+")
for r in range(8):
num_linha = 8 - r
linha_str = [f"{num_linha} |"]
for c in range(8):
peca = self._grade[r][c]
linha_str.append(peca.simbolo() if peca else "·")
linha_str.append(f"| {num_linha}")
print(" ".join(linha_str))
print(" +-----------------+")
print(" a b c d e f g h\n")
# ==============================================================================
# 4. EXECUÇÃO DEMONSTRATIVA
# ==============================================================================
if __name__ == "__main__":
print("=" * 80)
print(" MOTOR DE XADREZ POO EM PYTHON 3.12+ (UNICODE ENGINE)")
print("=" * 80)
tabuleiro = Tabuleiro()
# Montagem de um cenário tático de demonstração
pos_rei_branco = PosicaoXadrez("e", 1).para_posicao_matriz()
pos_torre_branca = PosicaoXadrez("a", 1).para_posicao_matriz()
pos_rei_preto = PosicaoXadrez("e", 8).para_posicao_matriz()
pos_torre_preta = PosicaoXadrez("h", 8).para_posicao_matriz()
rei_b = Rei(tabuleiro, Cor.BRANCA)
torre_b = Torre(tabuleiro, Cor.BRANCA)
rei_p = Rei(tabuleiro, Cor.PRETA)
torre_p = Torre(tabuleiro, Cor.PRETA)
tabuleiro.posicionar_peca(rei_b, pos_rei_branco)
tabuleiro.posicionar_peca(torre_b, pos_torre_branca)
tabuleiro.posicionar_peca(rei_p, pos_rei_preto)
tabuleiro.posicionar_peca(torre_p, pos_torre_preta)
print(">> Estado Inicial do Tabuleiro:")
tabuleiro.exibir()
# Cálculo dos movimentos possíveis da Torre Branca em 'a1'
movimentos_torre = torre_b.movimentos_possiveis(pos_torre_branca)
movimentos_algebricos = [str(PosicaoXadrez.de_posicao_matriz(m)) for m in movimentos_torre]
print(f"Torre Branca em 'a1': {len(movimentos_algebricos)} movimentos legais disponíveis:")
print(f"Casas alcançáveis: {', '.join(sorted(movimentos_algebricos))}")
print("-" * 80)
# Executa movimento da Torre Branca de 'a1' para 'a5'
pos_destino_a5 = PosicaoXadrez("a", 5).para_posicao_matriz()
print(">> Executando jogada da Torre Branca: a1 -> a5")
tabuleiro.remover_peca(pos_torre_branca)
tabuleiro.posicionar_peca(torre_b, pos_destino_a5)
tabuleiro.exibir()
print("=" * 80)