#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Wed Mar 4 22:32:32 2020 @author: AlexandreMouchel """ DEBUG = False import functools from opale.carte import * from opale.player import Player class Computer(Player): def __init__(self, board): super().__init__("OpaleIA") self.board = board self.witch_played = 0 def base_importance(t): return t.importance def importance(self): return { Chasseresse: Computer.base_importance(Chasseresse) - len(self.board.chasseresse), DragonCorail: Computer.base_importance(DragonCorail) + functools.reduce(lambda a,b: a + b, [0] + [p.score for p in self.board.pearl]), Pearl: Computer.base_importance(Pearl) - len(self.board.pearl) // 2, Witch: Computer.base_importance(Witch), DragonPetrified: Computer.base_importance(DragonPetrified) - len(self.board.dragonPetrified) // 2, Golem: Computer.base_importance(Golem) - len(self.board.golem) // 2, Guardian: Computer.base_importance(Guardian) - len(self.board.guardian), Horser: Computer.base_importance(Horser), City: Computer.base_importance(City) - len(self.board.city), } def play_turn(self, play_round): if DEBUG: print("HAND: %s" % self.hand) cards = self.search_play() if DEBUG: print("after search_play: %s" % cards) if type(cards[0]) == Witch: self.witch_played += len(cards) play_round(*cards) return cards def search_play(self, hand=None): if hand is None: hand = self.hand importance = self.importance() # On regroupe les cartes identiques cardgroup = {} for card in hand: if type(card) not in cardgroup: cardgroup[type(card)] = [] cardgroup[type(card)].append(card) # On trie les cartes, de sorte de toujours jouer les plus faibles d'abord for t in cardgroup.keys(): cardgroup[t].sort(key=lambda c: c.score) # Cas spécial pour les Witches : on veut récupérer les dragons à tout prix ! if Witch in cardgroup and not self.dragonPetrified: if len(self.board.dragonPetrified) > 0: if DEBUG: print("search_play RESOLUTION: taking the dragon is my priority") return [cardgroup[Witch][0]] # Cas spécial pour les Witches : on garde la dernière Witch pour récupérer un dragon if self.witch_played >= 3 and Witch in cardgroup: del cardgroup[Witch] # On recherche le(s) groupe(s) de carte(s) qui rapporte(nt) le plus de points scores = {} score_max = None for t in cardgroup.keys(): score = functools.reduce(lambda a,b: a + b, [0] + [c.score for c in self.board.try_cards(*cardgroup[t])]) if score > 0: scores[t] = score if score_max is None or scores[t] > scores[score_max]: score_max = t # Try by reducing the number of cards plays if score_max is not None: if DEBUG: print("search_play reduce with score=%d" % scores[score_max]) min_cards = 9 for t in [ty for ty in cardgroup.keys() if ty in scores and scores[ty] == scores[score_max]]: if DEBUG: print("search_play reducing starting with %s" % cardgroup[t]) ok = len(cardgroup[t]) while ok > 1: score = functools.reduce(lambda a,b: a + b, [0] + [c.score for c in self.board.try_cards(*cardgroup[t][0:ok - 1])]) if DEBUG: print("search_play reducing score=%d with %s" % (score, cardgroup[t][0:ok-1])) if score >= scores[score_max]: ok -= 1 else: break if ok != len(cardgroup[t]): if t == Guardian: cardgroup[t] = cardgroup[t][len(cardgroup[t]) - ok:] else: cardgroup[t] = cardgroup[t][0:ok] if DEBUG: print("search_play reduce to %d %s" % (ok, cardgroup[t])) if min_cards > ok: min_cards = ok # Return the first match for t in sorted([ty for ty in cardgroup.keys() if ty in scores and scores[ty] == scores[score_max] and len(cardgroup[ty]) == min_cards], key=lambda t: importance[t], reverse=True): if DEBUG: print("search_play RESOLUTION: play for score %d" % scores[score_max]) return cardgroup[t] print("WHY am I here? score_max=%d min_cards=%d groups=[%s] sorted=%s" % ( scores[score_max], min_cards, ','.join(["%s: %s" % (t.__name__, cardgroup[t]) for t in sorted([ty for ty in cardgroup.keys()], key=lambda t: importance[t], reverse=True)]), [t.__name__ for t in sorted([ty for ty in cardgroup.keys() if ty in scores and scores[ty] == scores[score_max] and len(cardgroup[ty]) == min_cards], key=lambda t: importance[t], reverse=True)] )) # Return the first match for t in sorted(cardgroup.keys(), key=lambda t: importance[t], reverse=True): if len(cardgroup[t]) > 1: if t == Pearl and cardgroup[t][0].score + cardgroup[t][0].score < 4: if DEBUG: print("search_play RESOLUTION: Pearl cards less than 4 points") return cardgroup[t][0:2] elif t == Pearl and len(cardgroup[t]) > 2: if DEBUG: print("search_play RESOLUTION: too much Pearl cards in hand") return cardgroup[t][0:2] elif len(cardgroup[t]) > 4: if DEBUG: print("search_play RESOLUTION: too much card type in hand") return cardgroup[t][0:2] if DEBUG: print("search_play RESOLUTION: fallback to default move") return [cardgroup[t][0]]