How to populate an array (like hangman) based on a guess - java

What I am trying to do is take a hidden String and then display it letter by letter in a random sequence every time the user presses the hint button. Currently, every time the hint button is pressed the entire solution displays once per character of the solution.
I am trying to make it so that when the hint button is pressed a random character from the string solution appears in the correct location. I am unsure about how to compare the location of the generated character to the string location.
public String letterGenerator(int count, String word) {
//String word is taken from another function and it is based on the current displayed card and associated answer
StringBuilder string = new StringBuilder();
Random rng = new Random();
char[] letters = word.toCharArray();
char[] answers = new char[letters.length];
int selected = rng.nextInt(letters.length);
for (int i = 0; i < word.length(); i++) {
if (i == selected) {
letters[i] = answers[i];
}
string.append(letters);
}
return string.toString();
}
For example if the answer is "a wallet" this code outputs the solution as "a walleta walleta walleta walleta walleta walleta walleta walleta" (It displays the output 8 times because it prints the solution once per character including blank spaces)
What it should be doing for each press of the hint button would be to display each character in a random order like so:
Press 1: "_ _ _ l_ _ _"
Press 2: "a _ _ l_ _ _"
Press 3: "a _ _ l _e _", and so on until the entire word appears on screen
Any help is appreciated!

Well, you append(letters) to your output for each iteration of your loop, and letters is an array of all your letters, not just one of them. So of course you end up with that output that you got.
But I think you can design this in a more elegant, and more object-oriented way. Instead of two character arrays for the answer and what is displayed, maybe make just one array of 'Letters'. This means you create a custom class Letter, which could hold the information whether it is 'solved' or not. Like so:
public class Letter{
char character;
boolean solved;
// ... Constructor, Getters, Setters
}
Then, you can just pass your array of letters to a method that selects a random letter that is not solved yet, and simply switch its solved property to true. Your code for displaying the thing to your user would then be something like this:
for(Letter letter : letterArray){
System.out.print(letter.isSolved() ? letter.getCharacter() : "_");
}

If I've understood correctly, then here's a few things to change;
1) You want to remember the last revealed hint, but you've stored it in a local variable.
You'll want a way to store the revealed letters. How you do that depend on how the rest of your class is setup, but either passing it back as part of the method return or setting a global variable should do
2) Since you are remembering the previous hints, you'll want to make sure that 'selected' has not been revealed before. Perhaps store what letter positions have been revealed before and compare against them.
3) I would put the internal of the loop more as
for (int i = 0; i < word.length(); i++) {
if(i == selected){
string.append(letters[i]);
}else{
string.append("_");
}
}
I hope this helps
Edit:
I've changed the for loop, now it should work as you wanted. Sorry I should have been more careful to start with.
As for storing the previously revealed letters, if you are using a Singleton class then it would be acceptable to store this values in another list. My suggestion would be to keep an ArrayList of revealed values, then do something like;
List<Integer> revealed = new ArrayList<>();
Random rng = new Random();
public int getNextSelected(int length){
int selected = rng.nextInt(length);
if(revealed.contains(selected)){
return getNextSelected(length);
}
return selected;
}
public String letterGenerator(int count, String word) {
...
int selected = getNextSelected(letters.length);
for (int i = 0; i < word.length(); i++) {
if (i == selected){
string.append(letters[i]);
} else if (revealed.contains(i)) {
string.append(letters[i]);
} else{
string.append("_");
}
}
revealed.add(selected);
return string.toString();
}
This should do what you need. There's plenty of ways to clean up the code, the suggestion by user3237736 is quite nice as it follows the 'tell don't ask' principle, but the design decisions of the class is up to you

public class SOEN_student {
public static void letterGenerator(String word) {
//String word is taken from another function and
//it is based on the current displayed card and associated answer
StringBuilder string;
Random rng = new Random();
char[] letters = word.toCharArray();
char[] answers = new char[letters.length];
boolean[] visited=new boolean[letters.length];
int selected;
for (int i = 0; i < word.length(); i++) {
do{
selected=rng.nextInt(letters.length);
}while(visited[selected]);
string=new StringBuilder();
for(int j=0;j<word.length();j++){
if(visited[j] | j==selected){
visited[selected]=true;
string.append(letters[j]);
}else{
string.append("_");
}
}
System.out.print(string.toString()+" ");
}
}
public static void main(String... args){
letterGenerator("a wallet");
}
}

