Ammendment: Changed WordToGuess.getWordsInTopic()WordToGuess.getWordsInTopic() to open stream using try with resources:
public class Main {
public static void main (String[] args){
Game game = new Game();
}
}
public class Main {
public static void main (String[] args){
Game game = new Game();
}
}
import javax.swing.JPanel;
import javax.swing.JOptionPane;
class Game {
private Progress progress;
private GUI gui;
Game() {
String targetWord = new WordToGuess().getWordToGuess();
progress = new Progress(targetWord);
JPanel alphabet = new Alphabet(this);
gui = new GUI(progress.getProgress(),alphabet);
gui.setVisible(true);
}
void recordGuess(char letter) {
progress.updateProgress(letter);
gui.showStatus(progress.getNumberOfWrongGuesses(), progress.getProgress());
if (progress.playerWins()) {
displayEndGameMessage("Well done, it was "+progress.getTargetWord()+", another game?");
}
if (progress.playerLooses()) {
displayEndGameMessage("Bad luck, it was "+progress.getTargetWord()+", another game?");
}
}
void displayEndGameMessage(String message){
int reply = JOptionPane.showConfirmDialog(gui, message, "end", JOptionPane.YES_NO_OPTION);
if (reply == JOptionPane.YES_OPTION) {
GUI oldGUI = gui;
new Game();
oldGUI.dispose();
} else {
System.exit(0);
}
}
}
import javax.swing.JPanel;
import javax.swing.JOptionPane;
class Game {
private Progress progress;
private GUI gui;
Game() {
String targetWord = new WordToGuess().getWordToGuess();
progress = new Progress(targetWord);
JPanel alphabet = new Alphabet(this);
gui = new GUI(progress.getProgress(),alphabet);
gui.setVisible(true);
}
void recordGuess(char letter) {
progress.updateProgress(letter);
gui.showStatus(progress.getNumberOfWrongGuesses(), progress.getProgress());
if (progress.playerWins()) {
displayEndGameMessage("Well done, it was "+progress.getTargetWord()+", another game?");
}
if (progress.playerLooses()) {
displayEndGameMessage("Bad luck, it was "+progress.getTargetWord()+", another game?");
}
}
void displayEndGameMessage(String message){
int reply = JOptionPane.showConfirmDialog(gui, message, "end", JOptionPane.YES_NO_OPTION);
if (reply == JOptionPane.YES_OPTION) {
GUI oldGUI = gui;
new Game();
oldGUI.dispose();
} else {
System.exit(0);
}
}
}
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.Random;
import java.util.function.Predicate;
import java.util.stream.Stream;
import static java.util.stream.Collectors.toList;
public class WordToGuess {
private static final int MAX_WORD_LENGTH = 20;
private static final int MIN_WORD_LENGTH = 3;
private final String word;
private final Predicate<String> wordLengthPredicate =
s -> s.length() <= MAX_WORD_LENGTH && s.length() >= MIN_WORD_LENGTH;
WordToGuess() {
List<String> candidateWords = getCandidateWords();
int randomIndex = new Random().nextInt(candidateWords.size());
word = candidateWords.get(randomIndex);
}
String getWordToGuess() {
return word;
}
private List<String> getCandidateWords() {
List<String> candidateWords = defaultWords();
try {
String topic = new TopicProvider().getTopic();
candidateWords = getWordsInTopic(topic);
}catch(NoWordsListsException e){
ErrorReporter.missingFiles();
}catch (TopicWordsMissingException e){
ErrorReporter.missingWords();
} catch (WordListDirectoryMissingException e) {
ErrorReporter.missingDirectory();
}
return candidateWords;
}
private List<String> getWordsInTopic(String topic) throws TopicWordsMissingException {
List<String> candidateWords;
try {
Path path = Paths.get(Constants.WORD_LIST_DIRECTORY +topic);
Stream<String> stream = Files.lines(path);
candidateWords = stream.map(String::toUpperCase)
.filter(wordLengthPredicate)
.collect(toList());
if (candidateWords.size() < 1) {
throw new TopicWordsMissingException("The file for that topic contained no words");
}
} catch (IOException e) {
throw new TopicWordsMissingException("The file for that topic was missing");
}
return candidateWords;
}
private static List<String> defaultWords(){
return List.of("FOXGLOVE", "MICROWAVE","ZOMBIE","PUPPY","RHUBARB","DWARF","BICYCLE",
"BUZZARD","OWL","CHAFFINCH","KIRIBATI","LIECHTENSTEIN","MOZAMBIQUE");
}
}
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.Random;
import java.util.function.Predicate;
import java.util.stream.Stream;
import static java.util.stream.Collectors.toList;
public class WordToGuess {
private static final int MAX_WORD_LENGTH = 20;
private static final int MIN_WORD_LENGTH = 3;
private final String word;
private final Predicate<String> wordLengthPredicate =
s -> s.length() <= MAX_WORD_LENGTH && s.length() >= MIN_WORD_LENGTH;
WordToGuess() {
List<String> candidateWords = getCandidateWords();
int randomIndex = new Random().nextInt(candidateWords.size());
word = candidateWords.get(randomIndex);
}
String getWordToGuess() {
return word;
}
private List<String> getCandidateWords() {
List<String> candidateWords = defaultWords();
try {
String topic = new TopicProvider().getTopic();
candidateWords = getWordsInTopic(topic);
}catch(NoWordsListsException e){
ErrorReporter.missingFiles();
}catch (TopicWordsMissingException e){
ErrorReporter.missingWords();
} catch (WordListDirectoryMissingException e) {
ErrorReporter.missingDirectory();
}
return candidateWords;
}
private List<String> getWordsInTopic(String topic) throws TopicWordsMissingException {
List<String> candidateWords;
try {
Path path = Paths.get(Constants.WORD_LIST_DIRECTORY +topic);
Stream<String> stream = Files.lines(path);
candidateWords = stream.map(String::toUpperCase)
.filter(wordLengthPredicate)
.collect(toList());
if (candidateWords.size() < 1) {
throw new TopicWordsMissingException("The file for that topic contained no words");
}
} catch (IOException e) {
throw new TopicWordsMissingException("The file for that topic was missing");
}
return candidateWords;
}
private static List<String> defaultWords(){
return List.of("FOXGLOVE", "MICROWAVE","ZOMBIE","PUPPY","RHUBARB","DWARF","BICYCLE",
"BUZZARD","OWL","CHAFFINCH","KIRIBATI","LIECHTENSTEIN","MOZAMBIQUE");
}
}
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 TopicProvider {
String getTopic() throws NoWordsListsException, WordListDirectoryMissingException {
List<String> categories = getTopics();
return getPlayerChoice(categories);
}
private List<String> getTopics() throws NoWordsListsException, WordListDirectoryMissingException {
Path path = Paths.get(Constants.WORD_LIST_DIRECTORY);
List<String> topics;
try {
Stream<Path> stream = Files.list(path);
topics = stream.filter(Files::isRegularFile)
.map(toTopic)
.collect(toList());
if (topics.size() < 1) {
throw new NoWordsListsException("Word lists missing");
}
} catch (IOException e) {
throw new WordListDirectoryMissingException("Word lists directory missing");
}
return topics;
}
private final Function<Path, String> toTopic = path -> path.getFileName().toString();
private String getPlayerChoice(List<String> Topics){
return new TopicDialogue().ShowTopicDialogue(Topics);
}
}
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 TopicProvider {
String getTopic() throws NoWordsListsException, WordListDirectoryMissingException {
List<String> categories = getTopics();
return getPlayerChoice(categories);
}
private List<String> getTopics() throws NoWordsListsException, WordListDirectoryMissingException {
Path path = Paths.get(Constants.WORD_LIST_DIRECTORY);
List<String> topics;
try {
Stream<Path> stream = Files.list(path);
topics = stream.filter(Files::isRegularFile)
.map(toTopic)
.collect(toList());
if (topics.size() < 1) {
throw new NoWordsListsException("Word lists missing");
}
} catch (IOException e) {
throw new WordListDirectoryMissingException("Word lists directory missing");
}
return topics;
}
private final Function<Path, String> toTopic = path -> path.getFileName().toString();
private String getPlayerChoice(List<String> Topics){
return new TopicDialogue().ShowTopicDialogue(Topics);
}
}
import javax.swing.JComboBox;
import javax.swing.JOptionPane;
import java.util.List;
class TopicDialogue {
private String topic;
String ShowTopicDialogue(List<String> categoryNames){
String[] categories = categoryNames.toArray(new String[0]);
topic = categories[0];
JComboBox<String> jComboBox = new JComboBox<>(categories);
jComboBox.addActionListener(e -> topic = (String) jComboBox.getSelectedItem());
JOptionPane.showMessageDialog(null, jComboBox, "Choose a topic", JOptionPane.PLAIN_MESSAGE);
return topic;
}
}
import javax.swing.JComboBox;
import javax.swing.JOptionPane;
import java.util.List;
class TopicDialogue {
private String topic;
String ShowTopicDialogue(List<String> categoryNames){
String[] categories = categoryNames.toArray(new String[0]);
topic = categories[0];
JComboBox<String> jComboBox = new JComboBox<>(categories);
jComboBox.addActionListener(e -> topic = (String) jComboBox.getSelectedItem());
JOptionPane.showMessageDialog(null, jComboBox, "Choose a topic", JOptionPane.PLAIN_MESSAGE);
return topic;
}
}
public class Progress {
private static final String placeHolder = "*";
private final char[] progress;
private int wrongGuessCount =0;
private final String targetWord;
private final int MAX_BAD_GUESSES = 11;
Progress(String targetWord){
this.targetWord=targetWord;
String progressString = targetWord.replaceAll("[A-Z]", placeHolder);
progress = progressString.toCharArray();
}
String getProgress(){
return new String(progress);
}
String getTargetWord(){
return targetWord;
}
boolean playerWins(){
return !new String(progress).contains(placeHolder);
}
boolean playerLooses(){
return (wrongGuessCount > MAX_BAD_GUESSES);
}
int getNumberOfWrongGuesses(){
return wrongGuessCount;
}
void updateProgress(char guess) {
if (isGoodGuess(guess)) {
for (int n = 0; n < targetWord.length(); n++) {
if (targetWord.charAt(n) == guess) {
progress[n] = guess;
}
}
} else {
wrongGuessCount++;
}
}
boolean isGoodGuess(char guess){
return targetWord.contains(Character.toString(guess));
}
}
public class Progress {
private static final String placeHolder = "*";
private final char[] progress;
private int wrongGuessCount =0;
private final String targetWord;
private final int MAX_BAD_GUESSES = 11;
Progress(String targetWord){
this.targetWord=targetWord;
String progressString = targetWord.replaceAll("[A-Z]", placeHolder);
progress = progressString.toCharArray();
}
String getProgress(){
return new String(progress);
}
String getTargetWord(){
return targetWord;
}
boolean playerWins(){
return !new String(progress).contains(placeHolder);
}
boolean playerLooses(){
return (wrongGuessCount > MAX_BAD_GUESSES);
}
int getNumberOfWrongGuesses(){
return wrongGuessCount;
}
void updateProgress(char guess) {
if (isGoodGuess(guess)) {
for (int n = 0; n < targetWord.length(); n++) {
if (targetWord.charAt(n) == guess) {
progress[n] = guess;
}
}
} else {
wrongGuessCount++;
}
}
boolean isGoodGuess(char guess){
return targetWord.contains(Character.toString(guess));
}
}
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.BoxLayout;
import java.awt.Dimension;
public class GUI extends JFrame {
private JLabel progressLabel;
private GibbetLabel gibbetLabel;
GUI(String prog, JPanel alphabet) {
JPanel container = new JPanel();
container.setLayout(new BoxLayout(container, BoxLayout.Y_AXIS));
add(container);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gibbetLabel = new GibbetLabel();
container.add(gibbetLabel);
progressLabel = new ProgressLabel(prog);
container.add(progressLabel);
container.add(alphabet);
setTitle("Hangman");
setSize(new Dimension(350, 450));
setLocationRelativeTo(null);
setVisible(true);
}
void showStatus(int count, String prog){
progressLabel.setText(prog);
gibbetLabel.updateGibbetImage(count);
}
}
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.BoxLayout;
import java.awt.Dimension;
public class GUI extends JFrame {
private JLabel progressLabel;
private GibbetLabel gibbetLabel;
GUI(String prog, JPanel alphabet) {
JPanel container = new JPanel();
container.setLayout(new BoxLayout(container, BoxLayout.Y_AXIS));
add(container);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gibbetLabel = new GibbetLabel();
container.add(gibbetLabel);
progressLabel = new ProgressLabel(prog);
container.add(progressLabel);
container.add(alphabet);
setTitle("Hangman");
setSize(new Dimension(350, 450));
setLocationRelativeTo(null);
setVisible(true);
}
void showStatus(int count, String prog){
progressLabel.setText(prog);
gibbetLabel.updateGibbetImage(count);
}
}
import javax.swing.JPanel;
import javax.swing.JButton;
class Alphabet extends JPanel{
Alphabet(Game game){
for(char c = 'A'; c <= 'Z'; ++c){
JButton button = new JButton(Character.toString(c));
button.addActionListener(e -> {
game.recordGuess(e.getActionCommand().charAt(0));
button.setEnabled(false);
});
add(button);
}
}
}
import javax.swing.JPanel;
import javax.swing.JButton;
class Alphabet extends JPanel{
Alphabet(Game game){
for(char c = 'A'; c <= 'Z'; ++c){
JButton button = new JButton(Character.toString(c));
button.addActionListener(e -> {
game.recordGuess(e.getActionCommand().charAt(0));
button.setEnabled(false);
});
add(button);
}
}
}
import javax.swing.JLabel;
import java.awt.Font;
import java.awt.Component;
public class ProgressLabel extends JLabel {
ProgressLabel(String prog){
setText(prog);
setFont(new Font("Monospaced", Font.PLAIN, 20));
setAlignmentX(Component.CENTER_ALIGNMENT);
}
}
import javax.swing.JLabel;
import java.awt.Font;
import java.awt.Component;
public class ProgressLabel extends JLabel {
ProgressLabel(String prog){
setText(prog);
setFont(new Font("Monospaced", Font.PLAIN, 20));
setAlignmentX(Component.CENTER_ALIGNMENT);
}
}
import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.util.ArrayList;
public class GibbetLabel extends JLabel {
private static final int IMAGE_COUNT = 13;
private ArrayList<File> gibbetImages = new ArrayList<>();
GibbetLabel() {
for (int i = 0; i < IMAGE_COUNT; i++) {
try {
gibbetImages.add(new File("images/" + i + ".png"));
} catch (Exception e) {
e.printStackTrace();
}
}
setIcon(new ImageIcon(String.valueOf(gibbetImages.get(0))));
setAlignmentX(Component.CENTER_ALIGNMENT);
}
void updateGibbetImage(int count){
setIcon(new ImageIcon(String.valueOf(gibbetImages.get(count))));
}
}
import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.util.ArrayList;
public class GibbetLabel extends JLabel {
private static final int IMAGE_COUNT = 13;
private ArrayList<File> gibbetImages = new ArrayList<>();
GibbetLabel() {
for (int i = 0; i < IMAGE_COUNT; i++) {
try {
gibbetImages.add(new File("images/" + i + ".png"));
} catch (Exception e) {
e.printStackTrace();
}
}
setIcon(new ImageIcon(String.valueOf(gibbetImages.get(0))));
setAlignmentX(Component.CENTER_ALIGNMENT);
}
void updateGibbetImage(int count){
setIcon(new ImageIcon(String.valueOf(gibbetImages.get(count))));
}
}

