EnkeiRC5
EnkeiRC5

Reputation: 139

Java hangman program gone horribly wrong

I am a beginner at Java, and was required to throw together an application for a Java final project. I wanted to do hangman (Seemed easy at the time). This is EXTREMELY DIFFICULT for me. Here is my code so far. (it's really an abomination of about 10 open source hangman games thrown together). See bottom for my question.

import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import java.util.ArrayList; 


public class Hangman implements ActionListener {
JFrame frame;
private String[] wordList = {"computer","java","activity","alaska","appearance","article", 
   "automobile","basket","birthday","canada","central","character","chicken","chosen", 
   "cutting","daily","darkness","diagram","disappear","driving","effort","establish","exact", 
   "establishment","fifteen","football","foreign","frequently","frighten","function","gradually", 
   "hurried","identity","importance","impossible","invented","italian","journey","lincoln", 
   "london","massage","minerals","outer","paint","particles","personal","physical","progress", 
   "quarter","recognise","replace","rhythm","situation","slightly","steady","stepped", 
   "strike","successful","sudden","terrible","traffic","unusual","volume","yesterday" }; 
public String mysteryWord; 
public int lives;
private boolean finished = false;
private boolean won = false;
private Button a[];
public boolean used[] = new boolean[26]; 

public static void main (String[] args) {
    Hangman gui = new Hangman();
    gui.go();
    }

class myDrawPanel extends JPanel {
    public void paintComponent(Graphics g) {
     setBackground(Color.white);
     g.setColor(Color.gray);
     g.fillRect(50, 200, 150, 20);
     g.fillRect(90,20,10,200);
     g.fillRect(90,20,60,10);
     g.setColor(Color.black);
     g.fillRect(145,20,5,25);
     g.setColor(Color.green);
        if (lives < 6 )
            g.drawOval(132,45,30,30);
        if (lives < 5 )
            g.drawLine(147,75,147,100);
        if (lives < 4 )
            g.drawLine(147,100,167,133);
        if (lives < 3 )
            g.drawLine(147,100,127,133);
        if (lives < 2 )
            g.drawLine(147,75,167,85);
        if (lives < 1 )
            g.drawLine(147,75,127,85);

            StringBuffer guessed = new StringBuffer();

            for (int cl = 0; cl < mysteryWord.length(); cl++) {
                    if (used[(int)mysteryWord.charAt(cl)-65])
                            guessed.append(mysteryWord.charAt(cl));
                    else
                            guessed.append(".");
                    }

            g.drawString(guessed.toString(),75,230);
                 //currentWordLA.setText("Current word: " + mysteryWord);



         if (lives < 1) {
            g.setColor(Color.white);
            g.fillRect(70, 200, 200, 30);
            g.setColor(Color.black);
            g.drawString(mysteryWord.toString(),75,230);
            Font fff = new Font("Helvetica",Font.BOLD,36);
            g.setFont(fff);

            g.setColor(Color.red);
            g.drawString("You lose!",200,100);

            finished = true;
            }

         if (won) {
            Font fff = new Font("Helvetica",Font.BOLD,36);
            g.setFont(fff);

//                Color red=new Color.red
            g.setColor(Color.red);

            g.drawString("You Win!",200,100);
            finished = true;
            }
  }
 }

public void go() {

///////////////////////DESIGN BEGIN//////////////////////////////////////////////
    frame = new JFrame("Hangman");
    JPanel topPanel = new JPanel();
    myDrawPanel noosePanel = new myDrawPanel();
    JPanel bottomPanel = new JPanel();
    JPanel scorePanel = new JPanel(new FlowLayout(FlowLayout.LEFT));

    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLayout( new GridLayout( 2, 0) );
    bottomPanel.setLayout( new GridLayout( 0, 2) );
    scorePanel.setSize(20,100);

    noosePanel.setBorder(BorderFactory.createTitledBorder("Your progress.")); 
    topPanel.setBorder(BorderFactory.createTitledBorder("Your arsenal.")); 
    scorePanel.setBorder(BorderFactory.createTitledBorder("Your score.")); 
    frame.add(topPanel);
    frame.add(bottomPanel);
    bottomPanel.add(scorePanel);
    bottomPanel.add(noosePanel);

//Just the stats panel.
    JPanel stats = new JPanel();
    JLabel currentWordLA = new JLabel("Current word:");
    JLabel triedLettersLA = new JLabel("Tried letters:");
    JLabel triesLeftLA = new JLabel("Tries remaining:");
    JButton restart = new JButton("Reset");

        currentWordLA.setFont(new Font("Verdana", Font.PLAIN, 10));
        currentWordLA.setForeground(Color.black);
        triedLettersLA.setFont(new Font("Verdana", Font.PLAIN, 10));
        triedLettersLA.setForeground(Color.black);
        triesLeftLA.setFont(new Font("Verdana", Font.PLAIN, 10));
        triesLeftLA.setForeground(Color.black);
        restart.setFont(new Font("Verdana", Font.PLAIN, 16));
        restart.setForeground(Color.red);

            stats.setLayout(new GridBagLayout()); 
            GridBagConstraints c = new GridBagConstraints(); 
            c.gridx = 0; 
            c.gridy = 0; 
            c.insets = new Insets(20,0,0,0); 
            c.anchor = GridBagConstraints.LINE_START;
            stats.add(currentWordLA, c); 
            c.gridx = 0; 
            c.gridy = 1; 
            c.anchor = GridBagConstraints.LINE_START;
            stats.add(triedLettersLA, c); 
            c.gridx = 0; 
            c.gridy = 2; 
            c.anchor = GridBagConstraints.LINE_START;
            stats.add(triesLeftLA, c); 
            c.gridx = 0; 
            c.gridy = 3; 
            c.anchor = GridBagConstraints.LINE_START;
            stats.add(restart, c); 
            scorePanel.add(stats);
///////////////////////DESIGN END////////////////////////////////////////////// 
///////////////////////ALPHABET BEGIN//////////////////////////////////////////
    int i;
    StringBuffer buffer;
    a = new Button[26];
    topPanel.setLayout( new GridLayout( 4,0, 10, 10) );
    for (i = 0; i <26; i++) {
           buffer = new StringBuffer();
            buffer.append((char)(i+65));
            a[i] = new Button(buffer.toString());
            a[i].setSize(100,100);
            a[i].addActionListener( this );
          topPanel.add(a[i]);
        }
///////////////////////ALPHABET END//////////////////////////////////////////
//Just shows the entire window.                  
    frame.setSize(500, 500);
    frame.setResizable(false);
    frame.setVisible(true);
//////////////////////GAMEPLAY BEGIN////////////////////////////////////////
    lives = 6;
    mysteryWord = wordGen();


}


//Returns a random word from the wordList bank.
    private String wordGen() {
        return wordList[0 + (int)(Math.random() * ((63 - 0) + 1)) ]; //Make sure to set these to nonprinted chars eventually
    }

    public void consultWord(int letter) {
        if (finished == false) {
            boolean found = false;
        boolean www = false;
                if (used[letter] = false) {
                for (int cl = 0 ; cl < mysteryWord.length(); cl++) {
                if (mysteryWord.charAt(cl)==((char)(letter+65))) found = true;
            }
            if (found == false) 
                    lives = lives - 1;
                }
    used[letter] = true;
            for (int cl = 0; cl < mysteryWord.length(); cl++) {
          if (!used[(int)(mysteryWord.charAt(cl)) - 65]) www = true;
            }
            if (www = false) won = true;        
            frame.repaint();
    }
    }

    public void actionPerformed( ActionEvent e) {
        int i;
        for (i = 0; i < 26; i++) {
            if (e.getSource() == a[i]) { 
            consultWord(i); }
  }
}       
}

At the moment this doesn't work. I run it, and tons of thread exeption errors come up. (It compiles beautifully). The first line it takes me to is

if (used[(int)mysteryWord.charAt(cl)-65])

I'm not sure what the issue is with this line. Also, the original author used the number 65. I tweaked my code and used my own variables so that I understood how it worked. But the number 65 and where it came from, I can't figure out for the life of me. Any ideas?

And I need to know what is causing all the thread exceptions. The GUI builds nicely. It's just all the math and triggers that mess things up. (The GUI I built all by myself! :) )

Exception

Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 34
    at Hangman$myDrawPanel.paintComponent(Hangman.java:55)
    at javax.swing.JComponent.paint(JComponent.java:1054)
    at javax.swing.JComponent.paintChildren(JComponent.java:887)
    at javax.swing.JComponent.paint(JComponent.java:1063)
    at javax.swing.JComponent.paintChildren(JComponent.java:887)
    at javax.swing.JComponent.paint(JComponent.java:1063)
    at javax.swing.JComponent.paintChildren(JComponent.java:887)
    at javax.swing.JComponent.paint(JComponent.java:1063)
    at javax.swing.JLayeredPane.paint(JLayeredPane.java:585)
    at javax.swing.JComponent.paintChildren(JComponent.java:887)

Upvotes: 1

Views: 783

Answers (4)

Stephen C
Stephen C

Reputation: 719396

This is mostly not a direct answer to your question, but it is relevant to the larger issue of learning to write software ... which is your overall goal. (And there's a real answer at the bottom.)

You write:

(it's really an abomination of about 10 open source hangman games thrown together)

Taking a bunch of existing programs (of dubious quality *) and mashing them together is NOT a good way to create software.

  • You inherit the problems of functionality and style in the existing code that you have "harvested".
  • You add a bunch of new functionality and style problems caused by mismatches between the different code bases ... and your conception.

Code reuse can be a good thing, but you need to be disciplined and selective:

  • Do design your own code ... following the design principles that you have been taught.
  • Do reuse at the library level, using well-engineered libraries.
  • Don't reuse by copy-and-pasting.
  • Don't reuse code (or libraries) that looks like a dog's breakfast. (If the author is sloppy with his/her code style and API design, that's a bad sign for other quality issues.)

(* The fact that you are seeing obscure numbers like 65 embedded in the code is a sign of poor code quality. The author could and should have written that as 'A'.)

In fact, this might be the root of your bug, since it looks like your "mystery" words are in lowercase. 'a' - 'A' is 32, and that is larger than the bounds of your used array.

And this brings us back to my main point. Because, apparently, in your code mashing you have failed to understand the implied invariants of the code you copied ... and broken them. The problematic statement that is throwing the exception is designed to work with uppercase-only words ... but you've changed that.

Upvotes: 6

mprivat
mprivat

Reputation: 21912

65 is ASCII for 'A', but your words are all in lowercase. So instead of (int)mysteryWord.charAt(cl)-65, you should do (int)mysteryWord.charAt(cl)-'a'

Upvotes: 1

Jeshurun
Jeshurun

Reputation: 23186

change

if (used[(int)mysteryWord.charAt(cl)-65])
    guessed.append(mysteryWord.charAt(cl));
else
    guessed.append(".");
}

to

if (used[(int)mysteryWord.charAt(cl)-97])
    guessed.append(mysteryWord.charAt(cl));
else
    guessed.append(".");
}

The code at line 55, when converting to ASCII, is ending up with a value larger than the size of the used array.

Upvotes: 0

derekerdmann
derekerdmann

Reputation: 18252

The 65 is the ASCII character code for the letter 'A'. The line in question is converting from the ASCII ordinal value to something in the range 0-25, which allows the used array to store whether each letter of the alphabet has been checked.

Upvotes: 1

Related Questions