From c092f7ca7e5f349efbb70a5f276aad2fca8b1083 Mon Sep 17 00:00:00 2001 From: lffloyd Date: Thu, 27 Sep 2018 00:28:43 -0300 Subject: [PATCH] Update Jogador.py --- classes_base/Jogador.py | 150 +++++++++++++++++++++++----------------- 1 file changed, 85 insertions(+), 65 deletions(-) diff --git a/classes_base/Jogador.py b/classes_base/Jogador.py index 7d29acc..6a8ac9b 100644 --- a/classes_base/Jogador.py +++ b/classes_base/Jogador.py @@ -1,9 +1,33 @@ -#Define a classe Jogador e seus atributos associados. +# MIT License +# +# Copyright (c) 2018 Luiz Felipe de Melo (lffloyd), Vítor Costa (vitorhardoim), Renato Bastos (RenatoBastos33) +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +############################################################################################################## + + +#Define a classe Jogador e seus atributos associados. A classe pode comportar-se como um jogador aleatório, humano ou +# de inteligência artificial. #Escrito por: Luiz Felipe, Vítor Costa, Renato Bastos. import random -import os from classes_base.Cor import * from classes_base.Peca import * from classes_busca.Expectiminimax import * @@ -13,10 +37,11 @@ class Jogador(): #Constantes para identificação do tipo de jogador. - RANDOM = 3 - MCTS = 2 - EXPECTMM = 1 - HUMANO = 0 + RANDOM = 3 #Jogador 'Random'. Executa qualquer das ações que tiver como disponíveis em qualquer momento do jogo. + MCTS = 2 #I.A. que emprega Monte Carlo tree search na determinação do melhor mov. a ser executado. + EXPECTMM = 1 #I.A. que emprega Expectiminimax para determinar a melhor jogada a ser feita. + HUMANO = 0 #Representa um jogador humano, que interage com o jogo escolhendo as jogadas que deseja realizar por + # linha de comando. #Construtor define atributos como a "mão" do jogador (i.e. suas peças), as peças jogáveis num dado momento (i.e. aque- #las que ele pode efetivamente encaixar no tabuleiro), qtd. de pontos acumulada e outros parãmetros de controle. @@ -35,8 +60,7 @@ def __init__(self, ind=None, tipo=HUMANO): elif (self.tipo == self.MCTS): self.tipoStr = "MCTS" else: self.tipoStr = "RANDOM" - self.vezesQueComecou = 0 - + #Rerpesentação textual da instância de Jogador. def __str__(self): resp = "J" + str(self.__ind) + " ("+ self.tipoStr + ") -" resp += "\tMão: " @@ -51,7 +75,6 @@ def adicionaPeca(self, peca): self.__mao.append(peca) #Remove uma dada instância de Peça da mão do jogador, caso ela exista. Necessita receber uma instância de Mesa #para manter a consistência da variável que armazena as peças jogáveis num dado momento pelo jogador. - def removePeca(self, mesa, peca): if (len(self.__mao) != 0): self.__mao.remove(peca) @@ -125,7 +148,6 @@ def pegaPecasJogaveis(self): return self.__maoJogaveis #Retorna todas as possibilidades de jogadas disponíveis no dado momento a esta instância de Jogador. #O retorno é composto de uma matriz contendo pares [Peça, Posição de jogada, Probabilidade da jogada]. - #Nenhum cálculo mais elaborado é executado ainda para a probabilidade. def possibilidadesJogaveis(self, mesa): possibilidades = [] probabilidade = 1//7 @@ -141,13 +163,11 @@ def possibilidadesJogaveis(self, mesa): else: possibilidades.append([peca, (0 if (peca.ehJogavel(esq)) else 1), (self.probabilidadeJogada(peca, esq, mesa) if (peca.ehJogavel(esq)) else self.probabilidadeJogada(peca, dir, mesa))]) - #Distribui uma probabilidade equivalente para cada uma das possíveis escolhas a serem feitas. - #for jogada in possibilidades: - # print("Peça.:"+str(jogada[0]) +",\tPos.:"+ str(jogada[1]) +",\tProb.:"+ str(jogada[2])) return possibilidades + #Calcula a probabilidade de uma dada peça ser encaixada numa dada posição do tabuleiro/mesa baseando-se no total + # de ocorrência dos valores das faces da peça no tabuleiro. def probabilidadeJogada(self, peca, pos, mesa): - if (self.tipo == self.RANDOM): return 0 contagemMax = 7 contagem = 1 probMax = 1 @@ -157,7 +177,8 @@ def probabilidadeJogada(self, peca, pos, mesa): return probabilidade #Compra peças da mesa enquanto existirem peças disponíveis para compra na mesma e/ou enquanto o jogador não - #tiver nenhuma peça jogável em mãos. + #tiver nenhuma peça jogável em mãos. Invólucro para o métod de compra de peças disponibilizado pela classe Mesa + # (mesa.comprarPeca()). def compraDaMesa(self, mesa): self.atualizaPecasJogaveis(mesa) while (len(self.pegaPecasJogaveis()) == 0): @@ -168,7 +189,7 @@ def compraDaMesa(self, mesa): else: break return - #Elimina todas as cartas de um jogador. + #Elimina todas as peças da mão de um jogador. def limparMao(self): self.__mao = [] self.__maoJogaveis = [] @@ -186,15 +207,14 @@ def somatorioPecas(self): for peca in self.__mao: soma += (peca.esq() + peca.dir()) return soma - #Incrementa a pontuação de um jogador. + #Incrementa a pontuação de um jogador de um valor passado por parâmetro. def somaPontos(self, soma): self.__pontos += soma #Retorna a qtd. de pontos acumulada até o momento do jogador. def pegaPontos(self): return self.__pontos - #Método que coordena cada uma das jogadas do jogador. Até o momento, necessita da interação de um humano para realizar - # uma jogada. Aguarda até que o jogador escolha uma peça válida para encaixar ou até que não possua nenhuma peça válida - #para jogar, passando a vez a seu oponente. + #Método que coordena qual o tipo de método de jogar será chamado. Há diferentes métodos para cada um dos diferentes tipos + # de jogadores existentes. def jogar(self, mesa, oponente): if (self.tipo == self.HUMANO): return self.jogarHumano(mesa, oponente) elif (self.tipo == self.EXPECTMM): return self.jogarExpectMM(mesa, oponente) @@ -208,7 +228,7 @@ def jogarHumano(self, mesa, oponente): self.atualizaPecasJogaveis(mesa) # Caso não existam peças jogáveis em sua mão, executa a compra de peças enquanto for possível. if (len(self.pegaPecasJogaveis()) == 0): self.compraDaMesa(mesa) - print("\n" + str(mesa)) + #print("\n" + str(mesa)) print("\n" + self.pecasJogaveis(mesa, self.__mao)) print(self) if (len(self.pegaPecasJogaveis()) == 0): @@ -238,12 +258,11 @@ def jogarExpectMM(self, mesa, oponente): self.atualizaPecasJogaveis(mesa) #Caso não existam peças jogáveis em sua mão, executa a compra de peças enquanto for possível. if (len(self.pegaPecasJogaveis()) == 0): self.compraDaMesa(mesa) - print("\n" + str(mesa)) + #print("\n" + str(mesa)) print("\n" + self.pecasJogaveis(mesa, self.__mao)) print(self) # Caso mesmo assim não seja possível conseguir uma peça jogável, pula esta rodada sem executar movimento. if (len(self.pegaPecasJogaveis()) == 0): - #mesa.fechada = True self.setaJogou(False) print("J" + str(self.__ind) + " passou a vez.") else: @@ -272,54 +291,55 @@ def jogarExpectMM(self, mesa, oponente): oponente.setaVez(True) return - # Define o método 'jogar' para um jogador controlado por inteligência artificial (Monte-Carlo tree search). + # Define o método 'jogar' para um jogador controlado por inteligência artificial (Monte Carlo tree search). def jogarMCTS(self, mesa, oponente): if self.__vezAtual == False: return else: - adicionou = False - while not adicionou: - print("\n" + self.pecasJogaveis(mesa, self.__mao)) - print(self) - print("\n" + str(mesa)) - while (len(self.__maoJogaveis) == 0): - if (len(mesa.pegaPecasAComprar()) != 0): - self.adicionaPeca(mesa.comprarPeca()) - self.__maoJogaveis = [] - print("\n" + self.pecasJogaveis(mesa, self.__mao)) - print(self) - else: - self.setaJogou(False) - self.setaVez(False) - oponente.setaVez(True) - print("J" + str(self.__ind) + " passou a vez.") - return - estadoAtual = EstadoMCTS(self, oponente, mesa) - noTeste = MonteCarloNo(estadoAtual) - noTeste.expandir() - print(noTeste) - noTeste.melhorFilho() - escolhida = int(input("Qual peça deseja jogar? ")) - if (len(mesa.pegaTabuleiro()) != 0): pos = int(input("Em que posição?(0 p/ esquerda, 1 p/ direita) ")) - else: pos = 0 - peca = self.__mao.pop(escolhida - 1) - adicionou = mesa.adicionarNaMesa(peca, pos) - if (not adicionou): self.__mao.append(peca) - else: self.setaJogou(True) - self.__maoJogaveis = [] - peca.ordem(len(mesa.pegaTabuleiro())) - self.setaVez(False) - oponente.setaVez(True) - return + print("\n" + self.pecasJogaveis(mesa, self.__mao)) + print(self) + #print("\n" + str(mesa)) + while (len(self.__maoJogaveis) == 0): + if (len(mesa.pegaPecasAComprar()) != 0): + self.adicionaPeca(mesa.comprarPeca()) + self.__maoJogaveis = [] + print("\n" + self.pecasJogaveis(mesa, self.__mao)) + print(self) + else: + self.setaJogou(False) + self.setaVez(False) + oponente.setaVez(True) + print("J" + str(self.__ind) + " passou a vez.") + return + estadoAtual = EstadoMCTS(self, oponente, mesa) + noTeste = MonteCarloNo(estadoAtual) + noTeste.expandir() + if len(noTeste.filhos)>1: + for i in range(100): + melhorfilho=noTeste.melhorFilho() + noTeste.gerarJogo(melhorfilho,False) + melhorfilho=noTeste.melhorFilho() + print(str(melhorfilho.UCT)) + self.removePeca(mesa,melhorfilho.estado.ultimaPecaJogada) + mesa.adicionarNaMesa(melhorfilho.estado.ultimaPecaJogada, melhorfilho.estado.onde) + self.setaJogou(True) + self.__maoJogaveis = [] + melhorfilho.estado.ultimaPecaJogada.ordem(len(mesa.pegaTabuleiro())) + #print("MCTS jogou a peça:"+ str(melhorfilho.estado.ultimaPecaJogada)+"na posição :"+ str(melhorfilho.estado.onde)+"\n" ) + self.setaVez(False) + oponente.setaVez(True) + return - # Define o método 'jogar' para um jogador 'random', usado para testes. + # Define o método 'jogar' para um jogador 'random'. Usado para testes. Realiza escolhas de jogadas sem obedecer nenhum + # padrão específico de jogo, escolhendo apenas qualquer das possibilidades existentes para ele num dado momento. def jogarRandom(self, mesa, oponente): - if (self.__vezAtual == False): return + if self.__vezAtual == False: return self.atualizaPecasJogaveis(mesa) # Caso não existam peças jogáveis em sua mão, executa a compra de peças enquanto for possível. - if (len(self.pegaPecasJogaveis()) == 0): - if (len(self.__mao) != 0): self.compraDaMesa(mesa) - if (len(self.pegaPecasJogaveis()) == 0): - self.setaJogou(False) + if (len(self.pegaPecasJogaveis()) == 0): self.compraDaMesa(mesa) + #print("\n" + str(mesa)) + #print("\n" + self.pecasJogaveis(mesa, self.__mao)) + #print(self) + if (len(self.pegaPecasJogaveis()) == 0): self.setaJogou(False) #print("J" + str(self.__ind) + " passou a vez.") else: possibilidades = self.possibilidadesJogaveis(mesa) @@ -339,4 +359,4 @@ def contarValor(self, valor): cont = 0 for peca in self.__mao: if (peca.esq() == valor) or (peca.dir() == valor): cont += 1 - return cont \ No newline at end of file + return cont