Beispiel #1
0
    void Update()
    {
        if (Main.isInitialised)
        {
            if (Main.Instance.mMachine.CurrentState.MyTurn == myTurn && !Main.isComplete)
            {
                if (!Main.Instance.mMachine.CurrentState.hasDrawn)                   //if has not drawn
                {
                    StartCoroutine(DrawingDelay());

                    if (draw == false)
                    {
                        AiAnim.SetTrigger("Drawing");
                        MCTSIterate();                                               //Get state that matches the current game state, then expand and simulate
                        treeNode = treeNode.select();                                //Based on calculation, select the best node to proceed
                        Main.Instance.AIDraw(treeNode.state.lastDrawDeck);           //Draw from a deck according to the node we just selected
                        Main.Instance.lastDrawDeck = treeNode.state.lastDrawDeck;    //Update game/board information

                        if (CardsInHand.CheckVictory(Main.Instance.computerCardsInHand))
                        {
                            treeNode.state.stateResult = MCTSState.Result.AIWin;
                        }
                    }
                }
                else if (Main.Instance.mMachine.CurrentState.hasDrawn)              //If has drawn
                {
                    //AiAnim.SetBool("Thinking", true);
                    StartCoroutine(DiscardingDelay());
                    if (draw == true)
                    {
                        AiAnim.SetTrigger("Discarded");
                        //AiAnim.SetTrigger("Discarding");
                        //AiAnim.SetBool("Thinking", false);
                        //AiAnim.SetTrigger("AIDiscard");
                        MCTSIterate();                                              //Get state that matches the current game state, then expand and simulate
                        treeNode          = treeNode.select();                      //Based on calculation, select the best node to proceed
                        Main.turnCounter += 1;
                        Main.Instance.AIDiscard(treeNode.state.lastDiscard);        //Draw a card according to the node selected
                        Main.Instance.lastDiscardCard = treeNode.state.lastDiscard; //Update game/board information
                        MCTSIterate();                                              //Now the children number has became zero, we need to iterate to get children
                    }
                }
            }
        }
    }
Beispiel #2
0
    public void HumanExecute()  //This function is used to draw or discard when the button clicked
    {
        if (!CardsInHand.CheckVictory(playerCardsInHand) && mMachine.CurrentState.GetName == "Player Turn State" && move == true)
        {
            DetectSelection();
            playerCardsInHand.ResetScore();//to show the potential score in the current hand right now (resets and displays at the start of every turn)
            playerCardsInHand.AnalyseHand(playerCardsInHand);

            if (!mMachine.CurrentState.hasDrawn)    //if has not drawn, then it will execute draw action
            {
                DeckAnimator.SetTrigger("Draw");
                mMachine.Execute(deckToDraw);
                lastDrawDeck = deckToDraw;
                mAI.MatchAndIterate();              //The AI will do its calculation even it's in player's turn, keeping track of the current state is necessary or the AI will be very dumb

                if (CardsInHand.CheckVictory(playerCardsInHand))
                {
                    UpdateEverything();
                    endCanvas.SetActive(true);
                    endText.text     = "Player Win!";
                    isComplete       = true;
                    playerWin        = true;
                    PlayerScore.text = playerScore; //Setting player score
                    for (int i = 0; i < displayCards_AI.Length; i++)
                    {
                        displayCards_AI[i].GetComponentInChildren <CardImage>().enabled = true;
                    }
                }
            }
            else    //if has drawn, then it will execute discard action
            {
                if (mMachine.Execute(cardToDiscard))
                {
                    lastDiscardCard = cardToDiscard;
                    turnCounter    += 1;
                    mAI.MatchAndIterate();
                    move = false;
                }
            }
            UpdateEverything();
        }
    }
