Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

Java Local Development Environments Advanced Tooling Teamwork

Kevin Faust
Kevin Faust
15,353 Points

hey craig is there a copy of the answer to the code challenge?

Hey Craig Dennis, im wondering if you have a master copy of the ide code? or does anyone else have the answer?

i essentially got all the TODOs done except this one. it only sometimes work. If i type in dweeb 5 times it may not work but then on the 6th it suddenly works. Or typing nerd one time may not work but another time it would work. this is what i have so far:

// TODO:csd - Prompt the user for the response to the phrase, make sure the word is censored, loop until you get a good response

main problem code:

    public String promptForWord(String phrase) throws IOException {
        System.out.println("Please write a " + phrase);
        String answer = mReader.readLine();
        // TODO:csd - Prompt the user for the response to the phrase, make sure the word is censored, loop until you get a good response
        for (String censoredWords : mCensoredWords) {
            while (censoredWords.contains(answer)) {
                System.out.println("Sorry that response is not acceptable");
                answer = mReader.readLine();
            }
        }
        return answer;
    }

rest of code: prompter.java:

package com.teamtreehouse;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


public class Prompter {
    private BufferedReader mReader;
    private Set<String> mCensoredWords;

    public Prompter() {
        mReader = new BufferedReader(new InputStreamReader(System.in));
        loadCensoredWords();
    }

    private void loadCensoredWords() {
        mCensoredWords = new HashSet<String>();
        Path file = Paths.get("resources", "censored_words.txt");
        List<String> words = null;
        try {
            words = Files.readAllLines(file);
        } catch (IOException e) {
            System.out.println("Couldn't load censored words");
            e.printStackTrace();
        }
        mCensoredWords.addAll(words);
    }

    public void run(Template tmpl) {
        List<String> results = null;
        try {
            results = promptForWords(tmpl);
        } catch (IOException e) {
            System.out.println("There was a problem prompting for words");
            e.printStackTrace();
            System.exit(0);
        }
        // TODO:csd - Print out the results that were gathered here by rendering the template
        System.out.println(tmpl.render(results));
    }

    /**
     * Prompts user for each of the blanks
     *
     * @param tmpl The compiled template
     * @return
     * @throws IOException
     */
    public List<String> promptForWords(Template tmpl) throws IOException {
        List<String> words = new ArrayList<String>();
        for (String phrase : tmpl.getPlaceHolders()) {
            String word = promptForWord(phrase);
            words.add(word);
        }
        return words;
    }


    /**
     * Prompts the user for the answer to the fill in the blank.  Value is guaranteed to be not in the censored words list.
     *
     * @param phrase The word that the user should be prompted.  eg: adjective, proper noun, name
     * @return What the user responded
     */
    public String promptForWord(String phrase) throws IOException {
        System.out.println("Please write a " + phrase);
        String answer = mReader.readLine();
        // TODO:csd - Prompt the user for the response to the phrase, make sure the word is censored, loop until you get a good response
        for (String censoredWords : mCensoredWords) {
            if (answer==censoredWords) {
                throw new IllegalArgumentException("That word is not allowed. Exiting");
            }
        }
        return answer;
    }
}

main:

package com.teamtreehouse;

import java.util.Arrays;
import java.util.List;

public class Main {

    public static void main(String[] args) {
    // write your code here
        // TODO:csd - Instantiate a new Prompter object and prompt for the story template
        Prompter prompter = new Prompter();
        String story = "Thanks __name__ for helping me out.  You are really a __adjective__ __noun__ and I owe you a __noun__.";
        Template tmpl = new Template(story);
        // TODO:csd - Use the prompter object to have it do the prompting, censoring and outputting.  Call Prompter.run
        prompter.run(tmpl);
    }
}

template:

package com.teamtreehouse;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


public class Template {
    /**
     * The string format that is waiting to receive values
     */
    private String mCompiled;
    private List<String> mPlaceholders;

