0% found this document useful (0 votes)
56 views13 pages

Message

This document describes a Wheel of Fortune game GUI created in Java. It includes classes for loading wheel images, tracking game state like player names and scores, and handling events like button clicks. The GUI allows input of player counts, names, and a puzzle phrase to start a new game.

Uploaded by

Benjamin
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
56 views13 pages

Message

This document describes a Wheel of Fortune game GUI created in Java. It includes classes for loading wheel images, tracking game state like player names and scores, and handling events like button clicks. The GUI allows input of player counts, names, and a puzzle phrase to start a new game.

Uploaded by

Benjamin
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd

/**

* EECS 285 Project 3 - Wheel of Fortune main GUI.


*
* See https://eecs285.github.io/p3-wheel/ for the specification.
*
* Project UID 7a0233619c14f47d99d949048c3b9c3319411051
*
* @author Andrew M. Morgan
* @author Amir Kamil
*/

package eecs285.proj3.benxzh; // replace with your uniqname

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import javax.swing.SwingConstants;
import java.io.File;
import java.io.FileFilter;
import java.lang.reflect.Array;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.HashMap;
import java.util.Locale;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JTextField;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.BorderFactory;
import javax.swing.border.TitledBorder;

public class WheelOfFortuneFrame extends JFrame {


/** Uniqname used for package and file paths. */
public static final String UNIQNAME = "benxzh";
// Replace the string above with your uniqname.

/** Number of wheel spaces in the game. */


public static final int NUM_WHEEL_SPACES = 24;

/** Path to images folder. */


public static final String IMAGES_PATH =
"eecs285/proj3/" + UNIQNAME + "/images";

/** File extension for images. */


public static final String IMAGE_EXTENSION = "jpg";

// Number of players
private int players;
// Names of players
private ArrayList<String> playerNames = new ArrayList<String>();
// Scores of players
private ArrayList<Integer> playerScore = new ArrayList<Integer>();
//amount of money for each player

// Solution phrase
private String phrase;
// Characters that have been guessed
private HashSet<String> charactersGuessed = new HashSet<String>();
// Characters that haven't been guessed from the phrase
private HashSet<String> charactersRemaining = new HashSet<String>();

// Indice of the player whose turn it currently is


private int playerTurn = 0;
// bools to turn buttons on and off
private boolean vowelEnable = false;
private boolean consEnable = false;
// num of vowels, consonants guessed
private int vowelsGuessed = 0;
private int consGuessed = 0;
// array of wheelspace objects
private WheelSpace[] wheelSpaces;
// random generator seed
private Random generator;
// current image for the wheel
private ImageIcon wheelImage;
// index of current spin
private int spin = 0;
// price of a vowel
private static final int VOWELPRICE = 250;

/**
* Loades wheel-space images from the images/ directory.
*
* Looks for files that follow the naming pattern
* <spaceNumber>_<value>.jpg. Ignores all other files in the
* directory. Assumes that there are exactly NUM_WHEEL_SPACES
* images, numbered from 1 to NUM_WHEEL_SPACES.
*
* @return array of WheelSpace objects representing the images
*/
static WheelSpace[] loadImages() {
File[] fileList;
File myDir = null;

// Allocate array for number of spaces, which is set to a constant


WheelSpace[] wheelSpaces = new WheelSpace[NUM_WHEEL_SPACES];

// Get a File object for the directory containing the images


try {
myDir = new File(WheelOfFortuneFrame.class.getClassLoader()
.getResource(IMAGES_PATH).toURI());
} catch (URISyntaxException uriExcep) {
System.out.println("Caught a URI syntax exception");
System.exit(4); // Just bail for simplicity in this project
}
// Loop from 1 to the number of spaces expected, so we can look
// for files named <spaceNumber>_<value>.jpg. Note: Space numbers
// in image filenames are 1-based, NOT 0-based.
for (int i = 1; i <= NUM_WHEEL_SPACES; i++) {
// Get a listing of files named appropriately for an image for
// wheel space #i. There should only be one, and this will be
// checked below.
fileList = myDir.listFiles(new WheelSpaceImageFilter(i));

if (fileList.length == 1) {
// Index starts at 0, space numbers start at 1: hence the - 1
wheelSpaces[i - 1] =
new WheelSpace(WheelSpaceImageFilter.getSpaceValue(fileList[0]),
new ImageIcon(fileList[0].toString()));
} else {
System.out.println("ERROR: Invalid number of images for space: " + i);
System.out.println(" Expected 1, but found " + fileList.length);
}
}

return wheelSpaces;
}

//need javadoc comments


private static class WheelSpace {
private int dollar;
private ImageIcon img;

WheelSpace(int dollar, ImageIcon img) {


this.dollar = dollar;
this.img = img;
}
}

// Helper nested class to filter images used for wheel spaces, based
// on specifically expected filename format.
private static class WheelSpaceImageFilter implements FileFilter {
/** Prefix of the requested filename. */
private String prefix; // The prefix of the filename we're looking
// for - what comes before the first underscore

/**
* Constructs a filter with the given prefix.
*
* @param inPref integer corresponding to the prefix
*/
WheelSpaceImageFilter(int inPref) {
// Sets the prefix member to string version of space number
prefix = new Integer(inPref).toString();
}

/**
* Tests whether the file provided should be accepted by our file
* filter. In the FileFilter interface.
*/
@Override
public boolean accept(File imageFile) {
boolean isAccepted = false;
// Accepted if matched "<prefix>_<...>.jpg" where
// IMAGE_EXTENSION is assumed to be "jpg" for this example
if (imageFile.getName().startsWith(prefix + "_") &&
imageFile.getName().endsWith("." + IMAGE_EXTENSION)) {
isAccepted = true;
}

return isAccepted;
}

/**
* Parses a wheel space image's filename to determine the dollar
* value associated with it.
*
* @param imageFile the wheel space image
* @return the dollar value associated with the image
*/
public static int getSpaceValue(File imageFile) {
String name = imageFile.getName();
int startIndex = 0;
int endIndex = 0;
for (int i = 0; i < name.length(); i++) {
if (name.charAt(i) == '_') {
startIndex = i + 1;
} else if (name.charAt(i) == '.') {
endIndex = i;
break;
}
}
String value = name.substring(startIndex, endIndex);

if (value.equals("loseATurn")) {
return -1;
} else if (value.equals("bankrupt")) {
return 0;
} else {
return Integer.parseInt(value);
}
}
}
/**
* Adds a listener for the countButton that progresses to name input
*
* @param countButton the button on the count panel
* @param countField the text field on the count panel
* @return doesn't return anything
*/
private JButton addCountListener(JButton countButton, JTextField countField) {
countButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String count = countField.getText();
//if input is not a number of is less than 1, display error
if (!isNumeric(count) || Integer.parseInt(count) < 1) {
JOptionPane.showMessageDialog(countButton,
"Input must be a positive integer",
"Input Error",
JOptionPane.ERROR_MESSAGE);
} else {
//otherwise, proceed to take in names
setVisible(false);
//parse input string into a usable int
players = Integer.parseInt(count);
for (int i = 0; i < players; i++) {
Object[] possibilities = {"OK"};
//query player names and initialize scores
String s = (String)JOptionPane.showInputDialog(null, "Enter name of
player #" + i,
"Player Name Input", JOptionPane.INFORMATION_MESSAGE, null,
null,"");
playerNames.add(i, s);
playerScore.add(i, 0);
//reload
pack();
revalidate();
repaint();
}
//create panel to get puzzle input
JPanel getInput = new JPanel();
setTitle("Puzzle Input");
getInput.setLayout(new BoxLayout(getInput, BoxLayout.Y_AXIS));
getContentPane().setSize(1500, 150);
JLabel inputLabel = new JLabel("Ask a non-player to enter a puzzle");
inputLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
getInput.add(inputLabel);
JTextField inputField = new JTextField(35);
inputField.setAlignmentX(Component.CENTER_ALIGNMENT);
getInput.add(inputField);
JButton inputButton = new JButton("OK");
inputButton.setAlignmentX(Component.CENTER_ALIGNMENT);
//take input when ok button is clicked
inputButton.addActionListener(new ActionListener() {
@Override
//parse input
public void actionPerformed(ActionEvent e) {
phrase = inputField.getText().toUpperCase();
for (int i = 0; i < phrase.length(); i++) {
charactersRemaining.add(phrase.substring(i, i + 1));
}
//create main game window
getContentPane().removeAll();
setPreferredSize(new Dimension(600, 400));
setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
add(getScorePanel());
add(getWheelPanel(true));
add(getLetterPanel());
add(getPhrasePanel());
pack();
revalidate();
repaint();
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
setVisible(true);
}
});
//adding input panel
getInput.add(inputButton);
getContentPane().removeAll();
getContentPane().add(getInput);
pack();
revalidate();
repaint();
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
setVisible(true);
return;
}
}
});

