Hangman Tutorial Lesson 6 – Tracking the Wrong Guesses

When a user guesses a letter incorrectly, we want to keep track of it. After a certain number of wrong guesses they lose the game.

Open the Graphical Layout, expand Form Widgets, click and drag “Small Text” onto your LinearLayout, in between the txtPhrase and txtButton.

Image

Let’s name the Id txtWrongGuesses and then go to the MainActivity to modify it. First, add a member variable called wrongGuesses that will keep track of how many wrong guesses they have.

private PhraseGenerator phraseGenerator;
private List<Button> letterButtons = new ArrayList<Button>();
private HangmanPhrase hangmanPhrase;
private int wrongGuesses = 0;

In our updatePhrase() method, we also want to update txtWrongGuesses with the number of wrong guesses they currently have. At the end of the method, add these lines:

TextView txtWrongGuesses = (TextView)findViewById(R.id.txtWrongGuesses);
txtWrongGuesses.setText(wrongGuesses + " wrong guesses");

This gets a reference to the txtWrongGuesses TextView that we just created, and updates the text to how many wrong guesses they have. Now we have to increment wrongGuesses anytime they have an incorrect guess. Go to the LetterButtonClickedListener and modify the onClick method:

private class LetterButtonClickedListener implements OnClickListener
{
    private String letter;

    public LetterButtonClickedListener(String letter)
    {
        this.letter = letter;
    }

    @Override
    public void onClick(View v)
    {
        ((Button) v).setEnabled(false);
        boolean correctGuess = hangmanPhrase.guessLetter(letter);
        if (!correctGuess)
            wrongGuesses++;
        updatePhrase();
    }
}

When we call hangmanPhrase.guessLetter(), it returns false if it was a wrong guess. If that’s the case, we increment wrongGuesses.

We don’t want to allow infinite wrong guesses. Let’s set a maximum of 6 wrong guesses, and if you reach that you lose. Also, we need to know when the user has completed the phrase. Let’s wrap both of these checks up into one method:

private void checkGameOver()
{
    if (hangmanPhrase.isAllRevealed())
    {
        new AlertDialog.Builder(this).setMessage("Congratulations you won!").setCancelable(false).setPositiveButton("Next game", new DialogInterface.OnClickListener()
        {
            @Override
            public void onClick(DialogInterface dialog, int which)
            {
                newGame();
            }
        }).show();
    }
    else if (wrongGuesses >= 6)
    {
        hangmanPhrase.revealAll();
        updatePhrase();
        new AlertDialog.Builder(this).setMessage("You lost!").setCancelable(false).setPositiveButton("Next game", new DialogInterface.OnClickListener()
        {
            @Override
            public void onClick(DialogInterface dialog, int which)
            {
                newGame();
            }
        }).show();
    }
}

checkGameOver() checks whether you have lost or won the game. The first check looks at whether all the letters have been revealed. If so, it builds an AlertDialog. Android has a nice builder for AlertDialog, where you can easily set the message, the text in the buttons, and the action you take when you click on a button. setCancelable() specifies whether you can cancel the dialog by pressing the back button or by clicking outside of the dialog. We set that to false so the user has to click the button. AlertDialog’s setPositiveButton() let’s you set the text of the button and the action. There are actually 2 other buttons you can make use of, setNeutralButton and setNegativeButton. In our case, it doesn’t which one you use because we are specifying the text and action associated with it.

When should we call checkGameOver()? After every letter button click, we should call it. Inside of LetterButtonClickedListener.onClick() method, add the line checkGameOver() at the end of the method:

public void onClick(View v)
{
    ((Button) v).setEnabled(false);
    boolean correctGuess = hangmanPhrase.guessLetter(letter);
    if (!correctGuess)
        wrongGuesses++;
    updatePhrase();
    checkGameOver();
}

Lastly, we need to reset the wrongGuesses to 0 for every new game. In the newGame() method, let’s add the logic:

