-3

I am working on a Hangman game. Game is working as it should except that when i start a new game, i am unable to clear the data that was stored from the previous game. So it gives me a screen that looks like the following after the user clicks "play again".

Screenshot of Hangman Game - How it should look after clicking "play again"

Screenshot of Hangman Game after clicking "play again"

How do i reset the data so that the textview and the buttons after the startNewGame method is executed?

tried to use textView.setText("") to do a reset but it is not working. Appreciate if you can help shed some light for me. Thanks!

My Codes are as follows.

package com.desmondwong.hangmangame;

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.GridLayout;
import android.widget.ImageSwitcher;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ViewSwitcher;

import java.util.Random;

public class GameActivity extends AppCompatActivity {

    //To reference the components
    ImageSwitcher imageSwitcher;
    TextView textView;
    TextView textViewScore;
    Button btn [] = new Button[26];

    //Images for the hangman
    int img [] = {R.drawable.img0,
            R.drawable.img1,
            R.drawable.img2,
            R.drawable.img3,
            R.drawable.img4,
            R.drawable.img5,
            R.drawable.img6,
            R.drawable.img7,
            R.drawable.img8};

    AlertDialog helpAlert;

    //Variables
    String strSecret = "", strGuess="", strText="";

    String strWords[] = {"APPLE", "ORANGE","BANANA"};

    int intError = 0; //Error made by player

    int livesRemaining = 8; //Lives remaining by player

    int numCorr = 0; //Correct letter guess by player

    Random random = new Random(); //Random generator


    public void startNewGame(){

        intError = 0; //Error made by player

        livesRemaining = 8; //Lives remaining by player

        numCorr = 0; //Correct letter guess by player

        imageSwitcher.removeAllViews();



        //textViewScore.setText(String.valueOf(livesRemaining));

        //textView.setText("");

        setupImageSwitcher();
        setup26Buttons();
        getSecretWord();

    }