return countButton;
}

/**
* Create and start a game of Wheel of Fortune.
*
* @param generator the random-number generator to use
*/
public WheelOfFortuneFrame(Random generator) {
//initializing size and close op
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
setSize(1500, 150);

//create panel to get number of players


JPanel getPlayerCount = new JPanel();
setTitle("Number of Players Input");
getPlayerCount.setLayout(new BoxLayout(getPlayerCount, BoxLayout.Y_AXIS));
getContentPane().setSize(1500, 150);
JLabel countLabel = new JLabel("Enter Number of Players (must be at least 1)",
0);
countLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
getPlayerCount.add(countLabel);
JTextField countField = new JTextField(35);
countField.setAlignmentX(Component.CENTER_ALIGNMENT);
getPlayerCount.add(countField);
JButton countButton = new JButton("OK");
countButton.setAlignmentX(Component.CENTER_ALIGNMENT);
getPlayerCount.add(countButton);

//action listener to check if input is valid


countButton = addCountListener(countButton, countField);

//adding count panel


getContentPane().removeAll();
getContentPane().add(getPlayerCount);
pack();
revalidate();
repaint();

//random seed
this.generator = generator;
//loads images and converts to wheelSpace objects
wheelSpaces = loadImages();
//initalize wheelImage to LOSE A TURN
wheelImage = wheelSpaces[0].img;
}

