

== CardsGame: AI

Now back to the basic, in a general card game, gameplay consist of fews ideas:


.  Which card to choose
.  Which state of that card to choose

In a magic card game, two opponents including AI should concern a few more and how to answer these question to defeat the other:


*  Which magic card support/destroy which card
*  How to get Best health point and best damage


== A – Tattic and stragegies

Now I kind of don’t want to write much about AI in the first tutorial but let’s go, it wont take too long.


In this game, the AI should have appropriate stragegies from Phase to Phase, even though, we should have a global stragegy for each round. Here are “naive” stragegies of the magic card AI:



=== Summon Cards (Main phase 1&2):

In the MainPhase, if you can summon, that mean there is card for you to have a valid summon. Wisely choose one option:



==== - STRAGEGY 1) Choose the biggest attack/defend card.

When you don’t have enough appropriate tribute cards to summon a “many stars” Card


.  Just summon the biggest attack\defend card you have.
.  To decide to summon (attack||defend), check what cards are in the field at the moment and compare your cards to your opponent cards, if the result is :
..  “GoodToAttack” – choose Biggest Attack – Attack State
..  “ShouldDefend” – choose Biggest Defend – Defend state

.  summon it, and to the next Phase


==== - STRAGEGY 2) Choose fews smallest card to tribute and summon a biggest one.

When you HAVE enough appropriate tribute cards to summon a “many stars” Card (always with big attack/defend points and have effects)


.  Choose the “biggest” and “most many stars” card.
.  Choose the “smallest” cards enough to tribute to summon this card.
..  If you can not even summon anything, have to Pass (by the rule).

.  Futher, if there is no card in your ground mark the Brain with “Dangerous situation” and Pass.

——



=== Use support Cards (every action phases):

In every action phase, except for DrawPhase and Endphase, you can use support card like MagicCard, TrapCard…etc. We can design a function to evaluate thoose card by how good is going to be when called in the game, but for the time being, we use such simplest tragagy:

'''


==== STRAGEGY 3) Use all the support cards in one turn

That mean you are very hungry for the final win. It’s not always intelligent to do so in the POV of a professional duelist but hey… Ok. Now we want to pull all out support cards in one turn.

'''


==== STRAGEGY 4) Category cards in the game

You should devide the support card and its effect to type and handle it by type, that’s the naive way but appropriate for DecisionTree technique we used here.

'''

Q&amp;A


.  Q: How many type of support card are there?
.  A: Trap card can flip whenever opponent take action like summon or attack. Magic card can do almost every effect from increase healpoint to destroy everything, change the field

.  Q: How many type this naive AI know how to use?
.  A: Many type of support card and effect are there in the real game but the AI use a “DecisionTree” technique just use a few which you know exactly what it do. For more complicated intelligent, we have to use complicated AI model like Neutral network or Genetic Algorimth..:

*  o) Support Point Card: Card that increase/decrease the demon cards point.
*  o) Heal Card: Card that increase/decrease the opponents point directly.
*  o) Special Summon Card: Card that can bring demon card to the field in special way.
*  o) Destroy/Clean Card: Card that destroy demons or other support card
*  o) State Constraint Card: Card that lock or unlock the Limit of the game, like noActtack, noDefend..

——



==== STRAGEGY 5) Bigger biggest – Smallest smaller

- Q: Which Support Point Card support to which demon?


- A: You want to combine a biggest possible Card. So all biggest support card to the biggest demon. In oposite, you want to decrease all the demon of opponent on the field to the point that you can destroy it by attack or can not attack you anymore. So you just try to find the way to decrease those attack point to


*  o) the smallest defend point of your defend demon if you have any defend demon
*  o) or smallest attack point if you only have attack demon
*  o) or 0 if you have no demon

We can have sotisphicated way to distribute thoose support point but just do it as simple as possible.

'''


=== Decide what to do:


==== STRAGEGY 6) Attack who and how? Decide to attack or defend

