Exemple #1
0
        /// <summary>
        /// Construtor dos nodos filhos
        /// </summary>
        /// <param name="parent"></param>
        /// <param name="state"></param>
        public BoardNode(BoardNode parent, int[] _Tabuleiro, int _corDoJogador)
        {
            this.tabuleiro = _Tabuleiro;
            this.pai = parent;

            for (int j = 0; j < _Tabuleiro.Length; j++)
                if (_Tabuleiro[j] == CorJogadorAdversario(_corDoJogador))
                    numeroPecasJogadorAdverario++;
                else if (_Tabuleiro[j] == _corDoJogador)
                    numeroPecasJogador++;

            //this.profundidade = parent.profundidade + 1;
        }
Exemple #2
0
        /// <summary>
        /// Construtor do nodo pai
        /// </summary>
        /// <param name="state"></param>
        public BoardNode(int[] _Tabuleiro, int _corDoJogador)
        {
            this.tabuleiro = _Tabuleiro;
            //this.profundidade = 0;
            this.stepCost = 0;
            this.pai = null;

            for (int j = 0; j < _Tabuleiro.Length; j++)
                if (_Tabuleiro[j] == CorJogadorAdversario(_corDoJogador))
                    numeroPecasJogadorAdverario++;
                else if (_Tabuleiro[j] == _corDoJogador)
                    numeroPecasJogador++;
        }
Exemple #3
0
        /// <summary>
        /// Algoritmo que realiza a jogada do computador.
        /// </summary>
        /// <param name="_Tabuleiro">aka Posição. Situacao atual do tabuleiro do jogo</param>
        /// <param name="_Profundidade">Profundidade da recursão. Esta ligada com a dificuldade
        /// do jogo (quanto mais profundo, mais dificil)</param>
        /// <param name="_udtJogador">Jogador que deve realizar a jogada.</param>
        /// <returns></returns>
        private int Minimax(BoardNode _Nodo, int _Profundidade,
            Jogador _udtJogadorMax, Jogador _udtJogadorMin, bool _isMax)
        {
            int numeroPecasJogadorAdverario = -1;
            //if (_Profundidade == 0)
            //{
            //    List<BoardNode> lstSucessores = new List<BoardNode>();
            //    lstSucessores = GeraMovimentos(_Nodo, _udtJogadorMax.CorDoJogador);
            //    for (int i = 0; i < lstSucessores.Count; i++)
            //    {
            //        lstSucessores[i] = Minimax(lstSucessores[i], _Profundidade + 1, _udtJogadorMax, _udtJogadorMin, false);
            //    }

            //    lstSucessores.Sort(Comparer<BoardNode>.Default);
            //    return lstSucessores[lstSucessores.Count - 1];
            //}
            if (_Profundidade == m_ProfundidadeTotal)
            {
                for (int i = 0; i < _Nodo.Tabuleiro.Length; i++)
                    if (_Nodo.Pai.Tabuleiro[i] == CorJogadorAdversario(this.CorDoJogador))
                        numeroPecasJogadorAdverario++;

                return CalculaValorJogada2(_Nodo.Tabuleiro, this.PecasRestantes, numeroPecasJogadorAdverario);

            }
            else
            {
                List<BoardNode> lstSucessores = new List<BoardNode>();
                lstSucessores = GeraMovimentos(_Nodo, _udtJogadorMin.CorDoJogador);
                if (lstSucessores.Count == 0)
                {
                    for (int i = 0; i < _Nodo.Tabuleiro.Length; i++)
                        if (_Nodo.Pai.Tabuleiro[i] == CorJogadorAdversario(this.CorDoJogador))
                            numeroPecasJogadorAdverario++;

                    return CalculaValorJogada2(_Nodo.Tabuleiro, this.PecasRestantes, numeroPecasJogadorAdverario);
                }
                else
                {
                    for (int i = 0; i < lstSucessores.Count; i++)
                    {
                        lstSucessores[i].StepCost = Minimax(lstSucessores[i], _Profundidade + 1, _udtJogadorMin, _udtJogadorMax, !_isMax);
                    }
                    lstSucessores.Sort(Comparer<BoardNode>.Default);

                    if (_isMax)
                    {
                        return lstSucessores[lstSucessores.Count - 1].StepCost;
                    }
                    else
                    {
                        return lstSucessores[0].StepCost;
                    }
                }
            }
        }