/**
* returns JPanel of scoreboard with player money
* marks player box as red if they are supposed to buy vowel, spin wheel, or
solve puzzle
*
* @return JPanel that represents scoreboard (players and how much money that
have)
*/
private JPanel getScorePanel() {
JPanel scorePanel = new JPanel(new GridLayout(1, players));

//creates panel for each player


for (int i = 0; i < players; i++) {
JPanel playerPanel = new JPanel(new BorderLayout());
playerPanel.add(new JLabel(Integer.toString(playerScore.get(i)),
SwingConstants.CENTER),
BorderLayout.CENTER);
TitledBorder playerTitle =
BorderFactory.createTitledBorder(playerNames.get(i));

//player whose turn it is has red border


if (i == playerTurn) {
playerTitle.setBorder(BorderFactory.createLineBorder(Color.RED));
}
playerTitle.setTitleJustification(TitledBorder.LEFT);
playerPanel.setBorder(playerTitle);
scorePanel.add(playerPanel);
}

return scorePanel;
}

/**
* sets private member variable wheelImage to img of new wheel spin
*
* @param img image of new wheel spin
*/
public void updateWheelImage(ImageIcon img) {
wheelImage = img;
}

/**
* Adds action listener for when the buy vowel button is pressed.
* PLayer loses $250 (or vowel price) and can guess a vowel
* If guess is correct, phrase will reveal those vowels
* Otherwise, no letter is revealed
*
* @param buyVowel JButton to which we will add the action listener to
* @return same button but with added action listener
*/
private JButton addBuyVowelListener(JButton buyVowel) {
buyVowel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//take away $250 (or vowel price) from user
playerScore.set(playerTurn, playerScore.get(playerTurn) - VOWELPRICE);
//enable vowel buttons to be able to be pressed
vowelEnable = true;
vowelsGuessed++;
getContentPane().removeAll();
getContentPane().add(getScorePanel());
getContentPane().add(getWheelPanel(false));
getContentPane().add(getLetterPanel());
getContentPane().add(getPhrasePanel());
pack();
revalidate();
repaint();
}
});

return buyVowel;
}

/**
* Adds action listener for when the spin wheel button is pressed.
* Spins wheel and wheel image is updated to show spin
* Grants user a guess or deducts money or skips user according to the spin
*
* @param spinWheel JButton to which we will add the action listener to
* @return same button but with added action listener
*/
private JButton addSpinWheelListener(JButton spinWheel) {
spinWheel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//spins wheel
spin = generator.nextInt(NUM_WHEEL_SPACES);
updateWheelImage(wheelSpaces[spin].img);

//enable is used to decide whether the buttons in wheelPanel should be


enabled
boolean enable;

if (wheelSpaces[spin].dollar == 0) {
//if 0 (bankrupt), user loses all money and is skipped
playerScore.set(playerTurn, 0);
playerTurn = (playerTurn + 1) % players;
enable = true;
consEnable = false;
} else if (wheelSpaces[spin].dollar == -1) {
//if -1 (bankrupt), user is skipped
playerTurn = (playerTurn + 1) % players;
enable = true;
consEnable = false;
} else {
//otherwise, user can guess (will guess later on)
enable = false;
consEnable = true;
consGuessed++;
}
getContentPane().removeAll();
getContentPane().add(getScorePanel());
getContentPane().add(getWheelPanel(enable));
getContentPane().add(getLetterPanel());
getContentPane().add(getPhrasePanel());
pack();
revalidate();
repaint();
}
});
return spinWheel;
}