    //To create help icon at top right
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    //To create help icon at top right
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            //case android.R.id.home:
               // NavUtils.navigateUpFromSameTask(this);
                //return true;
            case R.id.action_help:
                showHelp();
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_game);

        //Retrieve the reference
        imageSwitcher = findViewById(R.id.imageSwitcher);
        textView = findViewById(R.id.textView);
        textViewScore = findViewById(R.id.textViewScore);
        textViewScore.setText(String.valueOf(livesRemaining));

        setupImageSwitcher();
        setup26Buttons();
        getSecretWord();

    }


    private void setup26Buttons() {

        GridLayout g = findViewById(R.id.gridLayout);


        //to create 26 buttons
        for(int i = 0; i<btn.length; i++) {

            btn[i] = new Button(this, null, R.attr.buttonStyleSmall); //Buttonsytlesmall so that it fits the screen
            btn[i].setText(""+(char)('A'+i)); //need to set back to char, as +i will set it back to integer. "" to set this to a String so it is sync to setText
            btn[i].setTag(""+(char)('A'+i));
            btn[i].setOnClickListener(new View.OnClickListener() {
                @SuppressLint("ResourceAsColor")
                @Override
                public void onClick(View v) {

                    strGuess += v.getTag(); //Get letter that the player guessed and keep adding on to strGuess
                    v.setEnabled(false); //disable pressed button since the player already press
                    v.setBackgroundColor(android.R.color.black);

                    //Check for error guess. If the letter is not inside the strSecret, it will return less than 0
                    if (strSecret.indexOf(v.getTag().toString())<0){

                        intError++; //your error is added
                        int livesRemaining = 8;
                        livesRemaining -= intError; // Countdown based on errors recorded
                        textViewScore.setText(String.valueOf(livesRemaining));
                        imageSwitcher.setImageResource(img[intError]); //set the img no. to follow the error
                    }

                    else {

                        numCorr++;
                    }

                    boolean playerWin = true;
                    //Display all correct guesses
                    strText = ""; //reset the display

                    for (int i = 0 ; i<strSecret.length();i++){

                        char ch = strSecret.charAt(i); // get each character from strSecret

                        //To check if this letter can be found in strGuess
                        if(strGuess.indexOf(ch)>=0){
                            //found
                            strText += ch;

                        }

                        else{

                            //Not found
                            strText += "-";
                            playerWin=false;
                        }

                    }

                    textView.setText(strText);

                    if (playerWin) {

                        if (numCorr == strSecret.length()) {

                            //Toast.makeText(getApplicationContext(), "You won", Toast.LENGTH_LONG).show();

                            //let user know they have won, ask if they want to play again
                            AlertDialog.Builder winBuild = new AlertDialog.Builder(GameActivity.this);
                            winBuild.setTitle("Amazing! You save Batman!");

                            winBuild.setMessage("The Hangman\'s favourite fruit is:\n\n" + strSecret);

                            winBuild.setPositiveButton("Play Again",
                                    new DialogInterface.OnClickListener() {
                                        public void onClick(DialogInterface dialog, int id) {
                                            GameActivity.this.startNewGame();

                                        }
                                    });

                            winBuild.setNegativeButton("Exit",
                                    new DialogInterface.OnClickListener() {
                                        public void onClick(DialogInterface dialog, int id) {
                                            GameActivity.this.finish();

                                        }
                                    });
                            winBuild.show();

                        }

                    } else if (livesRemaining > 0) {

                        //still have lives remaining. do nothing
                    }

                    else {

                        //Toast.makeText(getApplicationContext(), "You Lost",Toast.LENGTH_LONG).show();

                        // Display Alert Dialog
                        AlertDialog.Builder loseBuild = new AlertDialog.Builder(GameActivity.this);
                        loseBuild.setTitle("Batman got executed!");
                        loseBuild.setMessage("You lose!\n\nThe answer was:\n\n"+ strSecret);
                        loseBuild.setPositiveButton("Play Again",
                                new DialogInterface.OnClickListener() {
                                    public void onClick(DialogInterface dialog, int id) {
                                        GameActivity.this.startNewGame();
                                    }});

                        loseBuild.setNegativeButton("Exit",
                                new DialogInterface.OnClickListener() {
                                    public void onClick(DialogInterface dialog, int id) {
                                        GameActivity.this.finish();
                                    }});

                        loseBuild.show();

                    }

                }

            });

            g.addView(btn[i]);

        }

    }



    private void getSecretWord() {

        int index = random.nextInt(strWords.length);
        strSecret = strWords[index];

        for(int i=0; i<strSecret.length(); i++) {

            strText += "-"; //to create multiple - for the unknown word

        }

        textView.setText(strText);


    }

    private void setupImageSwitcher() {

        //https://www.tutorialspoint.com/android/android_imageswitcher.htm
        imageSwitcher.setFactory(new ViewSwitcher.ViewFactory() {

            @Override
            public View makeView() {

                ImageView imageView = new ImageView(getApplicationContext());

                imageView.setImageResource(R.drawable.img0);

                return imageView;
            }
        });

        Animation aniOut = AnimationUtils.loadAnimation(this, android.R.anim.slide_out_right);

        Animation aniIn = AnimationUtils.loadAnimation(this, android.R.anim.slide_in_left);

        imageSwitcher.setOutAnimation(aniOut);

        imageSwitcher.setOutAnimation(aniIn);
    }

    //show help information
    public void showHelp(){
        AlertDialog.Builder helpBuild = new AlertDialog.Builder(this);
        helpBuild.setTitle("Help");
        helpBuild.setMessage("Whisper the password (Hangman's favourite fruit) to save Batman\n\n"
                + "You only have 8 tries!");
        helpBuild.setPositiveButton("OK",
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        helpAlert.dismiss();
                    }});
        helpAlert = helpBuild.create();
        helpBuild.show();
    }

}
DWing
  • 41
  • 7

1 Answers1

0

Your problem is every time you call startNewGame you:

  • add a new text to the existing value of strText instead of setting a new one
  • add new buttons in the btn array (without removing the old ones)

So you need to make sure startNewGame get rid off everything that has been created for the previous game and that you don't need anymore.

EDIT

One approach can be to have a 'Game' object that stores everything (strSecret, strGuess,...) instead of having them in the Activity. Every time startNewGame is called, you do myGame = new Game(); so you're sure that all the previous data are gone.

EDIT 2

A quick fix is:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_game);

    //Retrieve the reference
    imageSwitcher = findViewById(R.id.imageSwitcher);
    textView = findViewById(R.id.textView);
    textViewScore = findViewById(R.id.textViewScore);
    textViewScore.setText(String.valueOf(livesRemaining));


    // ** QUICK FIX **
    btn = new Button[26];
    strText = "";

    setupImageSwitcher();
    setup26Buttons();
    getSecretWord();
}