    /**
     * @param text A template with double underscored surrounded placeholders. eg: Hello __name__!
     */
    public Template(String text) {
        // Match on double underscore surrounded words, like __name__ or __proper noun__
        Pattern pattern = Pattern.compile("__([^__]+)__");
        Matcher matcher = pattern.matcher(text);
        mPlaceholders = new ArrayList<String>();
        while (matcher.find()) {
            String label = matcher.group(1);
            mPlaceholders.add(label);
        }
        mCompiled = matcher.replaceAll("%s");
    }


    /**
     * @return Ordered names of placeholders in the template
     */
    public List<String> getPlaceHolders() {

        return mPlaceholders;
    }


    /**
     * Given a list of values, replaces the fill in the blanks in order.
     *
     * @param values The replacements for the fill in the blank
     * @return The filled out TreeStory
     */
    public String render(List<String> values) {
        // String.format accepts the templates and Object... (a variable amount of objects)
        return String.format(mCompiled, values.toArray());
    }
}
Ken Alger
Ken Alger
Treehouse Teacher

Kevin;

My recollection of this task is that you need to be prompting the user for a story, not just use the sample story Craig provided. You could do both so that if a user doesn't pass in a story there will be one provided, but I am fairly certain that the code checker is attempting to pass in another story to see if the task passes.

Post back if you are still stuck.

Happy coding,
Ken

Kevin Faust
Kevin Faust
15,353 Points

Hey Ken,

My understanding is that we use that story, but we prompt for the variables in that story. we can see things like name, adjective, etc. using our Pattern/Matcher/regex code "([^]+)__", we prompt the user for things to replace those variables. The problem is when I run my code, and it prompts for a variable and I type in a censored word, it is supposed to reprompt me until it no longer is a censored word but it isnt completely working as i have written below.

  public String promptForWord(String phrase) throws IOException {
        System.out.println("Please write a " + phrase);
        String answer = mReader.readLine();
        // TODO:csd - Prompt the user for the response to the phrase, make sure the word is censored, loop until you get a good response
        for (String censoredWords : mCensoredWords) {
            while (censoredWords.contains(answer)) {
                System.out.println("Sorry that response is not acceptable");
                answer = mReader.readLine();
            }
        }
        return answer;
    }

Both you and craig have said i need to be prompting for a story but i dont understand what that means. are we not supposed to use that default story string and just prompt for an input to replace the regex pattern? If not, then i no longer understand what this code is even supposed to do.

Thanks

8 Answers

Ken Alger
STAFF
Ken Alger
Treehouse Teacher

Kevin;

I think you need to be asking for a user to input their own story to get through the challenge. As I mentioned you can make the supplied story as a default, but when new Prompter() is called it should be asking the user to enter a story. I believe that is what is being asked in test 1 of the pseudo-tests:

  1. The user is prompted for the string template (the one with the double underscores in it)

In terms of your checking for the censored words your code look almost the same as mine, but I don't have a for loop involved. You might take that out and go with something like:

promptForWordSnippet.java
public String promptForWord(String phrase) throws IOException {
    System.out.printf("Please enter your word for %s: %n", phrase);
    String entryWord = mReader.readLine();

    while (mCensoredWords.contains(entryWord.toLowerCase())) {
         System.out.printf("Be nice, please try another word for %s. %n", phrase);
         entryWord = mReader.readLine();
    }

    return entryWord.trim();
}

Hopefully my variable names are clear enough to see what is going on there. Post back if you are still stuck. Happy to assist.

Ken

Kevin Faust
Kevin Faust
15,353 Points

Hey Ken, thanks alot! For some reason I thought that I couldnt use the contains() method on a set and thats why i thought i had to loop. So now I understand how that part works and i got it working. The only thing that remains is asking the user to input their own story. I tried several different combinations but im not sure how to do it:

update i got it working now. The regex code was a double underscore but i thought it was a single one so thats why all my attempts were a fail. what im wondering now is that if a user writes a sentence that doesnt have our wanted regex code, i want them to try again. How would I do this?

Kevin Faust
Kevin Faust
15,353 Points

Im getting this error when trying to do the code challenge:

JavaTester.java:77: error: unreported exception IOException; must be caught or declared to be thrown Main.main(null); ^ 1 error

here is my code:

Main.java

