PythonExtra est un add-in Python alternatif pour (à ce stade) Graph 35+E II, Prizm et Graph 90+E. L'objectif est de fournir plus de fonctionnalités : modules standard, getkey(), fonctions de dessin plus performantes, etc.
Compile pour Graph 90+E (fx-CG 10/20/50) et Graph 35+E II (fx-9860G III)
Peu de RAM sur Graph 35+E II (c'est difficile d'en trouver sur ce modèle)
Un shell pas trop mal (saisie rapide, scrolling) avec de bonnes performances
Plein de modules standard
array, builtins, cmath, collections, io, math, random, struct, sys, time
Le module spécifique CASIO : casioplot (fidèle à part sur les polices)
Un nouveau module gint avec les fonctionnalités avancées de gint :
Pour l'instant, une bonne partie de <gint/display.h> et <gint/keyboard.h>
Donc getkey() (attente de touche) ainsi que keydown() (test instantané) !
Et des fonctions de dessin rapides comme dline() ou drect()
Le plan actuel :
Être sensiblement compatible avec l'appli Python officielle.
Pousser les fonctionnalités ajoutées pour vraiment relever le niveau de Python !
Si du temps de développement se débloque : support autres Graph mono (pas de promesses).
Updates et screenshots à venir. Je n'ai pas l'intention d'implémenter un million de fonctionnalités, juste ce qu'il faut pour s'assurer que ça ne finisse pas mal documenté et non maintenu comme CasioPython.
Dans l'exemple ci-dessous (réalisé par Mb88), un Flappy Bird déjà bien optimisé (dessin partiel etc, à gauche) est accéléré un bon gros coup en utilisant PythonExtra et le module gint pour le dessin (à droite).
Contexte historique
Aux journées APMEP 2022, redgl0w racontait comment le port MicroPython pour Numworks n'était finalement pas super difficile. Moi je parlais de comment un port maison résoudrait le problème de getkey(), et Critor m'a convaincu d'essayer sur-le-champ.
En fin de compte, j'ai clôné MicroPython Dimanche à midi et à 1 heure du matin j'avais un port fonctionnel avec getkey() sur ma Graph 90+E (que j'ai d'ailleurs montré à CASIO Lundi, pour la démo). Comme quoi, des fois ça marche tout seul !
(Enfin, le début marche tout seul. Faire une bonne UI et gérer tous les détails ensuite c'est une autre paire de manches !)
Ce n'est pas un probleme de version de micropython. PE embarque la version 1.25 donc pas de soucis.
Par contre on sait que l'on ne peut pas faire tourner des programmes trop gourmands en mémoire sur la G35+EII car on a très peu de RAM disponible à allouer. Et là il n'y a pas de miracle possible.
There are only 10 types of people in the world: Those who understand binary, and those who don't ...
je pense pour ma part que CASIO utillise la mémoire de stockage et pas la RAM ce quidonne plus de puissance à leur application (le fichier EACTWORK.tmp)
Non EACTWORK n'a absolument rien à voir avec cette affaire. CASIO utilise bien un tas plus gros, dans lequel on peut tenter de piocher, mais ça nous expose à des dépendances de version d'OS donc ce n'est pas encore codé.
Comment se fait-il que mon programme (et ces dépendances) fonctionnent sur l'appli Casio et pas sur PythonExtra
Comment allez-vous y prendre pour piocher dans le tas plus gros de CASIO
va t-il être facile sachant qui il ya eu une MàJ de l'OS il y pas longtemps
Graph 90+E 3.81 Correction d’un bug mineur 29/10/2025
et
Graph 35+E II 3.71 Correction d’un bug mineur 29/10/2025
C'est c programme (uno_main) et ese dépendances qui fonctionnent uniquement sur l'appli CASIO officiel sur ma graph 35 + E II
ia_learning.py
masquer
import urandom1 as r
# --- Paramètres du Q-Learning ---
ALPHA = 0.1 # Taux d'apprentissage (Learning Rate)
GAMMA = 0.9 # Facteur de rabais (Discount Factor)
EPSILON = 0.01 # Taux d'exploration (Exploration Rate)
# La Q-Table est stockee en memoire, elle est perdue a la fin de l'execution
Q_TABLE = {}
ACTIONS = ['JOUER', 'PIOCHER']
def obtenir_etat(main, carte_defausse, game_type):
if game_type == 2:
return generer_etat_dos(main, carte_defausse)
elif game_type == 3:
return generer_etat_no_mercy(main, carte_defausse, game_type)
elif game_type == 4:
return generer_etat_zero(main, carte_defausse)
elif game_type == 5:
return generer_etat_extreme(main, carte_defausse)
else:
return generer_etat_uno(main, carte_defausse, game_type)
def generer_etat_uno(main, carte_defausse, game_type):
taille_main = len(main)
couleur_defausse = carte_defausse[0]
valeur_defausse = carte_defausse[1]
# Simplification de la valeur de la carte de defausse pour reduire l'espace d'etat
if valeur_defausse.isdigit():
valeur_simplifiee = 'DIGIT'
elif valeur_defausse in ['+2', 'I', 'PTT']:
valeur_simplifiee = valeur_defausse
elif valeur_defausse in ['W', '+4']:
valeur_simplifiee = 'WILD'
else:
valeur_simplifiee = 'AUTRE'
# Le mode NoMerci est traite comme un mode UNO simple par defaut
mode_jeu='CLASSIC'
return (mode_jeu, taille_main, couleur_defausse, valeur_simplifiee)
def generer_etat_zero(main, carte_defausse):
etat = generer_etat_uno(main, carte_defausse, 4)
return ('ZERO', etat[1], etat[2], etat[3])
def generer_etat_extreme(main, carte_defausse):
etat = generer_etat_uno(main, carte_defausse, 5)
return ('EXTREME', etat[1], etat[2], etat[3])
def generer_etat_dos(main, defausse_piles):
taille_main = len(main)
carte_p1 = defausse_piles[0][-1]
carte_p2 = defausse_piles[1][-1]
couleur_p1 = carte_p1[0]
valeur_p1 = carte_p1[1]
couleur_p2 = carte_p2[0]
valeur_p2 = carte_p2[1]
# Simplification de la valeur de la carte de defausse (seulement chiffre ou W)
val_p1_simplifiee = 'DIGIT' if valeur_p1.isdigit() else valeur_p1
val_p2_simplifiee = 'DIGIT' if valeur_p2.isdigit() else valeur_p2
return ('DOS', taille_main, couleur_p1, val_p1_simplifiee, couleur_p2, val_p2_simplifiee)
def initialiser_q_valeur(etat, action):
if etat not in Q_TABLE:
Q_TABLE[etat] = {}
if action not in Q_TABLE[etat]:
Q_TABLE[etat][action] = 0.0
def choisir_action_apprentissage(etat, actions_legales, main):
if r.random() < EPSILON:
# Exploration: choisir une action aleatoire
if actions_legales:
return r.choice(actions_legales)
else:
return ('PIOCHER',)
else:
# Exploitation: choisir la meilleure action (la plus haute Q-valeur)
meilleure_action = None
meilleure_q_valeur = -float('inf')
# 1. Tester l'action PIOCHER
initialiser_q_valeur(etat, ('PIOCHER',))
q_piocher = Q_TABLE[etat][('PIOCHER',)]
meilleure_action = ('PIOCHER',)
meilleure_q_valeur = q_piocher
# 2. Tester toutes les actions JOUER legales
for action in actions_legales:
# L'action est un tuple (couleur, valeur, couleur_choisie) ou (couleur, valeur, pile_cible)
# Normalisons l'action pour la Q-table (ex: ('R', '1') ou ('N', '+4', 'B'))
# Action normalisee: tuple contenant (couleur, valeur) + un eventuel choix (couleur ou pile)
action_cle = action
initialiser_q_valeur(etat, action_cle)
q_jouer = Q_TABLE[etat][action_cle]
if q_jouer > meilleure_q_valeur:
meilleure_q_valeur = q_jouer
meilleure_action = action_cle
return meilleure_action
def mettre_a_jour_q_table(etat_precedent, action_precedente, recompense, nouvel_etat, actions_legales_nouvel_etat):
initialiser_q_valeur(etat_precedent, action_precedente)
# 1. Calculer la Q-valeur maximale pour le nouvel etat
max_q_nouvel_etat = 0
# 1.1 Inclure l'action PIOCHER dans les Q-valeurs maximales potentielles
initialiser_q_valeur(nouvel_etat, ('PIOCHER',))
max_q_nouvel_etat = Q_TABLE[nouvel_etat][('PIOCHER',)]
# 1.2 Verifier toutes les actions de JOUER
for action in actions_legales_nouvel_etat:
action_cle = action
initialiser_q_valeur(nouvel_etat, action_cle)
q_val = Q_TABLE[nouvel_etat][action_cle]
if q_val > max_q_nouvel_etat:
max_q_nouvel_etat = q_val
# 2. Appliquer la formule de Bellman (Q-Learning)
ancienne_q=Q_TABLE[etat_precedent][action_precedente]
nouvelle_q=(1-ALPHA) * ancienne_q+ALPHA*(recompense+GAMMA*max_q_nouvel_etat)
Q_TABLE[etat_precedent][action_precedente]=nouvelle_q
def charger_q_table():
global Q_TABLE
# Pas de persistance, on retourne la table actuelle
return Q_TABLE
def sauvegarder_q_table(q_table):
# Pas de persistance.
pass
def obtenir_recompense(taille_main_apres, taille_main_avant):
if taille_main_apres < taille_main_avant:
return 1
elif taille_main_apres > taille_main_avant:
return -10
else:
# A du piocher mais n'a pas pu jouer, ou a joue une carte "inutile"
return -5
uno_classique.py
masquer
import urandom1 as r
import trys as t
from uno_rules import Colors, Val_spe, Val_digits, W_cards, W_count, Nbr_cards_init, piocher_carte_aleatoire, appliquer_penalite, recycler_defausse, calculer_score
from ia_learning import charger_q_table, sauvegarder_q_table, generer_etat_uno, choisir_action_apprentissage, obtenir_recompense, mettre_a_jour_q_table
# Charger la Q-Table au debut du script
Q_TABLE = charger_q_table()
HISTORIQUE_IA = []
def creer_paquet_classique():
paquet = []
# Cartes chiffrees (0-9)
for couleur in Colors:
# Un seul '0' par couleur
paquet.append(('0',couleur,"0"))
# Deux de chaque chiffre (1-9)
for valeur in Val_digits[1:]:
paquet.append((valeur,couleur,"0"))
paquet.append((valeur,couleur,"1"))
# Cartes d'action (+2, I, PTT)
for couleur in Colors:
for valeur in Val_spe:
paquet.append((valeur,valeur,"0"))
paquet.append((valeur,couleur,"1"))
# Cartes sauvages (W, +4)
for valeur in W_cards:
for _ in range(W_count): # 4 cartes de chaque type (W, +4)
paquet.append((valeur,"","0"))
return r.shuffle(paquet)
def verifier_validite_uno_classique(carte_jouee, carte_defausse_tuple, couleur_actuelle):
couleur_jouee, valeur_jouee = carte_jouee
# Les cartes Joker ('N') sont toujours valides
if couleur_jouee == 'N':
return True
# La carte doit correspondre a la couleur actuelle ou a la valeur de la carte du dessus
return (couleur_jouee == couleur_actuelle or
valeur_jouee == carte_defausse_tuple[1])
def choisir_couleur_ia_classique(main_ia):
comptage_couleurs = {'R': 0, 'V': 0, 'B': 0, 'J': 0}
for couleur, _ in main_ia:
if couleur in comptage_couleurs:
comptage_couleurs[couleur] += 1
# Trouver la couleur avec le compte maximal
couleur_choisie = 'R' # Couleur par defaut
max_count = -1
for couleur, count in comptage_couleurs.items():
if count > max_count:
max_count = count
couleur_choisie = couleur
# Si egalite, on choisit aleatoirement parmi les meilleures options
best_colors = [c for c, count in comptage_couleurs.items() if count == max_count]
# Utilise 'random.choice' de l'import 'random'
return random.choice(best_colors)
def jouer_tour_ia_classique(main_ia, carte_defausse_tuple, couleur_actuelle, nbr_manches_jouees):
global Q_TABLE, HISTORIQUE_IA
# 1. Generer la liste des actions possibles
actions_possibles = []
# Cartes jouables (y compris les Jokers)
cartes_jouables = [
carte for carte in main_ia
if verifier_validite_uno_classique(carte, carte_defausse_tuple, couleur_actuelle)
]
# Creer la liste des actions pour la Q-Table: (carte, couleur_choisie)
for carte in cartes_jouables:
couleur, valeur = carte
if couleur == 'N': # Joker ou +4
# L'action inclut le choix de la couleur
for c in Colors:
actions_possibles.append((carte, c))
else:
# L'action n'inclut que la carte jouee (la couleur est celle de la carte)
actions_possibles.append((carte, couleur))
# Ajouter l'action de pioche
actions_possibles.append(VALEUR_PIOCHE)
# 2. Generer l'etat actuel
etat_actuel = generer_etat_uno_classique(main_ia, carte_defausse_tuple, couleur_actuelle)
# 3. Choisir l'action (Exploration ou Exploitation)
action_choisie_tuple = choisir_action_apprentissage(Q_TABLE, etat_actuel, actions_possibles, nbr_manches_jouees)
# 4. Enregistrer l'etat et l'action pour la mise a jour future
if action_choisie_tuple:
HISTORIQUE_IA.append({
'etat_precedent': etat_actuel,
'action_precedente': action_choisie_tuple,
'nbr_cartes_avant': len(main_ia)
})
# L'action est soit (carte, couleur_choisie) ou ('P', None)
if action_choisie_tuple[0] == 'P':
return (None, None, 'Piocher') # Pas de carte jouee, pas de couleur choisie
else:
carte_jouee, couleur_choisie = action_choisie_tuple
return (carte_jouee, couleur_choisie, 'Jouer')
def jouer_une_manche_classique(joueur_a_commencer, nbr_manches_jouees):
global Q_TABLE, HISTORIQUE_IA
paquet = creer_paquet_classique()
main_joueur_1 = piocher_carte_aleatoire(paquet, Nbr_cards_init)
main_joueur_2 = piocher_carte_aleatoire(paquet, Nbr_cards_init)
defausse_pile = []
# Tirer la premiere carte de defausse
while True:
carte_initiale = piocher_carte_aleatoire(paquet, 1)[0]
# La carte initiale ne peut pas etre une carte speciale (pour simplification)
if carte_initiale[0] != 'N' and carte_initiale[1] not in Val_spe:
defausse_pile.append(carte_initiale)
break
else:
# Remettre la carte dans le paquet (pas de melange)
paquet.append(carte_initiale)
# Etat initial du jeu
etat_tour = {
'sens_horaire': True,
'couleur_actuelle': defausse_pile[-1][0], # Couleur de la premiere carte
'sauter_tour_suivant': False,
'total_cartes_a_piocher': 0
}
joueur_courant = joueur_a_commencer
manche_terminee = False
gagnant = None
HISTORIQUE_IA = [] # Reinitialiser l'historique de l'IA pour la nouvelle manche
print("Premiere carte: %s de couleur %s" % (defausse_pile[-1][1], etat_tour['couleur_actuelle']))
while not manche_terminee:
carte_jouee = None
action_valide = False
couleur_choisie_par_joker = None
# 1. Gerer les cartes a piocher (+2 ou +4 empiles)
if etat_tour['total_cartes_a_piocher'] > 0:
penalite = etat_tour['total_cartes_a_piocher']
print("Penalite de %d cartes a appliquer." % penalite)
if joueur_courant == 1:
appliquer_penalite(main_joueur_1, paquet, defausse_pile[-1], penalite)
else: # IA
appliquer_penalite(main_joueur_2, paquet, defausse_pile[-1], penalite)
# Reinitialiser la penalite apres application
etat_tour['total_cartes_a_piocher'] = 0
# Passer au joueur suivant
joueur_courant = 3 - joueur_courant
continue # Fin du tour actuel, passage au suivant
# 2. Gestion du tour saute (PTT)
if etat_tour['sauter_tour_suivant']:
print("Tour saute pour le Joueur %d." % joueur_courant)
etat_tour['sauter_tour_suivant'] = False
joueur_courant = 3 - joueur_courant
continue # Fin du tour actuel, passage au suivant
# 3. Tour du Joueur 1
if joueur_courant==1:
while not action_valide:
k=d.pagination_cartes(defausse_pile[-1],main_joueur_1)
if k=='P':
# Action Piocher
cartes_piochees = piocher_carte_aleatoire(paquet, 1)
main_joueur_1.extend(cartes_piochees)
print("Vous piochez : %s" % str(cartes_piochees[0]))
# Offrir de jouer la carte piochee si elle est valide
carte_piochee = cartes_piochees[0]
if verifier_validite_uno_classique(carte_piochee, defausse_pile[-1], etat_tour['couleur_actuelle']):
# Retrait des accents dans l'invite
jouer_pioche =input("Voulez-vous jouer la carte piochee %s (O/N) ? " % str(carte_piochee)).upper()
if jouer_pioche == 'O':
carte_jouee = carte_piochee
main_joueur_1.remove(carte_jouee)
action_valide = True
if carte_jouee[0] == 'N': # Choix de couleur pour Joker/+4
print("Choisissez une couleur (R, V, B, J):")
couleur_choisie_par_joker = t.trys(input("Couleur: ").upper(), 1, 1, options=Colors)
action_valide = True # Termine le tour (soit en jouant, soit sans jouer)
else:
index_carte =k-1
carte_tentative = main_joueur_1[index_carte]
if verifier_validite_uno_classique(carte_tentative, defausse_pile[-1], etat_tour['couleur_actuelle']):
carte_jouee = carte_tentative
main_joueur_1.pop(index_carte)
action_valide = True
if carte_jouee[0] == 'N': # Choix de couleur pour Joker/+4
print("Choisissez une couleur (R, V, B, J):")
couleur_choisie_par_joker = t.trys(input("Couleur: ").upper(), 1, 1, options=Colors)
else:
# Retrait des accents
print("Carte invalide. ")
if action_valide and carte_jouee:
print("Vous jouez :%s." % str(carte_jouee))
# 4. Tour de l'IA (2)
else: # joueur_courant == 2
print("\n---------------------\nTour de l'IA (Joueur 2) - Cartes: %d" % len(main_joueur_2))
print("Defausse: %s " % (defausse_pile[-1]))
# Obtenir l'action de l'IA (carte_jouee, couleur_choisie, type_action)
action_result=jouer_tour_ia_classique(main_joueur_2, defausse_pile[-1], etat_tour['couleur_actuelle'], nbr_manches_jouees)
carte_jouee, couleur_choisie_par_joker, type_action = action_result
if type_action == 'Piocher':
# Action Piocher
cartes_piochees = piocher_carte_aleatoire(paquet, 1)
main_joueur_2.extend(cartes_piochees)
print("L'IA pioche 1 carte.")
# L'IA ne joue pas la carte piochee dans cette implementation simple
action_valide = True
elif type_action == 'Jouer':
# Action Jouer
if carte_jouee and carte_jouee in main_joueur_2:
main_joueur_2.remove(carte_jouee)
print("L'IA joue %s." % str(carte_jouee))
if carte_jouee[0] == 'N':
# Utiliser la strategie pour choisir la couleur si l'action choisie l'autorise
if couleur_choisie_par_joker is None:
# Si le choix de l'action Q-Learning n'a pas inclus de couleur (car c'est un Joker),
# l'IA applique sa strategie ici.
couleur_choisie_par_joker = choisir_couleur_ia_classique(main_joueur_2)
print("L'IA choisit la couleur %s" % couleur_choisie_par_joker)
action_valide = True
else:
# Retrait des accents
print("Erreur: L'IA a choisi une action invalide ou une carte non posee. Piocher par defaut.")
cartes_piochees = piocher_carte_aleatoire(paquet, 1)
main_joueur_2.extend(cartes_piochees)
action_valide = True # Le tour se termine par une pioche
# 5. Application des effets de la carte jouee
if carte_jouee and action_valide:
couleur_carte_jouee, valeur_carte_jouee = carte_jouee
defausse_pile.append(carte_jouee)
# Mise a jour de la couleur actuelle (couleur de la carte jouee ou couleur choisie par Joker)
if couleur_choisie_par_joker:
etat_tour['couleur_actuelle'] = couleur_choisie_par_joker
else:
etat_tour['couleur_actuelle'] = couleur_carte_jouee
# Effets de carte
if valeur_carte_jouee == '+2':
etat_tour['total_cartes_a_piocher'] += 2
etat_tour['sauter_tour_suivant'] = True
elif valeur_carte_jouee == 'I': # Inversion
etat_tour['sens_horaire'] = not etat_tour['sens_horaire']
elif valeur_carte_jouee == 'PTT': # Passe Ton Tour
etat_tour['sauter_tour_suivant'] = True
elif valeur_carte_jouee == '+4':
etat_tour['total_cartes_a_piocher'] += 4
etat_tour['sauter_tour_suivant'] = True
# Verification de fin de manche (main vide)
if joueur_courant == 1 and not main_joueur_1:
gagnant = 1
manche_terminee = True
elif joueur_courant == 2 and not main_joueur_2:
gagnant = 2
manche_terminee = True
# 6. Gestion du paquet vide
if not paquet:
# Note: recycler_defausse ne melange plus le paquet
recycler_defausse(paquet, defausse_pile)
# Retrait des accents
print("Paquet recycle.")
if not paquet:
# Retrait des accents
print("La defausse etait trop petite. Fin de manche par manque de cartes.")
manche_terminee = True
if len(main_joueur_1) < len(main_joueur_2):
gagnant = 1
else:
gagnant = 2
# 7. Mise a jour de la Q-Table de l'IA apres son tour
if joueur_courant == 2 and HISTORIQUE_IA and action_valide:
derniere_action_ia = HISTORIQUE_IA.pop()
# L'etat actuel de la partie pour l'IA est l'etat du joueur 1 a son tour
etat_actuel_ia = generer_etat_uno_classique(main_joueur_1, defausse_pile[-1], etat_tour['couleur_actuelle'])
if not manche_terminee and action_valide:
# Passage au joueur suivant (gestion de l'inversion par le 'sens_horaire')
if etat_tour['sens_horaire']:
joueur_courant = 3 - joueur_courant
else:
# Dans un jeu a 2 joueurs, Inversion ne change pas de joueur, on reste sur le meme
pass
# Fin de manche
if gagnant is None:
# Si la manche s'est terminee prematurement (paquet vide)
gagnant = 1 if len(main_joueur_1) < len(main_joueur_2) else 2
perdant = 3 - gagnant
if gagnant == 1:
points_marque_par_perdant = calculer_score(main_joueur_2, 'UNO')
else:
points_marque_par_perdant = calculer_score(main_joueur_1, 'UNO')
else:
perdant = 3 - gagnant
if gagnant == 1:
points_marque_par_perdant = calculer_score(main_joueur_2, 'UNO')
else:
points_marque_par_perdant = calculer_score(main_joueur_1, 'UNO')
# Sauvegarde de la Q-Table
sauvegarder_q_table(Q_TABLE)
print("\n=============================================")
# Retrait des accents et f-string
print("FIN DE MANCHE UNO CLASSIQUE ! Le Joueur %d a gagne." % gagnant)
print("Le Joueur %d marque %d points." % (perdant, points_marque_par_perdant))
print("Taille de la Q-Table : %d etats UNO_CL appris." % len([k for k in Q_TABLE.keys() if 'UNO_CL' in k]))
print("=============================================\n")
return gagnant, points_marque_par_perdant
uno_dos.py
masquer
import urandom1 as r
import trys as t
from uno_rules import Colors, Val_spe, Val_digits, W_cards, W_count, Nbr_cards_init, piocher_carte_aleatoire, appliquer_penalite, recycler_defausse, calculer_score
from ia_learning import charger_q_table, sauvegarder_q_table, generer_etat_uno, choisir_action_apprentissage, obtenir_recompense, mettre_a_jour_q_table
# Charger la Q-Table au debut du script
Q_TABLE = charger_q_table()
HISTORIQUE_IA = []
def creer_paquet_classique():
paquet = []
# Cartes chiffrees (0-9)
for couleur in Colors:
# Un seul '0' par couleur
paquet.append(('0',couleur,"0"))
# Deux de chaque chiffre (1-9)
for valeur in Val_digits[1:]:
paquet.append((valeur,couleur,"0"))
paquet.append((valeur,couleur,"1"))
# Cartes d'action (+2, I, PTT)
for couleur in Colors:
for valeur in Val_spe:
paquet.append((valeur,valeur,"0"))
paquet.append((valeur,couleur,"1"))
# Cartes sauvages (W, +4)
for valeur in W_cards:
for _ in range(W_count): # 4 cartes de chaque type (W, +4)
paquet.append((valeur,"","0"))
return r.shuffle(paquet)
def verifier_validite_uno_classique(carte_jouee, carte_defausse_tuple, couleur_actuelle):
couleur_jouee, valeur_jouee = carte_jouee
# Les cartes Joker ('N') sont toujours valides
if couleur_jouee == 'N':
return True
# La carte doit correspondre a la couleur actuelle ou a la valeur de la carte du dessus
return (couleur_jouee == couleur_actuelle or
valeur_jouee == carte_defausse_tuple[1])
def choisir_couleur_ia_classique(main_ia):
comptage_couleurs = {'R': 0, 'V': 0, 'B': 0, 'J': 0}
for couleur, _ in main_ia:
if couleur in comptage_couleurs:
comptage_couleurs[couleur] += 1
# Trouver la couleur avec le compte maximal
couleur_choisie = 'R' # Couleur par defaut
max_count = -1
for couleur, count in comptage_couleurs.items():
if count > max_count:
max_count = count
couleur_choisie = couleur
# Si egalite, on choisit aleatoirement parmi les meilleures options
best_colors = [c for c, count in comptage_couleurs.items() if count == max_count]
# Utilise 'random.choice' de l'import 'random'
return random.choice(best_colors)
def jouer_tour_ia_classique(main_ia, carte_defausse_tuple, couleur_actuelle, nbr_manches_jouees):
global Q_TABLE, HISTORIQUE_IA
# 1. Generer la liste des actions possibles
actions_possibles = []
# Cartes jouables (y compris les Jokers)
cartes_jouables = [
carte for carte in main_ia
if verifier_validite_uno_classique(carte, carte_defausse_tuple, couleur_actuelle)
]
# Creer la liste des actions pour la Q-Table: (carte, couleur_choisie)
for carte in cartes_jouables:
couleur, valeur = carte
if couleur == 'N': # Joker ou +4
# L'action inclut le choix de la couleur
for c in Colors:
actions_possibles.append((carte, c))
else:
# L'action n'inclut que la carte jouee (la couleur est celle de la carte)
actions_possibles.append((carte, couleur))
# Ajouter l'action de pioche
actions_possibles.append(VALEUR_PIOCHE)
# 2. Generer l'etat actuel
etat_actuel = generer_etat_uno_classique(main_ia, carte_defausse_tuple, couleur_actuelle)
# 3. Choisir l'action (Exploration ou Exploitation)
action_choisie_tuple = choisir_action_apprentissage(Q_TABLE, etat_actuel, actions_possibles, nbr_manches_jouees)
# 4. Enregistrer l'etat et l'action pour la mise a jour future
if action_choisie_tuple:
HISTORIQUE_IA.append({
'etat_precedent': etat_actuel,
'action_precedente': action_choisie_tuple,
'nbr_cartes_avant': len(main_ia)
})
# L'action est soit (carte, couleur_choisie) ou ('P', None)
if action_choisie_tuple[0] == 'P':
return (None, None, 'Piocher') # Pas de carte jouee, pas de couleur choisie
else:
carte_jouee, couleur_choisie = action_choisie_tuple
return (carte_jouee, couleur_choisie, 'Jouer')
def jouer_une_manche_classique(joueur_a_commencer, nbr_manches_jouees):
global Q_TABLE, HISTORIQUE_IA
paquet = creer_paquet_classique()
main_joueur_1 = piocher_carte_aleatoire(paquet, Nbr_cards_init)
main_joueur_2 = piocher_carte_aleatoire(paquet, Nbr_cards_init)
defausse_pile = []
# Tirer la premiere carte de defausse
while True:
carte_initiale = piocher_carte_aleatoire(paquet, 1)[0]
# La carte initiale ne peut pas etre une carte speciale (pour simplification)
if carte_initiale[0] != 'N' and carte_initiale[1] not in Val_spe:
defausse_pile.append(carte_initiale)
break
else:
# Remettre la carte dans le paquet (pas de melange)
paquet.append(carte_initiale)
# Etat initial du jeu
etat_tour = {
'sens_horaire': True,
'couleur_actuelle': defausse_pile[-1][0], # Couleur de la premiere carte
'sauter_tour_suivant': False,
'total_cartes_a_piocher': 0
}
joueur_courant = joueur_a_commencer
manche_terminee = False
gagnant = None
HISTORIQUE_IA = [] # Reinitialiser l'historique de l'IA pour la nouvelle manche
print("Premiere carte: %s de couleur %s" % (defausse_pile[-1][1], etat_tour['couleur_actuelle']))
while not manche_terminee:
carte_jouee = None
action_valide = False
couleur_choisie_par_joker = None
# 1. Gerer les cartes a piocher (+2 ou +4 empiles)
if etat_tour['total_cartes_a_piocher'] > 0:
penalite = etat_tour['total_cartes_a_piocher']
print("Penalite de %d cartes a appliquer." % penalite)
if joueur_courant == 1:
appliquer_penalite(main_joueur_1, paquet, defausse_pile[-1], penalite)
else: # IA
appliquer_penalite(main_joueur_2, paquet, defausse_pile[-1], penalite)
# Reinitialiser la penalite apres application
etat_tour['total_cartes_a_piocher'] = 0
# Passer au joueur suivant
joueur_courant = 3 - joueur_courant
continue # Fin du tour actuel, passage au suivant
# 2. Gestion du tour saute (PTT)
if etat_tour['sauter_tour_suivant']:
print("Tour saute pour le Joueur %d." % joueur_courant)
etat_tour['sauter_tour_suivant'] = False
joueur_courant = 3 - joueur_courant
continue # Fin du tour actuel, passage au suivant
# 3. Tour du Joueur 1
if joueur_courant==1:
while not action_valide:
k=d.pagination_cartes(defausse_pile[-1],main_joueur_1)
if k=='P':
# Action Piocher
cartes_piochees = piocher_carte_aleatoire(paquet, 1)
main_joueur_1.extend(cartes_piochees)
print("Vous piochez : %s" % str(cartes_piochees[0]))
# Offrir de jouer la carte piochee si elle est valide
carte_piochee = cartes_piochees[0]
if verifier_validite_uno_classique(carte_piochee, defausse_pile[-1], etat_tour['couleur_actuelle']):
# Retrait des accents dans l'invite
jouer_pioche =input("Voulez-vous jouer la carte piochee %s (O/N) ? " % str(carte_piochee)).upper()
if jouer_pioche == 'O':
carte_jouee = carte_piochee
main_joueur_1.remove(carte_jouee)
action_valide = True
if carte_jouee[0] == 'N': # Choix de couleur pour Joker/+4
print("Choisissez une couleur (R, V, B, J):")
couleur_choisie_par_joker = t.trys(input("Couleur: ").upper(), 1, 1, options=Colors)
action_valide = True # Termine le tour (soit en jouant, soit sans jouer)
else:
index_carte =k-1
carte_tentative = main_joueur_1[index_carte]
if verifier_validite_uno_classique(carte_tentative, defausse_pile[-1], etat_tour['couleur_actuelle']):
carte_jouee = carte_tentative
main_joueur_1.pop(index_carte)
action_valide = True
if carte_jouee[0] == 'N': # Choix de couleur pour Joker/+4
print("Choisissez une couleur (R, V, B, J):")
couleur_choisie_par_joker = t.trys(input("Couleur: ").upper(), 1, 1, options=Colors)
else:
# Retrait des accents
print("Carte invalide. ")
if action_valide and carte_jouee:
print("Vous jouez :%s." % str(carte_jouee))
# 4. Tour de l'IA (2)
else: # joueur_courant == 2
print("\n---------------------\nTour de l'IA (Joueur 2) - Cartes: %d" % len(main_joueur_2))
print("Defausse: %s " % (defausse_pile[-1]))
# Obtenir l'action de l'IA (carte_jouee, couleur_choisie, type_action)
action_result=jouer_tour_ia_classique(main_joueur_2, defausse_pile[-1], etat_tour['couleur_actuelle'], nbr_manches_jouees)
carte_jouee, couleur_choisie_par_joker, type_action = action_result
if type_action == 'Piocher':
# Action Piocher
cartes_piochees = piocher_carte_aleatoire(paquet, 1)
main_joueur_2.extend(cartes_piochees)
print("L'IA pioche 1 carte.")
# L'IA ne joue pas la carte piochee dans cette implementation simple
action_valide = True
elif type_action == 'Jouer':
# Action Jouer
if carte_jouee and carte_jouee in main_joueur_2:
main_joueur_2.remove(carte_jouee)
print("L'IA joue %s." % str(carte_jouee))
if carte_jouee[0] == 'N':
# Utiliser la strategie pour choisir la couleur si l'action choisie l'autorise
if couleur_choisie_par_joker is None:
# Si le choix de l'action Q-Learning n'a pas inclus de couleur (car c'est un Joker),
# l'IA applique sa strategie ici.
couleur_choisie_par_joker = choisir_couleur_ia_classique(main_joueur_2)
print("L'IA choisit la couleur %s" % couleur_choisie_par_joker)
action_valide = True
else:
# Retrait des accents
print("Erreur: L'IA a choisi une action invalide ou une carte non posee. Piocher par defaut.")
cartes_piochees = piocher_carte_aleatoire(paquet, 1)
main_joueur_2.extend(cartes_piochees)
action_valide = True # Le tour se termine par une pioche
# 5. Application des effets de la carte jouee
if carte_jouee and action_valide:
couleur_carte_jouee, valeur_carte_jouee = carte_jouee
defausse_pile.append(carte_jouee)
# Mise a jour de la couleur actuelle (couleur de la carte jouee ou couleur choisie par Joker)
if couleur_choisie_par_joker:
etat_tour['couleur_actuelle'] = couleur_choisie_par_joker
else:
etat_tour['couleur_actuelle'] = couleur_carte_jouee
# Effets de carte
if valeur_carte_jouee == '+2':
etat_tour['total_cartes_a_piocher'] += 2
etat_tour['sauter_tour_suivant'] = True
elif valeur_carte_jouee == 'I': # Inversion
etat_tour['sens_horaire'] = not etat_tour['sens_horaire']
elif valeur_carte_jouee == 'PTT': # Passe Ton Tour
etat_tour['sauter_tour_suivant'] = True
elif valeur_carte_jouee == '+4':
etat_tour['total_cartes_a_piocher'] += 4
etat_tour['sauter_tour_suivant'] = True
# Verification de fin de manche (main vide)
if joueur_courant == 1 and not main_joueur_1:
gagnant = 1
manche_terminee = True
elif joueur_courant == 2 and not main_joueur_2:
gagnant = 2
manche_terminee = True
# 6. Gestion du paquet vide
if not paquet:
# Note: recycler_defausse ne melange plus le paquet
recycler_defausse(paquet, defausse_pile)
# Retrait des accents
print("Paquet recycle.")
if not paquet:
# Retrait des accents
print("La defausse etait trop petite. Fin de manche par manque de cartes.")
manche_terminee = True
if len(main_joueur_1) < len(main_joueur_2):
gagnant = 1
else:
gagnant = 2
# 7. Mise a jour de la Q-Table de l'IA apres son tour
if joueur_courant == 2 and HISTORIQUE_IA and action_valide:
derniere_action_ia = HISTORIQUE_IA.pop()
# L'etat actuel de la partie pour l'IA est l'etat du joueur 1 a son tour
etat_actuel_ia = generer_etat_uno_classique(main_joueur_1, defausse_pile[-1], etat_tour['couleur_actuelle'])
if not manche_terminee and action_valide:
# Passage au joueur suivant (gestion de l'inversion par le 'sens_horaire')
if etat_tour['sens_horaire']:
joueur_courant = 3 - joueur_courant
else:
# Dans un jeu a 2 joueurs, Inversion ne change pas de joueur, on reste sur le meme
pass
# Fin de manche
if gagnant is None:
# Si la manche s'est terminee prematurement (paquet vide)
gagnant = 1 if len(main_joueur_1) < len(main_joueur_2) else 2
perdant = 3 - gagnant
if gagnant == 1:
points_marque_par_perdant = calculer_score(main_joueur_2, 'UNO')
else:
points_marque_par_perdant = calculer_score(main_joueur_1, 'UNO')
else:
perdant = 3 - gagnant
if gagnant == 1:
points_marque_par_perdant = calculer_score(main_joueur_2, 'UNO')
else:
points_marque_par_perdant = calculer_score(main_joueur_1, 'UNO')
# Sauvegarde de la Q-Table
sauvegarder_q_table(Q_TABLE)
print("\n=============================================")
# Retrait des accents et f-string
print("FIN DE MANCHE UNO CLASSIQUE ! Le Joueur %d a gagne." % gagnant)
print("Le Joueur %d marque %d points." % (perdant, points_marque_par_perdant))
print("Taille de la Q-Table : %d etats UNO_CL appris." % len([k for k in Q_TABLE.keys() if 'UNO_CL' in k]))
print("=============================================\n")
return gagnant, points_marque_par_perdant
uno_extreme.py
masquer
import trys as t
import ia_learning as ia # Importation du module d'apprentissage
import uno_rules as rules
import display as d
from uno_rules import Colors, Val_digits, Val_spe, W_cards, EXTREME_ACTION_SPE, EXTREME_W_CARDS, Nbr_cards_init_extreme
# --- CONSTANTES SPÉCIFIQUES À UNO EXTRÊME ---
GAME_MODE ='UNO_EX'
ALL_EXTREME_ACTIONS = Val_spe + EXTREME_ACTION_SPE
ALL_EXTREME_WILDS = W_cards + EXTREME_W_CARDS
def gerer_etat_uno_extreme():
etat = {
'sens_horaire': True, # True = sens horaire, False = sens anti-horaire
'couleur_actuelle': None, # Couleur de la carte du dessus
'uno_crie_joueur_1': False,
'uno_crie_joueur_2': False,
'sauter_tour_suivant': False, # Gère l'effet PTT, +2, +4, +6, +8W
'total_cartes_a_piocher': 0 # Compteur pour les cartes empilées
}
return etat
# Règle de base : correspondance de couleur, de valeur ou Joker
return (couleur_jouee == couleur_actuelle or # Correspondance de couleur choisie
valeur_jouee == carte_defausse_tuple[1] or # Correspondance de valeur
couleur_jouee == 'N')
# Effets de pioche (+2, +4, +6, +8W)
if valeur in ['+2', '+4', '+6', '+8W']:
pioche_valeur=int(valeur.replace('+', '').replace('W', ''))
etat_tour['total_cartes_a_piocher'] += pioche_valeur
print("La pioche est augmentee de {} cartes.".format(pioche_valeur))
# Le prochain joueur doit piocher ou jouer une carte +
etat_tour['sauter_tour_suivant'] = True
# Effets de saut de tour (I, PTT)
if valeur in ['I', 'PTT']:
etat_tour['sauter_tour_suivant'] = True
if valeur == 'I':
etat_tour['sens_horaire'] = not etat_tour['sens_horaire']
print("Le sens de jeu est inversé.")
if valeur == 'PTT':
print("Le prochain joueur passe son tour.")
# Effets Extrêmes Spécifiques
if valeur == 'PA': # Poser Tout (Poser toutes les cartes de même couleur que la carte jouée)
cartes_a_garder = []
cartes_defaussees_supp = []
main_joueur = main_joueur_1 if joueur_courant == 1 else main_joueur_2
for carte in main_joueur:
if carte[0] == etat_tour['couleur_actuelle']:
cartes_defaussees_supp.append(carte)
else:
cartes_a_garder.append(carte)
if cartes_defaussees_supp:
input("Joueur {} a pose\nTOUTES les cartes\n{} en plus\n({} cartes)!".format(joueur_courant,etat_tour['couleur_actuelle'],len(cartes_defaussees_supp)))
else:
input("Joueur {} a pose\nPA mais n'avait\npas d'autres cartes\n{} a poser.".format(joueur_courant,etat_tour['couleur_actulle']))
elif valeur == 'DA': # Défausser tout (Le joueur choisit une couleur et l'adversaire défausse toutes ses cartes de cette couleur)
# Le joueur qui a posé le DA choisit une couleur
couleur_choisie = t.get_color_choice(joueur_courant)
cartes_a_garder = []
cartes_defaussees_supp = []
for carte in main_cible:
if carte[0] == couleur_choisie:
cartes_defaussees_supp.append(carte)
else:
cartes_a_garder.append(carte)
if cartes_defaussees_supp:
input("L'adversaire (Joueur {}) doit defausser {} cartes {}.".format(prochain_joueur,len(cartes_defauses_supp),couleur_choisie))
else:
input("L'adversaire (Joueur {}) n'avait pas de cartes {} a defausser.".format(prochain_joueur,couleur_choisie))
return etat_tour
def jouer_une_manche_extreme(joueur_a_commencer, game_type):
# INITIALISATION DE LA Q-TABLE EN MÉMOIRE
Q_TABLE = ia.charger_q_table()
# 1. Initialisation de la manche
paquet_pioche = rules.creer_paquet_uno_extreme()
# Assurer que la première carte n'est pas une carte spéciale (pour l'instant, on simplifie)
while defausse_pile[0][1] in ALL_EXTREME_ACTIONS + ALL_EXTREME_WILDS:
paquet_pioche.insert(0, defausse_pile.pop(0))
r.shuffle(paquet_pioche)
defausse_pile.extend(rules.piocher_carte_aleatoire(paquet_pioche, 1))
print("Debut de manche.\nPremiere carte :{}.\nCouleur actuelle:\n{}".format(defausse-pile[-1],eta_tour['couleur_actuelle']))
while not manche_terminee:
# 2. Gestion des états et de l'affichage
carte_jouee = None
couleur_choisie = None
action_valide = False
if not paquet_pioche and len(defausse_pile) > 1:
rules.recycler_defausse(paquet_pioche, defausse_pile)
elif not paquet_pioche and len(defausse_pile) <= 1:
print("Paquet et défausse vides, fin de manche par manque de cartes.")
break
print("C'est au Joueur {}!".format(joueur_courant))
# Gestion de l'effet de pioche empilé
if etat_tour['total_cartes_a_piocher'] > 0:
print("Pioche en cours :{} cartes a prendre (ou a contrer).".format(etat_tour['total_cartes_a_piocher']))
if joueur_courant == 1:
jouer_ou_piocher = t.trys(input("Voulez-vous tenter de contrer avec un '+' (o/n) ?"), 'on', 'n')
main_joueur = main_joueur_1
cartes_jouables_plus = [c for c in main_joueur if c[1] in ['+2', '+4', '+6', '+8W'] and verifier_validite_extreme(c, defausse_pile[-1], etat_tour['couleur_actuelle'])]
if jouer_ou_piocher.lower() == 'o' and cartes_jouables_plus:
t.afficher_main(main_joueur, [c for c in main_joueur if c in cartes_jouables_plus])
index_carte = t.trys_index(input("Choisissez l'index de la carte '+' à jouer (ou 'p' pour piocher) :"), len(main_joueur))
if index_carte != 'p':
carte_jouee = main_joueur.pop(index_carte)
action_valide = True
else:
action_valide = False
else:
print("Aucune carte '+' jouable ou choix de piocher. Pénalité appliquée.")
action_valide = False
else: # IA
main_joueur = main_joueur_2
cartes_jouables_plus = [c for c in main_joueur if c[1] in ['+2', '+4', '+6', '+8W'] and verifier_validite_extreme(c, defausse_pile[-1], etat_tour['couleur_actuelle'])]
if cartes_jouables_plus:
carte_jouee = r.choice(cartes_jouables_plus)
main_joueur.remove(carte_jouee)
action_valide = True
print("L'IA contre avec {}.".format(carte_jouee))
else:
print("L'IA n'a pas pu contrer.")
action_valide = False
if not action_valide:
# Appliquer la pénalité et réinitialiser le compteur de pioche
rules.appliquer_penalite(main_joueur_1 if joueur_courant == 1 else main_joueur_2, paquet_pioche, defausse_pile[-1], etat_tour['total_cartes_a_piocher'])
etat_tour['total_cartes_a_piocher'] = 0
etat_tour['sauter_tour_suivant'] = False
joueur_courant = 3 - joueur_courant
continue
# 3. Tour normal (pas de pioche empilée en cours)
if etat_tour['total_cartes_a_piocher'] == 0:
if joueur_courant == 1: # Joueur Humain
print("Defausse :{}.".format(defausse_pile[-1]))
t.afficher_main(main_joueur_1)
cartes_jouables = [
carte for carte in main_joueur_1
if verifier_validite_extreme(carte, defausse_pile[-1], etat_tour['couleur_actuelle'])
]
if cartes_jouables:
t.afficher_main(main_joueur_1, cartes_jouables)
index_carte = t.trys_index(input("Choisissez l'index de la carte à jouer (ou 'p' pour piocher):"), len(main_joueur_1))
if index_carte == 'p':
main_joueur_1.extend(rules.piocher_carte_aleatoire(paquet_pioche))
print("Vous piochez 1 carte.")
action_valide = True
else:
carte_jouee = main_joueur_1.pop(index_carte)
action_valide = True
else:
main_joueur_1.extend(rules.piocher_carte_aleatoire(paquet_pioche))
print("Aucune carte jouable. Vous piochez 1 carte et passez votre tour.")
action_valide = True
else: # Joueur IA (Apprentissage par renforcement)
main_joueur = main_joueur_2
# 4. Traitement de la carte jouée
if action_valide and carte_jouee:
# 4a. Traitement des cartes Wild (Joker)
if carte_jouee[0] == 'N':
if joueur_courant == 1 and carte_jouee[1] in rules.W_cards + EXTREME_W_CARDS:
couleur_choisie = t.get_color_choice(joueur_courant)
if not couleur_choisie:
couleur_choisie = r.choice(rules.Colors)
# 4b. Mise à jour de la défausse et de la couleur actuelle
defausse_pile.append(carte_jouee)
etat_tour['couleur_actuelle'] = couleur_choisie if couleur_choisie else carte_jouee[0]
# 4d. Vérification de la fin de manche (main vide)
if not main_joueur_1 or not main_joueur_2:
manche_terminee = True
gagnant = 1 if not main_joueur_1 else 2
perdant = 3 - gagnant
main_perdant = main_joueur_2 if perdant == 2 else main_joueur_1
points_marque_par_perdant = rules.calculer_score(main_perdant, GAME_MODE)
# Mise à jour Q-Table finale (si l'IA a perdu/gagné)
if derniere_action_ia:
recompense = ia.obtenir_recompense(
game_mode=GAME_MODE,
victoire_ia=(gagnant == 2),
nbr_cartes_avant=derniere_action_ia['nbr_cartes_avant'],
nbr_cartes_apres=len(main_joueur_2),
action_carte=derniere_action_ia['action_precedente'],
main_ia_apres=main_joueur_2
)
ia.mettre_a_jour_q_table(
Q_TABLE,
derniere_action_ia['etat_precedent'],
derniere_action_ia['action_precedente'],
recompense,
None # État final
)
break
# 5. Mise à jour Q-Table (si le tour n'est pas terminé et que l'IA a joué)
if joueur_courant == 2 and derniere_action_ia and not manche_terminee:
etat_actuel_ia = ia.generer_etat_uno_classique(main_joueur_2, defausse_pile, GAME_MODE)
# 6. Passage au joueur suivant
if not manche_terminee and action_valide:
if etat_tour['total_cartes_a_piocher'] == 0 and etat_tour['sauter_tour_suivant']:
print("Joueur {} voit son tour sauté.".format(3-joueur_courant))
etat_tour['sauter_tour_suivant'] = False
else:
if etat_tour['sens_horaire']:
joueur_courant = 3 - joueur_courant
else:
joueur_courant = 3 - joueur_courant
elif not manche_terminee and action_valide and not carte_jouee:
joueur_courant = 3 - joueur_courant
# Résultat de la manche
if not manche_terminee:
score_j1 = rules.calculer_score(main_joueur_1, GAME_MODE)
score_j2 = rules.calculer_score(main_joueur_2, GAME_MODE)
print("==================")
print("FIN DE MANCHE UNO EXTREME !\nLe Joueur {} a gagne.".format(gagnant))
print("Le Joueur {} marque {points_marque_par_perdant} points.".format(perdant,points_marque_par_perdant))
print("==================")
return gagnant, points_marque_par_perdant
uno_main.py
masquer
import urandom1 as r
from uno_rules import types_paquets
from uno_classique import jouer_une_manche_classique
from uno_dos import jouer_une_manche_dos
from uno_nomerci import jouer_une_manche_no_merci
from uno_extreme import jouer_une_manche_extreme
from uno_zero import jouer_une_manche_zero
def launch_uno():
name=input("Nom du joueur ?")
score_joueur_1=0
score_joueur_2=0
joueur_a_commencer_prochaine_manche=1
game_type=types_paquets()
if game_type==2:
game_function=jouer_une_manche_dos
game_name="DOS"
elif game_type==3:
game_function=jouer_une_manche_no_merci
game_name="UNO NoMerci"
elif game_type==4: # NOUVELLE OPTION
game_function=jouer_une_manche_extreme
game_name="UNO Extreme"
elif game_type==5:
game_function=jouer_une_manche_zero
game_name="UNO Zero"
else:
game_function=jouer_une_manche_classique
game_name="UNO Classique"
print("---------------------")
print("{} contre l'IA\nstrategique !".format(game_name))
print("Le premier joueur\ndont l'adversaire\naccumule 500 points\ngagne la partie.")
while True:
print("=====================")
print("Joueur 1: {} points\nIA : {} points".format(score_joueur_1, score_joueur_2))
print("La manche commence.\nJoueur {} debute.".format(joueur_a_commencer_prochaine_manche))
print("=====================")
gagnant,points_marque_par_perdant=game_function(joueur_a_commencer_prochaine_manche, game_type)
if gagnant == 1:
score_joueur_1+=points_marque_par_perdant
perdant=2
else:
score_joueur_2+=points_marque_par_perdant
perdant=1
joueur_a_commencer_prochaine_manche = perdant # L'adversaire commence la manche suivante
if score_joueur_1 >= 500:
print("\\n*** FIN DE PARTIE ! ***")
print("Fellitation {}!tu a gagne la partie!".format(name))
break
elif score_joueur_2 >= 500:
print("\\n*** FIN DE PARTIE ! ***")
print("L'IA a gagn la partie complete !")
break
if __name__ == '__main__':
launch_uno()
uno_nomerci.py
masquer
import urandom1 as r
import trys as t
from uno_rules import Colors, Val_digits, W_cards, W_count, Nbr_cards_init, piocher_carte_aleatoire, appliquer_penalite, recycler_defausse, calculer_score
from ia_learning import charger_q_table, sauvegarder_q_table, generer_etat_uno, choisir_action_apprentissage, obtenir_recompense, mettre_a_jour_q_table #, VALEUR_PIOCHE
# Charger la Q-Table au debut du script
Q_TABLE = charger_q_table()
HISTORIQUE_IA = []
# --- CONSTANTES SPÉCIFIQUES À NO MERCY ---
# Cartes chiffrées de 0 à 10
VAL_CHIFFRES_NO_MERCI = [str(n) for n in range(0, 11)]
# Cartes Action Spéciales (selon le paquet étendu de No Mercy)
VAL_SPEC_NO_MERCI_SIMPLIFIE = ['+10', '+6', '+4I', 'PTT', 'I', '+2'] # 'RC' et 'PA' ne sont pas gérés ici pour simplification
# Cartes Joker
WILD_NO_MERCI = W_cards # W et +4
WILD_NO_MERCI_COUNT = 4
def creer_paquet_no_merci():
paquet = []
# Cartes chiffrées (0-10) - 2 par couleur
for couleur in Colors:
for valeur in VAL_CHIFFRES_NO_MERCI:
paquet.append((couleur, valeur))
paquet.append((couleur, valeur))
# Cartes Action (2 de chaque par couleur)
for couleur in Colors:
for valeur in VAL_SPEC_NO_MERCI_SIMPLIFIE:
paquet.append((couleur, valeur))
paquet.append((couleur, valeur))
# Cartes Sauvages (4 de chaque)
for valeur in WILD_NO_MERCI:
for _ in range(WILD_NO_MERCI_COUNT):
paquet.append(('N', valeur))
r.shuffle(paquet)
return paquet
def gerer_etat_no_merci():
"""Initialise l'etat de la manche UNO No Mercy."""
etat = {
'sens_horaire': True,
'couleur_actuelle': None,
'uno_crie_joueur_1': False,
'uno_crie_joueur_2': False,
'total_cartes_a_piocher': 0 # L'element CRITIQUE du No Mercy : le compteur de penalite
}
return etat
def verifier_validite_no_merci(carte_jouee, carte_defausse_tuple, couleur_actuelle, cartes_a_piocher):
"""
Verifie si la carte jouee est legale, en tenant compte du stacking de penalite.
"""
couleur_jouee, valeur_jouee = carte_jouee
# 1. Stacking de penalite actif
if cartes_a_piocher > 0:
# Seules les cartes +X et +4 sont valides
if valeur_jouee in ['+2', '+6', '+10'] and couleur_jouee == couleur_actuelle:
return True
if valeur_jouee in ['+4', '+4I']:
return True
# +2 sur +2 d'une couleur differente si la carte du dessus est un +2
if valeur_jouee == '+2' and carte_defausse_tuple[1] == '+2' and couleur_jouee == couleur_actuelle:
return True
# Si on ne stack pas, on ne peut rien jouer d'autre que Piocher/Accepter
return False
# 2. Jeu normal (pas de stacking actif)
# Règle UNO classique : correspondance de couleur, de valeur ou Joker
return (couleur_jouee == couleur_actuelle or
valeur_jouee == carte_defausse_tuple[1] or
couleur_jouee == 'N')
def choisir_carte_jouer_ia_no_merci(main_ia, defausse_pile, etat_tour, nbr_manches_jouees):
"""
Decide de l'action de l'IA (carte a jouer et couleur choisie) basee sur la Q-Table.
Retourne ((carte_jouee, couleur_choisie), None) ou (VALEUR_PIOCHE, -1)
"""
global Q_TABLE, HISTORIQUE_IA
for carte in main_ia:
is_valid = verifier_validite_no_merci(carte, defausse_pile[-1], couleur_actuelle, cartes_a_piocher)
if is_valid:
couleur_jouee, valeur_jouee = carte
# Si c'est un Joker ('W', '+4', '+4I'), l'IA choisit la couleur
if couleur_jouee == 'N':
# Strategie IA simplifiee : choisir la couleur qu'elle a le plus
couleurs_main = [c[0] for c in main_ia if c[0] != 'N']
couleur_choisie = max(set(couleurs_main), key=couleurs_main.count, default=r.choice(Colors))
actions_possibles.append(((carte, couleur_choisie), None))
else:
# Couleur non Joker, la couleur choisie est la couleur de la carte jouee
actions_possibles.append(((carte, couleur_jouee), None))
# Si penalite active et aucune carte jouable, la seule action est d'accepter la penalite (Piocher)
if cartes_a_piocher > 0 and not actions_possibles:
actions_possibles.append((VALEUR_PIOCHE, -1))
# Si aucune penalite active et aucune carte jouable, l'action est Piocher
if cartes_a_piocher == 0 and not actions_possibles:
actions_possibles.append((VALEUR_PIOCHE, -1))
# Si penalite active et actions de stacking possibles, on n'ajoute pas l'action pioche ici
# L'IA doit choisir entre les actions possibles de stacking, ou forcer la pioche
if cartes_a_piocher == 0 or actions_possibles:
# L'IA peut toujours decider de piocher pour eviter de jouer une carte cles
actions_possibles.append((VALEUR_PIOCHE, -1))
# 4. Enregistrer l'etat et l'action pour la mise a jour future
if action_choisie:
HISTORIQUE_IA.append({
'etat_precedent': etat_actuel,
'action_precedente': action_choisie,
'nbr_cartes_avant': len(main_ia)
})
return action_choisie
def jouer_une_manche_no_merci(joueur_a_commencer, nbr_manches_jouees):
"""
Simule une manche de UNO No Mercy (Joueur 1 vs IA).
Retourne (gagnant, points_marque_par_perdant).
"""
global Q_TABLE, HISTORIQUE_IA
# Initialiser la pile de defausse
while True:
carte_initiale = piocher_carte_aleatoire(paquet, 1)[0]
# On commence avec une carte chiffre normale
if carte_initiale[1] in VAL_CHIFFRES_NO_MERCI and carte_initiale[0] != 'N':
defausse_pile.append(carte_initiale)
break
else:
paquet.append(carte_initiale) # Remettre la carte dans le paquet
while not manche_terminee:
action_valide = False
carte_jouee = None
couleur_choisie = None
# Verifier si une penalite de pioche est active
is_penalty_active = etat_tour['total_cartes_a_piocher'] > 0
print("\n")
print("---------------------\nCarte du dessus: %s | Couleur actuelle: %s" % (str(defausse_pile[-1]), etat_tour['couleur_actuelle']))
if is_penalty_active:
print("ATTENTION: Penalite de PIOCHE de +%d cartes ACTIVE!" % etat_tour['total_cartes_a_piocher'])
# 1. Tour du Joueur Humain (1)
if joueur_courant == 1:
print("\nTour du Joueur 1 (Humain) - Cartes: %d" % len(main_joueur_1))
print("Votre main:", main_joueur_1)
cartes_jouables_indices = [
i for i, carte in enumerate(main_joueur_1)
if verifier_validite_no_merci(carte, defausse_pile[-1], etat_tour['couleur_actuelle'], is_penalty_active)
]
choix = t.trys(input("Action (J/P pour Jouer/Piocher): ").upper(), 1, 1)
if choix == 'P':
# Action Piocher / Accepter la penalite
if is_penalty_active:
appliquer_penalite(main_joueur_1, paquet, defausse_pile[-1], etat_tour['total_cartes_a_piocher'])
etat_tour['total_cartes_a_piocher'] = 0 # La penalite est purge
action_valide = True
else:
# Piocher 1 carte et passer son tour (regle No Mercy simplifiee)
cartes_piochees = piocher_carte_aleatoire(paquet, 1)
main_joueur_1.extend(cartes_piochees)
print("Vous piochez 1 carte.")
action_valide = True
# Si le joueur peut jouer la carte piochee, il le fait (simplification)
carte_piochee = cartes_piochees[0]
if verifier_validite_no_merci(carte_piochee, defausse_pile[-1], etat_tour['couleur_actuelle'], is_penalty_active):
print("Carte piochee jouee automatiquement: %s" % str(carte_piochee))
defausse_pile.append(carte_piochee)
etat_tour['couleur_actuelle'] = carte_piochee[0] if carte_piochee[0] != 'N' else r.choice(Colors)
main_joueur_1.remove(carte_piochee) # Retire la carte jouee
# Si jouee, il passe au joueur suivant, sans jouer de tour supplementaire.
# On doit recalculer les effets de la carte jouee
carte_jouee = carte_piochee
couleur_choisie = etat_tour['couleur_actuelle'] # Simuler le choix de couleur
elif choix == 'J' and cartes_jouables_indices:
# Action Jouer
try:
print("Cartes jouables (indices):", cartes_jouables_indices)
index_carte = int(input("Index de la carte a jouer: "))
if index_carte in cartes_jouables_indices:
carte_tentative = main_joueur_1[index_carte]
carte_jouee = carte_tentative
main_joueur_1.pop(index_carte)
action_valide = True
# Gestion des Jokers
if carte_jouee[0] == 'N':
choix_couleur = t.trys(input("Choisir couleur (R, V, B, J): ").upper(), 1, 1)
if choix_couleur in Colors:
couleur_choisie = choix_couleur
else:
couleur_choisie = r.choice(Colors) # Couleur par defaut si mauvaise entree
else:
couleur_choisie = carte_jouee[0]
except (ValueError, IndexError):
print("Choix invalide.")
else:
print("Action invalide ou aucune carte jouable. Vous devez piocher.")
# 2. Tour de l'IA (2)
else: # joueur_courant == 2
print("\nTour de l'IA (Joueur 2) - Cartes: %d" % len(main_joueur_2))
action_choisie = choisir_carte_jouer_ia_no_merci(main_joueur_2, defausse_pile, etat_tour, nbr_manches_jouees)
carte_action, couleur_action = action_choisie # carte_action peut etre VALEUR_PIOCHE
if carte_action is VALEUR_PIOCHE:
# Action Piocher / Accepter la penalite
if is_penalty_active:
appliquer_penalite(main_joueur_2, paquet, defausse_pile[-1], etat_tour['total_cartes_a_piocher'])
etat_tour['total_cartes_a_piocher'] = 0 # La penalite est purge
action_valide = True
print("L'IA accepte la penalite de +%d cartes." % etat_tour['total_cartes_a_piocher'])
else:
# Piocher 1 carte et passer son tour (regle No Mercy simplifiee)
cartes_piochees = piocher_carte_aleatoire(paquet, 1)
main_joueur_2.extend(cartes_piochees)
print("L'IA pioche 1 carte.")
action_valide = True
# L'IA joue la carte piochee si possible (simplification)
carte_piochee = cartes_piochees[0]
if verifier_validite_no_merci(carte_piochee, defausse_pile[-1], etat_tour['couleur_actuelle'], is_penalty_active):
carte_jouee = carte_piochee
couleur_choisie = carte_piochee[0] if carte_piochee[0] != 'N' else r.choice(Colors)
main_joueur_2.remove(carte_piochee) # Retire la carte jouee
defausse_pile.append(carte_jouee)
etat_tour['couleur_actuelle'] = couleur_choisie
print("L'IA joue la carte piochee: %s, Couleur choisie: %s" % (str(carte_jouee), couleur_choisie))
main_joueur_2.remove(carte_jouee)
defausse_pile.append(carte_jouee)
etat_tour['couleur_actuelle'] = couleur_choisie
action_valide = True
print("L'IA joue %s. Nouvelle couleur: %s" % (str(carte_jouee), couleur_choisie))
# 3. Application des effets de la carte jouee
if carte_jouee and action_valide:
valeur_carte_jouee = carte_jouee[1]
# Penalites de Pioche (Stacking)
penalites_stack = {'+2': 2, '+6': 6, '+10': 10, '+4': 4, '+4I': 4}
if valeur_carte_jouee in penalites_stack:
etat_tour['total_cartes_a_piocher'] += penalites_stack[valeur_carte_jouee]
# Dans No Mercy, le +4I inverse aussi le sens
if valeur_carte_jouee == '+4I':
etat_tour['sens_horaire'] = not etat_tour['sens_horaire']
# Actions non-stackables
elif valeur_carte_jouee == 'I': # Inversion
etat_tour['sens_horaire'] = not etat_tour['sens_horaire']
elif valeur_carte_jouee == 'PTT': # Passe Ton Tour
joueur_courant = 3 - joueur_courant # Passe deux fois
# Verification de fin de manche (main vide)
if joueur_courant == 1 and not main_joueur_1:
gagnant = 1
manche_terminee = True
elif joueur_courant == 2 and not main_joueur_2:
gagnant = 2
manche_terminee = True
# 4. Gestion du paquet vide
if not paquet:
recycler_defausse(paquet, defausse_pile)
if not paquet:
print("Fin de manche par manque de cartes.")
manche_terminee = True
gagnant = 1 if len(main_joueur_1) < len(main_joueur_2) else 2
# 5. Mise a jour de la Q-Table de l'IA apres son tour
if joueur_courant == 2 and HISTORIQUE_IA and action_valide:
derniere_action_ia = HISTORIQUE_IA.pop()
# L'etat actuel de la partie pour l'IA est l'etat du joueur 1 a son tour
etat_actuel_ia = generer_etat_uno_classique(main_joueur_1, defausse_pile, etat_tour['couleur_actuelle'], etat_tour['total_cartes_a_piocher'])
# 6. Passage au joueur suivant
if not manche_terminee and action_valide:
if etat_tour['sens_horaire']:
joueur_courant = 3 - joueur_courant
else:
joueur_courant = 3 - joueur_courant
# Fin de manche
perdant = 3 - gagnant
points_marque_par_perdant = calculer_score(main_joueur_2 if gagnant == 1 else main_joueur_1, 'NO_MERCI')
# Sauvegarde de la Q-Table
sauvegarder_q_table(Q_TABLE)
print("\n=============================================")
print("FIN DE MANCHE UNO NO MERCY ! Le Joueur %d a gagne." % gagnant)
print("Le Joueur %d marque %d points." % (perdant, points_marque_par_perdant))
print("Taille de la Q-Table : %d etats NO_MERCI appris." % len([k for k in Q_TABLE.keys() if 'NO_MERCI' in k]))
print("=============================================\n")
return gagnant, points_marque_par_perdant
uno_zero.py
masquer
import random as r
import trys as t
from uno_rules import Colors, Val_spe, Val_digits, W_cards, W_count, Nbr_cards_init, piocher_carte_aleatoire, appliquer_penalite, recycler_defausse, calculer_score, creer_paquet_uno_classique
# Importation des fonctions d'apprentissage
from ia_learning import charger_q_table, sauvegarder_q_table, generer_etat_uno, choisir_action_apprentissage, obtenir_recompense, mettre_a_jour_q_table
# Charger la Q-Table au debut du script
Q_TABLE = charger_q_table()
HISTORIQUE_IA = []
def verifier_validite_uno_zero(carte_jouee, carte_defausse_tuple, couleur_actuelle):
couleur_jouee, valeur_jouee = carte_jouee
# Regle UNO classique : correspondance de couleur, de valeur ou Joker
return (couleur_jouee == couleur_actuelle or # Correspondance de couleur choisie
valeur_jouee == carte_defausse_tuple[1] or # Correspondance de valeur
couleur_jouee == 'N')
def choisir_carte_jouer_ia_zero(main_ia, defausse_pile, etat_tour, nbr_manches_jouees):
global Q_TABLE, HISTORIQUE_IA
# 1. Générer l'état (utilise l'état classique car les cartes sont les mêmes)
etat_actuel = generer_etat_uno_classique(main_ia, defausse_pile, etat_tour['couleur_actuelle'], etat_tour['total_cartes_a_piocher'])
for carte in main_ia:
is_valid = verifier_validite_uno_zero(carte, defausse_pile[-1], couleur_actuelle)
if is_valid:
couleur_jouee, valeur_jouee = carte
# Si c'est un Joker ('N'), l'IA choisit la couleur
if couleur_jouee == 'N':
# Stratégie IA simplifiée : choisir la couleur qu'elle a le plus
couleurs_main = [c[0] for c in main_ia if c[0] != 'N']
couleur_choisie = max(set(couleurs_main), key=couleurs_main.count, default=r.choice(Colors))
actions_possibles.append(((carte, couleur_choisie), None))
else:
# Couleur non Joker, la couleur choisie est la couleur de la carte jouée
actions_possibles.append(((carte, couleur_jouee), None))
# 4. Enregistrer l'etat et l'action pour la mise a jour future
if action_choisie:
HISTORIQUE_IA.append({
'etat_precedent': etat_actuel,
'action_precedente': action_choisie,
'nbr_cartes_avant': len(main_ia)
})
return action_choisie
def jouer_une_manche_zero(joueur_a_commencer, nbr_manches_jouees):
global Q_TABLE, HISTORIQUE_IA
paquet = creer_paquet_uno_classique() # Le paquet est le même que le classique
main_joueur_1 = piocher_carte_aleatoire(paquet, Nbr_cards_init)
main_joueur_2 = piocher_carte_aleatoire(paquet, Nbr_cards_init)
defausse_pile = []
# Initialiser la pile de defausse
while True:
carte_initiale = piocher_carte_aleatoire(paquet, 1)[0]
# On commence avec une carte chiffre normale
if carte_initiale[1] in Val_digits and carte_initiale[0] != 'N':
defausse_pile.append(carte_initiale)
break
else:
paquet.append(carte_initiale) # Remettre la carte dans le paquet
# 1. Tour du Joueur Humain (1)
if joueur_courant == 1:
print("\nTour du Joueur 1 (Humain) - Cartes: %d" % len(main_joueur_1))
print("Votre main:", main_joueur_1)
cartes_jouables_indices = [
i for i, carte in enumerate(main_joueur_1)
if verifier_validite_uno_zero(carte, defausse_pile[-1], etat_tour['couleur_actuelle'])
]
choix = t.trys(input("Action (J/P pour Jouer/Piocher): ").upper(), 1, 1)
if choix == 'P':
# Piocher 1 carte
cartes_piochees = piocher_carte_aleatoire(paquet, 1)
main_joueur_1.extend(cartes_piochees)
print("Vous piochez 1 carte.")
action_valide = True
# Le joueur peut jouer la carte piochee (regle classique)
carte_piochee = cartes_piochees[0]
if verifier_validite_uno_zero(carte_piochee, defausse_pile[-1], etat_tour['couleur_actuelle']):
print("Carte piochee jouee automatiquement: %s" % str(carte_piochee))
defausse_pile.append(carte_piochee)
main_joueur_1.remove(carte_piochee)
carte_jouee = carte_piochee
couleur_choisie = carte_piochee[0] if carte_piochee[0] != 'N' else r.choice(Colors)
etat_tour['couleur_actuelle'] = couleur_choisie
elif choix == 'J' and cartes_jouables_indices:
# Action Jouer
try:
print("Cartes jouables (indices):", cartes_jouables_indices)
index_carte = int(input("Index de la carte a jouer: "))
if index_carte in cartes_jouables_indices:
carte_tentative = main_joueur_1[index_carte]
carte_jouee = carte_tentative
main_joueur_1.pop(index_carte)
action_valide = True
# Gestion des Jokers
if carte_jouee[0] == 'N':
choix_couleur = t.trys(input("Choisir couleur (R, V, B, J): ").upper(), 1, 1)
couleur_choisie = choix_couleur if choix_couleur in Colors else r.choice(Colors)
else:
couleur_choisie = carte_jouee[0]
# Application de l'effet spécial '0' - Échange de mains
if carte_jouee[1] == '0':
main_joueur_1, main_joueur_2 = main_joueur_2, main_joueur_1
print("!!! CARTE ZERO JOUÉE !!! Les mains ont été échangées!")
else:
print("Carte invalide ou non jouable.")
except (ValueError, IndexError):
print("Choix invalide.")
else:
print("Action invalide ou aucune carte jouable. Vous devez piocher.")
# 2. Tour de l'IA (2)
else: # joueur_courant == 2
print("\nTour de l'IA (Joueur 2) - Cartes: %d" % len(main_joueur_2))
action_choisie = choisir_carte_jouer_ia_zero(main_joueur_2, defausse_pile, etat_tour, nbr_manches_jouees)
carte_action, couleur_action = action_choisie # carte_action peut etre VALEUR_PIOCHE
if carte_action is VALEUR_PIOCHE:
# Action Piocher
cartes_piochees = piocher_carte_aleatoire(paquet, 1)
main_joueur_2.extend(cartes_piochees)
print("L'IA pioche 1 carte.")
action_valide = True
# L'IA joue la carte piochee si possible
carte_piochee = cartes_piochees[0]
if verifier_validite_uno_zero(carte_piochee, defausse_pile[-1], etat_tour['couleur_actuelle']):
carte_jouee = carte_piochee
couleur_choisie = carte_piochee[0] if carte_piochee[0] != 'N' else r.choice(Colors)
main_joueur_2.remove(carte_piochee) # Retire la carte jouee
defausse_pile.append(carte_jouee)
etat_tour['couleur_actuelle'] = couleur_choisie
print("L'IA joue la carte piochee: %s, Couleur choisie: %s" % (str(carte_jouee), couleur_choisie))
main_joueur_2.remove(carte_jouee)
defausse_pile.append(carte_jouee)
etat_tour['couleur_actuelle'] = couleur_choisie
action_valide = True
print("L'IA joue %s. Nouvelle couleur: %s" % (str(carte_jouee), couleur_choisie))
# Application de l'effet spécial '0' - Échange de mains
if carte_jouee[1] == '0':
main_joueur_1, main_joueur_2 = main_joueur_2, main_joueur_1
print("!!! CARTE ZERO JOUÉE PAR L'IA !!! Les mains ont été échangées!")
# 3. Application des autres effets de la carte jouee
if carte_jouee and action_valide:
valeur_carte_jouee = carte_jouee[1]
if valeur_carte_jouee == 'I': # Inversion
etat_tour['sens_horaire'] = not etat_tour['sens_horaire']
elif valeur_carte_jouee == 'PTT': # Passe Ton Tour
joueur_courant = 3 - joueur_courant # Passe deux fois
# Gestion des cartes +2 ou +4
if valeur_carte_jouee == '+2':
main_cible = main_joueur_2 if joueur_courant == 1 else main_joueur_1
appliquer_penalite(main_cible, paquet, defausse_pile[-1], 2)
elif valeur_carte_jouee == '+4':
main_cible = main_joueur_2 if joueur_courant == 1 else main_joueur_1
appliquer_penalite(main_cible, paquet, defausse_pile[-1], 4)
# Verification de fin de manche (main vide)
if joueur_courant == 1 and not main_joueur_1:
gagnant = 1
manche_terminee = True
elif joueur_courant == 2 and not main_joueur_2:
gagnant = 2
manche_terminee = True
# 4. Gestion du paquet vide
if not paquet:
recycler_defausse(paquet, defausse_pile)
if not paquet:
print("Fin de manche par manque de cartes.")
manche_terminee = True
gagnant = 1 if len(main_joueur_1) < len(main_joueur_2) else 2
# 5. Mise a jour de la Q-Table de l'IA apres son tour
if joueur_courant == 2 and HISTORIQUE_IA and action_valide:
derniere_action_ia = HISTORIQUE_IA.pop()
# L'etat actuel de la partie pour l'IA est l'etat du joueur 1 a son tour
etat_actuel_ia = generer_etat_uno_classique(main_joueur_1, defausse_pile, etat_tour['couleur_actuelle'], etat_tour['total_cartes_a_piocher'])
# 6. Passage au joueur suivant
if not manche_terminee and action_valide:
if etat_tour['sens_horaire']:
joueur_courant = 3 - joueur_courant
else:
joueur_courant = 3 - joueur_courant
# Fin de manche
perdant = 3 - gagnant
points_marque_par_perdant = calculer_score(main_joueur_2 if gagnant == 1 else main_joueur_1, 'UNO_ZERO')
# Sauvegarde de la Q-Table
sauvegarder_q_table(Q_TABLE)
print("\n=============================================")
print("FIN DE MANCHE UNO ZERO ! Le Joueur %d a gagne." % gagnant)
print("Le Joueur %d marque %d points." % (perdant, points_marque_par_perdant))
print("Taille de la Q-Table : %d etats UNO_ZERO appris." % len([k for k in Q_TABLE.keys() if 'UNO_ZERO' in k]))
print("=============================================\n")
return gagnant, points_marque_par_perdant
fichiers utillitaires :
urandom1.py
masquer
from random import *
def shuffle(l):
tmp=[]
while len(l)>0:
e=randint(0,len(l)-1)
tp=l[e]
tmp+=[tp]
l.pop(e)
return tmp
trys.py
masquer
def trys(i,e,s):
if i.isdigit()==True and s<=int(i)<=e:
return int(i)
else:
if i=="q":
return i
else:
print("Bad number or\ninvalid charactere")
return None
voici ce qui ce passe lorsque je tente de compiler JustUI. Comment pouvoir résoudre le problème?
giteapc install Lephenixnoir/JustUI
<giteapc> Cloning Lephenixnoir/JustUI...
<giteapc> Fetching Lephenixnoir/gint...
<giteapc> Fetching Lephenixnoir/sh-elf-gcc...
<giteapc> Fetching Lephenixnoir/sh-elf-binutils...
<giteapc> Fetching Lephenixnoir/fxsdk...
<giteapc> Fetching Lephenixnoir/OpenLibm...
<giteapc> Fetching Vhex-Kernel-Core/fxlibc...
remote: Enumerating objects: 11, done.
remote: Counting objects: 100% (11/11), done.
remote: Compressing objects: 100% (11/11), done.
remote: Total 11 (delta 3), reused 0 (delta 0), pack-reused 0 (from 0)
Dépaquetage des objets: 100% (11/11), 3.96 Kio | 675.00 Kio/s, fait.
Depuis https://git.planet-casio.com/Vhex-Kernel-Core/fxlibc
f284c12..7a70aae dev -> origin/dev
<giteapc> Will install: Lephenixnoir/fxsdk, Lephenixnoir/sh-elf-binutils, Lephenixnoir/sh-elf-gcc, Lephenixnoir/OpenLibm, Vhex-Kernel-Core/fxlibc, Lephenixnoir/gint, Lephenixnoir/JustUI
<giteapc> Is that okay (Y/n)? y
<giteapc> Lephenixnoir/fxsdk: Configuring
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/dello3/.local/share/giteapc/Lephenixnoir/fxsdk/build
<giteapc> Lephenixnoir/fxsdk: Building
make[1] : on entre dans le répertoire « /home/dello3/.local/share/giteapc/Lephenixnoir/fxsdk/build »
[ 22%] Built target fxgxa
[ 22%] Built target fxg1a
[ 25%] Built target fxsdk
[ 45%] Built target libfxlink
[ 93%] Built target fxlink
[100%] Built target fxsdk-gdb-bridge
make[1] : on quitte le répertoire « /home/dello3/.local/share/giteapc/Lephenixnoir/fxsdk/build »
<giteapc> Lephenixnoir/fxsdk: Installing
make[1] : on entre dans le répertoire « /home/dello3/.local/share/giteapc/Lephenixnoir/fxsdk/build »
[ 22%] Built target fxgxa
[ 22%] Built target fxg1a
[ 25%] Built target fxsdk
[ 45%] Built target libfxlink
[ 93%] Built target fxlink
[100%] Built target fxsdk-gdb-bridge
Install the project...
-- Install configuration: ""
make[1] : on quitte le répertoire « /home/dello3/.local/share/giteapc/Lephenixnoir/fxsdk/build »
<giteapc> Lephenixnoir/fxsdk: Done! :D
<giteapc> Lephenixnoir/sh-elf-binutils: Configuring
<sh-elf-binutils> binutils 2.42 already installed, skipping rebuild
<giteapc> Lephenixnoir/sh-elf-binutils: Building
<giteapc> Lephenixnoir/sh-elf-binutils: Installing
<giteapc> Lephenixnoir/sh-elf-binutils: Done! :D
<giteapc> Lephenixnoir/sh-elf-gcc: Configuring
<sh-elf-gcc> libsupc++.a found, libstdc++-v3 is already built
<sh-elf-gcc> GCC 14.1.0 with libstdc++-v3 already there; skipping rebuild
<giteapc> Lephenixnoir/sh-elf-gcc: Building
<giteapc> Lephenixnoir/sh-elf-gcc: Installing
<giteapc> Lephenixnoir/sh-elf-gcc: Done! :D
<giteapc> Lephenixnoir/OpenLibm: Configuring
<giteapc> Lephenixnoir/OpenLibm: Building
make[1] : on entre dans le répertoire « /home/dello3/.local/share/giteapc/Lephenixnoir/OpenLibm »
make[1]: Rien à faire pour « default ».
make[1] : on quitte le répertoire « /home/dello3/.local/share/giteapc/Lephenixnoir/OpenLibm »
<giteapc> Lephenixnoir/OpenLibm: Installing
make[1] : on entre dans le répertoire « /home/dello3/.local/share/giteapc/Lephenixnoir/OpenLibm »
mkdir -p /home/dello3/.local/share/fxsdk/sysroot/sh3eb-elf/lib
cp -RpP -f libopenlibm.a /home/dello3/.local/share/fxsdk/sysroot/sh3eb-elf/lib/
ln -sf libopenlibm.a /home/dello3/.local/share/fxsdk/sysroot/sh3eb-elf/lib/libm.a
mkdir -p /home/dello3/.local/share/fxsdk/sysroot/sh3eb-elf/include
cp -RpP -f \
include/openlibm.h \
include/openlibm_complex.h \
include/openlibm_defs.h \
include/openlibm_fenv.h \
include/openlibm_fenv_sh3eb.h \
include/openlibm_math.h \
/home/dello3/.local/share/fxsdk/sysroot/sh3eb-elf/include
make[1] : on quitte le répertoire « /home/dello3/.local/share/giteapc/Lephenixnoir/OpenLibm »
<giteapc> Lephenixnoir/OpenLibm: Done! :D
<giteapc> Vhex-Kernel-Core/fxlibc: Configuring
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/dello3/.local/share/giteapc/Vhex-Kernel-Core/fxlibc/build-gint
<giteapc> Vhex-Kernel-Core/fxlibc: Building
make[1] : on entre dans le répertoire « /home/dello3/.local/share/giteapc/Vhex-Kernel-Core/fxlibc/build-gint »
[100%] Built target fxlibcStatic
make[1] : on quitte le répertoire « /home/dello3/.local/share/giteapc/Vhex-Kernel-Core/fxlibc/build-gint »
<giteapc> Vhex-Kernel-Core/fxlibc: Installing
make[1] : on entre dans le répertoire « /home/dello3/.local/share/giteapc/Vhex-Kernel-Core/fxlibc/build-gint »
[100%] Built target fxlibcStatic
Install the project...
-- Install configuration: ""
make[1] : on quitte le répertoire « /home/dello3/.local/share/giteapc/Vhex-Kernel-Core/fxlibc/build-gint »
<giteapc> Vhex-Kernel-Core/fxlibc: Done! :D
<giteapc> Lephenixnoir/gint: Configuring
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/dello3/.local/share/giteapc/Lephenixnoir/gint/build-fx
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/dello3/.local/share/giteapc/Lephenixnoir/gint/build-cg
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/dello3/.local/share/giteapc/Lephenixnoir/gint/build-fxg3a
<giteapc> Lephenixnoir/gint: Building
[100%] Built target gint-fx
[100%] Built target gint-cg
[100%] Built target gint-fxg3a
<giteapc> Lephenixnoir/gint: Installing
[100%] Built target gint-fx
Install the project...
-- Install configuration: ""
[100%] Built target gint-cg
Install the project...
-- Install configuration: ""
-- Installing: /home/dello3/.local/share/fxsdk/sysroot/sh3eb-elf/lib/fxcg50.ld
-- Installing: /home/dello3/.local/share/fxsdk/sysroot/sh3eb-elf/lib/fxcg50_fastload.ld
[100%] Built target gint-fxg3a
Install the project...
-- Install configuration: ""
-- Installing: /home/dello3/.local/share/fxsdk/sysroot/sh3eb-elf/lib/fxcg50.ld
-- Installing: /home/dello3/.local/share/fxsdk/sysroot/sh3eb-elf/lib/fxcg50_fastload.ld
<giteapc> Lephenixnoir/gint: Done! :D
<giteapc> Lephenixnoir/JustUI: Configuring
-- The C compiler identification is GNU 14.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /home/dello3/.local/bin/sh-elf-gcc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Found Gint: TRUE (found suitable version "2.11.0", minimum required is "2.11")
-- Configuring done (0.5s)
-- Generating done (0.0s)
-- Build files have been written to: /home/dello3/.local/share/giteapc/Lephenixnoir/JustUI/build-fx
-- The C compiler identification is GNU 14.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /home/dello3/.local/bin/sh-elf-gcc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Found Gint: TRUE (found suitable version "2.11.0", minimum required is "2.11")
-- Configuring done (0.3s)
-- Generating done (0.0s)
-- Build files have been written to: /home/dello3/.local/share/giteapc/Lephenixnoir/JustUI/build-cg
<giteapc> Lephenixnoir/JustUI: Building
[ 5%] Building C object CMakeFiles/justui-fx.dir/src/jwidget.c.obj
[ 11%] Building C object CMakeFiles/justui-fx.dir/src/jlayout_box.c.obj
[ 16%] Building C object CMakeFiles/justui-fx.dir/src/jlayout_stack.c.obj
[ 22%] Building C object CMakeFiles/justui-fx.dir/src/jlayout_grid.c.obj
[ 27%] Building C object CMakeFiles/justui-fx.dir/src/jlabel.c.obj
/home/dello3/.local/share/giteapc/Lephenixnoir/JustUI/src/jlabel.c: Dans la fonction « jlabel_poly_render »:
/home/dello3/.local/share/giteapc/Lephenixnoir/JustUI/src/jlabel.c:308:38: erreur: « font_t » n'a pas de membre nommé « line_distance »
308 | int block_height = lines * (f->line_distance + l->line_spacing) -
| ^~
/home/dello3/.local/share/giteapc/Lephenixnoir/JustUI/src/jlabel.c:344:23: erreur: « font_t » n'a pas de membre nommé « line_distance »
344 | y += f->line_distance + l->line_spacing;
| ^~
make[3]: *** [CMakeFiles/justui-fx.dir/build.make:135: CMakeFiles/justui-fx.dir/src/jlabel.c.obj] Error 1
make[2]: *** [CMakeFiles/Makefile2:87: CMakeFiles/justui-fx.dir/all] Error 2
make[1]: *** [Makefile:136: all] Error 2
gmake: *** [/home/dello3/.local/share/giteapc/Lephenixnoir/JustUI/giteapc.make:10: build] Error 2
error: error 2 in command: g
Mets-toi sur la branche dev du fxSDK et de gint: giteapc install fxsdk@dev gint@dev et ensuite relance la commande. Tant que t'y es mets aussi JustUI sur dev au cas où.
À quoi sert les fichiers :
-Casio2RAMCPUInit.mem
-Casio2RAMInit.mem
-Casio2ROMInit.mem
et Casio2UserROMInit.mem
voici le lien pour y acéder https://drive.google.com/file/d/11oXuh-vBpRbLAS3yNpOBX4LYTfc0UPD2/view?pli=1
pour ce qui est de la forge je ne voit pas de bouton "s'incrire" comme le montre la capture enpièce jointe comment faire si il n'y a pa de possibilité pour s'inscrire
C'est des fichiers internes de l'émulateurs. Comme le nom l'indique, sans doute des données d'initialisation de la mémoire au début de l'émulation. Je ne vois pas du tout où tu veux en venir...
Pour la forge, on a dû rendre les inscriptions manuelles à cause des bots. Je peux te créer un compte moi-même. Si tu veux une adresse mail différente de ton compte PC dis-moi par MP, sinon je te le crée comme ça.
Uillise le même mail que celui de mon compte pour la forge
en ce qu'est des fichiers de l'émulateur je me suis dit qu'on pourrait trouver d'ou vient la limitation de RAM pour améliorer les performances des ADD-ins (j'ai quelque idées) et nous pourraons peut-être créer quelque chose pour accéder au system de fichier (root) de la CASIO et modifier l'appli Python (mettre à jour MicroPython vers la version 1.26.1) ainsi que d'optimiser le system et ajouter des fonctionalité de manières intégrés. Peut-tu améliorer le fxSDK en ajoutant une commande qui à partir d'un fichier compiler (g1a,g3a) donne le code source ce qui peut-être pratique pour les programme non-testé ou si on perd son code source et qu'il nous reste que le fichier g1a , si on a cette fonction on pourrais les récipérer ce qui est très pratique .
Invite a écrit : Peut-tu améliorer le fxSDK en ajoutant une commande qui à partir d'un fichier compiler (g1a,g3a) donne le code source ce qui peut-être pratique pour les programme non-testé ou si on perd son code source et qu'il nous reste que le fichier g1a , si on a cette fonction on pourrais les récipérer ce qui est très pratique .
Je mets juste que, à part si tu copierais l'entiereté du code source au temps de build, chose qui fera perdre une quantité significante d'espace (l'un de mes projets fait déja 800K de code SANS ASSETS, ce qui est déja 200K de plus que le g3a lui-même!), une telle chose est quasi-impossible automatiquement, encore plus avec les optimisations à la LTO. Si t'as pas envie de perdre ton code, utilise une forge Git
Invite a écrit : je me suis dit qu'on pourrait trouver d'ou vient la limitation de RAM
Pour le point original, on sait déja où se trouves les zones de mémoire dispo sur les modèles Prizm/monochrome, IIRC (je ne suis pas trop le dev de PyExtra), donc y'a pas trop d'utilité à cela j'assume
Le compte arrive ce soir. Pour le reste, euh... pas trop vite. Tu as beaucoup de bonnes idées mais elles sont pas toujours bien ancrées dans la réalité.
je me suis dit qu'on pourrait trouver d'ou vient la limitation de RAM
Pas de problème de ce côté-là, on sait déjà d'où ça vient.
créer quelque chose pour accéder au system de fichier (root) de la CASIO
Il n'existe pas de "système de fichiers root" sur la calculatrice
et modifier l'appli Python (mettre à jour MicroPython vers la version 1.26.1)
ainsi que d'optimiser le system et ajouter des fonctionalité de manières intégrés
Les applications officielles ne sont pas dans le système de fichiers et ne peuvent être modifiées que par une mise à jour officielle de CASIO.
Peut-tu améliorer le fxSDK en ajoutant une commande qui à partir d'un fichier compiler (g1a,g3a) donne le code source
Il est impossible de régénérer le code source à partir du binaire et absurde de mettre tout le code dedans à cause de la place que ça prend, qu'on a déjà assez de mal à contrôler.
Will PythonExtra work on the fxcg50 Os version 3.8? If so, is there a link to a compiled one? The g3a file.
Also, what about Ultimatepy.g3a? What is that, and will it work on the fxcg50 Os version 3.7 & 3.8? Is there a link to the files?
Is there any documentation on the gint module? For example, what are the arguments I can supply to the functions, especially those dealing with images?
I am not in a position to compile anything. Thanks for your help.
Planète Casio est un site communautaire non affilié à Casio. Toute reproduction de Planète Casio, même partielle, est interdite.
Les programmes et autres publications présentes sur Planète Casio restent la propriété de leurs auteurs et peuvent être soumis à des licences ou copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd
Citer : Posté le 25/11/2025 09:45 | #
Comme je disait il fonctionne sur l'appli officiel CASIO mais pas avec Python extra
Citer : Posté le 26/11/2025 09:04 | #
nouvelle version de micropython j'ai trouvé 2 fichiers que j'ai mis en pièce jointe e comme il n'est pas possible de s'inscrire sur la forge de planet-casio
lien vers la version stable
lien vers le fichier en developpement de micropython
Citer : Posté le 26/11/2025 14:18 | #
Ce n'est pas un probleme de version de micropython. PE embarque la version 1.25 donc pas de soucis.
Par contre on sait que l'on ne peut pas faire tourner des programmes trop gourmands en mémoire sur la G35+EII car on a très peu de RAM disponible à allouer. Et là il n'y a pas de miracle possible.
Citer : Posté le 26/11/2025 15:43 | #
je pense pour ma part que CASIO utillise la mémoire de stockage et pas la RAM ce quidonne plus de puissance à leur application (le fichier EACTWORK.tmp)
Citer : Posté le 26/11/2025 18:10 | #
Non EACTWORK n'a absolument rien à voir avec cette affaire. CASIO utilise bien un tas plus gros, dans lequel on peut tenter de piocher, mais ça nous expose à des dépendances de version d'OS donc ce n'est pas encore codé.
Citer : Posté le 27/11/2025 10:00 | #
Comment se fait-il que mon programme (et ces dépendances) fonctionnent sur l'appli Casio et pas sur PythonExtra
Comment allez-vous y prendre pour piocher dans le tas plus gros de CASIO
va t-il être facile sachant qui il ya eu une MàJ de l'OS il y pas longtemps
Graph 90+E 3.81 Correction d’un bug mineur 29/10/2025
et
Graph 35+E II 3.71 Correction d’un bug mineur 29/10/2025
Citer : Posté le 27/11/2025 11:21 | #
Comment ça se fait ? PythonExtra définit un tas plus petit.
Comment va-t-on s'y prendre ? En déclarant une arène supplémentaire.
La mise à jour récente de l'OS, qui est mineure, n'aura probablement pas d'impact.
Citer : Posté le 27/11/2025 13:30 | #
C'est c programme (uno_main) et ese dépendances qui fonctionnent uniquement sur l'appli CASIO officiel sur ma graph 35 + E II
# --- Paramètres du Q-Learning ---
ALPHA = 0.1 # Taux d'apprentissage (Learning Rate)
GAMMA = 0.9 # Facteur de rabais (Discount Factor)
EPSILON = 0.01 # Taux d'exploration (Exploration Rate)
# La Q-Table est stockee en memoire, elle est perdue a la fin de l'execution
Q_TABLE = {}
ACTIONS = ['JOUER', 'PIOCHER']
def obtenir_etat(main, carte_defausse, game_type):
if game_type == 2:
return generer_etat_dos(main, carte_defausse)
elif game_type == 3:
return generer_etat_no_mercy(main, carte_defausse, game_type)
elif game_type == 4:
return generer_etat_zero(main, carte_defausse)
elif game_type == 5:
return generer_etat_extreme(main, carte_defausse)
else:
return generer_etat_uno(main, carte_defausse, game_type)
def generer_etat_uno(main, carte_defausse, game_type):
taille_main = len(main)
couleur_defausse = carte_defausse[0]
valeur_defausse = carte_defausse[1]
# Simplification de la valeur de la carte de defausse pour reduire l'espace d'etat
if valeur_defausse.isdigit():
valeur_simplifiee = 'DIGIT'
elif valeur_defausse in ['+2', 'I', 'PTT']:
valeur_simplifiee = valeur_defausse
elif valeur_defausse in ['W', '+4']:
valeur_simplifiee = 'WILD'
else:
valeur_simplifiee = 'AUTRE'
# Le mode NoMerci est traite comme un mode UNO simple par defaut
mode_jeu='CLASSIC'
return (mode_jeu, taille_main, couleur_defausse, valeur_simplifiee)
def generer_etat_zero(main, carte_defausse):
etat = generer_etat_uno(main, carte_defausse, 4)
return ('ZERO', etat[1], etat[2], etat[3])
def generer_etat_extreme(main, carte_defausse):
etat = generer_etat_uno(main, carte_defausse, 5)
return ('EXTREME', etat[1], etat[2], etat[3])
def generer_etat_dos(main, defausse_piles):
taille_main = len(main)
carte_p1 = defausse_piles[0][-1]
carte_p2 = defausse_piles[1][-1]
couleur_p1 = carte_p1[0]
valeur_p1 = carte_p1[1]
couleur_p2 = carte_p2[0]
valeur_p2 = carte_p2[1]
# Simplification de la valeur de la carte de defausse (seulement chiffre ou W)
val_p1_simplifiee = 'DIGIT' if valeur_p1.isdigit() else valeur_p1
val_p2_simplifiee = 'DIGIT' if valeur_p2.isdigit() else valeur_p2
return ('DOS', taille_main, couleur_p1, val_p1_simplifiee, couleur_p2, val_p2_simplifiee)
def initialiser_q_valeur(etat, action):
if etat not in Q_TABLE:
Q_TABLE[etat] = {}
if action not in Q_TABLE[etat]:
Q_TABLE[etat][action] = 0.0
def choisir_action_apprentissage(etat, actions_legales, main):
if r.random() < EPSILON:
# Exploration: choisir une action aleatoire
if actions_legales:
return r.choice(actions_legales)
else:
return ('PIOCHER',)
else:
# Exploitation: choisir la meilleure action (la plus haute Q-valeur)
meilleure_action = None
meilleure_q_valeur = -float('inf')
# 1. Tester l'action PIOCHER
initialiser_q_valeur(etat, ('PIOCHER',))
q_piocher = Q_TABLE[etat][('PIOCHER',)]
meilleure_action = ('PIOCHER',)
meilleure_q_valeur = q_piocher
# 2. Tester toutes les actions JOUER legales
for action in actions_legales:
# L'action est un tuple (couleur, valeur, couleur_choisie) ou (couleur, valeur, pile_cible)
# Normalisons l'action pour la Q-table (ex: ('R', '1') ou ('N', '+4', 'B'))
# Action normalisee: tuple contenant (couleur, valeur) + un eventuel choix (couleur ou pile)
action_cle = action
initialiser_q_valeur(etat, action_cle)
q_jouer = Q_TABLE[etat][action_cle]
if q_jouer > meilleure_q_valeur:
meilleure_q_valeur = q_jouer
meilleure_action = action_cle
return meilleure_action
def mettre_a_jour_q_table(etat_precedent, action_precedente, recompense, nouvel_etat, actions_legales_nouvel_etat):
initialiser_q_valeur(etat_precedent, action_precedente)
# 1. Calculer la Q-valeur maximale pour le nouvel etat
max_q_nouvel_etat = 0
# 1.1 Inclure l'action PIOCHER dans les Q-valeurs maximales potentielles
initialiser_q_valeur(nouvel_etat, ('PIOCHER',))
max_q_nouvel_etat = Q_TABLE[nouvel_etat][('PIOCHER',)]
# 1.2 Verifier toutes les actions de JOUER
for action in actions_legales_nouvel_etat:
action_cle = action
initialiser_q_valeur(nouvel_etat, action_cle)
q_val = Q_TABLE[nouvel_etat][action_cle]
if q_val > max_q_nouvel_etat:
max_q_nouvel_etat = q_val
# 2. Appliquer la formule de Bellman (Q-Learning)
ancienne_q=Q_TABLE[etat_precedent][action_precedente]
nouvelle_q=(1-ALPHA) * ancienne_q+ALPHA*(recompense+GAMMA*max_q_nouvel_etat)
Q_TABLE[etat_precedent][action_precedente]=nouvelle_q
def charger_q_table():
global Q_TABLE
# Pas de persistance, on retourne la table actuelle
return Q_TABLE
def sauvegarder_q_table(q_table):
# Pas de persistance.
pass
def obtenir_recompense(taille_main_apres, taille_main_avant):
if taille_main_apres < taille_main_avant:
return 1
elif taille_main_apres > taille_main_avant:
return -10
else:
# A du piocher mais n'a pas pu jouer, ou a joue une carte "inutile"
return -5
import trys as t
from uno_rules import Colors, Val_spe, Val_digits, W_cards, W_count, Nbr_cards_init, piocher_carte_aleatoire, appliquer_penalite, recycler_defausse, calculer_score
from ia_learning import charger_q_table, sauvegarder_q_table, generer_etat_uno, choisir_action_apprentissage, obtenir_recompense, mettre_a_jour_q_table
# Charger la Q-Table au debut du script
Q_TABLE = charger_q_table()
HISTORIQUE_IA = []
def creer_paquet_classique():
paquet = []
# Cartes chiffrees (0-9)
for couleur in Colors:
# Un seul '0' par couleur
paquet.append(('0',couleur,"0"))
# Deux de chaque chiffre (1-9)
for valeur in Val_digits[1:]:
paquet.append((valeur,couleur,"0"))
paquet.append((valeur,couleur,"1"))
# Cartes d'action (+2, I, PTT)
for couleur in Colors:
for valeur in Val_spe:
paquet.append((valeur,valeur,"0"))
paquet.append((valeur,couleur,"1"))
# Cartes sauvages (W, +4)
for valeur in W_cards:
for _ in range(W_count): # 4 cartes de chaque type (W, +4)
paquet.append((valeur,"","0"))
return r.shuffle(paquet)
def verifier_validite_uno_classique(carte_jouee, carte_defausse_tuple, couleur_actuelle):
couleur_jouee, valeur_jouee = carte_jouee
# Les cartes Joker ('N') sont toujours valides
if couleur_jouee == 'N':
return True
# La carte doit correspondre a la couleur actuelle ou a la valeur de la carte du dessus
return (couleur_jouee == couleur_actuelle or
valeur_jouee == carte_defausse_tuple[1])
def choisir_couleur_ia_classique(main_ia):
comptage_couleurs = {'R': 0, 'V': 0, 'B': 0, 'J': 0}
for couleur, _ in main_ia:
if couleur in comptage_couleurs:
comptage_couleurs[couleur] += 1
# Trouver la couleur avec le compte maximal
couleur_choisie = 'R' # Couleur par defaut
max_count = -1
for couleur, count in comptage_couleurs.items():
if count > max_count:
max_count = count
couleur_choisie = couleur
# Si egalite, on choisit aleatoirement parmi les meilleures options
best_colors = [c for c, count in comptage_couleurs.items() if count == max_count]
# Utilise 'random.choice' de l'import 'random'
return random.choice(best_colors)
def jouer_tour_ia_classique(main_ia, carte_defausse_tuple, couleur_actuelle, nbr_manches_jouees):
global Q_TABLE, HISTORIQUE_IA
# 1. Generer la liste des actions possibles
actions_possibles = []
# Cartes jouables (y compris les Jokers)
cartes_jouables = [
carte for carte in main_ia
if verifier_validite_uno_classique(carte, carte_defausse_tuple, couleur_actuelle)
]
# Creer la liste des actions pour la Q-Table: (carte, couleur_choisie)
for carte in cartes_jouables:
couleur, valeur = carte
if couleur == 'N': # Joker ou +4
# L'action inclut le choix de la couleur
for c in Colors:
actions_possibles.append((carte, c))
else:
# L'action n'inclut que la carte jouee (la couleur est celle de la carte)
actions_possibles.append((carte, couleur))
# Ajouter l'action de pioche
actions_possibles.append(VALEUR_PIOCHE)
# 2. Generer l'etat actuel
etat_actuel = generer_etat_uno_classique(main_ia, carte_defausse_tuple, couleur_actuelle)
# 3. Choisir l'action (Exploration ou Exploitation)
action_choisie_tuple = choisir_action_apprentissage(Q_TABLE, etat_actuel, actions_possibles, nbr_manches_jouees)
# 4. Enregistrer l'etat et l'action pour la mise a jour future
if action_choisie_tuple:
HISTORIQUE_IA.append({
'etat_precedent': etat_actuel,
'action_precedente': action_choisie_tuple,
'nbr_cartes_avant': len(main_ia)
})
# L'action est soit (carte, couleur_choisie) ou ('P', None)
if action_choisie_tuple[0] == 'P':
return (None, None, 'Piocher') # Pas de carte jouee, pas de couleur choisie
else:
carte_jouee, couleur_choisie = action_choisie_tuple
return (carte_jouee, couleur_choisie, 'Jouer')
def jouer_une_manche_classique(joueur_a_commencer, nbr_manches_jouees):
global Q_TABLE, HISTORIQUE_IA
paquet = creer_paquet_classique()
main_joueur_1 = piocher_carte_aleatoire(paquet, Nbr_cards_init)
main_joueur_2 = piocher_carte_aleatoire(paquet, Nbr_cards_init)
defausse_pile = []
# Tirer la premiere carte de defausse
while True:
carte_initiale = piocher_carte_aleatoire(paquet, 1)[0]
# La carte initiale ne peut pas etre une carte speciale (pour simplification)
if carte_initiale[0] != 'N' and carte_initiale[1] not in Val_spe:
defausse_pile.append(carte_initiale)
break
else:
# Remettre la carte dans le paquet (pas de melange)
paquet.append(carte_initiale)
# Etat initial du jeu
etat_tour = {
'sens_horaire': True,
'couleur_actuelle': defausse_pile[-1][0], # Couleur de la premiere carte
'sauter_tour_suivant': False,
'total_cartes_a_piocher': 0
}
joueur_courant = joueur_a_commencer
manche_terminee = False
gagnant = None
HISTORIQUE_IA = [] # Reinitialiser l'historique de l'IA pour la nouvelle manche
print("Premiere carte: %s de couleur %s" % (defausse_pile[-1][1], etat_tour['couleur_actuelle']))
while not manche_terminee:
carte_jouee = None
action_valide = False
couleur_choisie_par_joker = None
# 1. Gerer les cartes a piocher (+2 ou +4 empiles)
if etat_tour['total_cartes_a_piocher'] > 0:
penalite = etat_tour['total_cartes_a_piocher']
print("Penalite de %d cartes a appliquer." % penalite)
if joueur_courant == 1:
appliquer_penalite(main_joueur_1, paquet, defausse_pile[-1], penalite)
else: # IA
appliquer_penalite(main_joueur_2, paquet, defausse_pile[-1], penalite)
# Reinitialiser la penalite apres application
etat_tour['total_cartes_a_piocher'] = 0
# Passer au joueur suivant
joueur_courant = 3 - joueur_courant
continue # Fin du tour actuel, passage au suivant
# 2. Gestion du tour saute (PTT)
if etat_tour['sauter_tour_suivant']:
print("Tour saute pour le Joueur %d." % joueur_courant)
etat_tour['sauter_tour_suivant'] = False
joueur_courant = 3 - joueur_courant
continue # Fin du tour actuel, passage au suivant
# 3. Tour du Joueur 1
if joueur_courant==1:
while not action_valide:
k=d.pagination_cartes(defausse_pile[-1],main_joueur_1)
if k=='P':
# Action Piocher
cartes_piochees = piocher_carte_aleatoire(paquet, 1)
main_joueur_1.extend(cartes_piochees)
print("Vous piochez : %s" % str(cartes_piochees[0]))
# Offrir de jouer la carte piochee si elle est valide
carte_piochee = cartes_piochees[0]
if verifier_validite_uno_classique(carte_piochee, defausse_pile[-1], etat_tour['couleur_actuelle']):
# Retrait des accents dans l'invite
jouer_pioche =input("Voulez-vous jouer la carte piochee %s (O/N) ? " % str(carte_piochee)).upper()
if jouer_pioche == 'O':
carte_jouee = carte_piochee
main_joueur_1.remove(carte_jouee)
action_valide = True
if carte_jouee[0] == 'N': # Choix de couleur pour Joker/+4
print("Choisissez une couleur (R, V, B, J):")
couleur_choisie_par_joker = t.trys(input("Couleur: ").upper(), 1, 1, options=Colors)
action_valide = True # Termine le tour (soit en jouant, soit sans jouer)
else:
index_carte =k-1
carte_tentative = main_joueur_1[index_carte]
if verifier_validite_uno_classique(carte_tentative, defausse_pile[-1], etat_tour['couleur_actuelle']):
carte_jouee = carte_tentative
main_joueur_1.pop(index_carte)
action_valide = True
if carte_jouee[0] == 'N': # Choix de couleur pour Joker/+4
print("Choisissez une couleur (R, V, B, J):")
couleur_choisie_par_joker = t.trys(input("Couleur: ").upper(), 1, 1, options=Colors)
else:
# Retrait des accents
print("Carte invalide. ")
if action_valide and carte_jouee:
print("Vous jouez :%s." % str(carte_jouee))
# 4. Tour de l'IA (2)
else: # joueur_courant == 2
print("\n---------------------\nTour de l'IA (Joueur 2) - Cartes: %d" % len(main_joueur_2))
print("Defausse: %s " % (defausse_pile[-1]))
# Obtenir l'action de l'IA (carte_jouee, couleur_choisie, type_action)
action_result=jouer_tour_ia_classique(main_joueur_2, defausse_pile[-1], etat_tour['couleur_actuelle'], nbr_manches_jouees)
carte_jouee, couleur_choisie_par_joker, type_action = action_result
if type_action == 'Piocher':
# Action Piocher
cartes_piochees = piocher_carte_aleatoire(paquet, 1)
main_joueur_2.extend(cartes_piochees)
print("L'IA pioche 1 carte.")
# L'IA ne joue pas la carte piochee dans cette implementation simple
action_valide = True
elif type_action == 'Jouer':
# Action Jouer
if carte_jouee and carte_jouee in main_joueur_2:
main_joueur_2.remove(carte_jouee)
print("L'IA joue %s." % str(carte_jouee))
if carte_jouee[0] == 'N':
# Utiliser la strategie pour choisir la couleur si l'action choisie l'autorise
if couleur_choisie_par_joker is None:
# Si le choix de l'action Q-Learning n'a pas inclus de couleur (car c'est un Joker),
# l'IA applique sa strategie ici.
couleur_choisie_par_joker = choisir_couleur_ia_classique(main_joueur_2)
print("L'IA choisit la couleur %s" % couleur_choisie_par_joker)
action_valide = True
else:
# Retrait des accents
print("Erreur: L'IA a choisi une action invalide ou une carte non posee. Piocher par defaut.")
cartes_piochees = piocher_carte_aleatoire(paquet, 1)
main_joueur_2.extend(cartes_piochees)
action_valide = True # Le tour se termine par une pioche
# 5. Application des effets de la carte jouee
if carte_jouee and action_valide:
couleur_carte_jouee, valeur_carte_jouee = carte_jouee
defausse_pile.append(carte_jouee)
# Mise a jour de la couleur actuelle (couleur de la carte jouee ou couleur choisie par Joker)
if couleur_choisie_par_joker:
etat_tour['couleur_actuelle'] = couleur_choisie_par_joker
else:
etat_tour['couleur_actuelle'] = couleur_carte_jouee
# Effets de carte
if valeur_carte_jouee == '+2':
etat_tour['total_cartes_a_piocher'] += 2
etat_tour['sauter_tour_suivant'] = True
elif valeur_carte_jouee == 'I': # Inversion
etat_tour['sens_horaire'] = not etat_tour['sens_horaire']
elif valeur_carte_jouee == 'PTT': # Passe Ton Tour
etat_tour['sauter_tour_suivant'] = True
elif valeur_carte_jouee == '+4':
etat_tour['total_cartes_a_piocher'] += 4
etat_tour['sauter_tour_suivant'] = True
# Verification de fin de manche (main vide)
if joueur_courant == 1 and not main_joueur_1:
gagnant = 1
manche_terminee = True
elif joueur_courant == 2 and not main_joueur_2:
gagnant = 2
manche_terminee = True
# 6. Gestion du paquet vide
if not paquet:
# Note: recycler_defausse ne melange plus le paquet
recycler_defausse(paquet, defausse_pile)
# Retrait des accents
print("Paquet recycle.")
if not paquet:
# Retrait des accents
print("La defausse etait trop petite. Fin de manche par manque de cartes.")
manche_terminee = True
if len(main_joueur_1) < len(main_joueur_2):
gagnant = 1
else:
gagnant = 2
# 7. Mise a jour de la Q-Table de l'IA apres son tour
if joueur_courant == 2 and HISTORIQUE_IA and action_valide:
derniere_action_ia = HISTORIQUE_IA.pop()
# L'etat actuel de la partie pour l'IA est l'etat du joueur 1 a son tour
etat_actuel_ia = generer_etat_uno_classique(main_joueur_1, defausse_pile[-1], etat_tour['couleur_actuelle'])
recompense = obtenir_recompense(
game_mode = 'UNO_CL',
victoire_ia = (gagnant == 2 if manche_terminee else False),
nbr_cartes_avant = derniere_action_ia['nbr_cartes_avant'],
nbr_cartes_apres = len(main_joueur_2),
action_carte = derniere_action_ia['action_precedente'],
main_ia_apres = main_joueur_2
)
mettre_a_jour_q_table(
Q_TABLE,
derniere_action_ia['etat_precedent'],
derniere_action_ia['action_precedente'],
recompense,
etat_actuel_ia
)
if not manche_terminee and action_valide:
# Passage au joueur suivant (gestion de l'inversion par le 'sens_horaire')
if etat_tour['sens_horaire']:
joueur_courant = 3 - joueur_courant
else:
# Dans un jeu a 2 joueurs, Inversion ne change pas de joueur, on reste sur le meme
pass
# Fin de manche
if gagnant is None:
# Si la manche s'est terminee prematurement (paquet vide)
gagnant = 1 if len(main_joueur_1) < len(main_joueur_2) else 2
perdant = 3 - gagnant
if gagnant == 1:
points_marque_par_perdant = calculer_score(main_joueur_2, 'UNO')
else:
points_marque_par_perdant = calculer_score(main_joueur_1, 'UNO')
else:
perdant = 3 - gagnant
if gagnant == 1:
points_marque_par_perdant = calculer_score(main_joueur_2, 'UNO')
else:
points_marque_par_perdant = calculer_score(main_joueur_1, 'UNO')
# Sauvegarde de la Q-Table
sauvegarder_q_table(Q_TABLE)
print("\n=============================================")
# Retrait des accents et f-string
print("FIN DE MANCHE UNO CLASSIQUE ! Le Joueur %d a gagne." % gagnant)
print("Le Joueur %d marque %d points." % (perdant, points_marque_par_perdant))
print("Taille de la Q-Table : %d etats UNO_CL appris." % len([k for k in Q_TABLE.keys() if 'UNO_CL' in k]))
print("=============================================\n")
return gagnant, points_marque_par_perdant
import trys as t
from uno_rules import Colors, Val_spe, Val_digits, W_cards, W_count, Nbr_cards_init, piocher_carte_aleatoire, appliquer_penalite, recycler_defausse, calculer_score
from ia_learning import charger_q_table, sauvegarder_q_table, generer_etat_uno, choisir_action_apprentissage, obtenir_recompense, mettre_a_jour_q_table
# Charger la Q-Table au debut du script
Q_TABLE = charger_q_table()
HISTORIQUE_IA = []
def creer_paquet_classique():
paquet = []
# Cartes chiffrees (0-9)
for couleur in Colors:
# Un seul '0' par couleur
paquet.append(('0',couleur,"0"))
# Deux de chaque chiffre (1-9)
for valeur in Val_digits[1:]:
paquet.append((valeur,couleur,"0"))
paquet.append((valeur,couleur,"1"))
# Cartes d'action (+2, I, PTT)
for couleur in Colors:
for valeur in Val_spe:
paquet.append((valeur,valeur,"0"))
paquet.append((valeur,couleur,"1"))
# Cartes sauvages (W, +4)
for valeur in W_cards:
for _ in range(W_count): # 4 cartes de chaque type (W, +4)
paquet.append((valeur,"","0"))
return r.shuffle(paquet)
def verifier_validite_uno_classique(carte_jouee, carte_defausse_tuple, couleur_actuelle):
couleur_jouee, valeur_jouee = carte_jouee
# Les cartes Joker ('N') sont toujours valides
if couleur_jouee == 'N':
return True
# La carte doit correspondre a la couleur actuelle ou a la valeur de la carte du dessus
return (couleur_jouee == couleur_actuelle or
valeur_jouee == carte_defausse_tuple[1])
def choisir_couleur_ia_classique(main_ia):
comptage_couleurs = {'R': 0, 'V': 0, 'B': 0, 'J': 0}
for couleur, _ in main_ia:
if couleur in comptage_couleurs:
comptage_couleurs[couleur] += 1
# Trouver la couleur avec le compte maximal
couleur_choisie = 'R' # Couleur par defaut
max_count = -1
for couleur, count in comptage_couleurs.items():
if count > max_count:
max_count = count
couleur_choisie = couleur
# Si egalite, on choisit aleatoirement parmi les meilleures options
best_colors = [c for c, count in comptage_couleurs.items() if count == max_count]
# Utilise 'random.choice' de l'import 'random'
return random.choice(best_colors)
def jouer_tour_ia_classique(main_ia, carte_defausse_tuple, couleur_actuelle, nbr_manches_jouees):
global Q_TABLE, HISTORIQUE_IA
# 1. Generer la liste des actions possibles
actions_possibles = []
# Cartes jouables (y compris les Jokers)
cartes_jouables = [
carte for carte in main_ia
if verifier_validite_uno_classique(carte, carte_defausse_tuple, couleur_actuelle)
]
# Creer la liste des actions pour la Q-Table: (carte, couleur_choisie)
for carte in cartes_jouables:
couleur, valeur = carte
if couleur == 'N': # Joker ou +4
# L'action inclut le choix de la couleur
for c in Colors:
actions_possibles.append((carte, c))
else:
# L'action n'inclut que la carte jouee (la couleur est celle de la carte)
actions_possibles.append((carte, couleur))
# Ajouter l'action de pioche
actions_possibles.append(VALEUR_PIOCHE)
# 2. Generer l'etat actuel
etat_actuel = generer_etat_uno_classique(main_ia, carte_defausse_tuple, couleur_actuelle)
# 3. Choisir l'action (Exploration ou Exploitation)
action_choisie_tuple = choisir_action_apprentissage(Q_TABLE, etat_actuel, actions_possibles, nbr_manches_jouees)
# 4. Enregistrer l'etat et l'action pour la mise a jour future
if action_choisie_tuple:
HISTORIQUE_IA.append({
'etat_precedent': etat_actuel,
'action_precedente': action_choisie_tuple,
'nbr_cartes_avant': len(main_ia)
})
# L'action est soit (carte, couleur_choisie) ou ('P', None)
if action_choisie_tuple[0] == 'P':
return (None, None, 'Piocher') # Pas de carte jouee, pas de couleur choisie
else:
carte_jouee, couleur_choisie = action_choisie_tuple
return (carte_jouee, couleur_choisie, 'Jouer')
def jouer_une_manche_classique(joueur_a_commencer, nbr_manches_jouees):
global Q_TABLE, HISTORIQUE_IA
paquet = creer_paquet_classique()
main_joueur_1 = piocher_carte_aleatoire(paquet, Nbr_cards_init)
main_joueur_2 = piocher_carte_aleatoire(paquet, Nbr_cards_init)
defausse_pile = []
# Tirer la premiere carte de defausse
while True:
carte_initiale = piocher_carte_aleatoire(paquet, 1)[0]
# La carte initiale ne peut pas etre une carte speciale (pour simplification)
if carte_initiale[0] != 'N' and carte_initiale[1] not in Val_spe:
defausse_pile.append(carte_initiale)
break
else:
# Remettre la carte dans le paquet (pas de melange)
paquet.append(carte_initiale)
# Etat initial du jeu
etat_tour = {
'sens_horaire': True,
'couleur_actuelle': defausse_pile[-1][0], # Couleur de la premiere carte
'sauter_tour_suivant': False,
'total_cartes_a_piocher': 0
}
joueur_courant = joueur_a_commencer
manche_terminee = False
gagnant = None
HISTORIQUE_IA = [] # Reinitialiser l'historique de l'IA pour la nouvelle manche
print("Premiere carte: %s de couleur %s" % (defausse_pile[-1][1], etat_tour['couleur_actuelle']))
while not manche_terminee:
carte_jouee = None
action_valide = False
couleur_choisie_par_joker = None
# 1. Gerer les cartes a piocher (+2 ou +4 empiles)
if etat_tour['total_cartes_a_piocher'] > 0:
penalite = etat_tour['total_cartes_a_piocher']
print("Penalite de %d cartes a appliquer." % penalite)
if joueur_courant == 1:
appliquer_penalite(main_joueur_1, paquet, defausse_pile[-1], penalite)
else: # IA
appliquer_penalite(main_joueur_2, paquet, defausse_pile[-1], penalite)
# Reinitialiser la penalite apres application
etat_tour['total_cartes_a_piocher'] = 0
# Passer au joueur suivant
joueur_courant = 3 - joueur_courant
continue # Fin du tour actuel, passage au suivant
# 2. Gestion du tour saute (PTT)
if etat_tour['sauter_tour_suivant']:
print("Tour saute pour le Joueur %d." % joueur_courant)
etat_tour['sauter_tour_suivant'] = False
joueur_courant = 3 - joueur_courant
continue # Fin du tour actuel, passage au suivant
# 3. Tour du Joueur 1
if joueur_courant==1:
while not action_valide:
k=d.pagination_cartes(defausse_pile[-1],main_joueur_1)
if k=='P':
# Action Piocher
cartes_piochees = piocher_carte_aleatoire(paquet, 1)
main_joueur_1.extend(cartes_piochees)
print("Vous piochez : %s" % str(cartes_piochees[0]))
# Offrir de jouer la carte piochee si elle est valide
carte_piochee = cartes_piochees[0]
if verifier_validite_uno_classique(carte_piochee, defausse_pile[-1], etat_tour['couleur_actuelle']):
# Retrait des accents dans l'invite
jouer_pioche =input("Voulez-vous jouer la carte piochee %s (O/N) ? " % str(carte_piochee)).upper()
if jouer_pioche == 'O':
carte_jouee = carte_piochee
main_joueur_1.remove(carte_jouee)
action_valide = True
if carte_jouee[0] == 'N': # Choix de couleur pour Joker/+4
print("Choisissez une couleur (R, V, B, J):")
couleur_choisie_par_joker = t.trys(input("Couleur: ").upper(), 1, 1, options=Colors)
action_valide = True # Termine le tour (soit en jouant, soit sans jouer)
else:
index_carte =k-1
carte_tentative = main_joueur_1[index_carte]
if verifier_validite_uno_classique(carte_tentative, defausse_pile[-1], etat_tour['couleur_actuelle']):
carte_jouee = carte_tentative
main_joueur_1.pop(index_carte)
action_valide = True
if carte_jouee[0] == 'N': # Choix de couleur pour Joker/+4
print("Choisissez une couleur (R, V, B, J):")
couleur_choisie_par_joker = t.trys(input("Couleur: ").upper(), 1, 1, options=Colors)
else:
# Retrait des accents
print("Carte invalide. ")
if action_valide and carte_jouee:
print("Vous jouez :%s." % str(carte_jouee))
# 4. Tour de l'IA (2)
else: # joueur_courant == 2
print("\n---------------------\nTour de l'IA (Joueur 2) - Cartes: %d" % len(main_joueur_2))
print("Defausse: %s " % (defausse_pile[-1]))
# Obtenir l'action de l'IA (carte_jouee, couleur_choisie, type_action)
action_result=jouer_tour_ia_classique(main_joueur_2, defausse_pile[-1], etat_tour['couleur_actuelle'], nbr_manches_jouees)
carte_jouee, couleur_choisie_par_joker, type_action = action_result
if type_action == 'Piocher':
# Action Piocher
cartes_piochees = piocher_carte_aleatoire(paquet, 1)
main_joueur_2.extend(cartes_piochees)
print("L'IA pioche 1 carte.")
# L'IA ne joue pas la carte piochee dans cette implementation simple
action_valide = True
elif type_action == 'Jouer':
# Action Jouer
if carte_jouee and carte_jouee in main_joueur_2:
main_joueur_2.remove(carte_jouee)
print("L'IA joue %s." % str(carte_jouee))
if carte_jouee[0] == 'N':
# Utiliser la strategie pour choisir la couleur si l'action choisie l'autorise
if couleur_choisie_par_joker is None:
# Si le choix de l'action Q-Learning n'a pas inclus de couleur (car c'est un Joker),
# l'IA applique sa strategie ici.
couleur_choisie_par_joker = choisir_couleur_ia_classique(main_joueur_2)
print("L'IA choisit la couleur %s" % couleur_choisie_par_joker)
action_valide = True
else:
# Retrait des accents
print("Erreur: L'IA a choisi une action invalide ou une carte non posee. Piocher par defaut.")
cartes_piochees = piocher_carte_aleatoire(paquet, 1)
main_joueur_2.extend(cartes_piochees)
action_valide = True # Le tour se termine par une pioche
# 5. Application des effets de la carte jouee
if carte_jouee and action_valide:
couleur_carte_jouee, valeur_carte_jouee = carte_jouee
defausse_pile.append(carte_jouee)
# Mise a jour de la couleur actuelle (couleur de la carte jouee ou couleur choisie par Joker)
if couleur_choisie_par_joker:
etat_tour['couleur_actuelle'] = couleur_choisie_par_joker
else:
etat_tour['couleur_actuelle'] = couleur_carte_jouee
# Effets de carte
if valeur_carte_jouee == '+2':
etat_tour['total_cartes_a_piocher'] += 2
etat_tour['sauter_tour_suivant'] = True
elif valeur_carte_jouee == 'I': # Inversion
etat_tour['sens_horaire'] = not etat_tour['sens_horaire']
elif valeur_carte_jouee == 'PTT': # Passe Ton Tour
etat_tour['sauter_tour_suivant'] = True
elif valeur_carte_jouee == '+4':
etat_tour['total_cartes_a_piocher'] += 4
etat_tour['sauter_tour_suivant'] = True
# Verification de fin de manche (main vide)
if joueur_courant == 1 and not main_joueur_1:
gagnant = 1
manche_terminee = True
elif joueur_courant == 2 and not main_joueur_2:
gagnant = 2
manche_terminee = True
# 6. Gestion du paquet vide
if not paquet:
# Note: recycler_defausse ne melange plus le paquet
recycler_defausse(paquet, defausse_pile)
# Retrait des accents
print("Paquet recycle.")
if not paquet:
# Retrait des accents
print("La defausse etait trop petite. Fin de manche par manque de cartes.")
manche_terminee = True
if len(main_joueur_1) < len(main_joueur_2):
gagnant = 1
else:
gagnant = 2
# 7. Mise a jour de la Q-Table de l'IA apres son tour
if joueur_courant == 2 and HISTORIQUE_IA and action_valide:
derniere_action_ia = HISTORIQUE_IA.pop()
# L'etat actuel de la partie pour l'IA est l'etat du joueur 1 a son tour
etat_actuel_ia = generer_etat_uno_classique(main_joueur_1, defausse_pile[-1], etat_tour['couleur_actuelle'])
recompense = obtenir_recompense(
game_mode = 'UNO_CL',
victoire_ia = (gagnant == 2 if manche_terminee else False),
nbr_cartes_avant = derniere_action_ia['nbr_cartes_avant'],
nbr_cartes_apres = len(main_joueur_2),
action_carte = derniere_action_ia['action_precedente'],
main_ia_apres = main_joueur_2
)
mettre_a_jour_q_table(
Q_TABLE,
derniere_action_ia['etat_precedent'],
derniere_action_ia['action_precedente'],
recompense,
etat_actuel_ia
)
if not manche_terminee and action_valide:
# Passage au joueur suivant (gestion de l'inversion par le 'sens_horaire')
if etat_tour['sens_horaire']:
joueur_courant = 3 - joueur_courant
else:
# Dans un jeu a 2 joueurs, Inversion ne change pas de joueur, on reste sur le meme
pass
# Fin de manche
if gagnant is None:
# Si la manche s'est terminee prematurement (paquet vide)
gagnant = 1 if len(main_joueur_1) < len(main_joueur_2) else 2
perdant = 3 - gagnant
if gagnant == 1:
points_marque_par_perdant = calculer_score(main_joueur_2, 'UNO')
else:
points_marque_par_perdant = calculer_score(main_joueur_1, 'UNO')
else:
perdant = 3 - gagnant
if gagnant == 1:
points_marque_par_perdant = calculer_score(main_joueur_2, 'UNO')
else:
points_marque_par_perdant = calculer_score(main_joueur_1, 'UNO')
# Sauvegarde de la Q-Table
sauvegarder_q_table(Q_TABLE)
print("\n=============================================")
# Retrait des accents et f-string
print("FIN DE MANCHE UNO CLASSIQUE ! Le Joueur %d a gagne." % gagnant)
print("Le Joueur %d marque %d points." % (perdant, points_marque_par_perdant))
print("Taille de la Q-Table : %d etats UNO_CL appris." % len([k for k in Q_TABLE.keys() if 'UNO_CL' in k]))
print("=============================================\n")
return gagnant, points_marque_par_perdant
import ia_learning as ia # Importation du module d'apprentissage
import uno_rules as rules
import display as d
from uno_rules import Colors, Val_digits, Val_spe, W_cards, EXTREME_ACTION_SPE, EXTREME_W_CARDS, Nbr_cards_init_extreme
# --- CONSTANTES SPÉCIFIQUES À UNO EXTRÊME ---
GAME_MODE ='UNO_EX'
ALL_EXTREME_ACTIONS = Val_spe + EXTREME_ACTION_SPE
ALL_EXTREME_WILDS = W_cards + EXTREME_W_CARDS
def gerer_etat_uno_extreme():
etat = {
'sens_horaire': True, # True = sens horaire, False = sens anti-horaire
'couleur_actuelle': None, # Couleur de la carte du dessus
'uno_crie_joueur_1': False,
'uno_crie_joueur_2': False,
'sauter_tour_suivant': False, # Gère l'effet PTT, +2, +4, +6, +8W
'total_cartes_a_piocher': 0 # Compteur pour les cartes empilées
}
return etat
def verifier_validite_extreme(carte_jouee, carte_defausse_tuple, couleur_actuelle):
couleur_jouee, valeur_jouee = carte_jouee
# Règle de base : correspondance de couleur, de valeur ou Joker
return (couleur_jouee == couleur_actuelle or # Correspondance de couleur choisie
valeur_jouee == carte_defausse_tuple[1] or # Correspondance de valeur
couleur_jouee == 'N')
def gerer_effet_carte_extreme(carte_jouee, joueur_courant, paquet, defausse_pile, main_joueur_1, main_joueur_2, etat_tour):
couleur, valeur = carte_jouee
prochain_joueur = 3 - joueur_courant
main_cible = main_joueur_1 if prochain_joueur == 1 else main_joueur_2
# Effets de pioche (+2, +4, +6, +8W)
if valeur in ['+2', '+4', '+6', '+8W']:
pioche_valeur=int(valeur.replace('+', '').replace('W', ''))
etat_tour['total_cartes_a_piocher'] += pioche_valeur
print("La pioche est augmentee de {} cartes.".format(pioche_valeur))
# Le prochain joueur doit piocher ou jouer une carte +
etat_tour['sauter_tour_suivant'] = True
# Effets de saut de tour (I, PTT)
if valeur in ['I', 'PTT']:
etat_tour['sauter_tour_suivant'] = True
if valeur == 'I':
etat_tour['sens_horaire'] = not etat_tour['sens_horaire']
print("Le sens de jeu est inversé.")
if valeur == 'PTT':
print("Le prochain joueur passe son tour.")
# Effets Extrêmes Spécifiques
if valeur == 'PA': # Poser Tout (Poser toutes les cartes de même couleur que la carte jouée)
cartes_a_garder = []
cartes_defaussees_supp = []
main_joueur = main_joueur_1 if joueur_courant == 1 else main_joueur_2
for carte in main_joueur:
if carte[0] == etat_tour['couleur_actuelle']:
cartes_defaussees_supp.append(carte)
else:
cartes_a_garder.append(carte)
main_joueur[:] = cartes_a_garder
defausse_pile.extend(cartes_defaussees_supp)
if cartes_defaussees_supp:
input("Joueur {} a pose\nTOUTES les cartes\n{} en plus\n({} cartes)!".format(joueur_courant,etat_tour['couleur_actuelle'],len(cartes_defaussees_supp)))
else:
input("Joueur {} a pose\nPA mais n'avait\npas d'autres cartes\n{} a poser.".format(joueur_courant,etat_tour['couleur_actulle']))
elif valeur == 'DA': # Défausser tout (Le joueur choisit une couleur et l'adversaire défausse toutes ses cartes de cette couleur)
# Le joueur qui a posé le DA choisit une couleur
couleur_choisie = t.get_color_choice(joueur_courant)
cartes_a_garder = []
cartes_defaussees_supp = []
for carte in main_cible:
if carte[0] == couleur_choisie:
cartes_defaussees_supp.append(carte)
else:
cartes_a_garder.append(carte)
main_cible[:] = cartes_a_garder
defausse_pile.extend(cartes_defaussees_supp)
if cartes_defaussees_supp:
input("L'adversaire (Joueur {}) doit defausser {} cartes {}.".format(prochain_joueur,len(cartes_defauses_supp),couleur_choisie))
else:
input("L'adversaire (Joueur {}) n'avait pas de cartes {} a defausser.".format(prochain_joueur,couleur_choisie))
return etat_tour
def jouer_une_manche_extreme(joueur_a_commencer, game_type):
# INITIALISATION DE LA Q-TABLE EN MÉMOIRE
Q_TABLE = ia.charger_q_table()
# 1. Initialisation de la manche
paquet_pioche = rules.creer_paquet_uno_extreme()
main_joueur_1 = rules.piocher_carte_aleatoire(paquet_pioche, Nbr_cards_init_extreme)
main_joueur_2 = rules.piocher_carte_aleatoire(paquet_pioche, Nbr_cards_init_extreme)
defausse_pile = rules.piocher_carte_aleatoire(paquet_pioche, 1)
# Assurer que la première carte n'est pas une carte spéciale (pour l'instant, on simplifie)
while defausse_pile[0][1] in ALL_EXTREME_ACTIONS + ALL_EXTREME_WILDS:
paquet_pioche.insert(0, defausse_pile.pop(0))
r.shuffle(paquet_pioche)
defausse_pile.extend(rules.piocher_carte_aleatoire(paquet_pioche, 1))
etat_tour = gerer_etat_uno_extreme()
etat_tour['couleur_actuelle'] = defausse_pile[-1][0]
joueur_courant = joueur_a_commencer
manche_terminee = False
derniere_action_ia = None # Pour l'apprentissage
print("Debut de manche.\nPremiere carte :{}.\nCouleur actuelle:\n{}".format(defausse-pile[-1],eta_tour['couleur_actuelle']))
while not manche_terminee:
# 2. Gestion des états et de l'affichage
carte_jouee = None
couleur_choisie = None
action_valide = False
if not paquet_pioche and len(defausse_pile) > 1:
rules.recycler_defausse(paquet_pioche, defausse_pile)
elif not paquet_pioche and len(defausse_pile) <= 1:
print("Paquet et défausse vides, fin de manche par manque de cartes.")
break
print("C'est au Joueur {}!".format(joueur_courant))
# Gestion de l'effet de pioche empilé
if etat_tour['total_cartes_a_piocher'] > 0:
print("Pioche en cours :{} cartes a prendre (ou a contrer).".format(etat_tour['total_cartes_a_piocher']))
if joueur_courant == 1:
jouer_ou_piocher = t.trys(input("Voulez-vous tenter de contrer avec un '+' (o/n) ?"), 'on', 'n')
main_joueur = main_joueur_1
cartes_jouables_plus = [c for c in main_joueur if c[1] in ['+2', '+4', '+6', '+8W'] and verifier_validite_extreme(c, defausse_pile[-1], etat_tour['couleur_actuelle'])]
if jouer_ou_piocher.lower() == 'o' and cartes_jouables_plus:
t.afficher_main(main_joueur, [c for c in main_joueur if c in cartes_jouables_plus])
index_carte = t.trys_index(input("Choisissez l'index de la carte '+' à jouer (ou 'p' pour piocher) :"), len(main_joueur))
if index_carte != 'p':
carte_jouee = main_joueur.pop(index_carte)
action_valide = True
else:
action_valide = False
else:
print("Aucune carte '+' jouable ou choix de piocher. Pénalité appliquée.")
action_valide = False
else: # IA
main_joueur = main_joueur_2
cartes_jouables_plus = [c for c in main_joueur if c[1] in ['+2', '+4', '+6', '+8W'] and verifier_validite_extreme(c, defausse_pile[-1], etat_tour['couleur_actuelle'])]
if cartes_jouables_plus:
carte_jouee = r.choice(cartes_jouables_plus)
main_joueur.remove(carte_jouee)
action_valide = True
print("L'IA contre avec {}.".format(carte_jouee))
else:
print("L'IA n'a pas pu contrer.")
action_valide = False
if not action_valide:
# Appliquer la pénalité et réinitialiser le compteur de pioche
rules.appliquer_penalite(main_joueur_1 if joueur_courant == 1 else main_joueur_2, paquet_pioche, defausse_pile[-1], etat_tour['total_cartes_a_piocher'])
etat_tour['total_cartes_a_piocher'] = 0
etat_tour['sauter_tour_suivant'] = False
joueur_courant = 3 - joueur_courant
continue
# 3. Tour normal (pas de pioche empilée en cours)
if etat_tour['total_cartes_a_piocher'] == 0:
if joueur_courant == 1: # Joueur Humain
print("Defausse :{}.".format(defausse_pile[-1]))
t.afficher_main(main_joueur_1)
cartes_jouables = [
carte for carte in main_joueur_1
if verifier_validite_extreme(carte, defausse_pile[-1], etat_tour['couleur_actuelle'])
]
if cartes_jouables:
t.afficher_main(main_joueur_1, cartes_jouables)
index_carte = t.trys_index(input("Choisissez l'index de la carte à jouer (ou 'p' pour piocher):"), len(main_joueur_1))
if index_carte == 'p':
main_joueur_1.extend(rules.piocher_carte_aleatoire(paquet_pioche))
print("Vous piochez 1 carte.")
action_valide = True
else:
carte_jouee = main_joueur_1.pop(index_carte)
action_valide = True
else:
main_joueur_1.extend(rules.piocher_carte_aleatoire(paquet_pioche))
print("Aucune carte jouable. Vous piochez 1 carte et passez votre tour.")
action_valide = True
else: # Joueur IA (Apprentissage par renforcement)
main_joueur = main_joueur_2
etat_actuel_ia = ia.generer_etat_uno_classique(main_joueur_2, defausse_pile, GAME_MODE)
action_choisie = ia.choisir_action_apprentissage(Q_TABLE, etat_actuel_ia, main_joueur_2, defausse_pile, GAME_MODE)
if action_choisie == ia.VALEUR_PIOCHE:
main_joueur_2.extend(rules.piocher_carte_aleatoire(paquet_pioche))
print("L'IA pioche 1 carte.")
action_valide = True
carte_jouee = None
else:
carte_jouee, couleur_choisie = action_choisie
main_joueur_2.remove(carte_jouee)
print("L'IA joue {}.".format(carte_jouee))
action_valide = True
derniere_action_ia = {
'etat_precedent': etat_actuel_ia,
'action_precedente': action_choisie,
'nbr_cartes_avant': len(main_joueur_2) + (1 if carte_jouee else 0),
}
# 4. Traitement de la carte jouée
if action_valide and carte_jouee:
# 4a. Traitement des cartes Wild (Joker)
if carte_jouee[0] == 'N':
if joueur_courant == 1 and carte_jouee[1] in rules.W_cards + EXTREME_W_CARDS:
couleur_choisie = t.get_color_choice(joueur_courant)
if not couleur_choisie:
couleur_choisie = r.choice(rules.Colors)
# 4b. Mise à jour de la défausse et de la couleur actuelle
defausse_pile.append(carte_jouee)
etat_tour['couleur_actuelle'] = couleur_choisie if couleur_choisie else carte_jouee[0]
# 4c. Gestion des effets spéciaux
etat_tour = gerer_effet_carte_extreme(carte_jouee, joueur_courant, paquet_pioche, defausse_pile, main_joueur_1, main_joueur_2, etat_tour)
# 4d. Vérification de la fin de manche (main vide)
if not main_joueur_1 or not main_joueur_2:
manche_terminee = True
gagnant = 1 if not main_joueur_1 else 2
perdant = 3 - gagnant
main_perdant = main_joueur_2 if perdant == 2 else main_joueur_1
points_marque_par_perdant = rules.calculer_score(main_perdant, GAME_MODE)
# Mise à jour Q-Table finale (si l'IA a perdu/gagné)
if derniere_action_ia:
recompense = ia.obtenir_recompense(
game_mode=GAME_MODE,
victoire_ia=(gagnant == 2),
nbr_cartes_avant=derniere_action_ia['nbr_cartes_avant'],
nbr_cartes_apres=len(main_joueur_2),
action_carte=derniere_action_ia['action_precedente'],
main_ia_apres=main_joueur_2
)
ia.mettre_a_jour_q_table(
Q_TABLE,
derniere_action_ia['etat_precedent'],
derniere_action_ia['action_precedente'],
recompense,
None # État final
)
break
# 5. Mise à jour Q-Table (si le tour n'est pas terminé et que l'IA a joué)
if joueur_courant == 2 and derniere_action_ia and not manche_terminee:
etat_actuel_ia = ia.generer_etat_uno_classique(main_joueur_2, defausse_pile, GAME_MODE)
recompense = ia.obtenir_recompense(
game_mode = GAME_MODE,
victoire_ia = False,
nbr_cartes_avant = derniere_action_ia['nbr_cartes_avant'],
nbr_cartes_apres = len(main_joueur_2),
action_carte = derniere_action_ia['action_precedente'],
main_ia_apres = main_joueur_2
)
ia.mettre_a_jour_q_table(
Q_TABLE,
derniere_action_ia['etat_precedent'],
derniere_action_ia['action_precedente'],
recompense,
etat_actuel_ia
)
# 6. Passage au joueur suivant
if not manche_terminee and action_valide:
if etat_tour['total_cartes_a_piocher'] == 0 and etat_tour['sauter_tour_suivant']:
print("Joueur {} voit son tour sauté.".format(3-joueur_courant))
etat_tour['sauter_tour_suivant'] = False
else:
if etat_tour['sens_horaire']:
joueur_courant = 3 - joueur_courant
else:
joueur_courant = 3 - joueur_courant
elif not manche_terminee and action_valide and not carte_jouee:
joueur_courant = 3 - joueur_courant
# Résultat de la manche
if not manche_terminee:
score_j1 = rules.calculer_score(main_joueur_1, GAME_MODE)
score_j2 = rules.calculer_score(main_joueur_2, GAME_MODE)
gagnant = 1 if score_j1 < score_j2 else 2
perdant = 3 - gagnant
points_marque_par_perdant = max(score_j1, score_j2)
print("==================")
print("FIN DE MANCHE UNO EXTREME !\nLe Joueur {} a gagne.".format(gagnant))
print("Le Joueur {} marque {points_marque_par_perdant} points.".format(perdant,points_marque_par_perdant))
print("==================")
return gagnant, points_marque_par_perdant
from uno_rules import types_paquets
from uno_classique import jouer_une_manche_classique
from uno_dos import jouer_une_manche_dos
from uno_nomerci import jouer_une_manche_no_merci
from uno_extreme import jouer_une_manche_extreme
from uno_zero import jouer_une_manche_zero
def launch_uno():
name=input("Nom du joueur ?")
score_joueur_1=0
score_joueur_2=0
joueur_a_commencer_prochaine_manche=1
game_type=types_paquets()
if game_type==2:
game_function=jouer_une_manche_dos
game_name="DOS"
elif game_type==3:
game_function=jouer_une_manche_no_merci
game_name="UNO NoMerci"
elif game_type==4: # NOUVELLE OPTION
game_function=jouer_une_manche_extreme
game_name="UNO Extreme"
elif game_type==5:
game_function=jouer_une_manche_zero
game_name="UNO Zero"
else:
game_function=jouer_une_manche_classique
game_name="UNO Classique"
print("---------------------")
print("{} contre l'IA\nstrategique !".format(game_name))
print("Le premier joueur\ndont l'adversaire\naccumule 500 points\ngagne la partie.")
while True:
print("=====================")
print("Joueur 1: {} points\nIA : {} points".format(score_joueur_1, score_joueur_2))
print("La manche commence.\nJoueur {} debute.".format(joueur_a_commencer_prochaine_manche))
print("=====================")
gagnant,points_marque_par_perdant=game_function(joueur_a_commencer_prochaine_manche, game_type)
if gagnant == 1:
score_joueur_1+=points_marque_par_perdant
perdant=2
else:
score_joueur_2+=points_marque_par_perdant
perdant=1
joueur_a_commencer_prochaine_manche = perdant # L'adversaire commence la manche suivante
if score_joueur_1 >= 500:
print("\\n*** FIN DE PARTIE ! ***")
print("Fellitation {}!tu a gagne la partie!".format(name))
break
elif score_joueur_2 >= 500:
print("\\n*** FIN DE PARTIE ! ***")
print("L'IA a gagn la partie complete !")
break
if __name__ == '__main__':
launch_uno()
import trys as t
from uno_rules import Colors, Val_digits, W_cards, W_count, Nbr_cards_init, piocher_carte_aleatoire, appliquer_penalite, recycler_defausse, calculer_score
from ia_learning import charger_q_table, sauvegarder_q_table, generer_etat_uno, choisir_action_apprentissage, obtenir_recompense, mettre_a_jour_q_table #, VALEUR_PIOCHE
# Charger la Q-Table au debut du script
Q_TABLE = charger_q_table()
HISTORIQUE_IA = []
# --- CONSTANTES SPÉCIFIQUES À NO MERCY ---
# Cartes chiffrées de 0 à 10
VAL_CHIFFRES_NO_MERCI = [str(n) for n in range(0, 11)]
# Cartes Action Spéciales (selon le paquet étendu de No Mercy)
VAL_SPEC_NO_MERCI_SIMPLIFIE = ['+10', '+6', '+4I', 'PTT', 'I', '+2'] # 'RC' et 'PA' ne sont pas gérés ici pour simplification
# Cartes Joker
WILD_NO_MERCI = W_cards # W et +4
WILD_NO_MERCI_COUNT = 4
def creer_paquet_no_merci():
paquet = []
# Cartes chiffrées (0-10) - 2 par couleur
for couleur in Colors:
for valeur in VAL_CHIFFRES_NO_MERCI:
paquet.append((couleur, valeur))
paquet.append((couleur, valeur))
# Cartes Action (2 de chaque par couleur)
for couleur in Colors:
for valeur in VAL_SPEC_NO_MERCI_SIMPLIFIE:
paquet.append((couleur, valeur))
paquet.append((couleur, valeur))
# Cartes Sauvages (4 de chaque)
for valeur in WILD_NO_MERCI:
for _ in range(WILD_NO_MERCI_COUNT):
paquet.append(('N', valeur))
r.shuffle(paquet)
return paquet
def gerer_etat_no_merci():
"""Initialise l'etat de la manche UNO No Mercy."""
etat = {
'sens_horaire': True,
'couleur_actuelle': None,
'uno_crie_joueur_1': False,
'uno_crie_joueur_2': False,
'total_cartes_a_piocher': 0 # L'element CRITIQUE du No Mercy : le compteur de penalite
}
return etat
def verifier_validite_no_merci(carte_jouee, carte_defausse_tuple, couleur_actuelle, cartes_a_piocher):
"""
Verifie si la carte jouee est legale, en tenant compte du stacking de penalite.
"""
couleur_jouee, valeur_jouee = carte_jouee
# 1. Stacking de penalite actif
if cartes_a_piocher > 0:
# Seules les cartes +X et +4 sont valides
if valeur_jouee in ['+2', '+6', '+10'] and couleur_jouee == couleur_actuelle:
return True
if valeur_jouee in ['+4', '+4I']:
return True
# +2 sur +2 d'une couleur differente si la carte du dessus est un +2
if valeur_jouee == '+2' and carte_defausse_tuple[1] == '+2' and couleur_jouee == couleur_actuelle:
return True
# Si on ne stack pas, on ne peut rien jouer d'autre que Piocher/Accepter
return False
# 2. Jeu normal (pas de stacking actif)
# Règle UNO classique : correspondance de couleur, de valeur ou Joker
return (couleur_jouee == couleur_actuelle or
valeur_jouee == carte_defausse_tuple[1] or
couleur_jouee == 'N')
def choisir_carte_jouer_ia_no_merci(main_ia, defausse_pile, etat_tour, nbr_manches_jouees):
"""
Decide de l'action de l'IA (carte a jouer et couleur choisie) basee sur la Q-Table.
Retourne ((carte_jouee, couleur_choisie), None) ou (VALEUR_PIOCHE, -1)
"""
global Q_TABLE, HISTORIQUE_IA
# 1. Generer l'etat
etat_actuel = generer_etat_uno_classique(main_ia, defausse_pile, etat_tour['couleur_actuelle'], etat_tour['total_cartes_a_piocher'])
# 2. Determiner les actions possibles: (carte, couleur_choisie)
actions_possibles = []
couleur_actuelle = etat_tour['couleur_actuelle']
cartes_a_piocher = etat_tour['total_cartes_a_piocher']
for carte in main_ia:
is_valid = verifier_validite_no_merci(carte, defausse_pile[-1], couleur_actuelle, cartes_a_piocher)
if is_valid:
couleur_jouee, valeur_jouee = carte
# Si c'est un Joker ('W', '+4', '+4I'), l'IA choisit la couleur
if couleur_jouee == 'N':
# Strategie IA simplifiee : choisir la couleur qu'elle a le plus
couleurs_main = [c[0] for c in main_ia if c[0] != 'N']
couleur_choisie = max(set(couleurs_main), key=couleurs_main.count, default=r.choice(Colors))
actions_possibles.append(((carte, couleur_choisie), None))
else:
# Couleur non Joker, la couleur choisie est la couleur de la carte jouee
actions_possibles.append(((carte, couleur_jouee), None))
# Si penalite active et aucune carte jouable, la seule action est d'accepter la penalite (Piocher)
if cartes_a_piocher > 0 and not actions_possibles:
actions_possibles.append((VALEUR_PIOCHE, -1))
# Si aucune penalite active et aucune carte jouable, l'action est Piocher
if cartes_a_piocher == 0 and not actions_possibles:
actions_possibles.append((VALEUR_PIOCHE, -1))
# Si penalite active et actions de stacking possibles, on n'ajoute pas l'action pioche ici
# L'IA doit choisir entre les actions possibles de stacking, ou forcer la pioche
if cartes_a_piocher == 0 or actions_possibles:
# L'IA peut toujours decider de piocher pour eviter de jouer une carte cles
actions_possibles.append((VALEUR_PIOCHE, -1))
# 3. Choisir l'action (Exploration ou Exploitation)
action_choisie = choisir_action_apprentissage(Q_TABLE, etat_actuel, actions_possibles, nbr_manches_jouees)
# 4. Enregistrer l'etat et l'action pour la mise a jour future
if action_choisie:
HISTORIQUE_IA.append({
'etat_precedent': etat_actuel,
'action_precedente': action_choisie,
'nbr_cartes_avant': len(main_ia)
})
return action_choisie
def jouer_une_manche_no_merci(joueur_a_commencer, nbr_manches_jouees):
"""
Simule une manche de UNO No Mercy (Joueur 1 vs IA).
Retourne (gagnant, points_marque_par_perdant).
"""
global Q_TABLE, HISTORIQUE_IA
paquet = creer_paquet_no_merci()
main_joueur_1 = piocher_carte_aleatoire(paquet, Nbr_cards_init)
main_joueur_2 = piocher_carte_aleatoire(paquet, Nbr_cards_init)
defausse_pile = []
# Initialiser la pile de defausse
while True:
carte_initiale = piocher_carte_aleatoire(paquet, 1)[0]
# On commence avec une carte chiffre normale
if carte_initiale[1] in VAL_CHIFFRES_NO_MERCI and carte_initiale[0] != 'N':
defausse_pile.append(carte_initiale)
break
else:
paquet.append(carte_initiale) # Remettre la carte dans le paquet
etat_tour = gerer_etat_no_merci()
etat_tour['couleur_actuelle'] = defausse_pile[-1][0]
joueur_courant = joueur_a_commencer
manche_terminee = False
gagnant = None
HISTORIQUE_IA = []
print("Carte du dessus : %s (Couleur actuelle: %s)" % (str(defausse_pile[-1]), etat_tour['couleur_actuelle']))
while not manche_terminee:
action_valide = False
carte_jouee = None
couleur_choisie = None
# Verifier si une penalite de pioche est active
is_penalty_active = etat_tour['total_cartes_a_piocher'] > 0
print("\n")
print("---------------------\nCarte du dessus: %s | Couleur actuelle: %s" % (str(defausse_pile[-1]), etat_tour['couleur_actuelle']))
if is_penalty_active:
print("ATTENTION: Penalite de PIOCHE de +%d cartes ACTIVE!" % etat_tour['total_cartes_a_piocher'])
# 1. Tour du Joueur Humain (1)
if joueur_courant == 1:
print("\nTour du Joueur 1 (Humain) - Cartes: %d" % len(main_joueur_1))
print("Votre main:", main_joueur_1)
cartes_jouables_indices = [
i for i, carte in enumerate(main_joueur_1)
if verifier_validite_no_merci(carte, defausse_pile[-1], etat_tour['couleur_actuelle'], is_penalty_active)
]
choix = t.trys(input("Action (J/P pour Jouer/Piocher): ").upper(), 1, 1)
if choix == 'P':
# Action Piocher / Accepter la penalite
if is_penalty_active:
appliquer_penalite(main_joueur_1, paquet, defausse_pile[-1], etat_tour['total_cartes_a_piocher'])
etat_tour['total_cartes_a_piocher'] = 0 # La penalite est purge
action_valide = True
else:
# Piocher 1 carte et passer son tour (regle No Mercy simplifiee)
cartes_piochees = piocher_carte_aleatoire(paquet, 1)
main_joueur_1.extend(cartes_piochees)
print("Vous piochez 1 carte.")
action_valide = True
# Si le joueur peut jouer la carte piochee, il le fait (simplification)
carte_piochee = cartes_piochees[0]
if verifier_validite_no_merci(carte_piochee, defausse_pile[-1], etat_tour['couleur_actuelle'], is_penalty_active):
print("Carte piochee jouee automatiquement: %s" % str(carte_piochee))
defausse_pile.append(carte_piochee)
etat_tour['couleur_actuelle'] = carte_piochee[0] if carte_piochee[0] != 'N' else r.choice(Colors)
main_joueur_1.remove(carte_piochee) # Retire la carte jouee
# Si jouee, il passe au joueur suivant, sans jouer de tour supplementaire.
# On doit recalculer les effets de la carte jouee
carte_jouee = carte_piochee
couleur_choisie = etat_tour['couleur_actuelle'] # Simuler le choix de couleur
elif choix == 'J' and cartes_jouables_indices:
# Action Jouer
try:
print("Cartes jouables (indices):", cartes_jouables_indices)
index_carte = int(input("Index de la carte a jouer: "))
if index_carte in cartes_jouables_indices:
carte_tentative = main_joueur_1[index_carte]
carte_jouee = carte_tentative
main_joueur_1.pop(index_carte)
action_valide = True
# Gestion des Jokers
if carte_jouee[0] == 'N':
choix_couleur = t.trys(input("Choisir couleur (R, V, B, J): ").upper(), 1, 1)
if choix_couleur in Colors:
couleur_choisie = choix_couleur
else:
couleur_choisie = r.choice(Colors) # Couleur par defaut si mauvaise entree
else:
couleur_choisie = carte_jouee[0]
defausse_pile.append(carte_jouee)
etat_tour['couleur_actuelle'] = couleur_choisie
else:
print("Carte invalide ou non jouable.")
except (ValueError, IndexError):
print("Choix invalide.")
else:
print("Action invalide ou aucune carte jouable. Vous devez piocher.")
# 2. Tour de l'IA (2)
else: # joueur_courant == 2
print("\nTour de l'IA (Joueur 2) - Cartes: %d" % len(main_joueur_2))
action_choisie = choisir_carte_jouer_ia_no_merci(main_joueur_2, defausse_pile, etat_tour, nbr_manches_jouees)
carte_action, couleur_action = action_choisie # carte_action peut etre VALEUR_PIOCHE
if carte_action is VALEUR_PIOCHE:
# Action Piocher / Accepter la penalite
if is_penalty_active:
appliquer_penalite(main_joueur_2, paquet, defausse_pile[-1], etat_tour['total_cartes_a_piocher'])
etat_tour['total_cartes_a_piocher'] = 0 # La penalite est purge
action_valide = True
print("L'IA accepte la penalite de +%d cartes." % etat_tour['total_cartes_a_piocher'])
else:
# Piocher 1 carte et passer son tour (regle No Mercy simplifiee)
cartes_piochees = piocher_carte_aleatoire(paquet, 1)
main_joueur_2.extend(cartes_piochees)
print("L'IA pioche 1 carte.")
action_valide = True
# L'IA joue la carte piochee si possible (simplification)
carte_piochee = cartes_piochees[0]
if verifier_validite_no_merci(carte_piochee, defausse_pile[-1], etat_tour['couleur_actuelle'], is_penalty_active):
carte_jouee = carte_piochee
couleur_choisie = carte_piochee[0] if carte_piochee[0] != 'N' else r.choice(Colors)
main_joueur_2.remove(carte_piochee) # Retire la carte jouee
defausse_pile.append(carte_jouee)
etat_tour['couleur_actuelle'] = couleur_choisie
print("L'IA joue la carte piochee: %s, Couleur choisie: %s" % (str(carte_jouee), couleur_choisie))
else:
# Action Jouer
carte_jouee = carte_action[0]
couleur_choisie = carte_action[1]
main_joueur_2.remove(carte_jouee)
defausse_pile.append(carte_jouee)
etat_tour['couleur_actuelle'] = couleur_choisie
action_valide = True
print("L'IA joue %s. Nouvelle couleur: %s" % (str(carte_jouee), couleur_choisie))
# 3. Application des effets de la carte jouee
if carte_jouee and action_valide:
valeur_carte_jouee = carte_jouee[1]
# Penalites de Pioche (Stacking)
penalites_stack = {'+2': 2, '+6': 6, '+10': 10, '+4': 4, '+4I': 4}
if valeur_carte_jouee in penalites_stack:
etat_tour['total_cartes_a_piocher'] += penalites_stack[valeur_carte_jouee]
# Dans No Mercy, le +4I inverse aussi le sens
if valeur_carte_jouee == '+4I':
etat_tour['sens_horaire'] = not etat_tour['sens_horaire']
# Actions non-stackables
elif valeur_carte_jouee == 'I': # Inversion
etat_tour['sens_horaire'] = not etat_tour['sens_horaire']
elif valeur_carte_jouee == 'PTT': # Passe Ton Tour
joueur_courant = 3 - joueur_courant # Passe deux fois
# Verification de fin de manche (main vide)
if joueur_courant == 1 and not main_joueur_1:
gagnant = 1
manche_terminee = True
elif joueur_courant == 2 and not main_joueur_2:
gagnant = 2
manche_terminee = True
# 4. Gestion du paquet vide
if not paquet:
recycler_defausse(paquet, defausse_pile)
if not paquet:
print("Fin de manche par manque de cartes.")
manche_terminee = True
gagnant = 1 if len(main_joueur_1) < len(main_joueur_2) else 2
# 5. Mise a jour de la Q-Table de l'IA apres son tour
if joueur_courant == 2 and HISTORIQUE_IA and action_valide:
derniere_action_ia = HISTORIQUE_IA.pop()
# L'etat actuel de la partie pour l'IA est l'etat du joueur 1 a son tour
etat_actuel_ia = generer_etat_uno_classique(main_joueur_1, defausse_pile, etat_tour['couleur_actuelle'], etat_tour['total_cartes_a_piocher'])
recompense = obtenir_recompense(
game_mode = 'NO_MERCI',
victoire_ia = (gagnant == 2 if manche_terminee else False),
nbr_cartes_avant = derniere_action_ia['nbr_cartes_avant'],
nbr_cartes_apres = len(main_joueur_2),
action_carte = derniere_action_ia['action_precedente'],
main_ia_apres = main_joueur_2
)
mettre_a_jour_q_table(
Q_TABLE,
derniere_action_ia['etat_precedent'],
derniere_action_ia['action_precedente'],
recompense,
etat_actuel_ia
)
# 6. Passage au joueur suivant
if not manche_terminee and action_valide:
if etat_tour['sens_horaire']:
joueur_courant = 3 - joueur_courant
else:
joueur_courant = 3 - joueur_courant
# Fin de manche
perdant = 3 - gagnant
points_marque_par_perdant = calculer_score(main_joueur_2 if gagnant == 1 else main_joueur_1, 'NO_MERCI')
# Sauvegarde de la Q-Table
sauvegarder_q_table(Q_TABLE)
print("\n=============================================")
print("FIN DE MANCHE UNO NO MERCY ! Le Joueur %d a gagne." % gagnant)
print("Le Joueur %d marque %d points." % (perdant, points_marque_par_perdant))
print("Taille de la Q-Table : %d etats NO_MERCI appris." % len([k for k in Q_TABLE.keys() if 'NO_MERCI' in k]))
print("=============================================\n")
return gagnant, points_marque_par_perdant
import trys as t
from uno_rules import Colors, Val_spe, Val_digits, W_cards, W_count, Nbr_cards_init, piocher_carte_aleatoire, appliquer_penalite, recycler_defausse, calculer_score, creer_paquet_uno_classique
# Importation des fonctions d'apprentissage
from ia_learning import charger_q_table, sauvegarder_q_table, generer_etat_uno, choisir_action_apprentissage, obtenir_recompense, mettre_a_jour_q_table
# Charger la Q-Table au debut du script
Q_TABLE = charger_q_table()
HISTORIQUE_IA = []
def verifier_validite_uno_zero(carte_jouee, carte_defausse_tuple, couleur_actuelle):
couleur_jouee, valeur_jouee = carte_jouee
# Regle UNO classique : correspondance de couleur, de valeur ou Joker
return (couleur_jouee == couleur_actuelle or # Correspondance de couleur choisie
valeur_jouee == carte_defausse_tuple[1] or # Correspondance de valeur
couleur_jouee == 'N')
def choisir_carte_jouer_ia_zero(main_ia, defausse_pile, etat_tour, nbr_manches_jouees):
global Q_TABLE, HISTORIQUE_IA
# 1. Générer l'état (utilise l'état classique car les cartes sont les mêmes)
etat_actuel = generer_etat_uno_classique(main_ia, defausse_pile, etat_tour['couleur_actuelle'], etat_tour['total_cartes_a_piocher'])
# 2. Déterminer les actions possibles: (carte, couleur_choisie)
actions_possibles = []
couleur_actuelle = etat_tour['couleur_actuelle']
for carte in main_ia:
is_valid = verifier_validite_uno_zero(carte, defausse_pile[-1], couleur_actuelle)
if is_valid:
couleur_jouee, valeur_jouee = carte
# Si c'est un Joker ('N'), l'IA choisit la couleur
if couleur_jouee == 'N':
# Stratégie IA simplifiée : choisir la couleur qu'elle a le plus
couleurs_main = [c[0] for c in main_ia if c[0] != 'N']
couleur_choisie = max(set(couleurs_main), key=couleurs_main.count, default=r.choice(Colors))
actions_possibles.append(((carte, couleur_choisie), None))
else:
# Couleur non Joker, la couleur choisie est la couleur de la carte jouée
actions_possibles.append(((carte, couleur_jouee), None))
# Action Piocher
actions_possibles.append((VALEUR_PIOCHE, -1))
# 3. Choisir l'action (Exploration ou Exploitation)
action_choisie = choisir_action_apprentissage(Q_TABLE, etat_actuel, actions_possibles, nbr_manches_jouees)
# 4. Enregistrer l'etat et l'action pour la mise a jour future
if action_choisie:
HISTORIQUE_IA.append({
'etat_precedent': etat_actuel,
'action_precedente': action_choisie,
'nbr_cartes_avant': len(main_ia)
})
return action_choisie
def jouer_une_manche_zero(joueur_a_commencer, nbr_manches_jouees):
global Q_TABLE, HISTORIQUE_IA
paquet = creer_paquet_uno_classique() # Le paquet est le même que le classique
main_joueur_1 = piocher_carte_aleatoire(paquet, Nbr_cards_init)
main_joueur_2 = piocher_carte_aleatoire(paquet, Nbr_cards_init)
defausse_pile = []
# Initialiser la pile de defausse
while True:
carte_initiale = piocher_carte_aleatoire(paquet, 1)[0]
# On commence avec une carte chiffre normale
if carte_initiale[1] in Val_digits and carte_initiale[0] != 'N':
defausse_pile.append(carte_initiale)
break
else:
paquet.append(carte_initiale) # Remettre la carte dans le paquet
etat_tour = {
'sens_horaire': True,
'couleur_actuelle': defausse_pile[-1][0],
'uno_crie_joueur_1': False,
'uno_crie_joueur_2': False,
'total_cartes_a_piocher': 0
}
joueur_courant = joueur_a_commencer
manche_terminee = False
gagnant = None
HISTORIQUE_IA = []
print("Carte du dessus : %s (Couleur actuelle: %s)" % (str(defausse_pile[-1]), etat_tour['couleur_actuelle']))
while not manche_terminee:
action_valide = False
carte_jouee = None
couleur_choisie = None
print("\n---------------------\nCarte du dessus: %s | Couleur actuelle: %s" % (str(defausse_pile[-1]), etat_tour['couleur_actuelle']))
# 1. Tour du Joueur Humain (1)
if joueur_courant == 1:
print("\nTour du Joueur 1 (Humain) - Cartes: %d" % len(main_joueur_1))
print("Votre main:", main_joueur_1)
cartes_jouables_indices = [
i for i, carte in enumerate(main_joueur_1)
if verifier_validite_uno_zero(carte, defausse_pile[-1], etat_tour['couleur_actuelle'])
]
choix = t.trys(input("Action (J/P pour Jouer/Piocher): ").upper(), 1, 1)
if choix == 'P':
# Piocher 1 carte
cartes_piochees = piocher_carte_aleatoire(paquet, 1)
main_joueur_1.extend(cartes_piochees)
print("Vous piochez 1 carte.")
action_valide = True
# Le joueur peut jouer la carte piochee (regle classique)
carte_piochee = cartes_piochees[0]
if verifier_validite_uno_zero(carte_piochee, defausse_pile[-1], etat_tour['couleur_actuelle']):
print("Carte piochee jouee automatiquement: %s" % str(carte_piochee))
defausse_pile.append(carte_piochee)
main_joueur_1.remove(carte_piochee)
carte_jouee = carte_piochee
couleur_choisie = carte_piochee[0] if carte_piochee[0] != 'N' else r.choice(Colors)
etat_tour['couleur_actuelle'] = couleur_choisie
elif choix == 'J' and cartes_jouables_indices:
# Action Jouer
try:
print("Cartes jouables (indices):", cartes_jouables_indices)
index_carte = int(input("Index de la carte a jouer: "))
if index_carte in cartes_jouables_indices:
carte_tentative = main_joueur_1[index_carte]
carte_jouee = carte_tentative
main_joueur_1.pop(index_carte)
action_valide = True
# Gestion des Jokers
if carte_jouee[0] == 'N':
choix_couleur = t.trys(input("Choisir couleur (R, V, B, J): ").upper(), 1, 1)
couleur_choisie = choix_couleur if choix_couleur in Colors else r.choice(Colors)
else:
couleur_choisie = carte_jouee[0]
defausse_pile.append(carte_jouee)
etat_tour['couleur_actuelle'] = couleur_choisie
# Application de l'effet spécial '0' - Échange de mains
if carte_jouee[1] == '0':
main_joueur_1, main_joueur_2 = main_joueur_2, main_joueur_1
print("!!! CARTE ZERO JOUÉE !!! Les mains ont été échangées!")
else:
print("Carte invalide ou non jouable.")
except (ValueError, IndexError):
print("Choix invalide.")
else:
print("Action invalide ou aucune carte jouable. Vous devez piocher.")
# 2. Tour de l'IA (2)
else: # joueur_courant == 2
print("\nTour de l'IA (Joueur 2) - Cartes: %d" % len(main_joueur_2))
action_choisie = choisir_carte_jouer_ia_zero(main_joueur_2, defausse_pile, etat_tour, nbr_manches_jouees)
carte_action, couleur_action = action_choisie # carte_action peut etre VALEUR_PIOCHE
if carte_action is VALEUR_PIOCHE:
# Action Piocher
cartes_piochees = piocher_carte_aleatoire(paquet, 1)
main_joueur_2.extend(cartes_piochees)
print("L'IA pioche 1 carte.")
action_valide = True
# L'IA joue la carte piochee si possible
carte_piochee = cartes_piochees[0]
if verifier_validite_uno_zero(carte_piochee, defausse_pile[-1], etat_tour['couleur_actuelle']):
carte_jouee = carte_piochee
couleur_choisie = carte_piochee[0] if carte_piochee[0] != 'N' else r.choice(Colors)
main_joueur_2.remove(carte_piochee) # Retire la carte jouee
defausse_pile.append(carte_jouee)
etat_tour['couleur_actuelle'] = couleur_choisie
print("L'IA joue la carte piochee: %s, Couleur choisie: %s" % (str(carte_jouee), couleur_choisie))
else:
# Action Jouer
carte_jouee = carte_action[0]
couleur_choisie = carte_action[1]
main_joueur_2.remove(carte_jouee)
defausse_pile.append(carte_jouee)
etat_tour['couleur_actuelle'] = couleur_choisie
action_valide = True
print("L'IA joue %s. Nouvelle couleur: %s" % (str(carte_jouee), couleur_choisie))
# Application de l'effet spécial '0' - Échange de mains
if carte_jouee[1] == '0':
main_joueur_1, main_joueur_2 = main_joueur_2, main_joueur_1
print("!!! CARTE ZERO JOUÉE PAR L'IA !!! Les mains ont été échangées!")
# 3. Application des autres effets de la carte jouee
if carte_jouee and action_valide:
valeur_carte_jouee = carte_jouee[1]
if valeur_carte_jouee == 'I': # Inversion
etat_tour['sens_horaire'] = not etat_tour['sens_horaire']
elif valeur_carte_jouee == 'PTT': # Passe Ton Tour
joueur_courant = 3 - joueur_courant # Passe deux fois
# Gestion des cartes +2 ou +4
if valeur_carte_jouee == '+2':
main_cible = main_joueur_2 if joueur_courant == 1 else main_joueur_1
appliquer_penalite(main_cible, paquet, defausse_pile[-1], 2)
elif valeur_carte_jouee == '+4':
main_cible = main_joueur_2 if joueur_courant == 1 else main_joueur_1
appliquer_penalite(main_cible, paquet, defausse_pile[-1], 4)
# Verification de fin de manche (main vide)
if joueur_courant == 1 and not main_joueur_1:
gagnant = 1
manche_terminee = True
elif joueur_courant == 2 and not main_joueur_2:
gagnant = 2
manche_terminee = True
# 4. Gestion du paquet vide
if not paquet:
recycler_defausse(paquet, defausse_pile)
if not paquet:
print("Fin de manche par manque de cartes.")
manche_terminee = True
gagnant = 1 if len(main_joueur_1) < len(main_joueur_2) else 2
# 5. Mise a jour de la Q-Table de l'IA apres son tour
if joueur_courant == 2 and HISTORIQUE_IA and action_valide:
derniere_action_ia = HISTORIQUE_IA.pop()
# L'etat actuel de la partie pour l'IA est l'etat du joueur 1 a son tour
etat_actuel_ia = generer_etat_uno_classique(main_joueur_1, defausse_pile, etat_tour['couleur_actuelle'], etat_tour['total_cartes_a_piocher'])
recompense = obtenir_recompense(
game_mode = 'UNO_ZERO',
victoire_ia = (gagnant == 2 if manche_terminee else False),
nbr_cartes_avant = derniere_action_ia['nbr_cartes_avant'],
nbr_cartes_apres = len(main_joueur_2),
action_carte = derniere_action_ia['action_precedente'],
main_ia_apres = main_joueur_2
)
mettre_a_jour_q_table(
Q_TABLE,
derniere_action_ia['etat_precedent'],
derniere_action_ia['action_precedente'],
recompense,
etat_actuel_ia
)
# 6. Passage au joueur suivant
if not manche_terminee and action_valide:
if etat_tour['sens_horaire']:
joueur_courant = 3 - joueur_courant
else:
joueur_courant = 3 - joueur_courant
# Fin de manche
perdant = 3 - gagnant
points_marque_par_perdant = calculer_score(main_joueur_2 if gagnant == 1 else main_joueur_1, 'UNO_ZERO')
# Sauvegarde de la Q-Table
sauvegarder_q_table(Q_TABLE)
print("\n=============================================")
print("FIN DE MANCHE UNO ZERO ! Le Joueur %d a gagne." % gagnant)
print("Le Joueur %d marque %d points." % (perdant, points_marque_par_perdant))
print("Taille de la Q-Table : %d etats UNO_ZERO appris." % len([k for k in Q_TABLE.keys() if 'UNO_ZERO' in k]))
print("=============================================\n")
return gagnant, points_marque_par_perdant
fichiers utillitaires :
def shuffle(l):
tmp=[]
while len(l)>0:
e=randint(0,len(l)-1)
tp=l[e]
tmp+=[tp]
l.pop(e)
return tmp
if i.isdigit()==True and s<=int(i)<=e:
return int(i)
else:
if i=="q":
return i
else:
print("Bad number or\ninvalid charactere")
return None
Citer : Posté le 28/11/2025 22:16 | #
voici les fichiers de ROM et de RAM et CPU si cela peut vous aider
lien vers le fichier google drive (j'ai pas d'autre solutions) et on voit qu'il y a plusieur fichier de RAM et de ROM user ou pas https://drive.google.com/file/d/11oXuh-vBpRbLAS3yNpOBX4LYTfc0UPD2/view?usp=sharing
Citer : Posté le 29/11/2025 22:49 | #
voici ce qui ce passe lorsque je tente de compiler JustUI. Comment pouvoir résoudre le problème?
<giteapc> Cloning Lephenixnoir/JustUI...
<giteapc> Fetching Lephenixnoir/gint...
<giteapc> Fetching Lephenixnoir/sh-elf-gcc...
<giteapc> Fetching Lephenixnoir/sh-elf-binutils...
<giteapc> Fetching Lephenixnoir/fxsdk...
<giteapc> Fetching Lephenixnoir/OpenLibm...
<giteapc> Fetching Vhex-Kernel-Core/fxlibc...
remote: Enumerating objects: 11, done.
remote: Counting objects: 100% (11/11), done.
remote: Compressing objects: 100% (11/11), done.
remote: Total 11 (delta 3), reused 0 (delta 0), pack-reused 0 (from 0)
Dépaquetage des objets: 100% (11/11), 3.96 Kio | 675.00 Kio/s, fait.
Depuis https://git.planet-casio.com/Vhex-Kernel-Core/fxlibc
f284c12..7a70aae dev -> origin/dev
<giteapc> Will install: Lephenixnoir/fxsdk, Lephenixnoir/sh-elf-binutils, Lephenixnoir/sh-elf-gcc, Lephenixnoir/OpenLibm, Vhex-Kernel-Core/fxlibc, Lephenixnoir/gint, Lephenixnoir/JustUI
<giteapc> Is that okay (Y/n)? y
<giteapc> Lephenixnoir/fxsdk: Configuring
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/dello3/.local/share/giteapc/Lephenixnoir/fxsdk/build
<giteapc> Lephenixnoir/fxsdk: Building
make[1] : on entre dans le répertoire « /home/dello3/.local/share/giteapc/Lephenixnoir/fxsdk/build »
[ 22%] Built target fxgxa
[ 22%] Built target fxg1a
[ 25%] Built target fxsdk
[ 45%] Built target libfxlink
[ 93%] Built target fxlink
[100%] Built target fxsdk-gdb-bridge
make[1] : on quitte le répertoire « /home/dello3/.local/share/giteapc/Lephenixnoir/fxsdk/build »
<giteapc> Lephenixnoir/fxsdk: Installing
make[1] : on entre dans le répertoire « /home/dello3/.local/share/giteapc/Lephenixnoir/fxsdk/build »
[ 22%] Built target fxgxa
[ 22%] Built target fxg1a
[ 25%] Built target fxsdk
[ 45%] Built target libfxlink
[ 93%] Built target fxlink
[100%] Built target fxsdk-gdb-bridge
Install the project...
-- Install configuration: ""
make[1] : on quitte le répertoire « /home/dello3/.local/share/giteapc/Lephenixnoir/fxsdk/build »
<giteapc> Lephenixnoir/fxsdk: Done! :D
<giteapc> Lephenixnoir/sh-elf-binutils: Configuring
<sh-elf-binutils> binutils 2.42 already installed, skipping rebuild
<giteapc> Lephenixnoir/sh-elf-binutils: Building
<giteapc> Lephenixnoir/sh-elf-binutils: Installing
<giteapc> Lephenixnoir/sh-elf-binutils: Done! :D
<giteapc> Lephenixnoir/sh-elf-gcc: Configuring
<sh-elf-gcc> libsupc++.a found, libstdc++-v3 is already built
<sh-elf-gcc> GCC 14.1.0 with libstdc++-v3 already there; skipping rebuild
<giteapc> Lephenixnoir/sh-elf-gcc: Building
<giteapc> Lephenixnoir/sh-elf-gcc: Installing
<giteapc> Lephenixnoir/sh-elf-gcc: Done! :D
<giteapc> Lephenixnoir/OpenLibm: Configuring
<giteapc> Lephenixnoir/OpenLibm: Building
make[1] : on entre dans le répertoire « /home/dello3/.local/share/giteapc/Lephenixnoir/OpenLibm »
make[1]: Rien à faire pour « default ».
make[1] : on quitte le répertoire « /home/dello3/.local/share/giteapc/Lephenixnoir/OpenLibm »
<giteapc> Lephenixnoir/OpenLibm: Installing
make[1] : on entre dans le répertoire « /home/dello3/.local/share/giteapc/Lephenixnoir/OpenLibm »
mkdir -p /home/dello3/.local/share/fxsdk/sysroot/sh3eb-elf/lib
cp -RpP -f libopenlibm.a /home/dello3/.local/share/fxsdk/sysroot/sh3eb-elf/lib/
ln -sf libopenlibm.a /home/dello3/.local/share/fxsdk/sysroot/sh3eb-elf/lib/libm.a
mkdir -p /home/dello3/.local/share/fxsdk/sysroot/sh3eb-elf/include
cp -RpP -f \
include/openlibm.h \
include/openlibm_complex.h \
include/openlibm_defs.h \
include/openlibm_fenv.h \
include/openlibm_fenv_sh3eb.h \
include/openlibm_math.h \
/home/dello3/.local/share/fxsdk/sysroot/sh3eb-elf/include
make[1] : on quitte le répertoire « /home/dello3/.local/share/giteapc/Lephenixnoir/OpenLibm »
<giteapc> Lephenixnoir/OpenLibm: Done! :D
<giteapc> Vhex-Kernel-Core/fxlibc: Configuring
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/dello3/.local/share/giteapc/Vhex-Kernel-Core/fxlibc/build-gint
<giteapc> Vhex-Kernel-Core/fxlibc: Building
make[1] : on entre dans le répertoire « /home/dello3/.local/share/giteapc/Vhex-Kernel-Core/fxlibc/build-gint »
[100%] Built target fxlibcStatic
make[1] : on quitte le répertoire « /home/dello3/.local/share/giteapc/Vhex-Kernel-Core/fxlibc/build-gint »
<giteapc> Vhex-Kernel-Core/fxlibc: Installing
make[1] : on entre dans le répertoire « /home/dello3/.local/share/giteapc/Vhex-Kernel-Core/fxlibc/build-gint »
[100%] Built target fxlibcStatic
Install the project...
-- Install configuration: ""
make[1] : on quitte le répertoire « /home/dello3/.local/share/giteapc/Vhex-Kernel-Core/fxlibc/build-gint »
<giteapc> Vhex-Kernel-Core/fxlibc: Done! :D
<giteapc> Lephenixnoir/gint: Configuring
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/dello3/.local/share/giteapc/Lephenixnoir/gint/build-fx
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/dello3/.local/share/giteapc/Lephenixnoir/gint/build-cg
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /home/dello3/.local/share/giteapc/Lephenixnoir/gint/build-fxg3a
<giteapc> Lephenixnoir/gint: Building
[100%] Built target gint-fx
[100%] Built target gint-cg
[100%] Built target gint-fxg3a
<giteapc> Lephenixnoir/gint: Installing
[100%] Built target gint-fx
Install the project...
-- Install configuration: ""
[100%] Built target gint-cg
Install the project...
-- Install configuration: ""
-- Installing: /home/dello3/.local/share/fxsdk/sysroot/sh3eb-elf/lib/fxcg50.ld
-- Installing: /home/dello3/.local/share/fxsdk/sysroot/sh3eb-elf/lib/fxcg50_fastload.ld
[100%] Built target gint-fxg3a
Install the project...
-- Install configuration: ""
-- Installing: /home/dello3/.local/share/fxsdk/sysroot/sh3eb-elf/lib/fxcg50.ld
-- Installing: /home/dello3/.local/share/fxsdk/sysroot/sh3eb-elf/lib/fxcg50_fastload.ld
<giteapc> Lephenixnoir/gint: Done! :D
<giteapc> Lephenixnoir/JustUI: Configuring
-- The C compiler identification is GNU 14.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /home/dello3/.local/bin/sh-elf-gcc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Found Gint: TRUE (found suitable version "2.11.0", minimum required is "2.11")
-- Configuring done (0.5s)
-- Generating done (0.0s)
-- Build files have been written to: /home/dello3/.local/share/giteapc/Lephenixnoir/JustUI/build-fx
-- The C compiler identification is GNU 14.1.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /home/dello3/.local/bin/sh-elf-gcc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Found Gint: TRUE (found suitable version "2.11.0", minimum required is "2.11")
-- Configuring done (0.3s)
-- Generating done (0.0s)
-- Build files have been written to: /home/dello3/.local/share/giteapc/Lephenixnoir/JustUI/build-cg
<giteapc> Lephenixnoir/JustUI: Building
[ 5%] Building C object CMakeFiles/justui-fx.dir/src/jwidget.c.obj
[ 11%] Building C object CMakeFiles/justui-fx.dir/src/jlayout_box.c.obj
[ 16%] Building C object CMakeFiles/justui-fx.dir/src/jlayout_stack.c.obj
[ 22%] Building C object CMakeFiles/justui-fx.dir/src/jlayout_grid.c.obj
[ 27%] Building C object CMakeFiles/justui-fx.dir/src/jlabel.c.obj
/home/dello3/.local/share/giteapc/Lephenixnoir/JustUI/src/jlabel.c: Dans la fonction « jlabel_poly_render »:
/home/dello3/.local/share/giteapc/Lephenixnoir/JustUI/src/jlabel.c:308:38: erreur: « font_t » n'a pas de membre nommé « line_distance »
308 | int block_height = lines * (f->line_distance + l->line_spacing) -
| ^~
/home/dello3/.local/share/giteapc/Lephenixnoir/JustUI/src/jlabel.c:344:23: erreur: « font_t » n'a pas de membre nommé « line_distance »
344 | y += f->line_distance + l->line_spacing;
| ^~
make[3]: *** [CMakeFiles/justui-fx.dir/build.make:135: CMakeFiles/justui-fx.dir/src/jlabel.c.obj] Error 1
make[2]: *** [CMakeFiles/Makefile2:87: CMakeFiles/justui-fx.dir/all] Error 2
make[1]: *** [Makefile:136: all] Error 2
gmake: *** [/home/dello3/.local/share/giteapc/Lephenixnoir/JustUI/giteapc.make:10: build] Error 2
error: error 2 in command: g
Citer : Posté le 29/11/2025 22:52 | #
Mets-toi sur la branche dev du fxSDK et de gint: giteapc install fxsdk@dev gint@dev et ensuite relance la commande. Tant que t'y es mets aussi JustUI sur dev au cas où.
Citer : Posté le 01/12/2025 10:55 | # |
Fichier joint
À quoi sert les fichiers :
-Casio2RAMCPUInit.mem
-Casio2RAMInit.mem
-Casio2ROMInit.mem
et Casio2UserROMInit.mem
voici le lien pour y acéder
https://drive.google.com/file/d/11oXuh-vBpRbLAS3yNpOBX4LYTfc0UPD2/view?pli=1
pour ce qui est de la forge je ne voit pas de bouton "s'incrire" comme le montre la capture enpièce jointe comment faire si il n'y a pa de possibilité pour s'inscrire
Citer : Posté le 01/12/2025 11:38 | #
C'est des fichiers internes de l'émulateurs. Comme le nom l'indique, sans doute des données d'initialisation de la mémoire au début de l'émulation. Je ne vois pas du tout où tu veux en venir...
Pour la forge, on a dû rendre les inscriptions manuelles à cause des bots. Je peux te créer un compte moi-même. Si tu veux une adresse mail différente de ton compte PC dis-moi par MP, sinon je te le crée comme ça.
Citer : Posté le 01/12/2025 14:22 | #
Uillise le même mail que celui de mon compte pour la forge
en ce qu'est des fichiers de l'émulateur je me suis dit qu'on pourrait trouver d'ou vient la limitation de RAM pour améliorer les performances des ADD-ins (j'ai quelque idées) et nous pourraons peut-être créer quelque chose pour accéder au system de fichier (root) de la CASIO et modifier l'appli Python (mettre à jour MicroPython vers la version 1.26.1) ainsi que d'optimiser le system et ajouter des fonctionalité de manières intégrés. Peut-tu améliorer le fxSDK en ajoutant une commande qui à partir d'un fichier compiler (g1a,g3a) donne le code source ce qui peut-être pratique pour les programme non-testé ou si on perd son code source et qu'il nous reste que le fichier g1a , si on a cette fonction on pourrais les récipérer ce qui est très pratique .
Citer : Posté le 01/12/2025 16:19 | #
Peut-tu améliorer le fxSDK en ajoutant une commande qui à partir d'un fichier compiler (g1a,g3a) donne le code source ce qui peut-être pratique pour les programme non-testé ou si on perd son code source et qu'il nous reste que le fichier g1a , si on a cette fonction on pourrais les récipérer ce qui est très pratique .
Je mets juste que, à part si tu copierais l'entiereté du code source au temps de build, chose qui fera perdre une quantité significante d'espace (l'un de mes projets fait déja 800K de code SANS ASSETS, ce qui est déja 200K de plus que le g3a lui-même!), une telle chose est quasi-impossible automatiquement, encore plus avec les optimisations à la LTO. Si t'as pas envie de perdre ton code, utilise une forge Git
je me suis dit qu'on pourrait trouver d'ou vient la limitation de RAM
Pour le point original, on sait déja où se trouves les zones de mémoire dispo sur les modèles Prizm/monochrome, IIRC (je ne suis pas trop le dev de PyExtra), donc y'a pas trop d'utilité à cela j'assume
Citer : Posté le 01/12/2025 16:34 | #
Le compte arrive ce soir. Pour le reste, euh... pas trop vite. Tu as beaucoup de bonnes idées mais elles sont pas toujours bien ancrées dans la réalité.
Pas de problème de ce côté-là, on sait déjà d'où ça vient.
Il n'existe pas de "système de fichiers root" sur la calculatrice
Les applications officielles ne sont pas dans le système de fichiers et ne peuvent être modifiées que par une mise à jour officielle de CASIO.
Il est impossible de régénérer le code source à partir du binaire et absurde de mettre tout le code dedans à cause de la place que ça prend, qu'on a déjà assez de mal à contrôler.
Citer : Posté le 18/12/2025 00:24 | #
Will PythonExtra work on the fxcg50 Os version 3.8? If so, is there a link to a compiled one? The g3a file.
Also, what about Ultimatepy.g3a? What is that, and will it work on the fxcg50 Os version 3.7 & 3.8? Is there a link to the files?
Is there any documentation on the gint module? For example, what are the arguments I can supply to the functions, especially those dealing with images?
I am not in a position to compile anything. Thanks for your help.