138 lines
6.0 KiB
Python
138 lines
6.0 KiB
Python
#!/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]]
|