/**
* Adds action listener for when the solve puzzle button is pressed.
* Prompts user to guess the phrase and responds according
* User either wins money or loses turn and game continues
*
* @param solvePuzzle JButton to which we will add the action listener to
* @return same button but with added action listener
*/
private JButton addSolvePuzzleListener(JButton solvePuzzle) {
solvePuzzle.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String s = (String)JOptionPane.showInputDialog(null, "Enter complete puzzle
exactly " +
"as displayed","Solve Puzzle", JOptionPane.PLAIN_MESSAGE, null,
null,"");
s = s.toUpperCase();
if (s.equals(phrase)) {
//phrase is guessed correctly
JOptionPane.showMessageDialog(null, playerNames.get(playerTurn) + " wins
$" +
playerScore.get(playerTurn), "Game Over", JOptionPane.PLAIN_MESSAGE);
dispose();
} else {
//phrase is guessed incorrectly
JOptionPane.showMessageDialog(null, "Guess by " +
playerNames.get(playerTurn)
+ " incorrect!","Wrong Answer", JOptionPane.ERROR_MESSAGE);
playerTurn = (playerTurn + 1) % players;
getContentPane().removeAll();
getContentPane().add(getScorePanel());
getContentPane().add(getWheelPanel(true));
getContentPane().add(getLetterPanel());
getContentPane().add(getPhrasePanel());
pack();
revalidate();
repaint();
}
}
});

return solvePuzzle;
}

/**
* sets up the panel with buy vowel, spin wheel, solve puzzle buttons and wheel
image
* Buy vowel button allows user to buy a vowel to guess
* Spin wheel allows user to spin wheel and guess consonant and gain points (when
possible)
* also updates the wheel image to the spin
* Solve puzzle allows user to guess the phrase
*
* @param enable determines whether the buy vowel, spin wheel, and solve puzzle
buttons should
* be enabled
* @return panel with buy vowel, spin wheel, solve puzzle buttons and wheel image
*/
private JPanel getWheelPanel(boolean enable) {
JPanel wheelPanel = new JPanel(new FlowLayout());
JPanel wheelButtons = new JPanel(new GridLayout(3,1));
JButton buyVowel = new JButton("Buy a Vowel");
JButton spinWheel = new JButton("Spin the Wheel");
JButton solvePuzzle = new JButton("Solve the Puzzle");

//enabled only when specified and letters of each respective category have not
been all guessed
buyVowel.setEnabled(enable && vowelsGuessed != 5);
spinWheel.setEnabled(enable && consGuessed != 21);
solvePuzzle.setEnabled(enable);

buyVowel = addBuyVowelListener(buyVowel);

//deactivate buy vowel option if all vowels have been guessed or not enough
money to purchase
// vowels
if (playerScore.get(playerTurn) < VOWELPRICE || vowelsGuessed == 5) {
buyVowel.setEnabled(false);
}

spinWheel = addSpinWheelListener(spinWheel);

//deactive spin wheel option if all consonants have been guessed


if (consGuessed == 21) {
spinWheel.setEnabled(false);
}

solvePuzzle = addSolvePuzzleListener(solvePuzzle);

wheelButtons.add(buyVowel);
wheelButtons.add(spinWheel);
wheelButtons.add(solvePuzzle);
wheelPanel.add(wheelButtons);
wheelPanel.add(new JLabel(wheelImage));
return wheelPanel;
}

/**
* set up vowel panel's dimensions, layout, border color, title, title
justification
*
* @return vowel panel without buttons
*/
private JPanel getVowelPanel() {
JPanel vowelPanel = new JPanel(new GridLayout(3,2));
vowelPanel.setPreferredSize(new Dimension(140, 150));
TitledBorder vowelTitle = BorderFactory.createTitledBorder("Vowels");
vowelTitle.setTitleJustification(TitledBorder.LEFT);
vowelPanel.setBorder(vowelTitle);
return vowelPanel;
}

