Tuesday, 2 July 2013

Java Hangman Game

Java Hangman Game Program

Java Code:
import javax.swing.JPanel;


/**
 * A panel containing a phrase, with the ability
 * to show, hide, and underline letters
 */
public class GuessPhrasePanel extends JPanel
{
    Text[] phrase;
    String phraseString;
   
    /**
     * Constructor
     * @param phraseStr - the test phrase to display
     */
    public GuessPhrasePanel(String phraseStr)
    {
        phrase = null;
        setPhrase(phraseStr);
    }
   
    /**
     * Initializes the panel with the given phrase.
     * @param phraseStr
     */
    public void setPhrase(String phraseStr)
    {
        phraseString = phraseStr;
        initializeLetters(); // initialize the letter objects and add them to this panel
    }
   
    /**
     * Cleans up the previous phrase, and creates
     * new letter objects for a new phrase contained
     * in phraseString.
     */
    private void initializeLetters()
    {
        this.removeAll(); // throw away existing letters in phrase
        this.updateUI();  // reset entire UI

        if (phraseString.length() == 0) return;
        phrase = new Text[phraseString.length()]; // allocate an array for all characters
      
        for (int i = 0; i < phrase.length; i++)
        {
            char c = phraseString.charAt(i); // get next character
            phrase[i] = new Text(String.valueOf(c)); // create the panel for the character
          
            if (Character.isAlphabetic(c)) // if its a letter
            {
                phrase[i].hideText(); // hide it
                phrase[i].showUnderline(); // underline
            }
            else phrase[i].hideUnderline(); // if its not a letter, dont hide and dont underline it
            add(phrase[i]); // add the letter to this panel
        }
      
        phraseString = phraseString.toLowerCase(); // convert to lower case for the hasLetter method
      
        this.revalidate(); // push changes through
    }

    /**
     * Cleans up current phrase
     */
    public void removeAll()
    {
        if (phrase == null) return;
   
        for (int i = 0; i < phrase.length; i++)
        {
            remove(phrase[i]); // remove letter from this panel
            phrase[i] = null;
        }
        phrase = null;
    }
   
    /**
     * Checks if a given letter is in the current phrase
     * @param c - the letter to look for, case insensitive
     * @return - true if the letter is in the phrase, false if not
     */
    public boolean hasLetter(char c)
    {
        c = Character.toLowerCase(c);
        return phraseString.contains(String.valueOf(c)); // the string is already converted to lower case
    }
   
    /**
     * If the letter exists in the phrase it's made visible
     * @param c - the letter to reveal
     */
    public void revealLetter(char c)
    {
        if (!hasLetter(c)) return; // do nothing if the letter is not in the phrase
        c = Character.toLowerCase(c); // convert to lower case
      
        // reveal all occurrences of this letter
        for (int i = 0; i < phrase.length; i++)
        {
            if (phraseString.charAt(i) == c)
            {
                phrase[i].showText();
                phrase[i].hideUnderline();
            }
        }
      
        this.updateUI();
        this.revalidate();
    }
   
    /**
     * Checks if the full phrase is revealed
     * @return - true if the phrase is revealed, false if not
     */
    public boolean isFullPhraseRevealed()
    {
        for (int i = 0; i < phrase.length; i++)
        {
            if (phrase[i].isUnderlined()) return false; // only hidden letters are underlined
        }
        return true;
    }

    /**
     * Reveals the whole phrase
     */
    public void revealFullPhrase()
    {
        // hidden letters are underlined
        for (int i = 0; i < phrase.length; i++)
        {
            if (phrase[i].isUnderlined())
            {
                phrase[i].showText();
                phrase[i].hideUnderline();
            }
        }
    }
   