Exemple #4
0
        private int MinimaxAlfaBeta(BoardNode _Nodo, int _Profundidade,
            Jogador _udtJogadorMax, Jogador _udtJogadorMin, bool _isMax, int _alpha, int _beta)
        {
            if (_Profundidade == m_ProfundidadeTotal)
            {
                return CalculaValorJogada2(_Nodo.Tabuleiro, _Nodo.NumeroPecasJogador, _Nodo.NumeroPecasJogadorAdverario);
            }
            else
            {
                List<BoardNode> lstSucessores = new List<BoardNode>();

                int i = 0;

                if (_isMax)
                {
                    lstSucessores = GeraMovimentos(_Nodo, _udtJogadorMax.CorDoJogador);
                }
                else
                {
                    lstSucessores = GeraMovimentos(_Nodo, _udtJogadorMin.CorDoJogador);
                }
                int nroSucessores = lstSucessores.Count;
                if (lstSucessores.Count == 0)
                {
                    return CalculaValorJogada2(_Nodo.Tabuleiro, _Nodo.NumeroPecasJogador, _Nodo.NumeroPecasJogadorAdverario);
                }
                else
                {
                    if (_isMax)
                    {
                        while (i < nroSucessores && _beta > _alpha)
                        {
                            lstSucessores[i].StepCost = MinimaxAlfaBeta(lstSucessores[i], _Profundidade + 1,
                                _udtJogadorMax, _udtJogadorMin, !_isMax, _alpha, _beta);

                            if (lstSucessores[i].StepCost > _alpha)
                            {
                                _alpha = lstSucessores[i].StepCost;
                            }
                            i++;
                        }
                        return _alpha;
                    }
                    else
                    {
                        while (i < nroSucessores && _beta > _alpha)
                        {
                            lstSucessores[i].StepCost = MinimaxAlfaBeta(lstSucessores[i], _Profundidade + 1,
                                 _udtJogadorMax, _udtJogadorMin, !_isMax, _alpha, _beta);

                            if (lstSucessores[i].StepCost < _beta)
                            {
                                _beta = lstSucessores[i].StepCost;
                            }
                            i++;

                        }
                        return _beta;
                    }
                }
            }
        }
