This code gets a random word from a word list for a category chosen by the player. The categories are the names of text file containing a list of words. "Words" can contain spaces and hyphens (e.g. "Charles Darwin" counts as a word). Eventually to be incorporated into a Hangman game. The current post is a revision in response to comments / suggested improvements from Martin Frank and RoToRa. The previous post is here. I'd be grateful for any additional comments. Specifically:
- Was subclassing JOptionPane a good way to go (CategoryDialogue.java)?
- Exception handling
- What's the best way of checking that the file of words is a text file? At the moment it crashes if I feed it a binary file.
Overall: style? clarity? You can run it at replit.
Main.java
import java.util.List;
import java.util.Random;
public class Main {
public static void main (String[] args){
List<String> candidateWords;
try {
String category = new CategoryProvider().getCategory();
candidateWords = new WordList().getWords(category);
} catch (MissingCategoriesException e){
candidateWords = new WordList().loadDefaultWords();
}
int randomIndex = new Random().nextInt(candidateWords.size());
String targetWord = candidateWords.get(randomIndex);
System.out.println(targetWord);
}
}
CategoryProvider.java
import javax.swing.JOptionPane;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Stream;
import static java.util.stream.Collectors.toList;
class CategoryProvider {
private Function<Path, String> toCategory = path -> path.getFileName().toString();
String getCategory() throws MissingCategoriesException {
List<String> categories;
String category;
Path path = Paths.get(Constants.WORD_LIST_DIRECTORY);
try {
Stream<Path> stream = Files.list(path);
categories = stream.filter(Files::isRegularFile)
.map(toCategory)
.collect(toList());
if (categories.size()>0) {
JOptionPane chooser = new CategoryDialogue(categories);
category = (String) chooser.getInputValue();
}else{
ErrorReporter.missingFiles();
throw new MissingCategoriesException ("No word lists in directory",null);
}
} catch (IOException e) {
ErrorReporter.missingDirectory();
throw new MissingCategoriesException ("Word lists directory missing",e);
}
return category;
}
}
CategoryDialogue.java
import javax.swing.JComboBox;
import javax.swing.JOptionPane;
import java.util.List;
class CategoryDialogue extends JOptionPane{
private String category;
CategoryDialogue(List<String> categoryNames){
String[] categories = categoryNames.toArray(new String[0]);
category = categories[0];
JComboBox<String> jComboBox = new JComboBox<>(categories);
jComboBox.addActionListener(e -> category = (String) jComboBox.getSelectedItem());
JOptionPane.showMessageDialog(null, jComboBox, "Word list", JOptionPane.QUESTION_MESSAGE);
}
public String getInputValue(){
return category;
}
}
WordList.java
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Stream;
import static java.util.stream.Collectors.toList;
public class WordList {
private static final int MAX_WORD_LENGTH = 20;
private static final int MIN_WORD_LENGTH = 3;
private Predicate<String> wordLengthPredicate =
s -> s.length() <= MAX_WORD_LENGTH && s.length() >= MIN_WORD_LENGTH;
List<String> getWords(String category){
List<String> words;
try {
var path = Paths.get(Constants.WORD_LIST_DIRECTORY +category);
Stream<String> stream = Files.lines(path);
words = stream.map(String::toUpperCase)
.filter(wordLengthPredicate)
.collect(toList());
if (words.size()<1){
ErrorReporter.missingWords();
words=loadDefaultWords();
}
} catch (IOException e) {
ErrorReporter.missingFile();
words=loadDefaultWords();
}
return words;
}
List<String> loadDefaultWords(){
return List.of("FOXGLOVE", "MICROWAVE","ZOMBIE","PUPPY","RHUBARB","DWARF","BICYCLE",
"BUZZARD","OWL","CHAFFINCH","KIRIBATI","LIECHTENSTEIN","MOZAMBIQUE");
}
}
Constants.java
public class Constants {
static final String WORD_LIST_DIRECTORY = "wordLists/";
}
MissingCategoriesException.java
import java.io.IOException;
class MissingCategoriesException extends Exception{
MissingCategoriesException(String errorMessage, IOException e) {
super(errorMessage);
}
}
ErrorReporter.java
import javax.swing.JOptionPane;
public class ErrorReporter {
static void missingFile(){
JOptionPane.showMessageDialog(null, "Word list file missing, using default words instead");
}
static void missingFiles(){
JOptionPane.showMessageDialog(null, "No word list files in directory, using default words instead");
}
static void missingWords(){
JOptionPane.showMessageDialog(null, "No valid words in list, using default words instead");
}
static void missingDirectory(){
JOptionPane.showMessageDialog(null, "Word list directory missing, using default words instead");
}
static void notTextFile(){
JOptionPane.showMessageDialog(null, "Chosen word list file not a text file, using default words instead");
}
}
Sample word list "scientists"
Charles Darwin
Max Planck
Albert Einstein
Michael Faraday
Richard Feynmann
Linnaeus
Lavoisier
Aristotle
Marie Curie
Isaac Newton