    /**
     * Calculates the difficulty of the current phrase.
     * @return the difficulty level of the current phrase
     *            0 - easy, 1 - medium , 2 - hard
     */
    public int getDifficultyLevel()
    {
        double[] frequency = new double[26];
        int offset = 'a';
      
        // frequency in % of letters in the English language
        // values taken from http://en.wikipedia.org/wiki/Letter_frequency
        frequency['a' - offset] = 8.167;
        frequency['b' - offset] = 1.492;
        frequency['c' - offset] = 2.782;
        frequency['d' - offset] = 4.253;
        frequency['e' - offset] = 12.702;
        frequency['f' - offset] = 2.228;
        frequency['g' - offset] = 2.015;
        frequency['h' - offset] = 6.094;
        frequency['i' - offset] = 6.966;
        frequency['j' - offset] = 0.153;
        frequency['k' - offset] = 0.772;
        frequency['l' - offset] = 4.025;
        frequency['m' - offset] = 2.406;
        frequency['n' - offset] = 6.749;
        frequency['o' - offset] = 7.507;
        frequency['p' - offset] = 1.929;
        frequency['q' - offset] = 0.095;
        frequency['r' - offset] = 5.987;
        frequency['s' - offset] = 6.327;
        frequency['t' - offset] = 9.056;
        frequency['u' - offset] = 2.758;
        frequency['v' - offset] = 0.978;
        frequency['w' - offset] = 2.360;
        frequency['x' - offset] = 0.150;
        frequency['y' - offset] = 1.974;
        frequency['z' - offset] = 0.074;
      
        // if a word consists of all the letters of the alphabet, the sum of unique frequencies will be 100%
        // let's assume that:
        // EASY - sum of frequencies of unique letters is <= 65
        // MEDIUM - sum of frequencies of unique letters is > 65 and <= 85
        // HARD - sum of frequencies of unique letters is > 85
      
        char c;
        double sum = 0;
        for (int i = 0; i < phrase.length; i++)
        {
            c = phraseString.charAt(i);
            if (Character.isAlphabetic(c)) // if its a letter
            {
                sum += frequency[c - offset]; // add the frequency of this letter
                frequency[c - offset] = 0; // zero the frequency to simulate that the letter was already counted, since we count only unique letters
            }
        }
      
        if (sum <= 65) return 0; // easy
        if (sum <= 85) return 1; // medium
        return 2; // hard
    }
}
---------------------------------------------------------
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JFrame;
import javax.swing.JOptionPane;

/**
 * Main game class
 */
public class HangmanGame extends JFrame implements KeyListener
{
    RandomString randString; // contains the phrases
    GuessPhrasePanel guessPanel; // the panel with the current phrase
   
    /**
     * Constructor
     */
    public HangmanGame()
    {
        super("Hangman Game");
      
        this.setSize(800, 80);
        this.setLocation(400, 200);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.addKeyListener(this);

        try
        {
            randString = new RandomString("guess_phrases.txt");
        }
        catch (Exception e)
        {
            e.printStackTrace();
            return;
        }
              
        guessPanel = new GuessPhrasePanel(randString.next());
        showDifficulty();
      
        this.add(guessPanel);
        this.setVisible(true);      
    }
   
    /**
     * Main function, starts the game
     * @param args
     */
    public static void main(String[] args)
    {
        new HangmanGame();
    }
   
    /**
     * Shows the difficulty in the title bar
     */
    void showDifficulty()
    {
        String difficulty = "";
        int diff = guessPanel.getDifficultyLevel();
        if (diff == 0) difficulty = "easy";
        if (diff == 1) difficulty = "medium";
        if (diff == 2) difficulty = "hard";
        this.setTitle("Hangman Game (" + difficulty + ")");
    }
   
    /**
     * Gets and shows the next phrase of the game
     */
    public void nextPhrase()
    {
        String newPhrase = randString.next();
        if (newPhrase.length() == 0)
        {
            JOptionPane.showMessageDialog(this, "No more phrases left!");
            return;
        }
      
        guessPanel.setPhrase(newPhrase);
        showDifficulty();
    }

    @Override
    public void keyPressed(KeyEvent arg0)
    {
        if (arg0.getKeyCode() == KeyEvent.VK_ENTER)
        {
            guessPanel.revealFullPhrase();
        }
        else if (arg0.getKeyCode() == KeyEvent.VK_SPACE)
        {
            nextPhrase();
        }
    }