EDIT 3 (Working improved example)

MainActivity

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.DrawableRes;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.GridLayout;
import android.widget.ImageSwitcher;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.ViewSwitcher;

import java.util.Random;

public class GameActivity extends AppCompatActivity {

    // Constants

    //Images for the hangman
    @DrawableRes
    private final static int img[] = {R.drawable.img0, // Img0 is when the player is dead
            R.drawable.img1,
            R.drawable.img2,
            R.drawable.img3,
            R.drawable.img4,
            R.drawable.img5,
            R.drawable.img6,
            R.drawable.img7,
            R.drawable.img8};

    private final static String strWords[] = {"APPLE", "ORANGE", "BANANA"};
    private final static Random random = new Random(); //Random generator

    // To reference the components
    private ImageSwitcher imageSwitcher;
    private TextView textView;
    private TextView textViewScore;

    // Other private fields
    private Game mGame;

    public void startNewGame() {
        mGame = new Game(img.length - 1); // The max lives is the size of the array - 1
        setup26Buttons();
        initSecretWord();
        imageSwitcher.reset();
        imageSwitcher.setImageResource(img[mGame.livesRemaining]);
        textViewScore.setText(String.valueOf(mGame.livesRemaining));
        textView.setText(mGame.hiddenWord);
    }

    //To create help icon at top right
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    //To create help icon at top right
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_help:
                showHelpDialog();
                return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_game);

        //Retrieve the reference
        imageSwitcher = findViewById(R.id.imageSwitcher);
        textView = findViewById(R.id.textView);
        textViewScore = findViewById(R.id.textViewScore);

        // Init the view components
        initImageSwitcher();

        // Start the game
        startNewGame();
    }

    private void setup26Buttons() {

        final GridLayout g = findViewById(R.id.gridLayout);
        g.removeAllViews(); // clear the children views (if exist)

        //to create 26 buttons
        final int maxLetters = 26;
        Button btn;
        for (int i = 0; i < maxLetters; i++) {

            btn = new Button(this, null, R.attr.buttonStyleSmall); //Buttonsytlesmall so that it fits the screen
            btn.setText(Character.toString((char) ('A' + i))); // Set the letter
            btn.setOnClickListener(listener);

            g.addView(btn);
        }
    }

    private final View.OnClickListener listener = new View.OnClickListener() {
        @SuppressLint("ResourceAsColor")
        @Override
        public void onClick(View v) {

            String guess = (((Button) v).getText()).toString();
            v.setEnabled(false); //disable pressed button since the player already press
            v.setBackgroundColor(android.R.color.black);

            // Check if the current letter is in the secret word
            if (!mGame.secretWord.contains(guess)) {
                mGame.livesRemaining--; // Remove a live
                imageSwitcher.setImageResource(img[mGame.livesRemaining]); //set the img no. to follow the error
                textViewScore.setText(String.valueOf(mGame.livesRemaining));

                if (mGame.livesRemaining == 0) {
                    showEndGameDialog("Batman got executed!", "You lose!\n\nThe answer was:\n\n" + mGame.secretWord);
                }
            } else {
                mGame.correctGuess += guess; // Add the letter to the ones correctly guessed
                //Display all correct guesses
                final StringBuilder sb = new StringBuilder();
                final char[] chars = mGame.secretWord.toCharArray();
                for (int i = 0; i < mGame.secretWord.length(); i++) {
                    //To check if this letter can be found in correctGuess
                    sb.append((mGame.correctGuess.contains(Character.toString(chars[i])))
                            ? chars[i] //found
                            : "-");
                }
                mGame.hiddenWord = sb.toString();
                textView.setText(mGame.hiddenWord);

                // If all the unique letters in the word have been found, it's a win
                if (mGame.correctGuess.length() == mGame.maxLetters) {
                    showEndGameDialog("Amazing! You save Batman!", "The Hangman\'s favourite fruit is:\n\n" + mGame.secretWord);
                }
            }
        }
    };

    private void showEndGameDialog(String title, String message) {
        new AlertDialog.Builder(GameActivity.this)
                .setTitle(title)
                .setMessage(message)
                .setPositiveButton("Play Again",
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                GameActivity.this.startNewGame();
                            }
                        })
                .setNegativeButton("Exit",
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                GameActivity.this.finish();
                            }
                        })
                .show();
    }

    private void initSecretWord() {

        int index = random.nextInt(strWords.length);
        String secretWord = strWords[index];
        // Replace all the letters by '-' ('\p{L}' matches any letter)
        String hiddenWord = secretWord.replaceAll("\\p{L}", "-");

        mGame.maxLetters = countUniqueLettersInWord(secretWord);
        mGame.secretWord = secretWord;
        mGame.hiddenWord = hiddenWord;
    }

    /**
     * Calculate the number of unique letter in the word
     * E.g BANANA has 3 unique letters (B,A,N)
     *
     * @param word The word to count the unique letter in
     * @return The total of unique letters
     */
    private static int countUniqueLettersInWord(final String word) {
        char[] chars = word.toCharArray();
        int count = 0;
        char curr;
        boolean contains;
        for (int i = 0; i < chars.length; i++) {
            curr = chars[i];
            // Check if the same letter exists in the visited letters (from pos 0 to current letter)
            contains = false;
            for (int j = 0; j < i; j++) {
                if (curr == chars[j]) {
                    contains = true;
                    break; // Don't need to continue if the letter already exists.
                }
            }
            if (!contains)
                count++;
        }

        return count;
    }

    private void initImageSwitcher() {

        //https://www.tutorialspoint.com/android/android_imageswitcher.htm
        imageSwitcher.setFactory(new ViewSwitcher.ViewFactory() {
            @Override
            public View makeView() {
                return new ImageView(getApplicationContext());
            }
        });

        Animation aniOut = AnimationUtils.loadAnimation(this, android.R.anim.slide_out_right);
        Animation aniIn = AnimationUtils.loadAnimation(this, android.R.anim.slide_in_left);

        imageSwitcher.setOutAnimation(aniOut);
        imageSwitcher.setOutAnimation(aniIn);
    }

    //show help information
    public void showHelpDialog() {
        new AlertDialog.Builder(this)
                .setTitle("Help")
                .setMessage("Whisper the password (Hangman's favourite fruit) to save Batman\n\n"
                        + "You only have 8 tries!")
                .setPositiveButton("OK",
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                dialog.dismiss();
                            }
                        })
                .show();
    }
}

