In my code I have a variable, points, that increments based on the consanants and vowels in strings inputted. The method parseSentence is supposed to increase points per word but also ignore spaces.
I've tried running a debugger to see where the problem is but the debugger dies when it reaches the for loop in parseSentence. The method makes the point variable's value the word's point value instead of adding it to the variable. What could be causing this?
import java.util.*;
public class WordGolf1 {
public static int points = 1;
public static void main(String[] args) {
String Input;
System.out.println("Enter word: ");
Scanner sc = new Scanner(System.in);
Input = sc.nextLine();
System.out.println("Not enough points. " + (100 - points) + " needed.");
while (points < 100) {
System.out.println("Enter word: ");
Input = sc.nextLine();
parseSentence(Input);
System.out.println(points + ": points");
System.out.println("Not enough points. " + (100 - points) + " needed.");
}
boolean overshot = true;
Loop:
while (overshot = true) {
if (points == 100) {
overshot = false;
break Loop;
}
points = 100 - (points - 100);
System.out.println("Overshot by " + (points - 100) + " points.");
Input = sc.nextLine();
parseSentence(Input);
}
System.out.println("Congratulations you win!");
sc.close();
}
public static int parseSentence(String input) {
String[] pieces = input.split("\\s+");
for (int y = 0; y < pieces.length; y++) {
if (pieces.length > 1) {
if (y == 0) {
parseWord(input);
} else {
parseWord(input, y);
}
} else {
parseWord(input);
}
}
return points;
}
public static int parseWord(String input) {
String[] pieces = input.split("\\s+");
String charList = "aeiouyAEIOUY";
String consanantList
= "bcdfghjklmnpqrstvwxzBCDFGHJKLMNPQRSTVWXZ";
int pointsTemp = 1;
for (int x = 0; x < pieces[0].length(); x++) {
if (charList.indexOf(pieces[0].charAt(x)) != -1) {
pointsTemp *= 2;
} else if (consanantList.indexOf(pieces[0].charAt(x))
!= -1) {
pointsTemp++;
}
}
points = pointsTemp;
return points;
}
public static int parseWord(String input, int number) {
String[] pieces = input.split("\\s+");
String charList = "aeiouyAEIOUY";
String consanantList
= "bcdfghjklmnpqrstvwxzBCDFGHJKLMNPQRSTVWXZ";
int pointsTemp = 1;
for (int x = 0; x < pieces[number].length(); x++) {
if (charList.indexOf(pieces[number].charAt(x)) != -1) {
pointsTemp *= 2;
} else if (consanantList.indexOf(pieces[number].charAt(x)) != -1) {
pointsTemp++;
}
}
points += pointsTemp;
return points;
}
}
You are not using the value returned by the parseSentence method.
Edit: I tried to rewrite this to be as close your original code with making the changes I feel where necessary.
Now Obviously your teacher has requirements and we can't go against that, but some points of interest you should keep in mind.
Multi Splitting
In your example you split the text to get the amount of words. Then instead of looping the already split text. You are sending the original input and then splitting it again. The "Double" splitting is why you needed "three" methods. If you don't double split you can simply loop the length from the single split and just use a single ParseWord method.
Deducting Values
In your example you take away 100 if the player overshot. The problem with this is let's say the person received a score like 200. Then it would loop twice to lower the value submitting the "You overshot message" twice. However let's say by some magical way a score of 100,000,000 was received. Then as you can see we would loop 1 million times to deduct this value essentially creating an not infinite but might as well be infinite loop.
To resolve this problem we simply do the below.
Value = Value % 100.
This will give us the remainder of our Value between 0 and 99. I.e. 167 will equal 67 and 12384 will be equal 84.
Using String (IndexOf)
What this does is takes the Character you provided and loop iterates over the String you provided. The worst case is 12 loops. There's also a lot of other stuff String and IndexOf do that is extra work and I recommend staying away from it if you can.
The alternative solution which I did is take the character and use " | 32" on it. I'm not going to go deep into how bits work, but basically these characters are 8 bit values but we only use 7 of it's bits ranging from 32 to 127. The amount of bits is like the power of 2. so 2^7 = 128 and 2^8 = 256. When we perform the "|" we are turning a bit on so if it's already on it won't change the value.
So in our example let's say we have the value 64.
This is bit 6 turned on. Now we want to turn on bit 5 "32" so the value becomes 96, but if we already had the value 96 and we turn bit 32 on it will still be 32.
Full List of ASCII Characters..
https://www.ascii-code.com/
The Game Loop
In your example you created "TWO" game loops the first one is when you start off, but once you overshot your score you enter the second loop and forget the first one. The problem is now your "Enter Words" and "You Undershot" code are never used anymore. So all someone will see is the line to enter text with no information on what to do or what occurred unless they overshot then they get the overshot message.
To fix this I made a single Game Loop which processes until the code ends via the SCORE == 100. You can see in the code that we begin every game loop with "Enter Words: " and parse the sentence. Then we add up our score and compare. If we undershot we simply restart the loop and try again. If we overshot we reduce the score and try again. If we succeeded we prompt the user if they would like to play again or end the game. Playing again will set the SCORE to 0 and start over the loop. Ending the game will "BREAK" the loop and cause it to end.
The Full Working Code With Recommended Changes
Feel free to comment if you need additional assistance.
import java.util.*;
public class WordGolf1
{
private static int SCORE = 0;
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
while (true)
{
System.out.print("\n\nEnter word: ");
ParseSentence(sc.nextLine());
if (SCORE == 100)
{
System.out.print("\nYou Won! Would you like to play again: Y/N?");
if ((sc.nextLine().charAt(0) | 32) == 'y')
{
SCORE = 0;
System.out.print("\nResetting Game...");
} else {
break;
}
}
else
{
if (SCORE > 100)
{
int overshot = SCORE - 100;
SCORE = SCORE % 100;
System.out.print("\nYou Overshot By " + overshot + " Points. You now have " + SCORE + " points.");
} else {
System.out.print("\nYou currently have " + SCORE + " points you need " + (100 - SCORE) + " more.");
}
}
}
}
private static int ParseSentence(String input)
{
String[] split = input.split(" ");
for (Strng s : input)
SCORE += ParseWord(s);
}
private static int ParseWord(String word)
{
int value = 1;
for (int i = 0; i < word.length(); ++i)
{
int c = (int)word.charAt(i) | 32;
if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u')
{
value *= 2;
} else {
value += 1;
}
}
return value;
}
}
Related
Where the commented section is, it says that there is a StackOverflowError - null. I am trying to get it to make random numbers to match up with an inputted value. The goal of this code is to do the following:
Accept a top number (ie 1000 in order to have a scale of (1-1000)).
Accept an input as the number for the computer to guess.
Computer randomly guesses the first number and checks to see if it is correct.
If it is not correct, it should go through a loop and randomly guess numbers, adding them to an ArrayList, until it guesses the input. It should check to see if the guess is already in the array and will generate another random number until it makes one that isn't in the list.
In the end, it will print out the amount of iterations with the count variable.
Code:
import java.util.*;
public class ArrNumGuess
{
public static Integer top, input, guess, count;
public static ArrayList <Integer> nums;
public static void main ()
{
System.out.println("Please enter the top number");
top = (new Scanner(System.in)).nextInt();
System.out.println("Please enter the number to guess (1 - " + top + ")");
input = Integer.parseInt(((new Scanner(System.in)).nextLine()).trim());
nums = new ArrayList<Integer>(); //use nums.contains(guess);
guess = (new Random()).nextInt(top) + 1;
nums.add(guess);
System.out.println("My first guess is " + guess);
count = 1;
if(guess != input)
{
guesser();
}
System.out.println("It took me " + count + " tries to find " + guess + " and " + input);
}
public static void guesser()
{
boolean check = false;
while(!check)
{
guess = (new Random()).nextInt(top) + 1; //Stack Overflow - null
if(nums.contains(guess) && !(guess.equals(input)))
{
count--;
guesser();
}
else if(guess.equals(input))
{
check = true;
System.out.println("My guess was " + guess);
// nums.add(guess);
count++;
}
else
{
System.out.println("My guess was " + guess);
nums.add(guess);
count++;
}
}
}
}
In guesser() method, you're invoking itself:
if(nums.contains(guess) && !(guess.equals(input)))
{
count--;
guesser();
}
There is quite a possibility it will never end. But all that is in while loop, so why not get rid of recurrence and do this in an iterative style?
OK - a different approach to your guesser for fun. Enumerate a randomized sequence of numbers in specified range (1 to 'top') and find the guess in the list whose index is effectively the number of "attempts" and return.
(BTW - #Andronicus answer is the correct one.)
/** Pass in 'guess' to find and 'top' limit of numbers and return number of guesses. */
public static int guesser(int guess, int top) {
List<Integer> myNums;
Collections.shuffle((myNums = IntStream.rangeClosed(1, top).boxed().collect(Collectors.toList())), new Random(System.currentTimeMillis()));
return myNums.indexOf(guess);
}
You are making it more complicated than it needs to be and introducing recursion unnecessarily. The recursion is the source of your stack overflow as it gets too deep before it "guesses" correctly.
There is a lot of sloppiness in there as well. Here's a cleaned up version:
import java.util.*;
public class Guess {
public static void main(String args[]) {
System.out.println("Please enter the top number");
Scanner scanner = new Scanner(System.in);
int top = scanner.nextInt();
System.out.println("Please enter the number to guess (1 - " + top + ")");
int input = scanner.nextInt();
if (input < 1 || input > top) {
System.out.println("That's not in range. Aborting.");
return;
}
ArrayList <Integer> nums = new ArrayList<>();
Random rng = new Random(System.currentTimeMillis());
while(true) {
int guess = rng.nextInt(top) + 1;
if (!nums.contains(guess)) {
nums.add(guess);
if (nums.size() == 1) {
System.out.println("My first guess is " + guess);
} else {
System.out.println("My guess was " + guess);
}
if (guess == input) {
System.out.println("It took me " + nums.size() + " tries to find " + guess);
break;
}
}
}
}
}
I'm doing an assignment in school and although I've checked through the entire written material I cannot for the life of me find out how to do this. We are supposed to enter strings like "0123 B" and the B at the end of the string is suppose to represent bronze and then add ++ to the Bronze integer. Then print the number of medals.
My issue here is that I'm trying to take the final character from the string (B, S, or G) and then add to that, but the thing is, it's a String and not a character. So I can't use medal.charAt(5).
Here is my code below:
EDITED, CODE IS SOLUTION
import java.util.Scanner;
public class CountMedals {
public static void main(String[] args) {
int bronze = 0;
int silver = 0;
int gold = 0;
int totalMedals = 0;
int incorrectMedals = 0;
char gol = 'G';
char sil = 'S';
char bro = 'B';
String medal = " ";
Scanner in = new Scanner(System.in);
System.out.println("Please enter the event number followed by the first letter of the medal type." +
" (I.E. \"0111" + " B\"). Type exit once completed");
while (!medal.equals("")) {
medal = in.nextLine();
if (medal.charAt(medal.length() - 1) == bro)
{
bronze++;
totalMedals++;
}
else if (medal.charAt(medal.length() - 1) == sil)
{
silver++;
totalMedals++;
}
else if (medal.charAt(medal.length() - 1) == gol)
{
gold++;
totalMedals++;
}
else if (medal.equals("exit"))
{
System.out.println("Gold medals: " + gold);
System.out.println("Silver medals: " + silver);
System.out.println("Bronze medals: " + bronze);
System.out.println("Total medals: " + totalMedals);
System.out.println(incorrectMedals + " incorrect medal(s) entered.");
}
else{
incorrectMedals++;
}
}
}
}
Just make gol, sil, and bro into chars instead of Strings.
char gol = 'G';
char sil = 'S';
char bro = 'B';
After that change, you should be able to use
medal.charAt(5) == gol
no problem.
Edit
To make this even more generic, you could use
medal.charAt(medal.length() - 1) == gol
which will always pull the last character, thereby avoiding errors with input that has less than 5 indices.
Why does the second while loop while (numberOfTries < 2) cancel both while loops? It runs perfect if there is no incorrect answer. But let's say I select 4 problems to be made, and I am only on the first problem. I give the incorrect answer 2 times so the program should say Incorrect two times and then give me a new question because while (numberOfTries < 2) should force it to break from that loop. But it doesn't, it just quits the whole thing. I know it has to be a logic issue, so what am I missing?
import java.util.Random;
import java.util.Scanner;
public class Howthe {
public static void main(String[] args) {
// Open Scanner
Scanner scan = new Scanner(System.in);
// Ask user to choose number of problems to be made.
// Can only choose 4, 9, or 16
System.out.print("Choose a number of problems to be made (4, 9, 16): ");
int userChoiceOfProblems = scan.nextInt();
// Ask user to choose a number between 0 and 12
System.out.print("\nChoose a number between 0 and 12: ");
int userNumberBetween0and12 = scan.nextInt();
// Ask user to choose between add/sub or multiply/divide
System.out.println("\nChoose to:"
+ "\n0: add/sub your chosen number"
+ " and the randomly generated number: "
+ "\n1: multiply/divide your chosen number"
+ " and the randomly generated number: ");
int userArithmeticChoice = scan.nextInt();
int counter = 0;
String equationString;
int equationAnswer;
int numberOfAnswersRight = 0;
int numberOfTries = 0;
int userAnswerToQuestion;
if (userArithmeticChoice == 0){
while (counter < userChoiceOfProblems){
// Create random number to decide if add or sub used.
// add is equal to 0 and sub is equal to 1
Random rand = new Random();
int randomNumberBetween0and1 = rand.nextInt(1) + 0;
// Create random number that is multiplied by userNumberBetween0and12
int randomNumberBetween0and12 = rand.nextInt(12) + 0;
// Add and increase counter by 1
if (randomNumberBetween0and1 == 0){
// If numberOfTries is more than 2, then display answer.
while (numberOfTries < 2){
// Compute the right answer (addition).
equationAnswer = userNumberBetween0and12 + randomNumberBetween0and12;
// Produce string of equation, then display string (addition).
equationString = userNumberBetween0and12 + " + "
+ randomNumberBetween0and12;
System.out.println(equationString);
userAnswerToQuestion = scan.nextInt();
// If answer is right, increase numberOfAnswersRight.
if (userAnswerToQuestion == equationAnswer){
numberOfAnswersRight++;
System.out.println("Correct!");
break;
}
// If answer is wrong, continue loop and increase numberOfTries
else if (userAnswerToQuestion != equationAnswer){
numberOfTries++;
System.out.println("Incorrect");
}
} // end of while (numberOfTries < 2 && !quit)
counter++;
}
} System.out.println("Yout got " + numberOfAnswersRight + " problem(s) right!");
}
}
}
numberOfTries is initialized outside of your loops. Once you try twice, it never gets set back to 0 which causes the loops to skip and finish on the next question because numberOfTries is already 2.
So I have the game already programmed. You take turns against the computer picking 1-3 straws and the point of the game is to leave the opponent with 1 straw. That entire section works, but now I have to program the Computer to get smarter through consecutive play.
I'm not entirely sure how this is done, however. The way it was explained to me was that you have 4 "cups", which I assume are arrays. Each cup contains the moves, (1, 2, 3). During the computer's turn it randomly picks a cup and randomly chooses one of the three moves. If that move doesn't work then it removes it from the cup.
After several games the computer should become unbeatable.I'm going to keep working on this but I'm having a lot of trouble. I've been at it for a couple hours now so I'll just post the raw code without my broken parts.
EDIT: I've added the Cup class at the bottom.
import java.util.*;
public class Nim
{
public static void main(String[] args)
{
Random r = new Random();
Scanner kb = new Scanner(System.in);
String reply;
int straws, cupNum, prevCupNum, prevComputerMove,
computerMove, humanMove, gameNumber = 0, humanWin = 0;
// create an array of four cups
Cup[] cup = new Cup[4];
for (int i = 0; i < cup.length; i++)
cup[i] = new Cup();
System.out.println("Let's play Nim");
System.out.println();
do
{
gameNumber++;
straws = r.nextInt(11) + 10;
// add 1 if necessary so computer nevers starts in losing config
if (straws%4 == 1)
straws++;
System.out.println("Straws to start = " + straws);
System.out.println();
// set to -1 to indicate just starting so no previous move
prevCupNum = -1; // no prev move so init to -1
prevComputerMove = -1;
do
{
cupNum = straws%4; // get cup number
// if cup is empty, then use 1 for move
if (cup[cupNum].count() == 0) // cup empty then move = 1
computerMove = 1;
else
computerMove = cup[cupNum].select(); // get move from cup
/*MISSING CODE
If cup is cup number 1, then remove the previous move
from the previous cup unless already empty*/
System.out.println
("Computer picks up " + computerMove + " straws");
straws = straws - computerMove;
if (straws < 0)
straws = 0;
System.out.println(straws + " left");
System.out.println();
// save this move so it can be removed later if necessary
prevCupNum = cupNum;
prevComputerMove = computerMove;
if (straws == 0)
{
System.out.println("Wow. You win!");
humanWin++;
/* MISSING CODE
Remove last move computer made from cup*/
}
else // get move from human
{
System.out.println();
do
{
System.out.print("Your move: enter ");
if (straws == 1)
System.out.println("1");
else
if (straws == 2)
System.out.println("1 or 2");
else
if (straws >= 3)
System.out.println("1, 2, or 3");
humanMove = kb.nextInt();
} while
(humanMove > 3 || humanMove < 1 || straws - humanMove < 0);
straws = straws - humanMove;
System.out.println(straws + " left");
if (straws == 0)
{
System.out.println();
System.out.println("Ha, ha. You lose!");
}
}
} while (straws > 0);
System.out.println
("Score: Human " + humanWin + " Computer " +
(gameNumber - humanWin));
if (kb.hasNextLine()) // get rid of stray newline
kb.nextLine();
System.out.println();
System.out.println("Want to play another game? Hit enter.");
System.out.println
("Or are you too CHICKEN? In that case, type in quit.");
reply = kb.nextLine();
reply = reply.trim();
if (reply.length() > 4) // require only 1st 4 to be quit
reply = reply.substring(0, 4);
}
while (!reply.toLowerCase().equals("quit"));
}
public class Cup
{
ArrayList<Integer> c = new ArrayList<Integer>();
public Cup()
{
c.add(1);
c.add(2);
c.add(3);
}
//-----------------------
public int count()
{
return c.size();
}
//-----------------------
public int select()
{
// random is a static method in Math that returns a double
// value greater than or equal to 0.0 and less than 1.0.
int index = (int)(c.size()*Math.random());
return c.get(index);
}
//-----------------------
public void remove(Integer move)
{
c.remove(move);
}
}
I'm afraid I don't understand the 'cup' strategy. There is a much simpler strategy to force the machine to learn through play, however. As it plays, record the number of straws it leaves after its turn. If it loses then ensure that it doesn't leave that many straws in turns in subsequent games.
Your code would look something like:
class AI_Player {
private final Set<Integer> losingMoves = new HashSet<>();
private final Set<Integer> currentGameMoves = new HashSet<>();
public void startGame() {
currentGameMoves.clear();
}
public int nextMove(int strawsRemaining) {
List<Integer> possibleMoves = Stream.of(1, 2, 3)
.filter(move -> move < strawsRemaining)
.filter(move -> !losingMoves.contains(strawsRemaining - move))
.collect(Collectors.toList());
int move = possibleMoves.get(Random.nextInt(possibleMoves.size()));
currentGameMoves.add(strawsRemaining - move);
return move;
}
public void registerLoss() {
losingMoves.addAll(currentGameMoves);
}
public void registerWin() {
losingMoves.removeAll(currentGameMoves);
}
}
This uses Java 8 streams but it's fairly trivial to convert if you haven't used them yet.
If you run the the game you can see that certain numbers the game cannot guess correctly. For example if your number is 13 the game will loop two times too many and will also guess your number as 12 instead of 13. I think this is an issue with the counting but I've tried tracing the loops repeatedly but cannot find the error. I think the issue mainly lies within my while loop.
//import statements
import java.util.Scanner;
public class Numbers
{
public static void binarySearch()
{
int position=0;
String answer;
int upper_BOUND=100;
int lower_BOUND=0;
Scanner input=new Scanner(System.in);
while( (lower_BOUND <= upper_BOUND))
{
position = (lower_BOUND + upper_BOUND) / 2;
System.out.println("Is your value greater than " + position + "?");
answer=input.next();
if((upper_BOUND-lower_BOUND<=1))
{
break;
}
if (answer.equals("no")) // If the number is > key, ..
{ // decrease position by one.
upper_BOUND = position --;
}
if(answer.equals("yes"))
{
lower_BOUND = position ++; // Else, increase position by one.
}
}
System.out.println("Is your number " + position + "?");
String answer2=input.next();
System.out.println(position+" is the answer.\n Thank you for playing the guessing game.");
//else
// System.out.println("Bruh pick a number from 1 to 100 ");
}
}
......
tester class
public class NumberGuesser
{
public static void main(String[] args)
{
int[ ] num = new int [100];
// Fill array
for (int i = 0; i <= 99; i++)
num[i]=i;
//The search method
Numbers.binarySearch();
}
}
Your issue should be with the increment that you do in "lower_BOUND = position ++; " here what happens is when you increment the position value, the "++" first increments and then assigns the value to position variable. The lowerbound is not actually assigned the incremented value of position but old value of positon. So please make a change to "lower_BOUND = ++ position ; "
Like below
if(answer.equals("yes"))
{
lower_BOUND = ++ position ; // Else, increase position by one.
}
And also my suggestion is to check your " if((upper_BOUND-lower_BOUND <= 1))" condition. I guess the condition should be like this " if((upper_BOUND-lower_BOUND == 0)) "
And please remove unused code in your "NumberGuesser" class, this will confuse people who are trying to answer your question.