#-------------------------------------------------------------------------------------- # EXEMPLE D'UNE CLASSE C_JOUEUR DEFINISSANT UNE IA JOUANT BETEMENT SES CARTES AU HASARD #-------------------------------------------------------------------------------------- from kblibpub import * try: from random import choice except: from urandom import choice class c_joueur: def __init__(self, num_joueur, nbr_joueurs, points_objectif): self.num_joueur = num_joueur # mon numero de joueur self.nbr_joueurs = nbr_joueurs # nombre total de joueurs # informations de jeu collectees sur l'ensemble des joueurs self.infos_joueurs = [ i == num_joueur and c_infos_jeu_et_main(i, nbr_joueurs, points_objectif) or c_infos_jeu(i, nbr_joueurs, points_objectif) for i in range(nbr_joueurs) ] # mes informations de jeu self.infos_joueur = self.infos_joueurs[num_joueur] # nom de l'IA self.nom_joueur = "Salvia" # version de l'IA self.ver_joueur = "19.0" # nom de groupe (optionnel, pour les participants decidant de rejoindre un groupe) self.nom_groupe = "br.AI.n all.IA.ge" # signature du groupe (a demander et recuperer aupres du chef de groupe) self.sig_groupe = "One BrAIn to Rule Them All." # cri de victoire de l'IA self.msg_joueur = ( "Et BIM, c'est qui le meilleur ?" ) #-------------------------------------------------- # DEBUT DES FONCTIONS NECESSITANT D'ETRE AMELIOREES #-------------------------------------------------- def decide_coup(self): carte = None origine, destination = self.num_joueur, self.num_joueur liste_bornes=[self.infos_joueurs[i].bornes+i for i in range(self.nbr_joueurs)] liste_bornes[self.infos_joueur.num_joueur]=-1 liste_bornes_adversaires=[liste_bornes[i]-i for i in range(self.nbr_joueurs) if i != self.infos_joueur.num_joueur] adversaires_ordre_decroissant_bornes=[liste_bornes.index(j) for j in sorted(liste_bornes)[::-1]][:-1] try: len(ancienne_main) ancienne_main,nouvelle_main=nouvelle_main[:],self.infos_joueur.main[:] except: ancienne_main,nouvelle_main=[],self.infos_joueur.main[:] nouvelles_cartes=[CARTE for CARTE in nouvelle_main if CARTE not in ancienne_main] # gestion de la liste des cartes de parade déjà posées pour évaluer la probabilité de les repiocher (soi-même, si besoin, ou par l'adversaire) : try: len(nb_parades_croisees) except: nb_parades_croisees=dict() for parade in cartes_parade(): nb_parades_croisees[parade]=0 for CARTE in nouvelles_cartes: # on compte les cartes de parades nouvellement piochées if est_carte_parade(CARTE): nb_parades_croisees[CARTE] += 1 DerniereCarteEtaitParade=[False]*self.nbr_joueurs for i in range(self.nbr_joueurs): if not DerniereCarteEtaitParade[i] and est_carte_parade(self.infos_joueurs[i].carte_bataille()) and self.infos_joueurs[i].carte_bataille() != I_FEU_VERT: DerniereCarteEtaitParade[i] = True nb_parades_croisees[self.infos_joueurs[i].carte_bataille()] += 1 elif DerniereCarteEtaitParade[i] and not est_carte_parade(self.infos_joueurs[i].carte_bataille()): DerniereCarteEtaitParade[i] = False effectifs_parades_decroissants=sorted(list(nb_parades_croisees.values()))[::-1] liste_parades_piochables_proba_croissante=[] for i in range(len(effectifs_parades_decroissants)): for parade in cartes_parade(): if nb_parades_croisees[parade] == effectifs_parades_decroissants[i] and parade not in liste_parades_piochables_proba_croissante: liste_parades_piochables_proba_croissante.append(parade) liste_attaques_dont_parade_peu_piochable=[attaque_pour(parade) for parade in liste_parades_piochables_proba_croissante] # gestion de la liste des cartes d'attaque déjà posées pour évaluer la probabilité de les repiocher (soi-même, si besoin, ou par l'adversaire) : try: len(nb_attaques_croisees) except: nb_attaques_croisees=dict() for attaque in cartes_attaque(): nb_attaques_croisees[attaque]=0 for CARTE in nouvelles_cartes: # on compte les cartes d'attaques nouvellement piochées if est_carte_attaque(CARTE): nb_attaques_croisees[CARTE] += 1 DerniereCarteEtaitAttaque=[False]*self.nbr_joueurs for i in range(self.nbr_joueurs): if not DerniereCarteEtaitAttaque[i] and est_carte_attaque(self.infos_joueurs[i].carte_bataille()) and self.infos_joueurs[i].carte_bataille() != I_FEU_ROUGE: DerniereCarteEtaitAttaque[i] = True nb_attaques_croisees[self.infos_joueurs[i].carte_bataille()] += 1 elif DerniereCarteEtaitAttaque[i] and not est_carte_attaque(self.infos_joueurs[i].carte_bataille()): DerniereCarteEtaitAttaque[i] = False effectifs_attaques_decroissants=sorted(list(nb_attaques_croisees.values()))[::-1] liste_attaques_piochables_proba_croissante=[] for i in range(len(effectifs_attaques_decroissants)): for attaque in cartes_attaque(): if nb_attaques_croisees[attaque] == effectifs_attaques_decroissants[i] and attaque not in liste_attaques_piochables_proba_croissante: liste_attaques_piochables_proba_croissante.append(attaque) liste_parades_dont_attaque_peu_piochable=[parade_pour(attaque) for attaque in liste_attaques_piochables_proba_croissante] if len(self.infos_joueur.main) != self.taille_main: if len(self.infos_joueur.coups_fourres_autorises) > 0: # coup fourré for CARTE in self.infos_joueur.main: if CARTE in self.infos_joueur.coups_fourres_autorises: return c_coup(self.infos_joueur.num_joueur,CARTE,self.infos_joueur.num_joueur) # si on a moins de cartes en main, alors on peut tirer une carte du et la rajouter a sa main return c_coup(SABOT,None,self.infos_joueur.num_joueur) # sinon, si on a cartes en main, alors on peut jouer une carte de sa main else: # Si on peut rouler et placer une carte qui permet de gagner la partie, alors on la joue. Mais si on a encore une carte de botte dans la main, alors on la joue juste avant. if self.infos_joueur.vehicule_roulant(): for CARTE in self.infos_joueur.main: if (self.infos_joueur.carte_vitesse() != I_LIMITATION or valeur_carte_bornes(CARTE) in [25,50]) and (self.infos_joueur.bornes + valeur_carte_bornes(CARTE) == self.infos_joueur.bornes_arrivee) and not (CARTE == I_200_BORNES and self.infos_joueur.bornes200 == 2): # si on a une carte bornes qui permet de gagner la partie for CARTE2 in self.infos_joueur.main: if est_carte_botte(CARTE2): # si on a une carte botte, alors on la joue return c_coup(self.infos_joueur.num_joueur, CARTE2, self.infos_joueur.num_joueur) return c_coup(self.infos_joueur.num_joueur, CARTE, self.infos_joueur.num_joueur) # sinon, on joue la carte borne gagnante # Si un des joueurs a bientôt gagné ou qu'il ne reste plus beaucoup de cartes dans la pioche et qu'il me reste une botte à jouer, alors je la joue if self.infos_joueur.bornes_arrivee - max(liste_bornes_adversaires) <= 200 or self.infos_joueur.nbr_cartes <= 4: # \\ paramètre à ajuster \\ for CARTE in self.infos_joueur.main: if est_carte_botte(CARTE): return c_coup(self.infos_joueur.num_joueur, CARTE, self.infos_joueur.num_joueur) # Si on ne peut pas rouler (ou si) et que l'adversaire est en passe de gagner (ou pas du tout) et qu'on a de quoi l'attaquer, alors on l'attaque : #if (not self.infos_joueur.vehicule_roulant()) and (self.infos_joueur.bornes_arrivee - max(liste_bornes_adversaires) <= 200): if self.infos_joueur.bornes_arrivee - max(liste_bornes_adversaires) <= 2000: for i in adversaires_ordre_decroissant_bornes: # on parcourt le numéro des adversaires par ordre décroissant de bornes posées if self.infos_joueurs[i].vehicule_roulant(): # si l'adversaire roule, donc est attaquable for CARTE in liste_attaques_dont_parade_peu_piochable: if CARTE in self.infos_joueur.main and CARTE not in [I_FEU_ROUGE, I_LIMITATION]: if (botte_pour(CARTE) in self.infos_joueur.main) or (botte_pour(CARTE) in self.infos_joueur.bottes): return c_coup(self.infos_joueur.num_joueur, CARTE, self.infos_joueurs[i].num_joueur) for CARTE in self.infos_joueur.main: if CARTE == I_FEU_ROUGE: if (botte_pour(CARTE) in self.infos_joueur.main) or (botte_pour(CARTE) in self.infos_joueur.bottes): return c_coup(self.infos_joueur.num_joueur, CARTE, self.infos_joueurs[i].num_joueur) #for CARTE in self.infos_joueur.main: # \\ A voir s'il n'est pas plus pertinent d'attaquer un autre adversaire qui n'aura pas la botte correspondante, donc pas de coup fourré possible, plutôt que d'attaquer l'adversaire le plus en avance mais en risquant qu'il fasse un coup fourré... for CARTE in liste_attaques_dont_parade_peu_piochable: if CARTE in self.infos_joueur.main and CARTE not in [I_FEU_ROUGE, I_LIMITATION]: if botte_pour(CARTE) not in self.infos_joueurs[i].bottes: return c_coup(self.infos_joueur.num_joueur, CARTE, self.infos_joueurs[i].num_joueur) for CARTE in self.infos_joueur.main: if CARTE == I_FEU_ROUGE: if botte_pour(CARTE) not in self.infos_joueurs[i].bottes: return c_coup(self.infos_joueur.num_joueur, CARTE, self.infos_joueurs[i].num_joueur) # Si l'adversaire peut rouler (ou pas) mais qu'il n'a pas déjà de limitation de vitesse et qu'il n'a pas posé de véhicule prioritaire, alors on lui colle une limitation de vitesse. if I_LIMITATION in self.infos_joueur.main: for i in adversaires_ordre_decroissant_bornes: if botte_pour(I_LIMITATION) not in self.infos_joueurs[i].bottes and self.infos_joueurs[i].carte_vitesse() != I_LIMITATION: return c_coup(self.infos_joueur.num_joueur, I_LIMITATION, self.infos_joueurs[i].num_joueur) # Si on peut rouler, alors on pose des bornes # Si on est sous le coup d'une limitaton de vitesse mais qu'on peut gagner en un coup, alors on le joue. if self.infos_joueur.vehicule_roulant() and self.infos_joueur.carte_vitesse() == I_LIMITATION: # si on peut rouler mais en étant sous le coup d'une limitation de vitesse if I_50_BORNES in self.infos_joueur.main and self.infos_joueur.bornes + 50 == self.infos_joueur.bornes_arrivee: return c_coup(self.infos_joueur.num_joueur, I_50_BORNES, self.infos_joueur.num_joueur) if I_25_BORNES in self.infos_joueur.main and self.infos_joueur.bornes + 25 == self.infos_joueur.bornes_arrivee: return c_coup(self.infos_joueur.num_joueur, I_25_BORNES, self.infos_joueur.num_joueur) if self.infos_joueur.main.count(I_25_BORNES) >= 2 and self.infos_joueur.bornes + 50 == self.infos_joueur.bornes_arrivee: # si on a 2 cartes de 25 bornes et qu'il reste 50 bornes avant l'arrivée, alors on joue une des deux cartes de 25. return c_coup(self.infos_joueur.num_joueur, I_25_BORNES, self.infos_joueur.num_joueur) if I_25_BORNES in self.infos_joueur.main and I_50_BORNES in self.infos_joueur.main and self.infos_joueur.bornes + 75 == self.infos_joueur.bornes_arrivee: # si on a une carte de 25 bornes et une carte de 50 bornes et qu'il reste 75 bornes avant l'arrivée, alors on joue la carte de 50. return c_coup(self.infos_joueur.num_joueur, I_50_BORNES, self.infos_joueur.num_joueur) if self.infos_joueur.main.count(I_50_BORNES) >= 2 and self.infos_joueur.bornes + 100 == self.infos_joueur.bornes_arrivee: # si on a 2 cartes de 50 bornes et qu'il reste 100 bornes avant l'arrivée, alors on joue une des deux cartes de 50. return c_coup(self.infos_joueur.num_joueur, I_50_BORNES, self.infos_joueur.num_joueur) # Si on est sous le coup d'une limitation de vitesse et qu'on peut l'annuler, alors on le fait if self.infos_joueur.carte_vitesse() == I_LIMITATION and I_FIN_LIMITATION in self.infos_joueur.main: return c_coup(self.infos_joueur.num_joueur, I_FIN_LIMITATION, self.infos_joueur.num_joueur) # Si on peut rouler et que l'adversaire est en passe de gagner (ou pas) mais qu'on peut poser un 200 bornes pour gagner, alors on le pose if self.infos_joueur.vehicule_roulant(): if I_200_BORNES in self.infos_joueur.main and self.infos_joueur.carte_vitesse() != I_LIMITATION and self.infos_joueur.bornes200 < 2 and self.infos_joueur.bornes + 200 <= self.infos_joueur.bornes_arrivee and self.infos_joueur.bornes_arrivee - max(liste_bornes_adversaires) <= 2000: return c_coup(self.infos_joueur.num_joueur, I_200_BORNES, self.infos_joueur.num_joueur) if self.infos_joueur.carte_vitesse() != I_LIMITATION: if I_100_BORNES in self.infos_joueur.main and self.infos_joueur.main.count(I_75_BORNES) >= 2 and self.infos_joueur.main.count(I_50_BORNES) == 0 and self.infos_joueur.bornes + 150 == self.infos_joueur.bornes_arrivee: # S'il reste 150 bornes à placer et qu'on a une certe 100 mais pas de carte 50 mais deux cartes 75, alors il vaut mieux poser une carte 75 (et l'autre carte 75 au tour suivant) return c_coup(self.infos_joueur.num_joueur, I_75_BORNES, self.infos_joueur.num_joueur) if I_100_BORNES in self.infos_joueur.main and self.infos_joueur.main.count(I_75_BORNES) >= 1 and self.infos_joueur.main.count(I_50_BORNES) >= 1 and self.infos_joueur.main.count(I_25_BORNES) == 0 and self.infos_joueur.bornes + 125 == self.infos_joueur.bornes_arrivee: # S'il reste 125 bornes à placer et qu'on a une certe 100 mais pas de carte 25 mais une carte 75 et une carte 50, alors il vaut mieux poser la carte 75 (et la carte 50 au tour suivant) return c_coup(self.infos_joueur.num_joueur, I_75_BORNES, self.infos_joueur.num_joueur) if I_100_BORNES in self.infos_joueur.main and self.infos_joueur.bornes + 100 <= self.infos_joueur.bornes_arrivee: return c_coup(self.infos_joueur.num_joueur, I_100_BORNES, self.infos_joueur.num_joueur) if I_75_BORNES in self.infos_joueur.main and self.infos_joueur.main.count(I_50_BORNES) >= 2 and self.infos_joueur.main.count(I_25_BORNES) == 0 and self.infos_joueur.bornes + 100 == self.infos_joueur.bornes_arrivee: # S'il reste 100 bornes à placer et qu'on a une certe 75 mais pas de carte 25 mais deux cartes 50, alors il vaut mieux poser une carte 50 (et l'autre carte 50 au tour suivant) return c_coup(self.infos_joueur.num_joueur, I_50_BORNES, self.infos_joueur.num_joueur) if I_75_BORNES in self.infos_joueur.main and self.infos_joueur.bornes + 75 <= self.infos_joueur.bornes_arrivee: return c_coup(self.infos_joueur.num_joueur, I_75_BORNES, self.infos_joueur.num_joueur) if I_50_BORNES in self.infos_joueur.main and self.infos_joueur.bornes + 50 <= self.infos_joueur.bornes_arrivee: return c_coup(self.infos_joueur.num_joueur, I_50_BORNES, self.infos_joueur.num_joueur) if I_25_BORNES in self.infos_joueur.main and self.infos_joueur.bornes + 25 <= self.infos_joueur.bornes_arrivee: return c_coup(self.infos_joueur.num_joueur, I_25_BORNES, self.infos_joueur.num_joueur) # Si on ne peut pas rouler parce qu'on est en panne, alors on essaye de réparer ou de poser la botte correspondante si on vient de la piocher. if not self.infos_joueur.vehicule_roulant(): if est_carte_attaque(self.infos_joueur.carte_bataille()): if parade_pour(self.infos_joueur.carte_bataille()) in self.infos_joueur.main: return c_coup(self.infos_joueur.num_joueur, parade_pour(self.infos_joueur.carte_bataille()), self.infos_joueur.num_joueur) if botte_pour(self.infos_joueur.carte_bataille()) in self.infos_joueur.main: return c_coup(self.infos_joueur.num_joueur, botte_pour(self.infos_joueur.carte_bataille()), self.infos_joueur.num_joueur) # Si on ne peut pas rouler mais en ayant déjà réparé, alors on pose un feu vert si on le peut. elif I_FEU_VERT in self.infos_joueur.main: return c_coup(self.infos_joueur.num_joueur, I_FEU_VERT, self.infos_joueur.num_joueur) elif I_VEHICULE_PRIORITAIRE in self.infos_joueur.main: return c_coup(self.infos_joueur.num_joueur, I_VEHICULE_PRIORITAIRE, self.infos_joueur.num_joueur) # Si on ne peut pas rouler et poser des bornes, ou réparer une panne ou poser une botte si la situation le recommande ou lancer une attaque, alors il ne reste plus qu'à se défausser d'une carte. Il va falloir bien choisir quelle carte on jette ! Mini_bornes=300 for CARTE in self.infos_joueur.main: if est_carte_bornes(CARTE) and valeur_carte_bornes(CARTE) self.infos_joueur.bornes_arrivee: return c_coup(self.infos_joueur.num_joueur, CARTE, SABOT) # Si on joue une partie à 2 et qu'on a une carte d'attaque pour laquelle l'adversaire a posé la botte, alors on peut la jeter. if est_carte_attaque(CARTE) and self.nbr_joueurs == 2: i = adversaires_ordre_decroissant_bornes[0] if botte_pour(CARTE) in self.infos_joueurs[i].bottes: return c_coup(self.infos_joueur.num_joueur, CARTE, SABOT) # Si on a une carte de fin de limitation de vitesse et seulement moins de 50 bornes avant la victoire (ou 100 bornes et une possibilité de victoire en 2 coups : 2 cartes de 50), alors on peut la jeter. if CARTE == I_FIN_LIMITATION: if self.infos_joueur.bornes_arrivee - self.infos_joueur.bornes <= 50: return c_coup(self.infos_joueur.num_joueur, CARTE, SABOT) if self.infos_joueur.main.count(I_50_BORNES)>=2 and self.infos_joueur.bornes_arrivee - self.infos_joueur.bornes == 100: return c_coup(self.infos_joueur.num_joueur, CARTE, SABOT) if self.infos_joueur.main.count(I_50_BORNES)>=2 and I_25_BORNES in self.infos_joueur.main and self.infos_joueur.bornes_arrivee - self.infos_joueur.bornes == 125: return c_coup(self.infos_joueur.num_joueur, CARTE, SABOT) if I_50_BORNES in self.infos_joueur.main and I_25_BORNES in self.infos_joueur.main and self.infos_joueur.bornes_arrivee - self.infos_joueur.bornes == 75: return c_coup(self.infos_joueur.num_joueur, CARTE, SABOT) # Si on a déjà posé 2 cartes de 200 bornes, alors on peut se débarrasser des autres. if CARTE == I_200_BORNES and self.infos_joueur.bornes200 == 2: return c_coup(self.infos_joueur.num_joueur, CARTE, SABOT) for CARTE in liste_parades_dont_attaque_peu_piochable: # Si on a au moins 3 cartes de parade pour la même attaque, alors on peut raisonnablement en jeter une. if CARTE in self.infos_joueur.main and self.infos_joueur.main.count(CARTE) >= 3: #nb_parades_croisees[CARTE] += 1 # \\ et carte pas feu vert ? \\ return c_coup(self.infos_joueur.num_joueur, CARTE, SABOT) # On peut jeter une carte de bornes si toutes les autres cartes de bornes sont suffisantes pour atteindre la ligne d'arrivée. for CARTE in cartes_bornes(): Somme=sum(valeur_carte_bornes(carte) for carte in self.infos_joueur.main if est_carte_bornes(carte)) if CARTE in self.infos_joueur.main and Somme-valeur_carte_bornes(CARTE) + self.infos_joueur.bornes == self.infos_joueur.bornes_arrivee: return c_coup(self.infos_joueur.num_joueur, CARTE, SABOT) # Ou au pire si ça dépasse la ligne d'arrivée, mais l'idéal est que ça tombe pile ! for CARTE in cartes_bornes(): Somme=sum(valeur_carte_bornes(carte) for carte in self.infos_joueur.main if est_carte_bornes(carte)) if CARTE in self.infos_joueur.main and Somme-valeur_carte_bornes(CARTE) + self.infos_joueur.bornes > self.infos_joueur.bornes_arrivee: # \\ est-ce vraiment un bon plan ? \\ return c_coup(self.infos_joueur.num_joueur, CARTE, SABOT) # Au pire, jetons une carte utile, mais pas une botte for CARTE in liste_parades_dont_attaque_peu_piochable: if CARTE in self.infos_joueur.main and self.infos_joueur.main.count(CARTE) > 1: #nb_parades_croisees[CARTE] += 1 # \\ et carte pas feu vert ? \\ return c_coup(self.infos_joueur.num_joueur, CARTE, SABOT) # Ou jeter une carte de 200 bornes et aucune carte 200 de déjà posée ou une carte d'attaque qu'on ne peut pas lancer dans l'immédiat if CARTE == I_200_BORNES and self.infos_joueur.bornes200 == 0: return c_coup(self.infos_joueur.num_joueur, CARTE, SABOT) for CARTE in liste_attaques_dont_parade_peu_piochable: if CARTE in self.infos_joueur.main: #nb_attaques_croisees[CARTE] += 1 return c_coup(self.infos_joueur.num_joueur, CARTE, SABOT) # Si on n'a trouvé aucune carte inutile à jeter, alors jetons la carte de bornes la plus petite de la main. for CARTE in self.infos_joueur.main: if est_carte_bornes(CARTE) and valeur_carte_bornes(CARTE)==Mini_bornes: return c_coup(self.infos_joueur.num_joueur, CARTE, SABOT) # Ou une carte de parade autre qu'un feu vert for CARTE in liste_parades_dont_attaque_peu_piochable: if CARTE in self.infos_joueur.main and CARTE != I_FEU_VERT: #nb_parades_croisees[CARTE] += 1 return c_coup(self.infos_joueur.num_joueur, CARTE, SABOT) # Ou une carte feu vert, au pire for CARTE in self.infos_joueur.main: if CARTE == I_FEU_VERT: return c_coup(self.infos_joueur.num_joueur, CARTE, SABOT) print("problème") print(self.infos_joueur.main) def pari_allonge(self, bornes_arrivee): # t = choice((True, False)) M=max([self.infos_joueurs[i].bornes for i in range(self.nbr_joueurs) if i != self.num_joueur]) if (self.infos_joueur.bornes - M > 500) and (self.infos_joueur.nbr_cartes > 10 and sum(valeur_carte_bornes(CARTE) for CARTE in self.infos_joueur.main if est_carte_bornes(CARTE)) == 300) and len(self.infos_joueur.bottes)>=3: return True return False #return [True,False][self.infos_joueur.nbr_cartes<30] #-------------------------------------------------- # FIN DES FONCTIONS NECESSITANT D'ETRE AMELIOREES #-------------------------------------------------- def id_str(self): return self.infos_joueur.id_str() + " {:s} v{:s}".format(self.nom_joueur, self.ver_joueur) def nouvelle_manche(self, nbr_cartes, taille_main, bornes_arrivee): self.taille_main = taille_main for infos_joueur in self.infos_joueurs: infos_joueur.nouvelle_manche(nbr_cartes, taille_main, bornes_arrivee) def fin_manche(self, bornes_joueurs, len_pioche): for infos_joueur in self.infos_joueurs: infos_joueur.fin_manche(bornes_joueurs, len_pioche) def allonge(self, num_joueur, bornes_arrivee): for infos_joueur in self.infos_joueurs: infos_joueur.allonge(num_joueur, bornes_arrivee) def traite_coup(self, coup): for i in range(self.nbr_joueurs): self.infos_joueurs[i].traite_coup(coup) def rejoint_groupe(self, num_joueur, nom_groupe): self.infos_joueurs[num_joueur].nom_groupe = nom_groupe