Related

Sudoku Code Program - Checking Rows,Columns, and Boxes

I need help checking rows, columns, and boxes for a Sudoku program. I am a high school student that needs help completing this project. If any one could provide help that would be awesome! I am currently working on checking boxes where I have a comment saying "Start Here". Thanks!
import java.util.*;
public class Run
{
Scanner scanner = new Scanner(System.in);
public static void main(String[] args)
{
char [][] board = new char [9][9];
Scanner scanner = new Scanner(System.in);
System.out.println("Welcome to Sudoku!\n");
fill(board);
printBoard(board);
inputLengthandDigits(board);
System.out.println();
printBoard(board);
}
public static void fill(char[][] arr){
for(int row = 0; row < arr.length; row++){
for(int col= 0; col< arr[row].length; col++){
arr[row][col] = '-';
}
}
}
public static void printBoard(char [][] array)
{
for(char[] row: array)
{
for(char play: row)
{
System.out.print(play+ " ");
}
System.out.println();
}
}
public static void inputLengthandDigits(char[][] array){
Scanner in = new Scanner(System.in);
for (int i = 0; i < 9; i++)
{
System.out.println("\nEnter the numbers in row " + (i+1) + ":");
String input = in.nextLine();
String numbers = "123456789-";
boolean numberscheck = false;
boolean endCheck = true;
boolean onlyOnce = true;
//Input Validation Starts Here!
//Checks if Input is only digits 0-9
do{
if(endCheck==false){
System.out.println("\nPlease input numbers only (1-9)!");
input = in.nextLine();
}
if(onlyOnce==false){
System.out.println("\nPlease input numbers only once!");
input = in.nextLine();
}
//Checks Length of User Input
while(input.length() < 9 || input.length() > 9){
System.out.println("\nPlease input 9 numbers!");
input = in.nextLine();
}
//Start Here
for(int a = 0; a<input.length()-1; a++){
for(int b= a + 1; b<input.length(); b++){
if(input.charAt(a)==input.charAt(b)){
onlyOnce = false;
}
}
}
for(int x = 0; x < input.length(); x++){
char thing = input.charAt(x);
numberscheck = false;
for(int y = 0; y < numbers.length(); y++){
char numbersn = numbers.charAt(y);
if(thing == numbersn){
numberscheck = true;
endCheck = true;
break;
}
}
if(numberscheck == false){
endCheck = false;
break;
}
}
}while(endCheck==false || onlyOnce==false);
for(int j=0; j<9; j++){
array[i][j] = input.charAt(j);
}
}
}
}
My initial response is too long for a comment. I'm not sure I have a solution to your problem, largely because you haven't actually pointed out which bit is a problem yet, but these pointers should help improve things anyway:
Please reformat your code. It is actually quite painful to look at. Spaces should be used consistently around variables, key words, brackets and operands. Opening curly braces should be on the same line as the method signature, for() loop or whatever else comes first. You have random blank lines within methods which don't separate logical sections so are just confusing. The compiler won't care about any of this, but if you can make your code look neater people will instinctively presume you care and are more likely to credit you with the ability to write decent code.
You have declared a new scanner variable three times. This is redundant and wasteful clutter. Either have a single, class-wide scanner, or (preferably), only create a scanner in a method which actually uses it and then remember to call scanner.close() once the scanner is no longer required.
inputLengthandDigits is a weird name. Is 'Lengthand' a single word, or should it be 'inputLengtHandDigits' or 'inputLengthAndDigits'? In camel case, capitalise every word except the first to make the whole easier to read. Whatever it should be, I don't understand from the name what this method does. It isn't inputting anything, it's getting inputs from someone else. Perhaps getData or populateGrid might be more explanatory.
9 appears quite a few times, with no explanation. I know where it came from, because I spend far too much time playing Sudoku, but it is a magic number and these are to be avoided at all costs. I met a magic number in the workplace once, wasted half a day trying to do what could have been a ten minute job if colleagues had recorded what the number was and where it came from. Here, just have a private static final int maxNumber = 9; statement.
A good thing: your main() method has almost no fiddly details in it. You have effectively used method calls to tell a story and describe what is happening elsewhere. This is a really, really good thing to do :)
Some of your logic tests can be tidied up a bit, e.g. !onlyOnce is the same as onlyOnce == false, and input.length() < maxNumber || input.length() > maxNumber can be simplified to input.length() != maxNumber. It's exactly the same logic, but faster to type and easier to read :)
It looks like your code under the //Start here comment is checking that you don't have any duplicate numbers. If you do get duplicate numbers, the program is still going to try and run the next bit of code before asking the user for alternative input. Is that something you want to happen, or a waste of time?
I actually burst out laughing when I saw a variable called 'thing'. Please, find a name which actually describes the purpose of this variable.
I have now run the code, and it rightly pointed out an error when I tried to key in duplicate numbers for row 4. However, it's now stuck there and keeps asking me to try again even when I put in a valid set of digits. This needs to be fixed. Look closely at which flags are triggering the request to retry. Run your code in debugging mode (you are using an IDE like IntelliJ or Eclipse, aren't you?) and deliberately enter a bad row to see the behaviour for yourself and where the logic is going wrong.
This whole method to get the row input, validate it, and then populate the array, is very big and confusing. You need to refactor it into a lot of smaller methods. Here is a suggestion to play with:
private static char[][] populateGrid(char[][] array) {
Scanner scanner = new Scanner(System.in);
for (int i = 0; i <maxNumber; i++) {
String rowData = getRowInput(scanner);
populateRow(array, rowNumber, rowData);
}
scanner.close;
return array;
}
private static String getRowInput(Scanner scanner) {
System.out.println("\nEnter the numbers in row " + (i + 1) + ":");
String input = scanner.nextLine();
while (!isValidInput(input) {
System.out.println("Please enter only the digits 1-9 in any order, with no duplicates or omissions");
input = scanner.nextLine();
}
return input;
}
private static boolean isValidInput(String input) {
if (!rightLengthOfInput(input)) {
return false;
}
if (!allUniqueDigits(input)) {
return false;
}
if (!usesCorrectCharacters(input)) {
return false;
}
return true;
}
I'll leave you to make the different input validation methods. It will largely be a case of moving your existing code, but the method names will help humans understand what each section is doing. This structure also allows you to cleanly add more validation checks, should such a thing be desired in the future.
Things to consider after all that:
Are you going to check that you have a viable Sudoku solution, or will you trust the user to put in correct data such that the columns also have each of the nine digits in them? How will you handle an invalid grid, e.g. each row is identical?
How far does this assignment want you to go? Do you need to systematically remove numbers to get a solvable puzzle rather than a completed grid? Will the assignment stop at a puzzle which can be seen in the console, or do you need a printable format, or will the user be able to play through the program? If the latter option, will this be in the console or using a graphical interface?
I appreciate that there is a lot to think about and work on here. Take it steadily, one step at a time, and keep asking questions if you need too.

How can I prevent the user from entering the same letter in Hangman JAVA?

I am writing a hangman program and one of the requirements to a hangman game is preventing the user from entering the same letter twice.
I have written the code for that, but the problem is every time I enter a letter it says it is already entered. I need to only say it when it is entered the second time. You guys have any suggestions? I've been trying to fix this for the past few hours, I figured I could ask on here to find some help. I already looked at another Stackoverflow question regarding something similar to this but all those solutions have the same result.
In Java, how can I determine if a char array contains a particular character?
I've tried something like this but it won't work either:
boolean contains = false;
for (char c : store) {
if (c == character) {
System.out.println("Already Entered");
contains = true;
break;
}
}
if (contains) {
// loop to top
continue;
}
SECOND CLASS-
public void hangman(String word, int life) {
KeyboardReader reader = new KeyboardReader();
char[] letter = new char[word.length()];
char[] store = new char[word.length()];
String guess;
int i = 0, tries = 0, incorrect = 0, count = 1, v = 0;
while (i < word.length()) {
letter[i] = '-';
I would just use the String.contains() method:
String aString = "abc";
char aChar = 'a';
return aString.contains(aChar + "");
To keep track of guessed letters you can use a StringBuffer, appending them using a StringBuffer.append() to append new letters (maintaining state) and use the StringBuffer.toString() method to get the String representation when you need to do the comparison above.
Since Java 1.5 the class String contains the method contains(). My idea is to collect all entered letters into a string variable and using above method:
// My code line
String letterAlreadyEntered = "";
// Your code line
char character = reader.readLine().charAt(0);
// My code line
if (letterAlreadyEntered.contains("" + character) == true) {
//Put code here what ever you want to do with existing letter
} else {
letterAlreadyEntered += character;
}
In my opinion, this is an easier way to check for occurrences than in arrays, where you have to write your own check method.

How to create a loop for

I need to create a loop that adds "o" after each consonant
I am going to walk you through what I corrected and changed in your code to make it work in order to make it quick and easy for you to comprehend why your code doesn't work and why my answer fixes it.
The mistakes you made are basic ones and frankly you shouldn't have to much of a hard time correcting them yourself if you would use a debugger that walks you step by step in how your code works. You should look on how to use a debugger (for example the debugger used in Eclipse, hopefully you are using an IDE to make your life easier).
Firstly, when you are looking for a consonant in your code, you are only walking through the half of it because of your condition for(int x = 0; x<20; x++) since your string holding the consonants if of a length of 40 characters. This means you are missing consonants like the letter s.
Then you are correctly the consonants you find according to your Swedish language game. But you are never handling characters that are not of these found consonants. You should make a case where you handle these "non consonant" letters, may they be vowels or any kind of character (like punctuation marks and so on). I am fixing this with the use of a simple boolean here.
Keep in mind that my goal here is to change your code as little as I can, thus I went for adding a boolean to handle your cases (checking the presence of a consonant). There are, obviously, many other ways to implement what you are trying to do.
Here come the changes you should add to your code:
/*This comes after your print "På rövarspråk:"*/
boolean isConsonant = false; //Boolean to check wether there is a consonant or not
for(int i = 0; i<length; i++) {
//You didn't go through the whole consonants list you made with your prevision condition
for(int x = 0; x<consonants.length; x++){
if(array[i] == consonants[x])
{
isConsonant = true; //Set the boolean accordingly
String add = array[i]+"o"+array[i];
slang = slang + add;
break;
}
}
if(!isConsonant){ //If we don't have a consonant, add the char to the result string
slang += array[i];
}
isConsonant = false; //Reset the boolean for the next character
}
/*Here you can print the result (slang) if you want, as you did*/
so the idea is to dublicate consonants and put "o" between them, like t becomes tot, s becomes sos. Vocals are just copied. So you need a method that tells you if a given character is a vocal or consonant to base your decision on that.
public static boolean isConsonant(char inputChar){
final String consonantsx = "bBcCdDfFgGhHjJkKlLmMnNpPqQrRsStTvVwWxXzZ";
char consonants[] = consonantsx.toCharArray(); // String to charr
for(int i=0; i < consonants.length;i++){
if(inputChar == consonants[i]){ //note that in Strings u use the equals method instead of "=="
return true;
}
}
return false;
}
Given this method you can use it in the "translator method".
public String rovarSpraket(String normalString) {
char[] array = normalString.toCharArray(); // Input to a char array
System.out.println("På rövarspråk:");
String slang = "";
for (int i = 0; i < normalString.length(); i++) {
String add = "" + array[i];
if(Goran.isConsonant(array[i])){
add += "o" + array[i];
}
slang += add;
}
return slang;
}
This translates stubborn to sostotubobboborornon like in the wikipedia article https://en.wikipedia.org/wiki/R%C3%B6varspr%C3%A5ket.

Finding the index of each character in a substring

I feel like my logic is decent here; I don't feel like I'm completely lost. However, I do know what exactly I'm doing wrong. I can always find the index of the start of the substring, but I can never find the full count (ex. 3,4,5,6) of the index of whatever word the user enters as the substring.
I have been struggling with this for about a week trying to figure out how to do it on my own, I can't get it right.
import java.util.Scanner;
public class midterm
{
public static void main (String[] args)
{
Scanner keyboard = new Scanner(System.in);
String simplePhrase;
String portionPhrase;
int portionIndex;
int portionCount;
int portionIndexTotal;
System.out.println("Enter a simple phrase:");
simplePhrase = keyboard.nextLine();
int phraseLength = simplePhrase.length();
System.out.println("Phrase length:" +phraseLength);
System.out.println("Enter a portion of previous phrase:");
portionPhrase = keyboard.nextLine();
String portionPhraseSub = simplePhrase.substring(portionPhrase);
portionIndex = simplePhrase.indexOf(portionPhraseSub);
for (portionIndex; portionIndex <= portionPhrase; portionIndex++)
{
System.out.println("Portion phrase index:"+portionIndex);
}
}
}
I'm still confused on what you want. There are just two simple things to know and you seem to be making this more complicated than it needs to be.
To get the index of a single character, such as "c" in the word "acorn", you would do this:
String s = "acorn";
int cIndex = s.indexOf("c");
System.out.println("The index of c is: " + cIndex);
If you want to see if the string contains a chunk, you use the exact same method. So if we are looking at the word "acorn" again and you want to see where "orn" happens, you'd do this:
String s = "acorn";
int ornIndex = s.indexOf("orn");
System.out.println("The index of orn is: " + ornIndex);
Remember that indexes start from 0 in java, so the index of "a" in "acorn" is 0, of "c" is 1, of "o" is 2, and so on.
I hope that helps. Good luck :)
EDIT: You just commented this:
"I guess, my question is one i get my code to compile, How would I go about counting every single letter of my substring?"
I'll answer that as best as I can, though again, that still is a confusing question.
What do you even mean by count" every letter? If you want to break your word into individual letters, you can do something like this:
String s = "acorn";
char[] characters = new char[s.length()-1];
for(int i = 0; i < s.length() - 1; i++) {
char[i] = s.charAt(i);
}
But I have no clue why you'd want to do that...you can always access any character in a string at a given index with STRING.charAt(index), or if you want to have a String result, STRING.substring(index, index+1)

Removing duplicate chars from a string passed as a parameter

I am a little confused how to approach this problem. The userKeyword is passed as a parameter from a previous section of the code. My task is to remove any duplicate chars from the inputted keyword(whatever it is). We have just finished while loops in class so some hints regarding these would be appreciated.
private String removeDuplicates(String userKeyword){
String first = userKeyword;
int i = 0;
while(i < first.length())
{
if (second.indexOf(first.charAt(i)) > -1){
}
i++;
return "";
Here's an update of what I have tried so far - sorry about that.
This is the perfect place to use java.util.Set, a construct which is designed to hold unique elements. By trying to add each word to a set, you can check if you've seen it before, like so:
static String removeDuplicates(final String str)
{
final Set<String> uniqueWords = new HashSet<>();
final String[] words = str.split(" ");
final StringBuilder newSentence = new StringBuilder();
for(int i = 0; i < words.length; i++)
{
if(uniqueWords.add(words[i]))
{
//Word is unique
newSentence.append(words[i]);
if((i + 1) < words.length)
{
//Add the space back in
newSentence.append(" ");
}
}
}
return newSentence.toString();
}
public static void main(String[] args)
{
final String str = "Words words words I love words words WORDS!";
System.out.println(removeDuplicates(str)); //Words words I love WORDS!
}
Have a look at this answer.
You might not understand this, but it does the job (it cleverly uses a HashSet that doesn't allow duplicate values).
I think your teacher might be looking for a solution using loops however - take a look at William Morisson's answer for this.
Good luck!
For future reference, StackOverflow normally requires you to post what you have, and ask for suggestions for improvement.
As its not an active day, and I am bored I've done this for you. This code is pretty efficient and makes use of no advanced data structures. I did this so you could more easily understand it.
Please do try to understand what I'm doing. Learning is what StackOverflow is for.
I've added comments in the code to assist you in learning.
private String removeDuplicates(String keyword){
//stores whether a character has been encountered before
//a hashset would likely use less memory.
boolean[] usedValues = new boolean[Character.MAX_VALUE];
//Look into using a StringBuilder. Using += operator with strings
//is potentially wasteful.
String output = "";
//looping over every character in the keyword...
for(int i=0; i<keyword.length(); i++){
char charAt = keyword.charAt(i);
//characters are just numbers. if the value in usedValues array
//is true for this char's number, we've seen this char.
boolean shouldRemove = usedValues[charAt];
if(!shouldRemove){
output += charAt;
//now this character has been used in output. Mark that in
//usedValues array
usedValues[charAt] = true;
}
}
return output;
}
Example:
//output will be the alphabet.
System.out.println(removeDuplicates(
"aaaabcdefghijklmnopqrssssssstuvwxyyyyxyyyz"));

Categories

Resources