Beispiel #3
0
    public void expand()                     //This function takes into account of every possibility of the game and make them children of current treeNode
    {                                        //In draw phase, there are 2 possibilities, draw from drawDeck or discardDeck
                                             //In discard phase, there are 9 possibilities, because you can discard any of the 9 cards
        if (state.hasDrawn)
        {
            #region DiscardPhase   //Discard phase expand, 9 possibilities

            #region HumanTurnDiscardExpand
            if (state.currentTurn == Main.Turn.Human)
            {
                state.humanCards.LeftShiftElement();
                foreach (Card cardToDiscard in state.humanCards.GetCards())
                {
                    TreeNode childNode = new TreeNode(new MCTSState(state.currentTurn, state.drawDeck, state.discardDeck, state.humanCards, state.AICards, state.hasDrawn, state.lastDiscard, state.lastDrawDeck));

                    if (cardToDiscard != null)
                    {
                        childNode.state.discardDeck.Add(cardToDiscard);
                        childNode.state.humanCards.Remove(cardToDiscard);
                        childNode.state.discardDeck.LeftShiftElement();
                        childNode.state.humanCards.LeftShiftElement();
                        childNode.state.lastDiscard = cardToDiscard;
                        childNode.state.stateResult = MCTSState.Result.None;
                        childNode.state.hasDrawn    = false;
                        childNode.state.currentTurn = Main.Turn.AI;
                        children.Add(childNode);
                    }
                }
            }
            #endregion

            #region AITurnDiscardExpand
            else if (state.currentTurn == Main.Turn.AI)
            {
                // Debug.Log("Expand AI turn, discard");
                state.humanCards.LeftShiftElement();
                foreach (Card cardToDiscard in state.AICards.GetCards())
                {
                    TreeNode childNode = new TreeNode(new MCTSState(state.currentTurn, state.drawDeck, state.discardDeck, state.humanCards, state.AICards, state.hasDrawn, state.lastDiscard, state.lastDrawDeck));

                    // Card cardToDiscard = childNode.state.AICards.GetCardByMeldType((MeldType)i);
                    if (cardToDiscard != null)
                    {
                        childNode.state.discardDeck.Add(cardToDiscard);
                        childNode.state.AICards.Remove(cardToDiscard);
                        childNode.state.discardDeck.LeftShiftElement();
                        childNode.state.AICards.LeftShiftElement();
                        childNode.state.lastDiscard = cardToDiscard;

                        childNode.state.currentTurn = Main.Turn.Human;
                        childNode.state.stateResult = MCTSState.Result.None;
                        childNode.state.hasDrawn    = false;
                        children.Add(childNode);
                    }
                }
            }
            #endregion

            #endregion
        }
        else
        {
            #region DrawPhase //Draw phase expand, 2 possibilities (1 possibility when discard deck is empty)

            #region HumanTurnDrawExpand
            if (state.currentTurn == Main.Turn.Human)
            {
                //Debug.Log("Expand human turn, draw");
                for (int i = 0; i < 2; i++)
                {
                    TreeNode childNode = new TreeNode(new MCTSState(state.currentTurn, state.drawDeck, state.discardDeck, state.humanCards, state.AICards, state.hasDrawn, state.lastDiscard, state.lastDrawDeck));
                    if (i == 0)
                    {
                        if (childNode.state.discardDeck.Count > 0)
                        {
                            childNode.state.humanCards.Add(childNode.state.discardDeck.Pop());
                            childNode.state.discardDeck.LeftShiftElement();
                            childNode.state.lastDrawDeck = CherkiMachineState.SourceDeck.DiscardDeck;
                        }
                    }
                    else
                    {
                        childNode.state.humanCards.Add(childNode.state.drawDeck.Pop());
                        childNode.state.lastDrawDeck = CherkiMachineState.SourceDeck.DrawDeck;
                    }

                    childNode.state.humanCards.LeftShiftElement();
                    childNode.state.hasDrawn = true;
                    if (CardsInHand.CheckVictory(childNode.state.humanCards))
                    {
                        childNode.state.stateResult = MCTSState.Result.HumanWin;
                    }
                    children.Add(childNode);
                }
            }
            #endregion

            #region AITurnDrawExpand
            else if (state.currentTurn == Main.Turn.AI)
            {
                //Debug.Log("Expand AI turn, draw");
                for (int i = 0; i < 2; i++)
                {
                    TreeNode childNode = new TreeNode(new MCTSState(state.currentTurn, state.drawDeck, state.discardDeck, state.humanCards, state.AICards, state.hasDrawn, state.lastDiscard, state.lastDrawDeck));
                    if (i == 0)
                    {
                        if (childNode.state.discardDeck.Count > 0)
                        {
                            childNode.state.AICards.Add(childNode.state.discardDeck.Pop());
                            childNode.state.discardDeck.LeftShiftElement();
                            childNode.state.lastDrawDeck = CherkiMachineState.SourceDeck.DiscardDeck;
                        }
                    }
                    else
                    {
                        childNode.state.AICards.Add(childNode.state.drawDeck.Pop());
                        childNode.state.lastDrawDeck = CherkiMachineState.SourceDeck.DrawDeck;
                    }
                    childNode.state.AICards.LeftShiftElement();
                    childNode.state.hasDrawn = true;
                    if (CardsInHand.CheckVictory(childNode.state.AICards))
                    {
                        childNode.state.stateResult = MCTSState.Result.AIWin;
                    }
                    children.Add(childNode);
                }
            }
            #endregion

            #endregion
        }
    }