package com.teamtreehouse;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

    public static void main(String[] args) throws IOException {
        // write your code here
        BufferedReader mReader = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("Make a story! Write a fill in the blank story with an underscore on each side of the variable like _noun/adjective/etc_");
        // TODO:csd - Instantiate a new Prompter object and prompt for the story template
        Prompter prompter = new Prompter();
        String story = mReader.readLine();
        Template tmpl = new Template(story);
        prompter.run(tmpl);
    }
}

Prompter.java

package com.teamtreehouse;

        import java.io.BufferedReader;
        import java.io.IOException;
        import java.io.InputStreamReader;
        import java.nio.file.Files;
        import java.nio.file.Path;
        import java.nio.file.Paths;
        import java.util.ArrayList;
        import java.util.HashSet;
        import java.util.List;
        import java.util.Set;


public class Prompter {
    private BufferedReader mReader;
    private Set<String> mCensoredWords;

    public Prompter() {
        mReader = new BufferedReader(new InputStreamReader(System.in));
        loadCensoredWords();
    }

    private void loadCensoredWords() {
        mCensoredWords = new HashSet<>();
        Path file = Paths.get("resources", "censored_words.txt");
        List<String> words = null;
        try {
            words = Files.readAllLines(file);
        } catch (IOException e) {
            System.out.println("Couldn't load censored words");
            e.printStackTrace();
        }
        mCensoredWords.addAll(words);
    }

    public void run(Template tmpl) {
        List<String> results = null;
        try {
            results = promptForWords(tmpl);
        } catch (IOException e) {
            System.out.println("There was a problem prompting for words");
            e.printStackTrace();
            System.exit(0);
        }
        // TODO:csd - Print out the results that were gathered here by rendering the template
        System.out.println(tmpl.render(results));
    }

    /**
     * Prompts user for each of the blanks
     *
     * @param tmpl The compiled template
     * @return
     * @throws IOException
     */
    public List<String> promptForWords(Template tmpl) throws IOException {
        List<String> words = new ArrayList<String>();
        for (String phrase : tmpl.getPlaceHolders()) {
            String word = promptForWord(phrase);
            words.add(word);
        }
        return words;
    }


    /**
     * Prompts the user for the answer to the fill in the blank.  Value is guaranteed to be not in the censored words list.
     *
     * @param phrase The word that the user should be prompted.  eg: adjective, proper noun, name
     * @return What the user responded
     */
    public String promptForWord(String phrase) throws IOException {
        System.out.println("Please write a " + phrase);
        String answer = mReader.readLine().trim();
        String editedAnswer = answer.toLowerCase().trim();
        while (mCensoredWords.contains(editedAnswer)) {
            System.out.printf("Sorry %s is an unacceptable word%n", answer);
            answer = mReader.readLine();
            editedAnswer = answer.toLowerCase().trim();
        }
        return answer;
    }
}
Craig Dennis
STAFF
Craig Dennis
Treehouse Teacher

Hi Kevin!

mCensoredWords is a set and it has the ability to check if a value exists using a method called contains. Instead of throwing an exception, I was hoping you would loop until they entered a valid response.

You are super close! You need to prompt for the story as well, instead of using the default test one I supplied. Add it to the Prompter.

Let me know if that gets you unstuck!

Ken Alger
STAFF
Ken Alger
Treehouse Teacher

Kevin;

Your error is due to your Main.java stating that it throws IOExceptions, but them not being dealt with anywhere. How about using the bubble up technique we learned in one of the Java courses and have the methods in Prompter.java throw the exceptions and then inside Main.java we do a try... catch block to handle everything?

Meaning you could do something in Main.java like:

snippetMain.java
Prompter prompt = new Prompter();

try {
    prompt.promptForStory();
} catch (IOException ioe) {
    // Do something pithy with the error
}
snippetPrompter.java
public String promptForStory() throws IOException {
    // Some magical code to get a user's story

    return story;
}

That error will then bubble up into Main.java to handle. Make any sense?

Ken

Kevin Faust
Kevin Faust
15,353 Points

Hey Ken thanks. I did what you said but this code checker still isnt working I added this :

