3therk1ll
3therk1ll

Reputation: 2421

Android button only initiating method on second click

I have a tic tac toe board made of buttons. Each button is linked to the method that initiated the logic. The problem I'm having is that when the human player (noughts) plays their turn, the logic is skipping that turn, running the AIs turn and then only going back to the human player, who this time around is working as expected.

On the click, the button is question should have setText method called and marked with either a 'O' for the human player, or 'X' for the AI. Following this the button is set to inactive and the array that tracks the board changes.

I am printing to the logs and from what I can see, the human users clicks are what are triggering the AIs moved, rather than this being done automatically. But I can't tell why this is happening. I assume there is a flaw in my logic but I can't pick out what the issue is. EDIT: It works fine for the first human click, it is the ones after that that are the problem.

Code:

package com.example.richardcurteis.connect3;

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TableLayout;
import android.widget.TableRow;
import java.util.Random;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    boolean noughtsTurn;
    ArrayList board;
    Players player;
    int aiPickedButton;
    int buttonPressed;
    int targetIndex;

    public void receiveClick(View view) {
        String takeButton = String.valueOf(view.getTag());
        buttonPressed = Integer.parseInt(takeButton);
        playNow(view);
        //checkForWin; Check winning conditions. Not yet implemented
    }

    public void playNow(View view) {
        if (noughtsTurn) {
            System.out.println("Player picked: " + buttonPressed);
            playerClick(view);
        } else {
            if (aiValidPick()) {
                playerClick(view);
            } else {
                playNow(view);
            }
        }
    }

    public void setTurn(boolean trueOrFalse) {
        if (trueOrFalse) {
            noughtsTurn = false;
        } else {
            noughtsTurn = true;
        }
    }

    public void playerClick(View view) {
        Button B;
        int boardSetIndex;
        int boardSetValue;

        if (view instanceof Button) {
            B = (Button) view;
            if ( noughtsTurn ) {
                B.setText(player.noughtsPlayer());
            } else {
                B = aiPlayerPick();
                System.out.println("AI picked: " + targetIndex);
                B.setText(player.crossesPlayer());
            }
            board.set(boardSetIndex(), boardSetValue());
            System.out.println("Board: " + board);
            B.setEnabled(false);
            setTurn(noughtsTurn);
        }
    }

    public int boardSetIndex() {
       int index;
        if (noughtsTurn) {
            index = buttonPressed;
        } else {
            index = targetIndex;
        }
        return  index;
    }

    public int boardSetValue() {
        int value;
        if (noughtsTurn) {
            value = player.humanTurnValue();
        } else {
            value = player.aiTurnValue();
        }
        return  value;
    }

    public Integer randomButtonPick() {
        Random randomNumber = new Random();
        int randomInt = randomNumber.nextInt(board.size());
        return randomInt;
    }

    public boolean aiValidPick() {
        aiPickedButton = randomButtonPick();
        if (board.get(aiPickedButton).equals(player.boardArrayDefaultValue())
                && !board.get(aiPickedButton).equals(player.humanTurnValue())
                && !board.get(aiPickedButton).equals(player.aiTurnValue())){
            return true;
        } else {
            return false;
        }
    }

    public Button aiPlayerPick() {
        Button btn = null;
        TableLayout tableLayout = (TableLayout) findViewById(R.id.tableLayout);
        for (int rowIndex = 0; rowIndex < tableLayout.getChildCount(); rowIndex++) {
            View tableLayoutChild = tableLayout.getChildAt(rowIndex);
            if (tableLayoutChild instanceof TableRow) {
                for (int i = 0; i < ((ViewGroup) tableLayoutChild).getChildCount(); i++) {
                    View view = ((ViewGroup) tableLayoutChild).getChildAt(i);
                    String targetButton = String.valueOf(aiPickedButton);
                    if (view instanceof Button && view.getTag().equals(targetButton) ) {
                        targetIndex = Integer.parseInt(targetButton);
                        View btn_v = view.findViewWithTag(targetButton);
                        btn = (Button) btn_v;
                        break;
                    }
                }
            }
        }
        return btn;
    }

    public class Players {
        public String noughtsPlayer() { return "O"; }
        public String crossesPlayer() { return "X"; }
        //public String blankButton() { return ""; }

        public int humanTurnValue() { return 0;}
        public int aiTurnValue() { return 1;}
        public int boardArrayDefaultValue() { return 2;}
    }

    public int getBoardSize() {
        int buttonCount = 0;
        TableLayout tableLayout = (TableLayout) findViewById(R.id.tableLayout);
        for (int rowIndex = 0; rowIndex < tableLayout.getChildCount(); rowIndex++) {
            View tableLayoutChild = tableLayout.getChildAt(rowIndex);
            if (tableLayoutChild instanceof TableRow) {
                for (int i = 0; i < ((ViewGroup) tableLayoutChild).getChildCount(); i++) {
                    View view = ((ViewGroup) tableLayoutChild).getChildAt(i);
                    if (view instanceof Button) {
                        buttonCount++;
                    }
                }
            }
        }
        return buttonCount;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
        noughtsTurn = true;
        player = new Players();
        board = new ArrayList();
        int boardSize = getBoardSize();
        for (int boardIndex = 0; boardIndex < boardSize; boardIndex++) {
            board.add(player.boardArrayDefaultValue());
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

XML

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.example.richardcurteis.connect3.MainActivity"
    tools:showIn="@layout/activity_main"
    android:background="#070000">

    <TableLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_alignParentRight="false"
        android:layout_alignParentEnd="false"
        android:layout_alignParentStart="false"
        android:layout_centerInParent="true"
        android:id="@+id/tableLayout"
        android:background="#000000">

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent"></TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent"></TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent"></TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent"></TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent"></TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent"></TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent"></TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent"></TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent"></TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent"></TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent"></TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <Button
                android:layout_width="100dp"
                android:layout_height="100dp"
                android:id="@+id/gridButton1"
                android:layout_column="4"
                android:onClick="receiveClick"
                android:tag="0" />
                android:nestedScrollingEnabled="false" />

            <Button
                android:layout_width="100dp"
                android:layout_height="100dp"
                android:id="@+id/gridButton2"
                android:layout_column="12"
                android:onClick="receiveClick"
                android:tag="1" />

            <Button
                android:layout_width="100dp"
                android:layout_height="100dp"
                android:id="@+id/gridButton3"
                android:layout_column="19"
                android:onClick="receiveClick"
                android:tag="2" />
        </TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent"></TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent"></TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent"></TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <Button
                android:layout_width="100dp"
                android:layout_height="100dp"
                android:id="@+id/gridButton4"
                android:layout_column="4"
                android:onClick="receiveClick"
                android:tag="3"/>

            <Button
                android:layout_width="100dp"
                android:layout_height="100dp"
                android:id="@+id/gridButton5"
                android:layout_column="12"
                android:onClick="receiveClick"
                android:tag="4"/>

            <Button
                android:layout_width="100dp"
                android:layout_height="100dp"
                android:id="@+id/gridButton6"
                android:layout_column="19"
                android:onClick="receiveClick"
                android:tag="5"/>
        </TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent"></TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent"></TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent"></TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <Button
                android:layout_width="100dp"
                android:layout_height="100dp"
                android:id="@+id/gridButton7"
                android:layout_column="4"
                android:onClick="receiveClick"
                android:tag="6"/>

            <Button
                android:layout_width="100dp"
                android:layout_height="100dp"
                android:id="@+id/gridButton8"
                android:layout_column="12"
                android:onClick="receiveClick"
                android:tag="7"/>

            <Button
                android:layout_width="100dp"
                android:layout_height="100dp"
                android:id="@+id/gridButton9"
                android:layout_column="19"
                android:onClick="receiveClick"
                android:tag="8" />
        </TableRow>
    </TableLayout>

    <Button

        android:layout_width="200dp"
        android:layout_height="120dp"
        android:text="New Game"
        android:id="@+id/newGameButton"
        android:layout_below="@+id/tableLayout"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="61dp" />
</RelativeLayout>

Upvotes: 1

Views: 509

Answers (2)

3therk1ll
3therk1ll

Reputation: 2421

Ok, so here is the final solution I came to for this issue. I kept the same logic but separated the human and AI turns into separate methods with the AI still basing it's turn on the noughtsTurn method.

Code:

public void receiveClick(View view) {
        String takeButton = String.valueOf(view.getTag());
        buttonPressed = Integer.parseInt(takeButton);
        humanPlayerTurn(view);
        aiPlayerTurn(view);
    }

    public void humanPlayerTurn(View view) {
        if (noughtsTurn) {
            System.out.println("Player picked: " + buttonPressed);
            playerClick(view);
        }
    }

    public void aiPlayerTurn(View view) {
        if (aiValidPick()) {
            playerClick(view);
        } else {
            aiPlayerTurn(view);
        }
    }

Upvotes: 0

TheSwisscows
TheSwisscows

Reputation: 36

The issue is not in your logic. The issue is how it is implemented.

You currently have a step-by-step logic system in place where each step in the logic is triggered by the receiveClick(View) method. The problem is that there is no automatic triggering of the AI turn.

  1. noughtsTurn = true
  2. receiveClick(View) works properly with the players turn.
  3. The turn logic completes in playerClick(View) with the value of noughtsTurn being inverted.
  4. The problem is nothing triggers the AI turn and the next time you click a button it calls receiveClick(View) but with a noughtsTurn value of false.
  5. So this simulates an AI turn even though the player just clicked.

You need to add some sort of logic to the end of playerClick(View) so that if the player just took their turn it reruns the logic for the AI turn.

Example:

public void playerClick(View view) {
    Button B;
    int boardSetIndex;
    int boardSetValue;

    if (view instanceof Button) {
        B = (Button) view;
        if ( noughtsTurn ) {
            B.setText(player.noughtsPlayer());
        } else {
            B = aiPlayerPick();
            System.out.println("AI picked: " + targetIndex);
            B.setText(player.crossesPlayer());
        }
        board.set(boardSetIndex(), boardSetValue());
        System.out.println("Board: " + board);
        B.setEnabled(false);
        //
        if(setTurn(noughtsTurn) == false){
            playNow(findViewByTag(randomButtonPick()))
        }
        //
    }
}

In the above example there are some critical things missing like checking that the randomButtonPick() is not already occupied and the fact that setTurn(boolean) returns void and not a boolean. You just need some way of checking if the player just took a turn and, if so, have the AI take a turn.

Upvotes: 1

Related Questions