private void newGame()
{
    wrongGuesses = 0;
    hangmanPhrase = phraseGenerator.nextPhrase();
    updatePhrase();
    for (Button button : letterButtons)
        button.setEnabled(true);
}

That should be it! Let’s try it out now.

device-2014-03-29-131659

Good, we’re getting close to the end. We are missing something big though – a picture of a hangman. We’ll leave that for the next lesson.

Again, for reference, here is the whole file for MainActivity:

package com.famlinkup.hangman;

import java.util.ArrayList;
import java.util.List;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TableLayout;
import android.widget.TableRow;
import android.widget.TextView;

public class MainActivity extends ActionBarActivity
{
    private PhraseGenerator phraseGenerator;
    private List<Button> letterButtons = new ArrayList<Button>();
    private HangmanPhrase hangmanPhrase;
    private int wrongGuesses = 0;

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

        phraseGenerator = new PhraseGenerator(this);
        newGame();
    }

    private void attachNextButton()
    {
        Button btnNext = (Button)findViewById(R.id.btnNext);
        btnNext.setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                newGame();
            }
        });
    }

    private void createLettersGrid()
    {
        TableLayout tl = (TableLayout) findViewById(R.id.tblLetters);
        String letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        TableRow currentRow = null;
        for (int i=0;i<letters.length(); i++)
        {
            if (i%6==0)
            {
                //create a new row
                currentRow = new TableRow(this);
                currentRow.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.MATCH_PARENT));
                currentRow.setGravity(Gravity.CENTER_HORIZONTAL);
                tl.addView(currentRow, new TableLayout.LayoutParams(TableLayout.LayoutParams.MATCH_PARENT, TableLayout.LayoutParams.MATCH_PARENT));
            }
            Button letterButton = createLetterButton(String.valueOf(letters.charAt(i)));
            letterButtons.add(letterButton);
            currentRow.addView(letterButton);
        }
    }

    private Button createLetterButton(String letter)
    {
        Button b = new Button(this, null, android.R.attr.buttonStyleSmall);
        b.setText(letter);
        b.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT));
        b.setOnClickListener(new LetterButtonClickedListener(letter));
        return b;
    }

    private class LetterButtonClickedListener implements OnClickListener
    {
        private String letter;

        public LetterButtonClickedListener(String letter)
        {
            this.letter = letter;
        }

        @Override
        public void onClick(View v)
        {
            ((Button) v).setEnabled(false);
            boolean correctGuess = hangmanPhrase.guessLetter(letter);
            if (!correctGuess)
                wrongGuesses++;
            updatePhrase();
            checkGameOver();
        }
    }

    private void updatePhrase()
    {
        TextView txtPhrase = (TextView)findViewById(R.id.txtPhrase);
        txtPhrase.setText(hangmanPhrase.getDisplayString());

        TextView txtWrongGuesses = (TextView)findViewById(R.id.txtWrongGuesses);
        txtWrongGuesses.setText(wrongGuesses + " wrong guesses");
    }

    private void newGame()
    {
        wrongGuesses = 0;
        hangmanPhrase = phraseGenerator.nextPhrase();
        updatePhrase();
        for (Button button : letterButtons)
            button.setEnabled(true);
    }

    private void checkGameOver()
    {
        if (hangmanPhrase.isAllRevealed())
        {
            new AlertDialog.Builder(this).setMessage("Congratulations you won!").setCancelable(false).setPositiveButton("Next game", new DialogInterface.OnClickListener()
            {
                @Override
                public void onClick(DialogInterface dialog, int which)
                {
                    newGame();
                }
            }).show();
        }
        else if (wrongGuesses >= 6)
        {
            hangmanPhrase.revealAll();
            updatePhrase();
            new AlertDialog.Builder(this).setMessage("You lost!").setCancelable(false).setPositiveButton("Next game", new DialogInterface.OnClickListener()
            {
                @Override
                public void onClick(DialogInterface dialog, int which)
                {
                    newGame();
                }
            }).show();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
        int id = item.getItemId();
        if (id == R.id.action_settings)
        {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s