String story = null;
        try {
            story = prompter.promptForStory();
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
public String promptForStory() throws IOException {
        return mReader.readLine();
}

I tried doing this as well:

Prompter prompter = new Prompter();
        String story = null;
        try {
            story = mReader.readLine();
        } catch (IOException e) {
            e.printStackTrace();
        }

but then the code checker says

"Make a story! Write a fill in the blank story with an underscore on each side of the variable like _noun/adjective/etc_
Please enter your word for first prompt: 
java.lang.NullPointerException
    at com.teamtreehouse.Prompter.promptForWord(Prompter.java:78)
    at com.teamtreehouse.Prompter.promptForWords(Prompter.java:61)
    at com.teamtreehouse.Prompter.run(Prompter.java:41)
    at com.teamtreehouse.Main.main(Main.java:22)
    at JavaTester.run(JavaTester.java:77)
    at JavaTester.main(JavaTester.java:39)

My IDE has had 0 errors, everything runs perfectly fine, but then this code checker is just being completely frustrating.

Craig Dennis
STAFF
Craig Dennis
Treehouse Teacher

Hey Kevin,

Remove the exception from the main method, it doesn't actually throw it anymore now that you caught it.

public static void main(String[] args) throws IOException {

Hope that is it, things look really good.

Kevin Faust
Kevin Faust
15,353 Points

All i can say is hallelujah. First time ive ever had a code challenge that ended up lasting me several days. The endless struggle has finally ended and thanks for the challenge !

Ken Alger
Ken Alger
Treehouse Teacher

Kevin;

Yahoo!!! :thumbsup:

Way to stick with it and hopefully now that you have gone through it my ramblings make a bit more sense. :smile:

Keep up the great work and perhaps you can turn this project into a JavaFX project.

Happy coding,
Ken

Kevin Faust
Kevin Faust
15,353 Points

Thanks Ken for helping me along the way :D

I look forward to starting the JavaFX track

Craig Dennis
STAFF
Craig Dennis
Treehouse Teacher

Congrats! Sorry it took so long! Glad you enjoyed the challenge, you're in the right field ;)

Will R
Will R
9,364 Points

I'm having a problem with the same challenge. It says I am not censoring the words properly, but it works fine when I run it. Here is my promptForWord method.

public String promptForWord(String phrase) throws IOException {
    System.out.printf("Enter a %s: ", phrase);
    String word = mReader.readLine().trim();
    while(mCensoredWords.contains(word.toLowerCase())) {
        System.out.printf("%s is censored. Enter a different %s: ", word, phrase);
        word = mReader.readLine().trim();
    }
    return word;
}
Amanda Lam
Amanda Lam
2,178 Points

I have the same problem. Did you find a solution for this??

Will R
Will R
9,364 Points

I tried the code challenge again a day later with the same exact code and it worked. I wish I knew why it worked the second time. There must be a bug. Try restarting the code challenge.

Andrew Sheragy
Andrew Sheragy
16,379 Points

I am having an issue with promptForWord always getting a null input. I also tried copying in the function above that Will R posted and its not even getting to the censored part, it got a nullpointer exception on the trim() line. Note this works on my computer fine its just when I submit online.

public String promptForWord(String phrase) throws IOException {
    System.out.println("Enter word for: " + phrase);

  String input = null;
  while(input == null) //This loop appears to runs until the server decides the program is running too long and exits early
  {
      input = mReader.readLine();
  }

    return input;
}
Amanda Lam
Amanda Lam
2,178 Points

Hey, I recommend going to here: https://teamtreehouse.com/community/code-challenge:8252 Lots of people had questions for the challenge and a lot of them got answered. I suggest comparing your code to one of the answers that people provided to see where you went wrong.

I just wanted to say it wasn't exactly super clear that there was a TODO that required the implementation of a method, promptForStory() or promptForTemplate(), to gather the story in the Prompter class. If that's where you're stuck, especially with the Out of Memory exceptions (OOM), then you have just about everything else working except that. The TODO in line 10 sort of explains it:

// TODO:csd - Instantiate a new Prompter object and prompt for the story template