    @Override
    public void keyReleased(KeyEvent arg0)
    {
      
    }

    @Override
    public void keyTyped(KeyEvent arg0)
    {
        char c = arg0.getKeyChar();
        if (guessPanel.hasLetter(c))
        {
            guessPanel.revealLetter(c);
        }
    }

}
----------------------------------------------------------------------------------
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * Keeps a list of phrases read from file
 * Provides random phrases on demand
 */
public class RandomString
{
    private List<String> lines; // list that holds all the lines read from a file
   
    /**
     * Constructor
     * @param fileName - the file from which the phrases are read
     * @throws IOException - when the file doesn't exist
     */
    public RandomString(String fileName) throws IOException
    {
        lines = new ArrayList<String>();
        BufferedReader reader;
      
        // read all lines from the file and store in a list
      
        reader = new BufferedReader(new FileReader(fileName));
        while (reader.ready()) lines.add(reader.readLine());
        reader.close();
    }
   
    /**
     * Removes that string from the list
     * @return - a random string from the list
     */
    public String next()
    {
        if (lines.size() == 0) return ""; // return empty string if the list is empty
      
        Random rand = new Random();
        int lineNr = rand.nextInt(lines.size()); // pick a random line number
        String randomString = lines.get(lineNr); // get the line
        lines.remove(lineNr); // remove the line from the list
        return randomString; // return the line
    }
   
    /**
     * Main test function for the class
     * @param args - main function arguments
     * @throws IOException - when the file doesn't exist
     */
    public static void main(String[] args) throws IOException
    {
        RandomString string = new RandomString("guess_phrases.txt");
      
        String line = string.next(); // get next line
        while (line.length() != 0) // if its not empty (so there are lines left)
        {
            System.out.println(line);
            line = string.next(); // get next line
        }
    }
}
-------------------------------------------------------------------------
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;

import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 * The Text class draws a String to the screen. 
 * It can show or hide the text, as well as an underline.
 * Other options include changing the letter or underline
 * color, and determining if the underline or text is
 * visible or not.
 *
 * Although intended to be used for single letters, the
 * Text class can be used to draw any length text to the
 * screen. Note that showing/hiding the text and underline
 * are independent. In other words, it is possible to
 * display the text without the underline showing, display
 * the underline without the text showing, show both, or
 * show neither.
 *
 */
public class Text extends JPanel {
   
    /////////////////////////////////////////////////////
    // CONSTANTS
    /////////////////////////////////////////////////////
    public static final int SPACE = 2;
   
    /////////////////////////////////////////////////////
    // FIELDS
    /////////////////////////////////////////////////////
    private String text;
    private boolean underline = true;
    private boolean visible = true;
    private Font font;
    private Color letterColor = Color.BLACK;
    private Color underlineColor = Color.BLACK;

    /////////////////////////////////////////////////////
    // CONSTRUCTOR
    /////////////////////////////////////////////////////
   
    /**
     * Initializes the text, sets the font, and sets the
     * dimensions for this panel.
     *
     * @param t the text string to be displayed by this
     * text panel
     */
    public Text(String t) {
        text = t;
        font = new Font("default", Font.BOLD, 18);
        this.setPreferredSize(new Dimension(20,20));
    }

    /////////////////////////////////////////////////////
    // GET / CHANGE THE TEXT DISPLAYED BY THIS OBJECT
    /////////////////////////////////////////////////////
   
    /**
     * Sets the text to be displayed by this object.
     *
     * @param t the text string to be displayed by this
     * text panel
     */
    public void setText(String t) {
        text = t;
        repaint();
    }
   
    /**
     * Returns the text string displayed by this text
     * panel when shown.
     *
     * @return the text string displayed by this text
     * panel
     */
    public String getText() {
        return text;
    }
   
    /**
     * Returns true if the text is whitespace consisting of
     * spaces, tabs, or returns. Returns false otherwise.
     *
     * @return true if the text is currently whitespace,
     * false otherwise.
     */
    public boolean isWhiteSpace() {
        return text == null || text.trim().equals("");
    }