Beispiel #4
0
    public double simulate() //It simulates all the way to the end of the game, from currentNode
    {                        //Based on the result of the simulation(Win/lose), it return different sim value, used to judge whether its a good node or not
        MCTSState simState = new MCTSState(state.currentTurn, state.drawDeck, state.discardDeck, state.humanCards, state.AICards, state.hasDrawn, state.lastDiscard, state.lastDrawDeck);

        simState.stateResult = state.stateResult;
        int simValue = int.MinValue;

        while (simState.stateResult == MCTSState.Result.None && simState.drawDeck.Count > 0)
        {
            if (!simState.hasDrawn)//In Draw phase
            {
                simState.hasDrawn = true;

                if (simState.currentTurn == Main.Turn.AI) //AI's turn
                {
                    if (simState.discardDeck.Count > 0)
                    {
                        if (simState.AICards.NumOfCardsOfType(simState.discardDeck.GetTop().MeldType) == 2) //if drawing from discard deck can form a meld
                        {
                            simState.AICards.Add(simState.discardDeck.Pop());                               //Draw from discard deck
                        }

                        else
                        {
                            simState.AICards.Add(simState.drawDeck.Pop());   //Other wise just take from draw deck
                        }
                    }
                    else     //If no card in discard deck, draw from draw deck
                    {
                        simState.AICards.Add(simState.drawDeck.Pop());
                    }

                    if (simState.drawDeck.Count <= 0)  //After draw finish, if the draw deck is empty, mark the game result as draw
                    {
                        simState.stateResult = MCTSState.Result.Draw;
                        break;
                    }

                    if (CardsInHand.CheckVictory(simState.AICards))       //If victory goal met, mark the game result as AIWIN
                    {
                        simState.stateResult = MCTSState.Result.AIWin;
                        break;
                    }
                }
                else if (simState.currentTurn == Main.Turn.Human)  //Human's turn,everything same as above, basically duplicated code
                {
                    if (simState.discardDeck.Count > 0)
                    {
                        if (simState.humanCards.NumOfCardsOfType(simState.discardDeck.GetTop().MeldType) == 2)  //if drawing from discard deck can form a meld
                        {
                            simState.humanCards.Add(simState.discardDeck.Pop());
                        }
                        else
                        {
                            simState.humanCards.Add(simState.drawDeck.Pop());
                        }
                    }
                    else
                    {
                        simState.humanCards.Add(simState.drawDeck.Pop());
                    }

                    if (simState.drawDeck.Count <= 0)
                    {
                        simState.stateResult = MCTSState.Result.Draw;
                        break;
                    }

                    if (CardsInHand.CheckVictory(simState.humanCards))
                    {
                        simState.stateResult = MCTSState.Result.HumanWin;
                        break;
                    }
                }
            }

            else if (simState.hasDrawn)//In discard phase
            {
                simState.hasDrawn = false;
                if (simState.currentTurn == Main.Turn.AI)                                       //AI's turn
                {
                    MeldType typeToDiscard = MostUselessType(simState.AICards);                 //Get the least valuable meld type among the cards in hand
                    Card     cardToDiscard = simState.AICards.GetCardByMeldType(typeToDiscard); //get a card of that meld type, then discard it
                    simState.AICards.Remove(cardToDiscard);
                    simState.AICards.LeftShiftElement();
                    simState.discardDeck.Add(cardToDiscard);
                    simState.discardDeck.LeftShiftElement();
                    simState.currentTurn = Main.Turn.Human;
                }

                else   //duplicated code
                {
                    MeldType typeToDiscard = MostUselessType(simState.humanCards);
                    Card     cardToDiscard = simState.humanCards.GetCardByMeldType(typeToDiscard);
                    simState.humanCards.Remove(cardToDiscard);
                    simState.humanCards.LeftShiftElement();
                    simState.discardDeck.Add(cardToDiscard);
                    simState.discardDeck.LeftShiftElement();
                    simState.currentTurn = Main.Turn.AI;
                }
            }
        }

        switch (simState.stateResult)
        {
        case MCTSState.Result.Draw:
        {
            // Debug.Log("Draw result simed");
            simValue = 0;
            break;
        }

        case MCTSState.Result.HumanWin:
        {
            // Debug.Log("HumanWin result simed");
            simValue = -1;         //1 means victory, -1 means defeat
            break;
        }

        case MCTSState.Result.AIWin:
        {
            //Debug.Log("AIWin result simed");
            simValue = 1;
            break;
        }

        default:
        {
            // Debug.LogError("illegal simStateResult value");
            break;
        }
        }
        return(simValue);
    }
Beispiel #5
0
 public override bool CheckVictory()
 {
     return(CardsInHand.CheckVictory(mCards));
 }