Image you have a few demons in the field to attack your opponent.



===== Step1, first glance calculation:

There is 3 situation here:


.  All your demon are better than your opponent’s current avaiable cards, so you will not lose any health point in the next turn, even if your opponent attack back. It’s called Dominance in game theory   
.  In our game, this situation call “GoodToAttack”
.  You have a few better and a few worse, you want to attack. – This situation call “Average” and need futher calulation.
.  You can not attack at all, or lost points. So you should switch to defend. – This situation call “ShouldDefend”. (Not to mention: Affaid of trap card will flip when you take action?)
.  In fact, 3 above situations can be calculated by dertemine “forecast” result health point of two opponents.


===== Step2, further calculation:

Apply the attack of all your the demons to each of your opponent demons and calculate the result points of both, call it a case. Best case is you win directly, less good case is you cause damage a lot, worse case, you should not attack cause you lose or lost points, it’s a bad idea.



===== Step3, Apply:

After finish calculation, you apply the whole case in the current turn.

'''


==== STRAGEGY 7) Dangerous – Prevent attack | GoodToAttack – Prevent deffend

The state constraints are very powerful stragegy when you can use it.
If you in Dangerous situation, which your AI brain mark. You can prevent your opponent not to attack in a few rounds or forever. In opposite, you can prevent your opponent to take defend by the opposite constraint.
If you only have the magic card to constraint one card, use it with the biggest or smallest card possible so your benifit is maximum!


The usage of Heal Card ,Destroy/Clean Card,Special Summon are trivial and pretty obvious by combining the previous stragegy so I ommited this part! :p

'''


== B-AI Techs

As the result of making a sotiphicated AI, AI common techniques are used in mixed form, specific with the native of languages and tied to the game or the game engine. 


But it's a good idea to clarify some parts of them to help you see the design more clearly and recoginize the pattern for your futher developing.


It's also worth to mention some patterns that already used in JME3 here and there: like State pattern, .



=== Decision/Behavior Tree

Decision/Behavior Tree


From wikipedia 


In this game, Decision/Behavior Tree is not metioned as a implementation of Data base Decision/Behavior Tree like common in AI playground, but a structure to define actions and behaviours, that's a tree. Whatever your tree building techniques is, the Tree than decide very separation situations in a nested form.


That's why Decision Tree is pretty straight forward for almost programming language (via built in branching controls, such as : switch or if/else ).


In this game, Decision Tree help in organize situations in each phases.



=== Finite State Machine

In this game, Finite State Machine help to implement simple Card Character AI.



=== MiniMax

In the previous section, we talked about “Forecast what will happen in a few next rounds”, if you know the result, you can definitely choose a most appropriate path. There is a related problem in the field of AI Tactic, called Minimax. The basic idea of minimax is .


From wikipedia 


In this game, MiniMaxing is a little bit different from what you see in a normal Board/Chess game for example. MiniMaxing here help to evaluate the DesisionTree in a short term (mean short in time and light in processing space..)



=== FuzzyLogic

FuzzyLogic  is 


link:http://en.wikipedia.org/wiki/Fuzzy_logic[http://en.wikipedia.org/wiki/Fuzzy_logic]


In this game, FuzzyLogic is applied to extract the features and the situation from the game state and help decide what situation its it. Its upper layer is Case base (formed by more exact , accurate AI situation model)



=== CaseBase


== C-AtomAI usages


== D-Implementation

In above sections, we already declare a few rules which can have us to filter out which card are in hand, which card are in grave, ground, magic… etc. Later we will use them as ultilites in the AI.


The first try to implement the AI


[source,java]

----

package magiccard.gameplay.ai

import magiccard.*
import magiccard.gameplay.*
import static magiccard.gameplay.TurnPhase.TurnPhaseType.*
/**
 * This class is the AI for playing YugiOh Magic Card game.
 * The main technique used is DecisionTree & NeutralNetwork to decide actions
 */