Exemple #5
0
        /// <summary>
        /// Gera uma lista de proximas confiruações de tabuleiro possiveis a partir de um estado atual
        /// do tabuliero e do jogador que está jogando.
        /// </summary>
        /// <returns></returns>
        private List<BoardNode> GeraMovimentos(BoardNode _nodoTabuleiro, int _corJogador)
        {
            #region Coments...
            /*
             * Uma peca pode jogar:
             * - quando um vizinho estiver vazio
             *
             * - quando um vizinho contiver uma peca do adversario e a proxima casa na reta que passa
             * por ambos estiver vazia. Essa proxima casa pode ser calculada pela soma/subtracao do
             * modulo da diferenca da casa da peca que esta jogando para a peca adversaria vizinha.
             * --subtrae quando vizinho MENOR endereco_peca_atual
             * --soma quando vizinho MAIR endereco_peca_atual
             * Exemplo:
             *  Branca joga;
             *  Branca em 19; preta em 13;
             *  13 < 19? entao tabuleiro[13 - |19 - 13|] = 7; 7 vazia? entao branca_19 come preta_13
             *
             *  Branca joga;
             *  Branca 11; preta 17;
             *  11 < 17? senao tabuleiro[17 + |13 - 17|] = 21; 21 vazia? senao nao pode comer preta_17
             *
             *  Devemos bolar um geito (no pior dos casos muitos if's...) para tratar as bordas.
             *  Exemplo: se 19 for comer 15, será testado a casa 11, mas nao é possivel realizar esse movimento
             *  pelo tabuleiro.
             *  SOLUCAO: a casa onde a pedra que está comendo a adversario vai parar deve continuar sendo vizinha
             *  da casa onde estava a adversaria!!! :D
             *
             * Com isso, "é facil ver que" precisamos de duas listas: uma com movimentos para casas vazias e
             * outra com movimentos apenas de "comer pecas". Caso a lista de comer pecas seja diferente de NULL,
             * descartamos a primeira lista. Com isso, todos os proximos movimentos possiveis retornados serao
             * de comer.
             * Caso a lista de comer seja vazia, descartamos ela e retornamos a lista apenas com os movimentos
             * possiveis para vizinhos vazios.
             */
            #endregion

            List<BoardNode> lstVizinhosVazios = new List<BoardNode>();
            List<BoardNode> lstPecasAComer = new List<BoardNode>();

            List<int> vizinhosDaPeca;
            List<int> vizinhosDoAdversario;
            int ProximaCasaLivre;
            int[] novoTabuleiro;

            for (int casa = 1; casa < _nodoTabuleiro.Tabuleiro.Length; casa++)
            {
                if (_nodoTabuleiro.Tabuleiro[casa] == _corJogador)
                {
                    //vizinhosDaPeca = new List<int>();
                    //Lista com os vizinhos da casa atual
                    vizinhosDaPeca = Vizinhos[casa].ToList<int>();

                    //Testa para cada vizinho da casa atual se ele esta vazio. Se estiver, cria um novo
                    //estado de Tabuleiro, ocupando o vizinho vazio, esvaziando a casa antiga e gerando
                    //um novo nodo na lista.
                    foreach (int vizinho in vizinhosDaPeca)
                    {
                        /*
                         * Vizinho tem tres possibilidades:
                         * - ou esta VAZIO e a peca pode ocupar --> ocupa
                         * - ou esta ocupado por peca do adversario e talvez possa comer --> tentar comer
                         * - ou esta ocupado com propria peca --> nao faz nada
                         */
                        if (_nodoTabuleiro.Tabuleiro[vizinho] == VAZIA)
                        {
                            //Aparentemente é necessario usar o CopyTo pois ao atribuir um array no outro, apenas
                            //a referencia na mem é copiada ai os dois apontam pro mesmo lugar e da muita merda...
                            novoTabuleiro = new int[26];
                            _nodoTabuleiro.Tabuleiro.CopyTo(novoTabuleiro, 0);

                            novoTabuleiro[0] = NAO_COMEU;
                            novoTabuleiro[casa] = VAZIA;
                            novoTabuleiro[vizinho] = _corJogador;

                            lstVizinhosVazios.Add(new BoardNode(_nodoTabuleiro, novoTabuleiro, this.CorDoJogador));
                        }
                        //como já nao é vazio, ou é do mesmo time (entao == _corJogador)
                        //ou entao != _corJogador
                        else if (_nodoTabuleiro.Tabuleiro[vizinho] != _corJogador)
                        {
                            #region Coments...
                            //Vizinho == Adversario
                            /*
                             * Re-explicando...
                             * Se o vizinho contem um adversario e a proxima casa na mesma direcao do adversario
                             * tambem estiver vazia, o jogador que esta jogando pode comer essa peca.
                             *
                             * Para comela, entretanto, essa terceira casa (a que deve estar livre) tem que ser acessivel
                             * a partir da casa vizinha. Se nao, por exemplo, alguem que estiver na casa 19 pode tentar comer
                             * alguem da casa 15 e ir parar na 11, o q é impossivel pelo tabuleiro.
                             *
                             * Para resolver isso, esta sendo testado se a proxima casa vazia é vizinha da casa com
                             * a peca adversaria (a "passiva" q esta sendo comida...). Se for, entao o movimento
                             * pode ser realizado.
                             *
                             * Para calcular o endereco dessa proxima casa basta acessar o indice do tabuleiro referente
                             * a [end_vizinho +- |end_casa - end_vizinho|] => endereco do vizinho adversario menos ou mais o
                             * modulo da diferenca do endereco da casa da peca atual com o endereco do vizinho. Menos se o
                             * endereco do vizinho for menor que o da casa ("comendo para cima") ou mais se o endereco do vizinho
                             * for maior que o da casa ("comendo para baixo").
                             *
                             * Entao, cria-se um novo estado de tabuleiro com a casa da peca e do vizinho comido vazios,
                             * a proxima casa depois do vizinho ocupada.
                             */
                            #endregion

                            vizinhosDoAdversario = Vizinhos[vizinho].ToList<int>();

                            if (vizinho < casa)
                            {
                                ProximaCasaLivre = vizinho - Math.Abs(casa - vizinho);

                                if (ProximaCasaLivre >= 1 && ProximaCasaLivre <= 25)
                                {
                                    if (_nodoTabuleiro.Tabuleiro[ProximaCasaLivre] == VAZIA &&
                                        vizinhosDoAdversario.Contains(ProximaCasaLivre))
                                    {
                                        //Aparentemente é necessario usar o CopyTo pois ao atribuir um array no outro, apenas
                                        //a referencia na mem é copiada ai os dois apontam pro mesmo lugar e da muita merda...
                                        novoTabuleiro = new int[26];
                                        _nodoTabuleiro.Tabuleiro.CopyTo(novoTabuleiro, 0);

                                        novoTabuleiro[0] = COMEU_PECA;
                                        novoTabuleiro[casa] = VAZIA;
                                        novoTabuleiro[vizinho] = PECA_COMIDA;
                                        novoTabuleiro[ProximaCasaLivre] = _corJogador;

                                        lstPecasAComer.Add(new BoardNode(_nodoTabuleiro, novoTabuleiro, this.CorDoJogador));
                                    }
                                }
                            }
                            else if (vizinho > casa)
                            {
                                ProximaCasaLivre = vizinho + Math.Abs(casa - vizinho);

                                if (ProximaCasaLivre >= 1 && ProximaCasaLivre <= 25)
                                {
                                    if (_nodoTabuleiro.Tabuleiro[ProximaCasaLivre] == VAZIA &&
                                        vizinhosDoAdversario.Contains(ProximaCasaLivre))
                                    {
                                        //Aparentemente é necessario usar o CopyTo pois ao atribuir um array no outro, apenas
                                        //a referencia na mem é copiada ai os dois apontam pro mesmo lugar e da muita merda...
                                        novoTabuleiro = new int[26];
                                        _nodoTabuleiro.Tabuleiro.CopyTo(novoTabuleiro, 0);

                                        novoTabuleiro[0] = COMEU_PECA;
                                        novoTabuleiro[casa] = VAZIA;
                                        novoTabuleiro[vizinho] = PECA_COMIDA;
                                        novoTabuleiro[ProximaCasaLivre] = _corJogador;

                                        lstPecasAComer.Add(new BoardNode(_nodoTabuleiro, novoTabuleiro, this.CorDoJogador));
                                    }
                                }
                            }
                        }
                        else
                        {
                            //Aqui, o vizinho é do proprio time, nao faz nada.
                        }
                    }
                }
            }

            if (lstPecasAComer.Count == 0)
                return lstVizinhosVazios;
            else
                return lstPecasAComer;
        }