/**
* set up consonant panel's dimensions, layout, border color, title, title
justification
*
* @return consonant panel without buttons
*/
private JPanel getConsPanel() {
JPanel consonantsPanel = new JPanel(new GridLayout(3,7));
consonantsPanel.setPreferredSize(new Dimension(460, 150));
TitledBorder consonantsTitle = BorderFactory.createTitledBorder("Consonants");
consonantsTitle.setTitleJustification(TitledBorder.LEFT);
consonantsPanel.setBorder(consonantsTitle);
return consonantsPanel;
}

/**
* Adds action listener for when the letter button is pressed.
* If guessed correct consonant, distribute points.
* If guessed incorrect, game moves on to next player.
*
* @param button JButton to which we will add the action listener to
* @param character letter that the button represents
* @return same button but with added action listener
*/
private JButton addLetterListener(JButton button, String character) {
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
charactersGuessed.add(character);

//count number of times a guessed letter appear in phrase


int times = 0;
for (int i = 0; i < phrase.length(); i++) {
if (String.valueOf(phrase.charAt(i)).equals(character)) {
times++;
}
}

//can't earn points for vowels


if (!character.equals("A") && !character.equals("E") && !
character.equals("I")
&& !character.equals("O") && !character.equals("U")) {
//distribute points to players
playerScore.set(playerTurn,
playerScore.get(playerTurn) + times * wheelSpaces[spin].dollar);
}

int previousSize = charactersRemaining.size();


charactersRemaining.remove(character);
//if none of characters from phrase is guessed, move on to next player
if (charactersRemaining.size() == previousSize) {
playerTurn = (playerTurn + 1) % players;
}
//disable all cons and vowel buttons
consEnable = false;
vowelEnable = false;
//rebuild the JFrame
getContentPane().removeAll();
getContentPane().add(getScorePanel());
getContentPane().add(getWheelPanel(true));
getContentPane().add(getLetterPanel());
getContentPane().add(getPhrasePanel());
pack();
revalidate();
repaint();
}
});
return button;
}

private ArrayList<JPanel> addButtons(ArrayList<JPanel> panels) {


for (int i = 0; i < 26; i++) {
String character = String.valueOf((char) (((int) 'A') + i));
JButton button = new JButton(character);
button = addLetterListener(button, character);

if (character.equals("A") || character.equals("E") || character.equals("I")


||
character.equals("O") || character.equals("U")) {
if (!vowelEnable) {
button.setEnabled(false);
}
panels.get(0).add(button);
} else {
if (!consEnable) {
button.setEnabled(false);
}
panels.get(1).add(button);
}

if (charactersGuessed.contains(character)) {
//if letter is guessed, disable the button
button.setEnabled(false);
}
}

return panels;
}

/**
* sets up the panel with the letter buttons to guess
*
* @return panel with vowel and consonant buttons
*/
private JPanel getLetterPanel() {
JPanel letterPanel = new JPanel();
letterPanel.setLayout(new BoxLayout(letterPanel, BoxLayout.X_AXIS));
letterPanel.setSize(600, 150);

JPanel vowelPanel = getVowelPanel();


JPanel consonantsPanel = getConsPanel();

ArrayList<JPanel> panels = new ArrayList<JPanel>();


panels.add(vowelPanel);
panels.add(consonantsPanel);

panels = addButtons(panels);

letterPanel.add(panels.get(0));
letterPanel.add(panels.get(1));
return letterPanel;
}

/**
* sets up the panel that displays the phrase
*
* @return panel that displays the phrase
*/
private JPanel getPhrasePanel() {
JPanel phrasePanel = new JPanel(new FlowLayout());
String hiddenPhrase = "";
for (int i = 0; i < phrase.length(); i++) {
String str = phrase.substring(i, i + 1);
if (charactersGuessed.contains(str)) {
// if letter is guessed, reveal that letter
hiddenPhrase += str + " ";
} else if (!(phrase.charAt(i) >= 'A' && phrase.charAt(i) <= 'Z')) {
// if it is puncuation, number, etc. -- not a letter -- then reveal that
symbol
hiddenPhrase += str + " ";
} else {
// otherwise, hide the letter
hiddenPhrase += "- ";
}
}
phrasePanel.add(new JLabel(hiddenPhrase));
return phrasePanel;
}

private boolean isNumeric(String strNum) {


if (strNum == null) {
return false;
}
try {
} catch (NumberFormatException nfe) {
return false;
}
return true;
}

You might also like