    /////////////////////////////////////////////////////
    // SHOW/HIDE TEXT
    /////////////////////////////////////////////////////

    /**
     * Causes the text to be shown the next time
     * {@link #paintComponent(Graphics)} is called.
     */
    public void showText() {
        visible = true;
        repaint();
    }
   
    /**
     * Causes the text to be hidden the next time
     * {@link #paintComponent(Graphics)} is called.
     */
    public void hideText() {
        visible = false;
        repaint();
    }
   
    /**
     * Returns true if the text will be shown the next time
     * {@link #paintComponent(Graphics)} is called. This
     * method returns false if the text will be invisible.
     *
     * @return true if the text will be shown, false
     * otherwise.
     */
    public boolean isTextVisible() {
        return visible;
    }
   
    /////////////////////////////////////////////////////
    // SHOW/HIDE UNDERLINE
    /////////////////////////////////////////////////////
   
    /**
     * Causes the underline to be shown the next time
     * {@link #paintComponent(Graphics)} is called.
     */
    public void showUnderline() {
        underline = true;
        repaint();
    }
   
    /**
     * Causes the underline to be hidden the next time
     * {@link #paintComponent(Graphics)} is called.
     */
    public void hideUnderline() {
        underline = false;
        repaint();
    }
   
    /**
     * Returns true if the underline will be shown the next
     * time {@link #paintComponent(Graphics)} is called.
     * This method returns false if the underline will be
     * invisible.
     *
     * @return true if the underline will be shown, false
     * otherwise.
     */
    public boolean isUnderlined() {
        return underline;
    }
   
    /////////////////////////////////////////////////////
    // LETTER & UNDERLINE COLOR METHODS
    /////////////////////////////////////////////////////
   
    /**
     * Returns the {@code Color} object used to determine
     * the display color of the text. Note the color is
     * independent of whether the text will be visible
     * or hidden.
     *
     * @return the display color of the text
     */
    public Color getLetterColor() {
        return letterColor;
    }

    /**
     * Sets the display color used when drawing the text.
     *
     * @param letterColor the {@code Color} object to be
     * used
     */
    public void setLetterColor(Color letterColor) {
        this.letterColor = letterColor;
        repaint();
    }

    /**
     * Returns the {@code Color} object used to determine
     * the display color of the underline. Note the color
     * is independent of whether the underline will be
     * visible or hidden.
     *
     * @return the display color of the underline
     */
    public Color getUnderlineColor() {
        return underlineColor;
    }

    /**
     * Sets the display color used when drawing the
     * underline.
     *
     * @param underlineColor the {@code Color} object to
     * be used
     */
    public void setUnderlineColor(Color underlineColor) {
        this.underlineColor = underlineColor;
        repaint();
    }
   
    /////////////////////////////////////////////////////
    // PAINT METHOD
    /////////////////////////////////////////////////////
   
    /**
     * Draws the text panel to the screen based on the
     * field values.
     */
    public void paintComponent(Graphics page) {
        super.paintComponent(page);
        page.setFont(font);
      
        int w = this.getWidth();
        int h = this.getHeight();
      
        if (visible) {
            page.setColor(letterColor);
            page.drawString(text, SPACE, h - SPACE - 1);
        }
      
        if (underline) {
            page.setColor(underlineColor);
            page.fillRect(SPACE, h - SPACE,
                    (text.length()+1)*7, h);
        }
    }


    /////////////////////////////////////////////////////
    // MAIN METHOD FOR TESTING
    /////////////////////////////////////////////////////
    /**
     * Main method for testing.
     *
     * @param args none necessary
     */
    public static void main(String[] args) {

          JFrame frame = new JFrame ("Hangman Game");
          frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);

          JPanel panel = new Text(" ");

          frame.getContentPane().add(panel);

          frame.pack();
          frame.setVisible(true);

    }
}
 

Screenshots:


2 comments: