Java hangman game with gui, problems with incrementing/decrementing numbers - java

The following part of the code doesn't work, as the won/lost count keeps incrementing by more than 1 for each word, and sometimes I get a nullpointerexception with the string length. Moreover, although the player is supposed to get 7 tries(int no), sometimes he gets more, sometimes less. The Strings are taken from a text file "Hangeng.txt". The whole game is inside a keyboard keytyped listener that is inside a button listener. Any tips on how the layout of the game should generally be arranged so as to avoid errors are welcome, as I am only beginning to work with swing and gui stuff.
public class test{
static int won = 0;
static int lost = 0;
static String key = "";
static String word = null;
static int no = 0;
static StringBuffer toguess;
public static void main(String[] args) throws IOException{
JFrame frame = new JFrame();
frame.setLayout(new GridLayout(3,1));
JPanel panel1 = new JPanel();
JPanel panel2 = new JPanel();
JPanel panel3 = new JPanel();
JButton button = new JButton();
JLabel label = new JLabel();
JLabel label2 = new JLabel();
panel1.add(label);
panel2.add(button);
panel3.add(label2);
frame.setSize(800,600);
frame.add(panel1);
frame.add(panel2);
frame.add(panel3);
frame.setVisible(true);
//the button that starts the game or gets a new word
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
frame.requestFocus();
no = 0;
label2.setText("won " + won + ", lost " + lost);
button.setText("Next");
//get random word from file
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(
"hangeng.txt"));
} catch (FileNotFoundException e1) {
e1.printStackTrace();
}
int lineno = (int) (Math.random() * 100);
for (int i = 0; i < lineno; i++) {
try {
reader.readLine();
} catch (IOException e1) {
e1.printStackTrace();
}
}
try {
word = reader.readLine().replace(" ", "");
} catch (IOException e1) {
e1.printStackTrace();
}
String missing = "";
for (int u = 0; u < (word.length() - 2); u++) {
missing = missing + "*";
}
final String guess = word.charAt(0) + missing
+ word.charAt((word.length() - 1));
toguess = new StringBuffer(guess);
label.setText(toguess.toString());
final ArrayList<String> tried = new ArrayList<String>();
//keylistener that listens to key clicks by the user
frame.addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent arg0) {
}
public void keyReleased(KeyEvent arg0) {
}
public void keyTyped(KeyEvent arg0) {
key = "" + arg0.getKeyChar();
String guessing = null;
boolean k = false;
if ((no < 6)) {
guessing = key;
System.out.println(guessing);
if (!(tried.contains(guessing))) {
tried.add(guessing);
for (int length = 1; length < (guess
.length() - 1); length++) {
if (guessing.equals(String.valueOf(word.charAt(length)))) {
toguess.replace(length,
(length + 1),
String.valueOf(word.charAt(length)));
k = true;
}
}
if (k == true) {
label.setText(toguess.toString());
} else {
no = no + 1;
}
k = false;
}
label.setText(toguess.toString());
if (toguess.toString().equals(word)) {
label.setText("Correct! The word was " + word);
no = 6;
won = won + 1;
}
}
else if ((no == 6)
&& (!(toguess.toString().equals(word)))) {
label.setText("Sorry, but the word was " + word);
lost = lost + 1;
}
}
});
}
});
}
}

+1 to all comments....
Adding to them:
Do not use KeyListener use a KeyAdapter however as you are using Swing and not AWT you should use KeyBindings for Swing see here for example.
Dont forget to create and manipulate Swing components on Event Dispatch Thread via SwingUtiltities.invokeLater(..) block see here for more.
Check class naming schemes they shuld start with capital letter, i.e test should be Test and every new word after that should be capitalized.
Do not call setSize on JFrame rather use appropriate LayoutManager and/or override getPreferredSize() of JPanel and return a size which fits its content and call pack() on JFrame instance after adding all components.
Also SSCCE should be compilable from copy and paste this is not.... i.e variables needed to be changed to final and I dont have a sample of Hangeng.txt so cant test
Lastly use the #Override annotation to ensure you are overriding the correct methods, i.e
#Override
public void actionPerformed(ActionEvent e) {
}

Related

Adding and removing checkboxes dynamically

I want to make ToDoList App. After successfully adding task to do (which contains checkbox, JLabel and date, all putted in a box) i want to remove them dynamically. With adding it's not problem but when i try to remove (ater clicking checked in checkbox) it works only once. Then it either removes not once which are intended or not removing them at all. I am not sure why it's not working so I paste all code below.
JSpinner dateSpin;
Box eventBox, boxBox;
Box[] taskBox = new Box[1000];
JTextField eventName;
Date date;
Checkbox[] doneCheck = new Checkbox[1000];
JLabel taskLabel;
JPanel panel;
JScrollPane scrollPane;
SimpleDateFormat simpleDate;
int i = 0;
public static void main(String[] args) {
new Main();
}
private Main(){
this.setSize(400, 600);
this.setTitle("To-Do List");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setResizable(false);
this.setLocationRelativeTo(null);
panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
boxBox = Box.createVerticalBox();
scrollPane = new JScrollPane(panel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
eventBox = Box.createHorizontalBox();
eventBox.setBorder(BorderFactory.createEtchedBorder());
JLabel plusSign = new JLabel("+");
plusSign.setFont(new Font("Serafi", PLAIN, 20));
plusSign.setMaximumSize(new Dimension(Integer.MAX_VALUE, plusSign.getMinimumSize().height));
eventBox.add(plusSign);
eventName = new JTextField(20);
eventName.setFont(new Font("Times", Font.ITALIC, 15));
eventName.setMaximumSize(new Dimension(Integer.MAX_VALUE, eventName.getMinimumSize().height));
eventName.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == eventName){
/* to do: saving every task in some file, figure out how to remove
those tasks (checkbox + jlabel) -> whole box from screen or how to send them to "done"
also "done" to do*/
simpleDate = new SimpleDateFormat("E-dd-MM-yyyy");
taskBox[i] = Box.createHorizontalBox();
taskBox[i].setBorder(BorderFactory.createTitledBorder(simpleDate.format(date)));
doneCheck[i] = new Checkbox();
doneCheck[i].addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
int k = 0;
for (int j = 0; j < doneCheck.length; j++) {
if(doneCheck[j].getState()){
//remove(doneCheck[k]);
//System.out.println("?" + i + "?" + k + " " + e.getSource().toString());
System.out.println("xxxxx" + doneCheck[j].getState());
break;
}
System.out.println("oooooo");
k++;
}
System.out.println(doneCheck.length + taskBox[k].toString());
//System.out.println("! " + k + " " + e.getSource().toString());
boxBox.remove(taskBox[k]);
//boxBox.removeAll();
boxBox.revalidate();
boxBox.repaint();
}
});
taskBox[i].add(doneCheck[i]);
String taskName = eventName.getText();
taskLabel = new JLabel(taskName);
taskLabel.setMinimumSize(new Dimension(500,10));
taskLabel.setPreferredSize(new Dimension(300, 10));
taskBox[i].add(taskLabel);
boxBox.add(taskBox[i]);
boxBox.setMaximumSize(new Dimension(Integer.MAX_VALUE, boxBox.getMinimumSize().height + 11));
panel.add(boxBox);
panel.revalidate();
panel.repaint();
i++;
}
}
});
eventBox.add(eventName);
date = new Date();
dateSpin = new JSpinner(new SpinnerDateModel(date, null, null, Calendar.DAY_OF_MONTH));
JSpinner.DateEditor dateEditor = new JSpinner.DateEditor(dateSpin, "dd/MM/yy");
dateSpin.setEditor(dateEditor);
dateSpin.setMaximumSize(new Dimension(Integer.MAX_VALUE, dateSpin.getMinimumSize().height));
dateSpin.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
if(e.getSource() == dateSpin){
date = (Date) dateSpin.getValue();
}
}
});
eventBox.add(dateSpin);
panel.add(eventBox, new FlowLayout());
this.add(scrollPane);
this.setVisible(true);
}
You never remove elements from the taskBox and doneCheck arrays.
Now if you mark the first entry as done, your ItemListener will always find this first entry when looping over the doneCheck array.
Marking the entries as done in reverse order (always the last shown entry) will remove one entry after the other.
As to your software design: it's considered bad practice to manage your data in several parallel arrays.
Please consider creating a custom class for the todo items that manages all the elements of a single todo item.
Unless you are initializing doneCheck items somewhere, this:
Checkbox[] doneCheck = new Checkbox[1000];
And this:
int k = 0;
for (int j = 0; j < doneCheck.length; j++) {
if (doneCheck[j].getState()) {
--------^^^^^^^^^^^^
Is probably one the reason it fails: you probably got a NullPointerException somewhere, eg: when value of j > 0. The NPE will probably be catched by the EventDispatchThread which may or may not be kind enough to show it on stderr...
I fail to see why you are using this array, and you can shorten your code and avoid NPE like this:
Checkbox cb = new Checkbox();
cb.addItemListener(event -> {
if (cb.getState()) { // not null!
boxBox.remove(cb);
boxBox.revalidate();
boxBox.repaint();
}
});
doneCheck[i] = cb; // I still don't know why you need that.
My guess is that you have 2 variables global int i = 0 and local int k = 0 in here
public void itemStateChanged(ItemEvent e) {
// int k = 0;//<-------- LOCAL
for (int j = 0; j < doneCheck.length; j++) {
if(doneCheck[j].getState()){
//Either k = j;
boxBox.remove(taskBox[j]);
//remove(doneCheck[k]);
//System.out.println("?" + i + "?" + k + " " + e.getSource().toString());
System.out.println("xxxxx" + doneCheck[j].getState());
break;
}
System.out.println("oooooo");
//k++;//<-- ALWAYS == last j value before the break;
}
System.out.println(doneCheck.length + taskBox[k].toString());
//System.out.println("! " + k + " " + e.getSource().toString());
//boxBox.remove(taskBox[k]);//
//boxBox.removeAll();
boxBox.revalidate();
boxBox.repaint();
}
Every time you call for itemStateChanged int k = 0; will be initialized to 0 and you will be removing element[j] from array of taskBox. As you k++ statement will be equal to the last j value before the break; because it sits after the if(doneCheck[j].getState()){...
Try moving boxBox.remove(taskBox[j]); inside the for loop and using j instead of k.

Image keeps on repeating although it is already randomized

I'm developing a simple game where all the images are randomized. I've noticed that some of the image are repeated although I have put the random code. I'm still new to Java. I hope that someone can help me solve my problem. Below is my coding.
import java.awt.*;
import java.awt.event.*;
import java.sql.*;
import java.util.Random;
import javax.swing.*;
public class Task1 extends JFrame implements KeyListener,ActionListener {
JFrame frame = new JFrame("FYP");
JTextField textField = new JTextField();
JButton btnNext = new JButton("NEXT");
int sum=0;
int Error=0;int total_test = 0;
static String inputID;
static int index;
String[] imgFileHP = {"1.jpg","3.jpg","4.jpg","7.jpg","9.jpg","10.jpg","12.jpg","16.jpg","17.jpg","18.jpg"};
String[] imgNo = {"5","4","6","3","5","3","4","4","6","6"};
int randomNo;
Random rand = new Random();
public Task1(String inputID)
{
frame.setSize(2200,2500);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
frame.getContentPane().setLayout(new BorderLayout(0, 0));
Task(inputID);
}
public void Task(String inputID)
{
JPanel panel = new JPanel();
JLabel labelUsername = new JLabel("");
frame.getContentPane().add(panel, BorderLayout.CENTER);
panel.setBackground(Color.WHITE);
Collections.shuffle(Arrays.asList(imgFileHP));
Set<Integer> uniqueList = new HashSet<Integer>();//This would create list with the number 0 to 9
for(int count=0;count<imgFileHP.length;count++){
uniqueList.add(count);
labelUsername.setIcon(new ImageIcon(getClass().getResource("/image/" + imgFileHP[count])));
if(!uniqueList.isEmpty()){
index = (int) (Math.random() * (upper - lower)) + lower;
if(uniqueList.contains(index)){
uniqueList.remove(index);//particular number is delete from the list so that duplicate images doesnt show up
System.out.println(imgFileHP[r]);//This printf statement is just for your reference
}
}
}
textField.setText("");
textField.setColumns(10);
textField.addKeyListener(this);
btnNext.addActionListener(this);
panel.add(labelUsername);
panel.add(textField);
panel.add(btnNext);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent ae)
{
if(!textField.getText().equals("")){
total_test += 1;
if(isNumeric(textField.getText())){
//********************Correct Integer**********************
if(Integer.valueOf(imgNo[randomNo])==Integer.valueOf(textField.getText())){
//********************Correct Answer**********************
System.out.println("Correct");
sum+=1;
}else{
//********************Incorrect Answer**********************
System.out.println("Incorrect");
Error+=1;
}
refreshFrame();
}else{
//********************Incorrect Integer/Alphabet**********************
System.out.println("Invalid");
Error+=1;
refreshFrame();
}
}else{
System.out.println("Null Input");
}
//System.out.println(Integer.valueOf(imgNo[randomNo]));
}
public void refreshFrame(){
if(total_test>=10){
// add result page to see how many score
//Task2(sum, Error);
System.out.println("Correct: "+sum+" Incorrect: "+Error);
frame.dispose();
}else{
btnNext.removeActionListener(this);
frame.getContentPane().removeAll();
getContentPane().removeAll();
Task(inputID);
}
}
public static void main(String args[]) {
Task1 a = new Task1(inputID);
}
#Override
public void keyPressed(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
public static boolean isNumeric(String str)
{
try
{
Integer.valueOf(str);
}
catch(NumberFormatException nfe)
{
return false;
}
return true;
}
}
EDIT part (But some of the image is still repeating.)
Collections.shuffle(Arrays.asList(imgFileHP));
Set<Integer> uniqueList = new HashSet<Integer>();//This would create list with the number 0 to 9
for(int count=0;count<imgFileHP.length;count++){
uniqueList.add(count);
}
if(!uniqueList.isEmpty()){
index = (int) (Math.random() * (upper - lower)) + lower;
randomNo = index;
if(uniqueList.contains(index)){
labelUsername.setIcon(new ImageIcon(getClass().getResource("/image/" + imgFileHP[index])));
uniqueList.remove(index);//particular number is delete from the list so that duplicate images doesnt show up
System.out.println(imgFileHP[r]);//This printf statement is just for your reference
}
}
Here is how Random works. Even though you have mentioned rand.nextInt(10);but everytime it gets called, there is not pre-defined rule in java that it has to generate unique numbers and not the duplicate the previously generated ones.
For Example:
when you call -
int index = rand.nextInt(10); // Index could be 2
index = rand.nextInt(10); // Now again the value could be 2 as well
So what you need to do is you have to add an extra piece of code to check the uniqueness every time random is called.
Since you want to generate numbers between 0 to 10. Try the following code, it might help you understand.
String[] imgFileHP = {"1.jpg","3.jpg","4.jpg","7.jpg","9.jpg","10.jpg","12.jpg","16.jpg","17.jpg","18.jpg"};
int upper = imgFileHP.length;
int lower = 0;
int r=0;
int index=0;
Set<Integer> uniqueList = new HashSet<Integer>();//This would create list with the number 0 to 9
for(int count=0;count<imgFileHP.length;count++){
uniqueList.add(count);
}
if(!uniqueList.isEmpty()){
index = (int) (Math.random() * (upper - lower)) + lower;
if(uniqueList.contains(index)){
uniqueList.remove(index);//particular number is delete from the list so that duplicate images doesnt show up
System.out.println(imgFileHP[r]);//This printf statement is just for your reference
}
}
Another easier method is to use Collections.Shuffle as shown below:
Collections.shuffle(Arrays.asList(imgFileHP));
Example of Collection.shuffle().
Lets say you have an array String[] arr = {"abc","def","xyz","bla"}
when you do Collections.shuffle(Arrays.asList(arr));
then print array from index 0 to 3. Array might be shuffled something like this: {"def","bla","abc","xyz"}
**EDIT 2:**Solution based on your edit in main code:
for(int count=0;count<imgFileHP.length;count++){//first add the counters into List
uniqueList.add(count);
}
if(!uniqueList.isEmpty()){
index = (int) (Math.random() * (upper - lower)) + lower;
if(uniqueList.contains(index)){
labelUsername.setIcon(new ImageIcon(getClass().getResource("/image/" + imgFileHP[index])));
uniqueList.remove(index);//particular number is delete from the list so that duplicate images doesnt show up
System.out.println(imgFileHP[r]);//This printf statement is just for your reference
}
}

for loop for array only processing one element in java?

I can't figure out why whenever I cycle through my array using the for-loop it only produces one element (the first) to console? I'm pretty sure it's a rookie-mistake I'm looking over, so any tips and suggestions would help.
I'm making a program for fun that compares two strings typed in a text field and if they don't exist in the array it produces a JOPtionPane message on the contrary. It's for a battle-hack I may produce in the future for vBulletin forum, but I'm messing around with algorithms before I move to that step. Thanks, guys!
package battleoptionspart1;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.lang.*;
import javax.swing.border.*;
public class BattleOptionsPart1 extends JFrame{
JButton newthread, previewpost;
JRadioButton battle1;
JTextField postcount, oppA, oppB;
JLabel battle2, max;
JPanel panel;
String [] array = {"Bill","Tom","Wendy", "Paula"};
public BattleOptionsPart1 () {
panel = new JPanel();
Toolkit tool = Toolkit.getDefaultToolkit();
Dimension dim = tool.getScreenSize();
this.setSize(500, 500);
this.setTitle("Battle Options");
GridLayout grid = new GridLayout(0,1,2,2);
this.setLayout(grid);
newthread = new JButton("Post New Thread");
previewpost = new JButton("Preview Post");
postcount = new JTextField("", 4);
oppA = new JTextField("",10);
oppB = new JTextField("",10);
battle1 = new JRadioButton();
battle2 = new JLabel("Would you like to start a recorded battle?");
max = new JLabel("Enter max post count user must have to vote");
ListenForButton listen = new ListenForButton();
newthread.addActionListener(listen);
previewpost.addActionListener(listen);
JPanel opponents = new JPanel();
Border oppBorder = BorderFactory.createTitledBorder("Battlers");
opponents.setBorder(oppBorder);
opponents.add(oppA);
opponents.add(oppB);
JPanel battle = new JPanel();
Border battleBorder = BorderFactory.createTitledBorder("Start Battle");
battle.setBorder(battleBorder);
battle.add(battle1);
battle.add(battle2);
JPanel buttons = new JPanel();
Border buttonBorder = BorderFactory.createTitledBorder("Create Thread");
buttons.setBorder(buttonBorder);
buttons.add(newthread);
buttons.add(previewpost);
JPanel restriction = new JPanel();
Border resBorder = BorderFactory.createTitledBorder("Restrictions");
restriction.setBorder(buttonBorder);
restriction.add(postcount);
restriction.add(max);
this.add(opponents);
this.add(battle);
this.add(restriction);
this.add(buttons);
this.add(panel);
int xPos = (dim.width / 2) - (this.getWidth() / 2);
int yPos = (dim.height / 2) - (this.getHeight() / 2);
this.setLocation(xPos,yPos); //places form in the middle
this.setVisible(true); // users can see form
this.setResizable(false); //users can't resize the form
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private class ListenForButton implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
String compareA = oppA.getText();
String compareB = oppB.getText();
if (e.getSource() == newthread)
{
System.out.println(compareA + "\n" + compareB);
for(int j = 0; j < array.length; j++)
{
System.out.println(array[j]);
if(!compareA.equals(array[j]))
{
JOptionPane.showMessageDialog(null, compareA + " doesn't exist!", "Error Message", JOptionPane.ERROR_MESSAGE);
oppA.requestFocus();
break;
}
if (!compareB.equals(array[j]))
{
JOptionPane.showMessageDialog(null, compareB + " doesn't exist!", "Error Message", JOptionPane.ERROR_MESSAGE);
oppB.requestFocus();
break;
}
else
{
JOptionPane.showMessageDialog(null, "New thread created successfully!", "Success", JOptionPane.INFORMATION_MESSAGE);
break;
}
}
}
else if (e.getSource() == previewpost)
{
System.exit(0);
}
}
}
public static void main(String[] args) {
BattleOptionsPart1 battle = new BattleOptionsPart1();
}
}
In each of the possible options in your loop, you use break, which leaves the loop immediately. If you remove those statements, you'll process each object in the array.
If you want to check if there's a match, you need to go through every element and do your processing after going through the whole array. Here is an example for an array of type int:
boolean contains = false;
for (int i = 0; i < arr.length; i++)
{
if (arr[i] == searchKey)
{
contains = true;
break;
}
}
You're breaking out of the loop. with the break; command after the first array element

JTextPane color everything instead of few chars

So Im trying to write simple editor. I want to color gray all chars witch are between " characters. Fragment which does it is:
class MainPanel extends JPanel {
private int WIDTH = 800;
private int HEIGHT = 500;
private JTextPane codePane = new JTextPane(); //Pole, w które wpisywany jest kod
private JLabel codeLabel = new JLabel("JNotepad");
private StyledDocument doc = codePane.getStyledDocument();
private final String[] keywords; //Słowa kluczowe
private final Map<String, String> shortcuts = new HashMap<>(); //syso -> System.out.println() itp.
MainPanel() {
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setLayout(new BorderLayout());
//Dodanie głównego pola w polu przewijanym
JScrollPane scroll = new JScrollPane(codePane);
add(scroll, BorderLayout.CENTER);
add(codeLabel, BorderLayout.SOUTH);
codePane.addKeyListener(new KeyHandler());
codePane.setFont(new Font("Monospaced", Font.PLAIN, 15));
//Załadowanie słów kluczowych
Scanner in = new Scanner(getClass().getResourceAsStream("res/keywords.txt"));
List<String> words = new LinkedList<>();
while (in.hasNext()) {
words.add(in.nextLine());
}
keywords = words.toArray(new String[words.size()]);
in.close();
}
private class KeyHandler extends KeyAdapter {
#Override
public void keyReleased(KeyEvent ev) {
highlight();
}
private void highlight() {
String code = codePane.getText();
//Zmiana koloru słów kluczowych
String[] words = code.replaceAll("\\(|\\)|\\{|\\}|\\[|\\]", " ").split("\\s");
int lastIndex = 0;
for (int a = 0; a < words.length; a++) {
SimpleAttributeSet set = new SimpleAttributeSet();
if (Arrays.asList(keywords).contains(words[a])) {
StyleConstants.setForeground(set, Color.BLUE);
}
doc.setCharacterAttributes(lastIndex, lastIndex + words[a].length(), set, true);
//Zwiekszenie ostatniego indexu
lastIndex += words[a].length() + 1; //+1 bo jeszcze spacja
}
}
}
}
When " occurs it paints characters gray, but it paints all characters after first " sign. What's wrong with this code? EDIT: Here you are, this is the full code.
Second argument in setCharacterAttributes() method is a length, not end index. It was your problem.
boolean isString = false;
char[] text = code.toCharArray();
for (int i = 0; i < text.length; i++) {
if (text[i] == '\"') {
isString = !isString;
if(!isString) {
document.setCharacterAttributes(i, 1, attributes, true);
}
}
if (isString) {
document.setCharacterAttributes(i, 1, attributes, true);
}
}
Original question was shorter with only with few lines of code but mKorbel has right:
... in this case (it's a) job for DocumentFilter, never to use KeyListener for JTextComponent.
You should check that, it could help: How to Write a Document Listener
Because the condition is true.if (string) will be true.String will be given true once it equals("\"")) .So it carry on's for the next string.
In if (string){.....} block, in the end make string=false

Hangman masking string, unhiding character

I'm writing a hangman application and I'm at the point where I have to write the code to Hide each char in the string (the word being guessed) with "-"... And I've posted a lot of questions on hoe to do it and one of my replies was:Hangman - hide String and then unhide each char if guessed correct
public class HangmanWord {
private static final char HIDECHAR = '_';
private String original;
private String hidden;
public HangmanWord(String original) {
this.original = original;
this.hidden = this.createHidden();
}
private String createHidden() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < this.original.length; i++) {
sb.append(HIDECHAR);
}
return sb.toString();
}
public boolean check(char input) {
boolean found = false;
for (int i = 0; i < this.original.length; i++) {
if (this.original[i].equals(input)) {
found = true;
this.hidden[i] = this.original[i];
}
}
return found;
}
//getter and setter
}
public class TestClass() {
public static void main(String[] args) {
String secret = "stackoverflow";
int wrongGuesses = 0;
HangmanWord hngm = new HangmanWord(secret);
System.out.println(hngm.getHidden()); // _____________
if (hngm.check('a')) {
System.out.println(hngm.getHidden()); // __a_________
}
else {
wrongGuesses++;
}
//... and so on...
}
}
I tried to use this code with mine and I had a lot of errors and conclusion it didn't work with my code. In my code i've created an array buttons where if the person clicks on a button I get an message saying if the letter is in the word or not... Now I want to replace this code with where it doesn't give me an message but unhides the char and if there's no char it has to change the image
If possible can anyone explain why it didn't work with my code or can anyone please explain to me what to do...
my button array:
public JButton getButton(final String text){
final JButton button = new JButton(text);
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
if(original.toUpperCase().indexOf(button.getText())!=-1){
JOptionPane.showMessageDialog(null, "Your word does contain " + text );
}
else{
JOptionPane.showMessageDialog(null, "There is no " + text );
error++;
if(error >= 0) imageName = "hangman1.jpg";
if(error >= 1) imageName = "hangman2.jpg";
if(error >= 2) imageName = "hangman3.jpg";
if(error >= 3) imageName = "hangman4.jpg";
if(error >= 4) imageName = "hangman5.jpg";
if(error >= 5) imageName = "hangman6.jpg";
if(error >= 7) imageName = "hangman7.jpg";
}
}
});
return button;
}
my full code:
import java.awt.*;
import java.awt.event.*;
import java.util.Arrays;
import javax.swing.*;
import java.io.*;
import java.util.ArrayList;
import java.util.Random;
import java.util.List;
public final class Hangman extends JFrame implements ActionListener{
String original = readWord();
int error;
String imageName;
JButton btnAddWord = new JButton("Add New Word");
JButton btnRestart = new JButton("Restart");
JButton btnHelp = new JButton("Help");
JButton btnExit = new JButton("Exit");
JLabel word = new JLabel(original);
static JPanel panel1 = new JPanel();
static JPanel panel2 = new JPanel();
static JPanel panel3 = new JPanel();
static JPanel panel4 = new JPanel();
public Hangman(){
Container content =getContentPane();
content.setLayout(new GridLayout(0,1));
btnAddWord.addActionListener(this);
btnRestart.addActionListener(this);
btnHelp.addActionListener(this);
btnExit.addActionListener(this);
ImageIcon icon = null;
if(imageName != null){
icon = new ImageIcon(imageName);
}
JLabel image = new JLabel();
image.setIcon(icon);
panel2.add(image);
panel3.add(word);
panel4.add(btnAddWord);
panel4.add(btnRestart);
panel4.add(btnHelp);
panel4.add(btnExit);
for(char i = 'A'; i <= 'Z'; i++){
String buttonText = new Character(i).toString();
JButton button = getButton(buttonText);
panel1.add(button);
}
}
public JButton getButton(final String text){
final JButton button = new JButton(text);
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
if(original.toUpperCase().indexOf(button.getText())!=-1){
JOptionPane.showMessageDialog(null, "Your word does contain " + text );
}
else{
JOptionPane.showMessageDialog(null, "There is no " + text );
error++;
if(error >= 0) imageName = "hangman1.jpg";
if(error >= 1) imageName = "hangman2.jpg";
if(error >= 2) imageName = "hangman3.jpg";
if(error >= 3) imageName = "hangman4.jpg";
if(error >= 4) imageName = "hangman5.jpg";
if(error >= 5) imageName = "hangman6.jpg";
if(error >= 7) imageName = "hangman7.jpg";
}
}
});
return button;
}
public String readWord(){
try{
BufferedReader reader = new BufferedReader(new FileReader("Words.txt"));
String line = reader.readLine();
List<String> words = new ArrayList<String>();
while(line != null){
String[] wordsLine = line.split(" ");
boolean addAll = words.addAll(Arrays.asList(wordsLine));
line = reader.readLine();
}
Random rand = new Random(System.currentTimeMillis());
String randomWord = words.get(rand.nextInt(words.size()));
return randomWord;
}catch (Exception e){
return null;
}
}
public void actionPerformed(ActionEvent e){
if(e.getSource() == btnAddWord){
try{
FileWriter fw = new FileWriter("Words.txt", true);
PrintWriter pw = new PrintWriter(fw, true);
String word = JOptionPane.showInputDialog("Please enter a word: ");
pw.println(word);
pw.close();
}
catch(IOException ie){
System.out.println("Error Thrown" + ie.getMessage());
}
}
if(e.getSource() == btnRestart){
}
if(e.getSource() == btnHelp){
String message = "The word to guess is represented by a row of dashes, giving the number of letters and category of the word."
+ "\nIf the guessing player suggests a letter which occurs in the word, the other player writes it in all its correct positions."
+ "\nIf the suggested letter does not occur in the word, the other player draws one element of the hangman diagram as a tally mark."
+ "\n"
+ "\nThe game is over when:"
+ "\nThe guessing player completes the word, or guesses the whole word correctly"
+ "\nThe other player completes the diagram";
JOptionPane.showMessageDialog(null,message, "Help",JOptionPane.INFORMATION_MESSAGE);
}
if(e.getSource() == btnExit){
System.exit(0);
}
}
public static void main (String [] args){
Hangman frame = new Hangman();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 600);
frame.add(panel1, BorderLayout.NORTH);
frame.add(panel2, BorderLayout.CENTER);
frame.add(panel3, BorderLayout.SOUTH);
frame.add(panel4, BorderLayout.SOUTH);
}
}
You've had a good start with your code, but first you need to get the design clear in your mind, before writing code. Let's think about it, in steps:
When the application is launched, you load all the words in the file. So that's a step that is performed only once, and its result (the words in the file) should be saved.
The previous step does not seem to be related to your GUI code, so you may want to do it in your main method, and then pass the results to your GUI class. You can even extract this functionality into a separate class, along with choosing a random word.
Once the GUI is shown, you show a label symbolizing the hidden word. The text of this label should contain as many hidden characters ('-') as the word's characters.
Whenever a correct button is pressed, all matching characters in the word should be shown.
Whenever a wrong button is pressed, an error counter is incremented and an image is shown.
When the whole word is uncovered, character buttons should be disabled.
This leads to a design where you have a separate helper class with a method for reading the words file and another for choosing a random word. Possibly something along the lines of this:
class WordsReader {
public String[] readWords(String filename) {
// ...
}
public String chooseWord(String[] words) {
// ...
}
}
Once a new word is chosen, you should update the label. This is where the HangmanWord class suggested above comes in handy. It stores both the original word and its hidden representation. This allows you to call the check method in the buttons' handler, and update the label's text with the updated hidden representation. The rest of your code should work fine, although it can still be improved.
You could get the chars of the string, and replace the guessed letters with '-' in a new string, and display that (while behind the scenes you still have the full one)
public [static] String hideString(String string, int[] guessedLetterIndices) {
char[] chars = string.toCharArray();
for(int index : guessedLetterIndices)
chars[i] = '-';//Replace this with any letter
for(int i = 0; i < chars.length; i++) {
char c = '-';
for(int index : guessedLetterIndices)
if(index == i)
c = chars[i];
chars[i] = c;
}
return new String(chars);
}
or if you currently have an array of chars that they have chosen, as opposed to indices of characters...
public [static] String hideString(String string, char[] guessedLetters) {
char[] chars = string.toCharArray();
char[] hidden = (string.replaceAll("(.|\n)", "-").toCharArray();
for(int i=0;i<chars.length;i++) {
for(char c : guessedLetters)
if(chars[i] == c) {
hidden[i] = chars[i];
break;
}
]
return new String(chars);
}
That's what I'd do. As far as why yours does not work, could you tell me the errors you're getting? Make sure you're importing StringBuilder and stuff (whatever else they use)

Categories

Resources