Game class

public class Game {

    String secretWord, correctGuess, hiddenWord;

    //Lives remaining by player
    int livesRemaining;

    public int maxLetters;

    public Game(int lives) {
        secretWord = "";
        correctGuess = "";
        hiddenWord = "";
        livesRemaining = lives;
    }
}
Eselfar
  • 3,759
  • 3
  • 23
  • 43
  • Hi @Eselfar, yes. i understand. i am having trouble trying to reset this data that was created in the previous game. – DWing May 25 '18 at 13:14
  • Tried your quick fix solution. It is not working. I think it should be under the startNewGame method rather since this is the method that is activated when the "Play Again" button is clicked. but it doesn't work too. Will take up your suggestion to create a new Game to store the Strings. Just thought, there is an easier way to wipe clean the data like what i did for imageSwitcher.removeAllViews(); – DWing May 25 '18 at 13:39
  • Ah yeah you're right, my mistake. This fix should be in the `startNewGame` method – Eselfar May 25 '18 at 13:47
  • I've added a working example. I've changed your code a lot. Have a look – Eselfar May 25 '18 at 15:30
  • Thanks! you built it in an amazing and well structured way. Will learn from this. – DWing May 26 '18 at 04:46
  • Hi @Eselfar, i am facing another problem in the same program. i just added a CountDownTimer and the count down timer is working as it should. But once i start the "Play again", i realise that the timer is still ticking from the previous game. When i put timer.cancel() in the if (mGame.correctGuess.length() == mGame.maxLetters) { ....} loop, the app crashes. any idea how i can refresh the timer when a new game is played? – DWing May 27 '18 at 16:10
  • Idk how you've implemented it. I can crashes for a lot of reasons. But the `Logcat`should give you a clue. If you haven't solve the issue, ask a new question with both the code and the error, and link it here if you want me to have a look – Eselfar May 29 '18 at 09:00
  • But basically to restart a `CountDownTimer` you need to cancel the current one and create a new one. [Have a look here](https://stackoverflow.com/a/46226413/1827254) – Eselfar May 29 '18 at 09:07