Search code examples
androidandroid-imageviewmultiplayer

How to pass a turn to AI in a game?


I am writing a simple game for 2 players, where they have to make turns after each other - select a few objects to remove from the board (removing is actually setting an ImageView invisible), then a player presses "End turn" at the end to pass the turn to another player.

The board is a GridLayout with the ImageViews, all ImageViews have onClickListener(), and they are all visible at the beginning of the game. A player clicks on several ImageViews (at these moments their IDs are placed in an array) and then clicks "End turn", this array of his move is analyzed, the corresponding ImageViews are set to invisible, and after that the turn should be passed to another player (the array is cleaned and the number of the current player changes).

All objects on the board have onClickListeners() attached. Upon clicking, their IDs are placed in an array, and a variable contains the number of the current player. The turns are switched in onClick() method on a onClickListener(), attached to the "End turn" button, and it's simply cleaning the array of the IDs and updating the number of the current player.

It works fine for the case of 2 humans playing (on the same device). But if a person plays with the computer, the AI calculates and makes its move in the same onClick() method. Since the user interface updates only after processing the onClick(), (ImageViews are set to invisible, and so on), AI's moves are not drawn on the screen and the player sees as if after his move (clicks on the objects), the board was redrawn immediately with the added changes made by the computer's move (objects removed).

So, I need to pass the turn to AI somehow differently, not in onClick() of the "End turn" button to be able to draw the AI's selection and hide selected views - before the player can make his next move. But how to do that and where?

onClick() method for the "End turn" button:

public void onClick(View v) {
    hideSelectedImageViews();
    if (currentGame.isWinningState()) {
        //you won
    } else {
        changePlayer();
        if (playWithAI) {
             calculateAImove(currentGame);
             showSelectedImageViewsByAI(); //doesn't work even with .invalidate()
             hideSelectedImageViews();
             if (currentGame.isWinningState()) {
                  //AI won
             }
             changePlayer();
        }
    }
 }

In showSelectedImageViewsByAI(), a specific image resource is set for the ImageViews, so that they will look differently ("selected").


Solution

  • You can create a new Thread where it will run the AI's moves, when the AI makes their selections you can make the thread delay some seconds (so their selection can be shown) and then remove them. Your code has that problem, once the AI makes a selection, it's removed instantly (even if you did invalidate() twice)

    If you are not familiar with Threads here is an example:

    //I assume your code was inside an Activity
    public class mainActivity extends Activity implements Runnable
    {
        Thread aiThread;
    
        /*...*/
    
        public void onClick(View v) 
        {
            hideSelectedImageViews();
            if (currentGame.isWinningState()) { /*you won*/ } 
            else 
            {
                changePlayer();
                if (playWithAI) 
                {
                    aiThread = new Thread(this);
                    aiThread.start();
                }
            }
        }
    
        public void run()
        {
            calculateAImove(currentGame);
            showSelectedImageViewsByAI();
            Thread.sleep(1000); //This will make thread wait for 1 second before removing selected (note the number is in milliseconds)
            hideSelectedImageViews();
            if (currentGame.isWinningState()) { /*AI won*/ }
            changePlayer();
        }
    }
    

    Please note that when using a thread to influence the UI you shouldn't affect views directly, you should instead call view.post() instead, if you are unfamiliar with either Threads or the view.post() method I recommend searching online for them.