Spaces:
Sleeping
Sleeping
File size: 8,460 Bytes
ee85eae 4dda931 cf0ed35 ae42fd3 cf0ed35 ae334a5 cb73a54 4dda931 cb73a54 4dda931 cf0ed35 cb73a54 87470f0 cb73a54 cf0ed35 fd81920 cb73a54 cf0ed35 269695f cf0ed35 cb73a54 cf0ed35 269695f e34aa4b cb73a54 cf0ed35 80518b7 cb73a54 cf0ed35 cb73a54 2542f52 cf0ed35 cb73a54 cf0ed35 cb73a54 cf0ed35 cb73a54 cf0ed35 cb73a54 cf0ed35 cb73a54 cf0ed35 cb73a54 cf0ed35 cb73a54 cf0ed35 cb73a54 cf0ed35 cb73a54 cf0ed35 cb73a54 cf0ed35 cb73a54 cf0ed35 cb73a54 cf0ed35 cb73a54 cf0ed35 cb73a54 cf0ed35 ae42fd3 cf0ed35 8c77c9b cf0ed35 2542f52 cb73a54 cf0ed35 cb73a54 cf0ed35 cb73a54 cf0ed35 cb73a54 cf0ed35 cb73a54 cf0ed35 cb73a54 cf0ed35 cb73a54 cf0ed35 cb73a54 0ded54a fd81920 cf0ed35 0ded54a cb73a54 f6680cb cb73a54 0ded54a cb73a54 2542f52 cf0ed35 2542f52 cf0ed35 cb73a54 2542f52 0ded54a cf0ed35 0ded54a cb73a54 2542f52 cf0ed35 d862602 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 |
import streamlit as st
import chess
import chess.svg
import os
import git
import sys
import random
# Configuration de la page
st.set_page_config(page_title="Échecs contre IA", layout="wide")
def render_svg(svg_string):
"""Render un SVG dans Streamlit."""
from streamlit.components.v1 import html
html(f"""
<div style="display: flex; justify-content: center;">
{svg_string}
</div>
""", height=400)
def calculate_max_length(move_count):
"""
Calcule le max_length optimal basé sur le nombre de coups joués
- Début de partie: besoin minimum (15 tokens)
- Milieu de partie: augmentation progressive
- Fin de partie: plafonnement à 50 tokens
"""
base_length = 15 # Longueur minimum pour un coup simple
increment = 1 # Augmentation par coup
max_length = 100 # Plafond maximum
dynamic_length = base_length + (move_count * increment)
return min(dynamic_length, max_length)
# Setup du modèle
@st.cache_resource
def setup_inference():
if not os.path.exists('chess_char'):
git.Repo.clone_from('https://github.com/l-pommeret/chess_char.git', 'chess_char')
if 'chess_char' not in sys.path:
sys.path.append('chess_char')
from inference import InferenceConfig, ChessGenerator
# Configuration initiale avec max_length minimal
config = InferenceConfig(
model_name="Zual/chess_char",
temperature=0.1,
max_length=6 # Sera ajusté dynamiquement pendant la partie
)
return ChessGenerator(config)
# Initialisation
try:
generator = setup_inference()
except Exception as e:
st.error("Erreur lors de l'initialisation.")
st.stop()
# Initialisation de l'état
if 'board' not in st.session_state:
st.session_state.board = chess.Board()
st.session_state.moves = []
st.session_state.last_move = None
def get_ai_move(prompt):
"""Obtient le coup de l'IA avec max_length dynamique"""
print(f"\n=== Tour de l'IA ===")
moves_count = len(st.session_state.moves)
# Mise à jour du max_length en fonction du nombre de coups
dynamic_max_length = calculate_max_length(moves_count)
generator.config.max_length = dynamic_max_length
print(f"max_length actuel: {dynamic_max_length} pour {moves_count} coups joués")
print(f"État actuel de la partie: {prompt}")
print(f"FEN actuel: {st.session_state.board.fen()}")
print(f"Coups légaux: {[st.session_state.board.san(move) for move in st.session_state.board.legal_moves]}")
try:
# On ne génère que jusqu'au prochain coup
if not prompt: # Premier coup
response = generator.generate("1.")
else:
# On prend les derniers coups pour ne pas surcharger le contexte
moves = prompt.split()
last_moves = " ".join(moves[-4:]) # Garder seulement les 2 derniers coups complets
if len(moves) % 2 == 0: # Si on vient de finir un coup noir
next_move_num = f"{(len(moves)//2 + 1)}."
response = generator.generate(f"{last_moves} {next_move_num}")
else: # Si on vient de finir un coup blanc
response = generator.generate(f"{last_moves}")
print(f"Réponse brute de l'IA: {response}")
# Gestion de la réponse quelle que soit sa forme
moves = response[0].split() if isinstance(response, list) else response.split()
print(f"Coups extraits: {moves}")
# On prend toujours le dernier coup généré
next_move = moves[-1]
if '.' in next_move and len(moves) > 1:
next_move = moves[-2]
print(f"Coup candidat de l'IA: {next_move}")
# Vérification de la validité
try:
move = st.session_state.board.parse_san(next_move)
print(f"Coup parsé en UCI: {move}")
if move in st.session_state.board.legal_moves:
print(f"Coup valide trouvé: {next_move}")
return next_move
else:
print(f"Coup non légal: {next_move}")
except ValueError as e:
print(f"Erreur de parsing: {e}")
# En cas d'échec, jouer un coup légal aléatoire
legal_moves = list(st.session_state.board.legal_moves)
if legal_moves:
random_move = random.choice(legal_moves)
random_san = st.session_state.board.san(random_move)
print(f"Utilisation d'un coup aléatoire: {random_san}")
return random_san
except Exception as e:
print(f"Erreur dans get_ai_move: {e}")
return None
def try_move(move_str):
"""Applique un coup au plateau"""
print(f"\n=== Tentative de coup: {move_str} ===")
print(f"État avant le coup: {get_game_string()}")
print(f"FEN avant: {st.session_state.board.fen()}")
try:
# Nettoyer le coup (enlever le numéro si présent)
clean_move = move_str.split('.')[-1].strip()
print(f"Coup nettoyé: {clean_move}")
move = st.session_state.board.parse_san(clean_move)
print(f"Coup parsé en UCI: {move}")
if move in st.session_state.board.legal_moves:
st.session_state.board.push(move)
st.session_state.moves.append(clean_move)
st.session_state.last_move = clean_move
print(f"Coup appliqué avec succès")
print(f"Nouvel état: {get_game_string()}")
print(f"Nouveau FEN: {st.session_state.board.fen()}")
return True
print(f"Coup illégal")
return False
except ValueError as e:
print(f"Erreur de parsing: {e}")
return False
def get_game_string():
"""Renvoie la notation de la partie"""
result = []
for i in range(0, len(st.session_state.moves), 2):
move_num = i//2 + 1
result.append(f"{move_num}.{st.session_state.moves[i]}")
if i+1 < len(st.session_state.moves):
result.append(st.session_state.moves[i+1])
return " ".join(result)
# Interface utilisateur
st.title("♟️ Échecs contre IA")
col1, col2 = st.columns([2, 1])
with col1:
# Plateau avec la nouvelle méthode d'affichage
board_svg = chess.svg.board(
board=st.session_state.board,
lastmove=st.session_state.board.peek() if st.session_state.board.move_stack else None,
size=400 # Taille fixe pour l'échiquier
)
render_svg(board_svg)
# Input du joueur avec key dynamique
move = st.text_input(
"Votre coup",
key=f"move_input_{len(st.session_state.moves)}",
placeholder="ex: e4, Nf3, O-O"
)
with col2:
# État actuel
print(f"\n=== État actuel ===")
print(f"Partie en cours: {get_game_string()}")
print(f"FEN: {st.session_state.board.fen()}")
# Affichage du max_length actuel
current_max_length = calculate_max_length(len(st.session_state.moves))
st.info(f"Longueur de génération actuelle: {current_max_length} tokens")
# Historique
st.subheader("Partie en cours")
game_str = get_game_string()
if game_str:
st.text_area("Historique", value=game_str, height=100, label_visibility="collapsed")
# Instructions
st.markdown("""
**Comment jouer:**
- Pion: e4, d5
- Cavalier: Nf3, Nc6
- Fou: Bc4, Be7
- Tour: Ra1, Rd8
- Dame: Qd1, Qh4
- Roi: Ke2, Kg8
- Roque: O-O ou O-O-O
""")
# Nouvelle partie
if st.button("Nouvelle partie"):
st.session_state.board = chess.Board()
st.session_state.moves = []
st.session_state.last_move = None
st.rerun()
# Logique du jeu
if move:
if try_move(move):
game_str = get_game_string()
# Tour de l'IA
with st.spinner("L'IA réfléchit..."):
ai_move = get_ai_move(game_str)
if ai_move and try_move(ai_move):
if st.session_state.board.is_checkmate():
st.success("Échec et mat!")
elif st.session_state.board.is_game_over():
st.info("Partie terminée!")
else:
st.error("Problème avec le coup de l'IA")
st.rerun()
else:
st.error("Coup invalide")
# État du jeu
if st.session_state.board.is_check():
st.warning("⚠️ Échec et mat !") |