import java.io.*; import java.util.Random; import java.util.StringTokenizer; public class ExtraCreditWheelOfFortune { /* * Instance variables. */ private Random randGen; // For random character guessing. /* * These int variables keep track of the players' scores. */ private int humansScoreForRound; private int computersScoreForRound; private int humansTotalScore = 0; private int computersTotalScore = 0; /* * These BufferedReaders are for keyboard input and file input. */ private BufferedReader userInput = new BufferedReader(new InputStreamReader(System.in)); private BufferedReader fileInput; /* * These booleans are for controlling the loops for turns of play. */ private boolean turnOver; private boolean roundOver; private String secretPhrase; /* The phrase to be guessed. */ /* * The part of the phrase revealed to the players. It is a StringBuffer * so we can modify it easily. */ private StringBuffer pattern; /* * This boolean array is to record letters already guessed in a round. * For example, if 'A' has been guessed, then alreadyGuessed[0] is set * to true, if 'B' has been guessed, then alreadyGuessed[1] is set * to true, ... if 'Z' has been guessed, then alreadyGuessed[25] is * set to true. */ private boolean[] alreadyGuessed = new boolean[26]; /* * This integer variable is a counter index for stepping through * the letters in the order of frequency. */ private int guessIndex; /* * This char array lists the letters in order of frequency. */ private char[] orderOfFrequency = {'E','T', 'A', 'O', 'N', 'R', 'I', 'S', 'H', 'D', 'L', 'F', 'C', 'M', 'U', 'G', 'Y', 'P', 'W', 'B', 'V', 'K', 'X', 'J', 'Q', 'Z'}; /* * The main program gets the command line arguments and uses them * to start a game. Note that the integer seed argument is now ignored * because the computer is not guessing randomly in this extra credit * version. */ public static void main(String[] args) { /* Instance of the class. */ ExtraCreditWheelOfFortune theWheel = new ExtraCreditWheelOfFortune(); try { theWheel.fileInput = new BufferedReader(new FileReader(args[0])); theWheel.playGame(); } catch(Exception e) // Probably caused by bad command-line arguments. { System.out.println("Usage: ExtraCreditWheelOfFortune "); e.printStackTrace(); } } /* * Run the main loops for controlling the game. */ public void playGame() { try { /* Loop for each line read from the file. Note how it combines * an assignment and a test. This is explained in the non-extra * credit version of the program. */ while ((secretPhrase = fileInput.readLine()) != null) { makePattern(); // Use * to hide the secret phrase. /* * Initialize the state of a round. */ roundOver = false; humansScoreForRound = 0; computersScoreForRound = 0; /* * Reinitialize the computer's position in stepping through * the array of letters in order of frequency. */ guessIndex = 0; /* * Reinitialize the computer's record of already guessed letters * in a round. */ for(int i = 0; i < 26; i ++) { alreadyGuessed[i] = false; } while (!roundOver) // Loop until someone guesses the secret phrase. { turnOver = false; while (!turnOver) // Loop until human guesses wrong. { System.out.println(pattern); humanGuess(); } if (roundOver) // The human finished the secret phrase. { break; // So we jump out of round loop and start the next round. } turnOver = false; while(!turnOver) // Loop until computer guesses wrong. { computerGuess(); } } showRoundResult(); } showGameResult(); } catch(IOException e) { System.out.println("Something went wrong reading file."); e.printStackTrace(); } } /* * Initialize the pattern by replacing the words with *'s. */ private void makePattern() { pattern = new StringBuffer(); StringTokenizer t = new StringTokenizer(secretPhrase); while (t.hasMoreTokens()) // Loop for each word in the phrase. { hideWord(t.nextToken()); pattern.append(' '); // The space between the words. } } /* * Given a word, generate a StringBuffer of *'s of the same length. */ private void hideWord(String w) { for (int i = 1; i <= w.length(); i++) { pattern.append('*'); } } /* * Reveal all occurrences of the given character in the pattern. */ private void updatePattern(char c) { int pos = -1; /* * Loop for each occurrence of the character in the word. * Another example of combining an assignment with a comparison. */ while ((pos = secretPhrase.indexOf(c, ++pos)) != -1) { pattern.setCharAt(pos, c); // Replace the * with the character. } } /* * Count the number of occurrences of the character in the pattern. */ private int numOccurrences(char c, String s) { int count = 0; int pos = -1; /* Loop for each occurrence of the character in the word. */ while ((pos = secretPhrase.indexOf(c, ++pos)) != -1) { count++; } return count; } /* * Return true if and only if all characters in the word have been revealed. */ private boolean isPatternComplete() { return (pattern.toString().indexOf('*') == -1); // No more *'s. } /* * One turn by the human player. */ private void humanGuess() { while (!turnOver) // Keep guessing until player guesses wrong. { System.out.println("Please guess a letter."); char guess; try { guess = userInput.readLine().charAt(0); // First letter of input line. guess = Character.toUpperCase(guess); // Convert to upper case. alreadyGuessed[letterIndex(guess)] = true; // Mark letter as guessed. } catch(IOException e) { e.printStackTrace(); guess = 'A'; // If the I/O fails, default to 'A'. alreadyGuessed[0] = true; // Mark 'A' as guessed. } /* * If the letter is in the secret phrase but hasn't been guessed * already and been revealed in the pattern, then it's a right guess. */ if ((secretPhrase.indexOf(guess) != -1) && (pattern.toString().indexOf(guess) == -1)) { updatePattern(guess); // Reveal the occurrences of the letter. System.out.println(pattern); humansScoreForRound += numOccurrences(guess, secretPhrase); System.out.println("You guessed right."); System.out.println("Your score is now " + humansScoreForRound + "."); if (isPatternComplete()) // The human found the secret phrase. { turnOver = true; roundOver = true; System.out.println("You win this round."); humansTotalScore += humansScoreForRound; } } else // It's a wrong guess. { System.out.println("You guessed wrong."); turnOver = true; } } } /* * One turn by the computer player. */ private void computerGuess() { while (!turnOver) { char guess = nextCharInFreqOrder(); System.out.println("The computer guesses " + guess + "." ); /* * If the letter is in the secret phrase but hasn't been guessed * already and been revealed in the pattern, then it's a right guess. */ if ((secretPhrase.indexOf(guess) != -1) && (pattern.toString().indexOf(guess) == -1)) { alreadyGuessed[letterIndex(guess)] = true; // Mark as already guessed. updatePattern(guess); // Reveal the occurrences of the letter. System.out.println(pattern); computersScoreForRound += numOccurrences(guess, secretPhrase); System.out.println("The computer's score is now " + computersScoreForRound + "."); if (isPatternComplete()) // The computer found the secret phrase. { turnOver = true; roundOver = true; System.out.println("The computer wins this round."); computersTotalScore += computersScoreForRound; } } else // It's a wrong guess. { System.out.println("The computer guessed wrong."); turnOver = true; } } } /* * Get the next letter from the orderOfFrequency array which has * not been already guessed. */ private char nextCharInFreqOrder() { int i; char guess = orderOfFrequency[guessIndex]; for (i = guessIndex; i < 26; i++) { guess = orderOfFrequency[i]; if(!(alreadyGuessed[letterIndex(guess)])) // Found one not yet guessed. { alreadyGuessed[letterIndex(guess)] = true; // Now mark it as guessed. break; // Break out of the loop to make this guess. } } guessIndex = i + 1; // Record the position in orderOfFrequency array. return guess; } /* * Print out the results of one round. */ private void showRoundResult() { System.out.println("Your total score for all rounds is now " + humansTotalScore + "."); System.out.println("The computer's total score for all rounds is now " + computersTotalScore + "."); } /* * Print out the results of the game. */ private void showGameResult() { if (humansTotalScore > computersTotalScore) { System.out.println("You win this game."); } else if (humansTotalScore < computersTotalScore) { System.out.println("The computer wins this game."); } else { System.out.println("The game is tied."); } } /* * The index corresponding to a letter. For example, the index for * 'A' is 0, the index for 'B' is 1, ... the index for 'Z' is 25. * Useful for indexing into the alreadyGuessed array. */ private int letterIndex(char c) { return (int)(c - 'A'); } }