public class CardPlayerAI {
    enum AILevel {Starter,Normal,HardCore,Duelist,Best;
        int deep;
    }
    AILevel level;
    CardGamePlay gamePlay;
    CardPlayer player;
    enum StragegySituation {GoodToAttack,ShouldDefend,Unknown,Dangeous}
    StragegySituation situation= StragegySituation.Unknown;
    def memories = [:]
    // The list of special card (id) that will have higher priority at any time
    def listOfSpecialCards = []

    /**
     *AI sepecific params
     **/
    int maxTime = 5000
    int maxSteps = 500
    int maxBranch = 50
    int maxGuess = 5

    int randomness = 30

    // save delayed action
    def actions
    public CardPlayerAI(CardGamePlay gamePlay){
        this.gamePlay = gamePlay;
        this.actions = []
    }

    public String toString(){
        return “AI level : “+this.level.toString() + ” status :” + this.situation.toString()
    }
    public int think(){
        int startTime = System.currentTimeMillis()
        if (gamePlay.currentTurn.currentPhase.type == MainPhase){
            // try to summon
            if (!gamePlay.currentTurn.currentPhase.monsterSummoned){
                def summonableCards = player.hand.findAll{card-> canSummon(card)==true};
                if (!summonableCards.isEmpty()){
                    def bestCard = summonableCards.max{card-> card.attack}
                    actions<
            delayedAct()
        }

        actions.clear();
    }
    //self action

    void summon(Card card){
        gamePlay.notifyMoveCard(card,”enableHover”)
        gamePlay.fromHandToGround(card);
        gamePlay.currentTurn.currentPhase.monsterSummoned = true;
    }
    /**
     * MINIMAX SUPPORT
     * See the game as the minimum forecastable loss problem and calculate the case
     * In fact, you can use minimax as a base heristic case and then extend
     */

    /**
     * CASE BASE SUPPORT
     * Not for a naive approach anymore.
     * In fact, you can build a heristic case and calculate the result in a few next round to see if the value you gain (win) or lost is sastified
     */
    def tryCase(Case aCase){
        return result;
    }
    def askForSelect(type,inCardList,info,condition){

    }
    public Case findBestSummonCase(){

    }
    public Case findBestMagicCase(){

    }
    public Case findBestSupportCase(){

    }
    public Case findBestOveralCase(){}

    // self evaluation
    public float evalGoodToAttack(Card card){

    }
    public float evalGoodToDefend(Card card){

    }
    /* This function evaluate the value of these two cards when the AI choose to support targetCard with the approriate supportCard*/
    public float evalGoodToSupport(Card targetCard,Card supportCard){

    }
    /* This function evaluate the value of this card when they want to keep or discard it by purpose */
    public float evalGoodOveral(Card card){

    }
    // Rule
    public boolean canSummon(Card aCard){

        // enough tribute
        int stars = aCard.level.toInteger()
        boolean enoughStar=false;
        if ( stars > 6){
            if (stars – 5 > player.ground.size()){
                enoughStar =true
            } else {
                enoughStar =false
            }

        } else {
            enoughStar=true;
        }
        //(!aCard.summonCancel) && && sastifySummonCondition(aCard)
        return (enoughStar && aCard.isMonsterCard());
    }

}

----

And the way to call it … CardGamePlay 


[source,java]

----

            case MainPhase:
                if (!currentTurn.player.aiPlayer){
                    if (isPlayerChangePhase(MainPhase)){
                        nextPhase()
                    } else {
                        humanSelectFunction();
                    }
                } else {
                    println(currentTurn.player.ai);
                    currentTurn.player.ai.think();
                    currentTurn.player.ai.act();
                }

----

The fun things here are we delayed Action we want the AI and save to Actions list made from Closure. In the main loop, we wait till ai.act is called then execute all the delayed action. The power of Groovy once again shown! By this technique we can easily introduce paralel computing with an cool ulitities of Groovy named <<gpars#,GPars>>. But we don’t use it right now though ! 


:roll:

