Hello all,
So I have been scouring the internet trying to find an answer to my question. I usually never have to post a question because someone somewhere has asked it, but I guess there is a first for everything.
I am a VERY intro level, brand spankin new 'programmer' (can't even call me that yet). I have 0 hours of college, just high school diploma, but I read a lot. I have been learning Java programming for about 3 months now and am trying to get an idea of where I am and if I am learning at a slow pace or at an average pace. This is my first programming language, so all the concepts are new to me. I haven't done any other programming.
What I am trying to figure out is "What level am I at" and I suppose I mean that in a college kind of way. So what 'grade' in college would you expect this to come from? Would a day 1 freshman pump this code out easily or is it more sophmore year? Something like that.
These are the concepts that I feel comfortable with (at a beginner level at least):
Variables/data types/arrays all that basic stuff
Loops/logic/conditionals/switch
Classes
Methods
Arguments
The Pass-by-value concept makes sense
Inheritance
Interfaces
Abstract classes/methods
Polymorphism
Exceptions
SOME file I/O and streams. Only the basics as you can see
Some swing knowlege. My game isn't very pretty but it is decent with some graphics
Just started on the whole Generics thing and am just getting into the chapters on collections, some of which I have already used in my code and understand.
The thing with this program that took the most thought was how to make a Variable Length MultiDimensional Array for all the word lists. This is when I started to learn the collections framework. Give me another month and I will have that down solid I beleive.
Now I've got my eye on that "Threads" chapter..... IM SO EXCITED! That stuff looks so cool I cant wait to get into that chapter after collections are done.
So I would just like some feedback. It would be SO very much appreciated. I don't have any professional friends who will give me feedback or let me know what I'm doing wrong. I am sure you can easily tell from my code for my little hangman game that I don't know much at all. I used all very basic concepts to build this and there is nothing fancy. I'm sure a pro could have made this game with half the code or less lol. But to me it's the coolest thing in the entire world because I made it ;)
Ok enough rambling. Can anyone offer some tips/advice/recommendations. What level of college would I be learning this? Freshman year day one? Or have I covered a bit more than that? I know classes tend to move pretty slow sometimes and I am reading my book like 4 hours a day. Literally nothing you say could hurt my feelings so please be blunt. Don't sugar coat anything, that's not what I want. I want straight forward (harsh is better than tactful for me) so I know where I stand. I plan to continue my studying and I WISH I started this years ago. I'm 26 now. I wish I started when I was 12 lol.
Also, final note, all the code for this hangman game is completely original. I did look up some suggestions online when I was stuck on something but I never ended up using what they said, maybe sort of a modified version. But the concepts and design of my game are 100% my own, so all the concepts here are what I understand fully.
Thanks so much everyone.
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.border.EmptyBorder;
import java.util.ArrayList;
import java.util.Random;
public class Hangman extends JFrame{
private JButton a;
private JButton b;
private JButton c;
private JButton d;
private JButton e;
private JButton f;
private JButton g;
private JButton h;
private JButton i;
private JButton j;
private JButton k;
private JButton l;
private JButton m;
private JButton n;
private JButton o;
private JButton p;
private JButton q;
private JButton r;
private JButton s;
private JButton t;
private JButton u;
private JButton v;
private JButton w;
private JButton x;
private JButton y;
private JButton z;
private JButton[] buttons = new JButton[26]; //add buttons to array so I can loop through them later.
private JLabel trysRemaining;
private int setTrysHere = 6; //I used this so you can adjust the number of lives in one spot only.
private int trys = setTrysHere;
private int badGuesses = 0;
private int wins = 0;
private int losses = 0;
private JLabel winsLabel = new JLabel("Wins: " + wins);
private JLabel lossesLabel = new JLabel("Losses: " + losses);
private JLabel letters[] = new JLabel[30]; //used to display "_" for each letter. When letter is guessed, it changes to display that letter.
private String word; //current word to guess. Pulled from the word list at random (whichever word list is selected by user).
private Boolean firstGame = true;
private String[] arr; //stores the list when converted from ArrayList to a String array.
private JPanel contentPane;
private ArrayList<String> words = new ArrayList<String>(); //holds the list selected by the user. Turned into 'arr[]' later on for working on.
private ListSelector frame; //refers to the ListSelector window. I needed a 'global' like variable to reference the two windows.
private Hangman hang; //refers to this object. I am sure there was a better way to do this but this is all I could come up with lol.
private ButtonGroup difficultyGroup = new ButtonGroup();
private String lastDifficulty = "Medium";
private JRadioButtonMenuItem rbEasy; //these specific options needed to be declared up here so that I could use them inside another handler class later.
private JRadioButtonMenuItem rbMedium;
private JRadioButtonMenuItem rbHard;
private JRadioButtonMenuItem rbNoMercy;
private JLabel currentDifficulty = new JLabel("Current Difficulty: " + lastDifficulty);
private JLabel victim;
private Boolean drawings = true;
private BufferedImage hang0;
private BufferedImage hang1;
private BufferedImage hang2;
private BufferedImage hang3;
private BufferedImage hang4;
private BufferedImage hang5;
private BufferedImage hang6;
private BufferedImage hang7;
private BufferedImage hang8;
private BufferedImage hang9;
private BufferedImage hang10;
private Color green = new Color(20,110,30);
private Color yellow = new Color(155,155,0);
private Color red = new Color(200,0,0);
public Hangman(){
super("Hangman");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(300, 300, 620, 300);
//create the menu.///////////add all action listeners as abstract classes within this section//////////
JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
JMenu menuHangman = new JMenu("Hangman");
menuBar.add(menuHangman);
JMenu menuDifficulty = new JMenu("Difficulty");
menuHangman.add(menuDifficulty);
DifficultyHandler diffHandle = new DifficultyHandler();
rbEasy = new JRadioButtonMenuItem("Easy");
difficultyGroup.add(rbEasy);
menuDifficulty.add(rbEasy);
rbEasy.addActionListener(diffHandle);
rbMedium = new JRadioButtonMenuItem("Medium");
difficultyGroup.add(rbMedium);
menuDifficulty.add(rbMedium);
rbMedium.setSelected(true);
rbMedium.addActionListener(diffHandle);
rbHard = new JRadioButtonMenuItem("Hard");
difficultyGroup.add(rbHard);
menuDifficulty.add(rbHard);
rbHard.addActionListener(diffHandle);
rbNoMercy = new JRadioButtonMenuItem("No Mercy");
difficultyGroup.add(rbNoMercy);
menuDifficulty.add(rbNoMercy);
rbNoMercy.addActionListener(diffHandle);
JMenuItem menuItemChangeList = new JMenuItem("Change List");
menuHangman.add(menuItemChangeList);
menuItemChangeList.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
hang.setVisible(false);
frame.setVisible(true);
}
});
JMenuItem menuItemNewWord = new JMenuItem("New Word");
menuHangman.add(menuItemNewWord);
menuItemNewWord.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
int option = JOptionPane.showConfirmDialog(null, "This will give you a loss. Are you sure?", "Quitter!", JOptionPane.OK_CANCEL_OPTION);
if(option == JOptionPane.OK_OPTION){
resetGame();
newWord();
losses++;
lossesLabel.setText("Losses: " + losses);
}
}
});
JMenuItem menuItemResetStats = new JMenuItem("Reset Stats");
menuHangman.add(menuItemResetStats);
menuItemResetStats.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
int option = JOptionPane.showConfirmDialog(null, "Are you sure you want to reset your stats?\n" +
"(this will not reset the current word)", "Reset Stats?", JOptionPane.OK_CANCEL_OPTION);
if(option == JOptionPane.OK_OPTION){
wins = 0;
losses = 0;
winsLabel.setText("Wins: " + wins);
lossesLabel.setText("Losses: " + losses);
}
}
});
JMenuItem menuItemExit = new JMenuItem("Exit");
menuHangman.add(menuItemExit);
//end menu creation./////////////////
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null); //use absolute positioning for all frames.
//initialize each button. I add them to a button array so I can work on them easily later.
a = new JButton("a");
buttons[0] = a;
b = new JButton("b");
buttons[1] = b;
c = new JButton("c");
buttons[2] = c;
d = new JButton("d");
buttons[3] = d;
e = new JButton("e");
buttons[4] = e;
f = new JButton("f");
buttons[5] = f;
g = new JButton("g");
buttons[6] = g;
h = new JButton("h");
buttons[7] = h;
i = new JButton("i");
buttons[8] = i;
j = new JButton("j");
buttons[9] = j;
k = new JButton("k");
buttons[10] = k;
l = new JButton("l");
buttons[11] = l;
m = new JButton("m");
buttons[12] = m;
n = new JButton("n");
buttons[13] = n;
o = new JButton("o");
buttons[14] = o;
p = new JButton("p");
buttons[15] = p;
q = new JButton("q");
buttons[16] = q;
r = new JButton("r");;
buttons[17] = r;
s = new JButton("s");
buttons[18] = s;
t = new JButton("t");
buttons[19] = t;
u = new JButton("u");
buttons[20] = u;
v = new JButton("v");
buttons[21] = v;
w = new JButton("w");
buttons[22] = w;
x = new JButton("x");
buttons[23] = x;
y = new JButton("y");
buttons[24] = y;
z = new JButton("z");
buttons[25] = z;
//add buttons to screen in proper locations. Two loops for two rows.
int xLoc = 10;
for(int i=0; i<13; ++i){
buttons[i].setBounds(xLoc, 176, 45, 23);
contentPane.add(buttons[i]);
xLoc += 45;
}
xLoc = 10;
for(int i=13; i<26; ++i){
buttons[i].setBounds(xLoc, 204, 45, 23);
contentPane.add(buttons[i]);
xLoc += 45;
}
//display remaining attempts. Decrement each time you miss a letter.
trysRemaining = new JLabel("Trys Remaining: " + trys);
trysRemaining.setBounds(385, 70, 150, 20);
contentPane.add(trysRemaining);
trysRemaining.setFont(new Font("comic sans ms", Font.BOLD, 14));
trysRemaining.setForeground(green);
//display wins and losses. Resets when program ends.
winsLabel.setBounds(385, 10, 75, 20);
contentPane.add(winsLabel);
winsLabel.setFont(new Font("comic sans ms", Font.BOLD, 14));
lossesLabel.setBounds(485, 10, 75, 20);
contentPane.add(lossesLabel);
lossesLabel.setFont(new Font("comic sans ms", Font.BOLD, 14));
currentDifficulty.setBounds(385, 40, 200, 20);
contentPane.add(currentDifficulty);
currentDifficulty.setFont(new Font("comic sans ms", Font.BOLD, 14));
//initialize 30 JLabels (30 is the max length for a word in this version).
//these will later be added to the frame and each time a word is loaded, the corresponding JLabels will be '_' by default,
//and when the user guesses a correct letter, all occurrences of that letter will change from '_' to the letter.
for(int i=0; i<30; ++i){
letters[i] = new JLabel();
}
HandlerClass handler = new HandlerClass();
for(int i=0; i<26; ++i){
buttons[i].addActionListener(handler);
}
try{
hang0 = ImageIO.read(new File("src\\Pics\\hang0.gif"));
hang1 = ImageIO.read(new File("src\\Pics\\hang1.gif"));
hang2 = ImageIO.read(new File("src\\Pics\\hang2.gif"));
hang3 = ImageIO.read(new File("src\\Pics\\hang3.gif"));
hang4 = ImageIO.read(new File("src\\Pics\\hang4.gif"));
hang5 = ImageIO.read(new File("src\\Pics\\hang5.gif"));
hang6 = ImageIO.read(new File("src\\Pics\\hang6.gif"));
hang7 = ImageIO.read(new File("src\\Pics\\hang7.gif"));
hang8 = ImageIO.read(new File("src\\Pics\\hang8.gif"));
hang9 = ImageIO.read(new File("src\\Pics\\hang9.gif"));
hang10 = ImageIO.read(new File("src\\Pics\\hang10.gif"));
drawings = true;
}catch(Exception e){
JOptionPane.showMessageDialog(null, "The picture files are corrupt, so you won't see the drawings");
drawings = false;
}
//create victim label to display victim (if possible)
victim = new JLabel();
victim.setBounds(150, 10, 200, 200);
contentPane.add(victim);
drawVictim();
}
//handler class for the difficulty level option buttons.
public class DifficultyHandler implements ActionListener{
public void actionPerformed(ActionEvent e){
String action = e.getActionCommand();
Boolean fresh = true; //if you have already guessed a letter for the current word, this will be false.
for(int i=0; i<26; ++i){ //(have you guessed anything yet? you can tell by checking for disabled buttons)
if(!buttons[i].isEnabled()){
fresh = false;
}
}
int option = JOptionPane.showConfirmDialog(null, "Are you sure you want to change difficulty?\n" +
"If you have already guessed a letter for this word\n" +
"then you will get a loss. If you haven't guessed\n" +
"yet then you will not get a loss", "Change Difficulty?", JOptionPane.OK_CANCEL_OPTION);
if(option == JOptionPane.OK_OPTION){ //if they are sure, continue.
switch (action){
case "Easy":
resetGame();
newWord();
setTrysHere = 10;
trys = setTrysHere;
trysRemaining.setText("Trys Remaining: " + trys);
lastDifficulty = "Easy";
trysRemaining.setForeground(green);
break;
case "Medium":
resetGame();
newWord();
setTrysHere = 6;
trys = setTrysHere;
trysRemaining.setText("Trys Remaining: " + trys);
lastDifficulty = "Medium";
trysRemaining.setForeground(green);
break;
case "Hard":
resetGame();
newWord();
setTrysHere = 4;
trys = setTrysHere;
trysRemaining.setText("Trys Remaining: " + trys);
lastDifficulty = "Hard";
trysRemaining.setForeground(yellow);
break;
case "No Mercy":
resetGame();
newWord();
setTrysHere = 1;
trys = setTrysHere;
trysRemaining.setText("Trys Remaining: " + trys);
lastDifficulty = "No Mercy";
trysRemaining.setForeground(red);
break;
}
if(!fresh){ //if they already guessed something, give them a loss.
losses++;
lossesLabel.setText("Losses: " + losses);
}
}else{ //if they hit cancel then you need to set the selected option button back to where it was before the click. This is why i needed the option buttons to be class level variables instead of being declared inside the constructor like the rest of the menu was.
switch (lastDifficulty){
case "Easy":
rbEasy.setSelected(true);
break;
case "Medium":
rbMedium.setSelected(true);
break;
case "Hard":
rbHard.setSelected(true);
break;
case "No Mercy":
rbNoMercy.setSelected(true);
break;
}
}
}
}
//the setFrame and setHang are how I access the windows for the ListSelector and Hangman instances. Is there a better way to do this or is this ok?
public void setFrame(ListSelector e){
frame = e;
}
public void setHang(Hangman e){
hang = e;
}
//used to set the current word list to whatever the user selected in the ListSelector's comboBox.
public void setList(ArrayList<String> list){
words = list;
}
//does a lot of stuff to set the next word to be guessed.
public String newWord(){
//reset the labels after the game is over so you can reset them for the next word.
if(!firstGame){
for(int i=0; i<word.length(); ++i){
letters[i].setText("");
}
}
//set the current list to whatever the user has selected in the ListSelector.
setList(frame.getWordsList());
//choose a random number then use the corresponding word in the current word list.
arr = words.toArray(new String[0]);
Random rand = new Random();
int n = rand.nextInt(arr.length);
word = arr[n].toLowerCase();
//create a label array with a length of word.length() and show a '_' for each letter until guessed.
//xPos is used to line them up 10 pixels away from eachother.
Font labelFont = new Font("courier", Font.BOLD, 20);
int xPos = 300;
for(int i=0; i<word.length(); ++i){
if(word.charAt(i)!=' '){
letters[i].setFont(labelFont); //must use monospaced font otherwise wide letters like 'm' and 'w' will crowd the other letters.
letters[i].setText("_");
}else{
letters[i].setFont(labelFont);
letters[i].setText(" "); //if there is a space, then that slot is set to " ". Sort of gives it away for the states but it's either that or I combine the words like 'newyork' which looks stupid.
}
letters[i].setBounds(xPos, 131, 55, 30);
contentPane.add(letters[i]);
xPos += 15;
}
firstGame = false;;
return word;
}
public void drawVictim(){
//if(drawings) is there so that if any of the image files failed to load then the game will just continue without the drawing of the victim.
//this method checks diffictulty and draws the images based on difficulty && number of bad guesses. They were set up so the drawing was even with number of guesses.
if(drawings){
switch (lastDifficulty){
case "Easy":
switch (badGuesses){
case 0:
victim.setIcon(new ImageIcon(hang0));
break;
case 1:
victim.setIcon(new ImageIcon(hang1));
break;
case 2:
victim.setIcon(new ImageIcon(hang2));
break;
case 3:
victim.setIcon(new ImageIcon(hang3));
break;
case 4:
victim.setIcon(new ImageIcon(hang4));
break;
case 5:
victim.setIcon(new ImageIcon(hang5));
break;
case 6:
victim.setIcon(new ImageIcon(hang6));
trysRemaining.setForeground(yellow);
break;
case 7:
victim.setIcon(new ImageIcon(hang7));
break;
case 8:
victim.setIcon(new ImageIcon(hang8));
trysRemaining.setForeground(Color.RED);
break;
case 9:
victim.setIcon(new ImageIcon(hang9));
break;
case 10:
victim.setIcon(new ImageIcon(hang10));
break;
}
break;
case "Medium":
switch (badGuesses){
case 0:
victim.setIcon(new ImageIcon(hang0));
break;
case 1:
victim.setIcon(new ImageIcon(hang1));
break;
case 2:
victim.setIcon(new ImageIcon(hang2));
trysRemaining.setForeground(yellow);
break;
case 3:
victim.setIcon(new ImageIcon(hang4));
break;
case 4:
victim.setIcon(new ImageIcon(hang6));
trysRemaining.setForeground(red);
break;
case 5:
victim.setIcon(new ImageIcon(hang8));
break;
case 6:
victim.setIcon(new ImageIcon(hang10));
break;
}
break;
case "Hard":
switch (badGuesses){
case 0:
victim.setIcon(new ImageIcon(hang0));
break;
case 1:
victim.setIcon(new ImageIcon(hang1));
break;
case 2:
victim.setIcon(new ImageIcon(hang2));
trysRemaining.setForeground(red);
break;
case 3:
victim.setIcon(new ImageIcon(hang6));
break;
case 4:
victim.setIcon(new ImageIcon(hang10));
break;
}
break;
case "No Mercy":
switch (badGuesses){
case 0:
victim.setIcon(new ImageIcon(hang0));
break;
case 1:
victim.setIcon(new ImageIcon(hang10));
break;
}
break;
}
}
}
//one handler class for all the letter buttons.
public class HandlerClass implements ActionListener{
public void actionPerformed(ActionEvent e){
Character guess = e.getActionCommand().charAt(0); //set guess to the character of the button pressed.
Boolean done = true; //used later to see if there is a '_' left so I know if word is still not guessed completely.
JButton source = (JButton)e.getSource();
source.setEnabled(false); //used to disable the button after pressing it.
//check to see if the word even contains the string, so if it doesn't you don't waste time looping and searching.
//this if statement isn't needed, but I figured it would save some (surely insignificant) loop time. Do you think so?
if(word.contains(guess.toString())){
for(int i=0; i<word.length(); ++i){ //if it does, find each location and change it to the letter guessed.
if(word.charAt(i) == guess){
letters[i].setText(guess.toString());
}
}
}else{
--trys;
++badGuesses;
trysRemaining.setText("Trys Remaining: " + trys);
drawVictim();
if(trys==0){
JOptionPane.showMessageDialog(null, "YOU'RE OUT OF CHANCES! \n" +
"The word was \"" + word + "\". \n" +
"Try to get the next one right!");
++losses;
lossesLabel.setText("Losses: " + losses);
resetGame();
newWord();
}
}
//if any '_' are left then you haven't guessed all the letters yet.
for(int i=0; i<word.length(); ++i){
if(letters[i].getText().equals("_")){
done = false;
}
}
//if there are no '_' left then the word is guessed. Congratulate user, update stats and reset game.
if(done==true){
JOptionPane.showMessageDialog(null, "Congratulations! You guessed the word!\n" +
"Keep it going!");
++wins;
winsLabel.setText("Wins: " + wins);
resetGame();
newWord();
}
done = true;
}
}
//when game is won or lost, this is called to reset everything for next game.
public void resetGame(){
for(int i=0; i<26; ++i){
buttons[i].setEnabled(true);
}
trys = setTrysHere;
trysRemaining.setText("Trys Remaining: " + trys);
badGuesses = 0;
victim.setIcon(new ImageIcon(hang0));
//reset the color of the trysRemaining label accordingly.
switch (lastDifficulty){
case "Easy":
trysRemaining.setForeground(green);
break;
case "Medium":
trysRemaining.setForeground(green);
break;
case "Hard":
trysRemaining.setForeground(yellow);
break;
case "No Mercy":
trysRemaining.setForeground(red);
break;
}
}
}
import java.awt.EventQueue;
import java.awt.Frame;
import java.io.File;
import java.util.ArrayList;
import java.util.Scanner;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JMenuBar;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.ButtonGroup;
public class ListSelector extends JFrame {
private JPanel contentPane;
private ArrayList<ArrayList<String>> words = new ArrayList<ArrayList<String>>(); //an ArrayList of ArrayLists (multi-dimensional ArrayList). This was the hardest part of this entire program for me. Took me a while to figure it out. This way you can add text files to the game for more words lists. This allows a variable amount of lists with a variable amount of words.
private ArrayList<String> names = new ArrayList<String>(); //holds the names of each text file in the Words List directory (without the .txt). Used to populate the multi-dimensional ArrayList.
private JComboBox<String> comboBox;
private ArrayList<String> wordsList = new ArrayList<String>(); //this stores the list that is SELECTED from the comboBox to send to the game.
private Boolean badWord = false; //used to check if a word contains anything other than a letter.
private Boolean firstRun = true;
private int lastSelected = 0; //if you click "change list" and then click "cancel" then this will be used to set the comboBox selection back to where it was. If you DO change the list then this is set to the new list for next time.
public static ListSelector frame; //i needed these to be global but can't in java so I declared them here in both classes and defined set/get methods in both classes to set the references so they act like global variables.
public static Hangman hang; //same as above.
private final ButtonGroup difficultyGroup = new ButtonGroup();
public static void main(String[] args) {
frame = new ListSelector();
frame.setVisible(true);
}
public ListSelector() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(400, 400, 450, 330);
setResizable(false);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
comboBox = new JComboBox<String>();
comboBox.setBounds(30, 89, 380, 22);
contentPane.add(comboBox);
JLabel lblNewLabel = new JLabel("Select the category you would like to play:");
lblNewLabel.setBounds(30, 51, 239, 27);
contentPane.add(lblNewLabel);
JButton btnLetsPlay = new JButton("Lets Play!");
btnLetsPlay.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
if(firstRun){
frame.setVisible(false);
wordsList = new ArrayList<String>(words.get(comboBox.getSelectedIndex())); //get the selected list from the comboBox.
hang = new Hangman(); //calls constructor only once. After this it is referenced as the only instance of Hangman.
hang.setLocation(400, 400);
hang.setResizable(false);
firstRun = false;
hang.setFrame(frame);
hang.setHang(hang);
hang.newWord();
hang.setVisible(true);
lastSelected = comboBox.getSelectedIndex(); //sets lastSelected so that if you hit cancel later the comboBox will revert back to where it was before.
}else{
frame.setVisible(false);
hang.resetGame();
wordsList = new ArrayList<String>(words.get(comboBox.getSelectedIndex()));
hang.newWord();
hang.setVisible(true);
lastSelected = comboBox.getSelectedIndex();
}
}
});
btnLetsPlay.setBounds(319, 239, 91, 23);
contentPane.add(btnLetsPlay);
JButton btnCancel = new JButton("Cancel");
btnCancel.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(firstRun){
System.exit(0); //on first run, if you hit cancel it just closes the program.
}else{
frame.setVisible(false);
hang.setVisible(true);
comboBox.setSelectedIndex(lastSelected); //set the comboBox selection back to where it was before you changed it.
}
}
});
btnCancel.setBounds(208, 239, 91, 23);
contentPane.add(btnCancel);
FolderList();
}
//Hangman and ListSelector both have the same variables to refer to themselves and each other. So they act as global variables (is this bad practice or is it ok? It's the only thing I could think of.)
public Hangman getHang(){ //this is how I get the references.
return hang;
}
public ArrayList<String> getWordsList(){
return wordsList;
}
public void FolderList(){
//open the Word Lists file and get the name of every file in there (without the .txt). ONLY gets .txt files, all others are ignored.
//if the .txt file doesn't contain any eligible words (less than 21 characters, no special characters, can contain spaces) then that file is ignored.
try{
File folder = new File("src\\Word Lists");
File[] listOfFiles = folder.listFiles();
//this entire for loop loops through each .txt file and as long as the file contains one eligible word then it is added to the list.
for (int i = 0; i < listOfFiles.length; i++) {
if (listOfFiles[i].isFile()) {
int j = listOfFiles[i].toString().lastIndexOf("\\");
if(listOfFiles[i].toString().endsWith("txt")){
Scanner sc = new Scanner(new File(listOfFiles[i].toString()));
Boolean okWord = false; //very important line. initially set to false, but if the while loop finds at least one eligible word then it is set to true so that the list can be added to the names ArrayList.
while(sc.hasNext()){ //this is important because the program will fail if it encounters a situation where it doesn't have any words to work with. Run-time error. Wouldn't be found at compile time.
String currentWord = sc.nextLine();
if(currentWord.length()<=21 && currentWord.length()>1){
for(int k=0; k<currentWord.length(); ++k){
if(Character.isLetter(currentWord.charAt(k)) || Character.isSpaceChar(currentWord.charAt(k))){
okWord = true;
}else{
okWord = false;
break; //if the current character of the current word is bad, then break the loop and move to the next word right away so that okWord isn't set to true when the next character is a letter or space.
}
}
}
}
sc.close();
if(okWord){
names.add(listOfFiles[i].toString().substring(j+1, listOfFiles[i].toString().length()-4));
}
}
}
}
//if there were no files with at least 1 eligible word then exit program, telling user to add some word lists.
if(names.toArray().length==0){
JOptionPane.showMessageDialog(null, "No word lists with eligible words were found!\n" +
"You can add word list .txt files to the \"src\\WordLists\" file.\n" +
"The format is one word per line, no special characters (spaces ok)\n" +
"and each word must be 20 characters or less.");
System.exit(0);
}
//add all the names (without .txt) to the comboBox for selection.
for(int i=0; i < names.toArray().length; ++i){
comboBox.addItem(names.toArray()[i].toString());
}
}catch(Exception e){
JOptionPane.showMessageDialog(null, "There seems to be an issue with the Word Lists file.\n" +
"Word lists must be in the \"src\\Word Lists\" folder.\n" +
"Program will now close.");
System.exit(0);
}
//opens each .txt file one at a time, adding an ArrayList to the ArrayList for each one.
//adds all the words to the corresponding ArrayList within the main ArrayList.
//so 'words[0][0]' is the first word of the first list and so on.
//only adds words that have letters and spaces only, no numbers or other signs.
try{
for(int i=0; i<names.toArray().length; ++i){
Scanner sc = new Scanner(new File("src\\Word Lists\\" + names.toArray()[i].toString() + ".txt"));
words.add(new ArrayList<String>());
while(sc.hasNext()){
String currentWord = sc.nextLine();
if(currentWord.length()<=21 && currentWord.length()>1){
for(int j=0; j<currentWord.length(); ++j){
if(!Character.isLetter(currentWord.charAt(j)) && !Character.isSpaceChar(currentWord.charAt(j))){
badWord = true;
}
}
if(!badWord){
words.get(i).add(currentWord);
}
}
badWord = false;
}
sc.close();
}
}catch(Exception e){
JOptionPane.showMessageDialog(null, "There seems to be an issue with the Animals.txt");
e.printStackTrace();
System.exit(0);
}
}
}