I have an array of Strings and when the user taps the button inside my app I generate a random number and use it to select a random String from my facts[] array. However, I tried improving my code so that the same random number would "never" occur(leading to the same String been shown to the user). Despite my efforts, my "Check" blocks doesn't seem to work since it generates a random fact when I click the button for the first time and then it does nothing. Please help me figure out the correct logic behind this and maybe write a more efficient code-block.
My current logic: check if the random number that has been generated already exists in my int[] factsCheck array and if it does create another one.If it doesn't add it to the array so that the program knows it has already been created once.
int[] factsCheck = new int[facts.length];
boolean isNotNewRandomNumber = true;
int count = 0;
int randomNumberToReturn;
private void initFactsCheck() {
for(int i=0; i<=factsCheck.length;i++) {
factsCheck[i] = -1;
}
}
String getFact() {
// Randomly select a fact
Random randomGenerator = new Random();
while(isNotNewRandomNumber) {
randomNumberToReturn = randomGenerator.nextInt(facts.length);
for(int i = 0; i<factsCheck.length; i++) {
if(factsCheck[i] == randomNumberToReturn) {
break;
} else {
count++;
}
}
if (count == factsCheck.length) {
// Doesn't exist
isNotNewRandomNumber = false;
}
count = 0;
}
return facts[randomNumberToReturn];
}
In the beginning of getFacts(), add this:
isNotNewRandomNumber = true;
The problem is that you isNotNewRandomNumber to false the first time you call getFacts(), then you never set it to true again, so you will never go into the while loop again.
I'm not sure that's all you need to do. There might be other errors too. It seems unnecessary to have a for loop inside the while loop. There must be a better way. And you probably want to set factsCheck[x] to some appropriate value just before the return statement.
Related
I'm building a very simple Android-app without almost any knowledge in java programming.
The application is almost done and what the app does is that when I press a button it shows a value randomly from an string array.
What I would like to achieve is a small "animation" where it quickly scrolls through all the values in the array and then randomly stops. Almost as a "spinning wheel of text".
I have figuered out that maybe a Timer-function is the way to go. Would be great if someone could help me out.
This is the array with all values:
final String[] myNames = {
"Sax12345",
"Tyg12345",
"Djur12345",
"Hund12345",
"Trafik2019",
"Gruvan2019",
"Kaffe2019"
};
And this is what happens when the button is pressed:
genButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Random randGen = new Random();
int rando = randGen.nextInt(7);
textOne.setText(myNames[rando]);
}
});
Simply duplicate (or even multiplicate - depends on the animation length) values inside your array and shuffle this. Then in a loop, iterate over the table, putting with some interval the following values to the view, and stop on the last element - this one will be the random one (thanks to the shuffle method)
Something like
List<String> presentationList = new ArrayList<>();
for(int i = 0; i < HOW_MUCH_SHOULD_IT_BE_MULTIPLICATED; i++) {
presentationList.addAll(Arrays.asList(myNames));
}
Collections.shuffle(presentationList);
String winnerString = presentationList.get(presentationList.size() - 1); //this is basically winner string
// now the time for 'animation'
for(String value : presentationList) {
textOne.setText(value);
// wait for a Xms
}
I'm trying to make a number guessing game. When the user presses the start button, the program will randomly generate a number. The user can then input a number and the program will tell the user if they need to go higher or lower, after 8 guesses the program stops.
I have managed to generate a random number and write a loop that allows the user to guess 8 times. There are no compiling errors but I get a lot of errors when pressing the "guessBtn". This is my code:
private void startBtnActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
Random rand = new Random();
int getal = rand.nextInt(100)+1;
}
private void guessBtnActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
String randomNumTxt = startBtn.getText();
int getal = Integer.parseInt(randomNumTxt);
String gokNumTxt = guessTxt.getText();
int gok = Integer.parseInt(gokNumTxt);
int aantalGok = 0;
while ((gok != getal) && (aantalGok <9)){
if (gok < getal){
antwoordLbl.setText("Hoger!");
aantalGok++;
}
if (gok > getal){
antwoordLbl.setText("Lager!");
aantalGok++;
}
}
if (gok == getal){
antwoordLbl.setText("Geraden!");
}
else if (aantalGok == 8){
antwoordLbl.setText("Jammer, het getal was "+getal);
}
}
I figured that I'm doing something wrong when trying to read the randomly generated number but I can't figure out how to do it correct. Any tips?
From the comments and based on your code, consider the below class where actual stores a randomly generated value each time the "start" button is clicked. As an instance variable (not class variable as mentioned in the comment), the value continues to be available between methods of the same instance of the class.
public class MyFrame extends JFrame implements ... {
// keep track of a randomly generated value
private int actual; // part of the class, not within a method
// each instance of the class will have its own value
// the variable exists as long as the instance exists
private void startBtnActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
Random rand = new Random(); // this could also be an instance variable instead of creating a new one each time
// int getal = rand.nextInt(100)+1; getal would be a local method variable and is lost when the method returns
actual = rand.nextInt(100)+1; // keep track of the random value
}
private void guessBtnActionPerformed(java.awt.event.ActionEvent evt) {
...
int guess = ... // whatever the user guessed
if (guess == actual) {
...
} else if (guess > actual) {
...
} else {
...
}
}
}
Further reading: search on "java variable scope".
I'm a bit new to Android Studio and I want to make small quiz app. On the start screen, there are two buttons. With the first button, you just click through your questions and you can start at a specific question number if you want (this is already working). With the second button, I wand to create a random mode BUT every question should only be asked once. So there should not be the possibility to get the same questions twice.
For that I created an Array:
public ArrayList<Integer> questionsDone = new ArrayList<>();
And got the lenght of the Question Array:
public int maxQuestions = QuestionLibrary.nQuestions.length;
then I have a function for updating the question:
private void updateQuestion(){
//RANDOM MODE
if (startNumber == -1) {
if (questionsDone.size() >= maxQuestions) {
finishQuiz();
} else {
nQuestionNumber = (int) (Math.random() * (maxQuestions));
do {
if (questionsDone.contains(nQuestionNumber)) {
nQuestionNumber = nQuestionNumber - 1;
if (nQuestionNumber == -1) {
nQuestionNumber = maxQuestions-1;
}
} else {
questionsDone.add(nQuestionNumber);
notDone = true;
}
} while (notDone = false);
}
}
nQuestionView.setText(nQuestionLibrary.getQuestion(nQuestionNumber));
nButtonChoice1.setText(nQuestionLibrary.getChoice1(nQuestionNumber));
nButtonChoice2.setText(nQuestionLibrary.getChoice2(nQuestionNumber));
nButtonChoice3.setText(nQuestionLibrary.getChoice3(nQuestionNumber));
So my idea was that when I start random mode, I pass the value "-1". If the size of the array (questions were done) equals the number of the available questions the quiz should stop. If not, I just get a random number and multiply it by the number of questions. Then there is a do-while function which makes sure that if the questionsDone-Array already contains the number it will get a new number and after getting a number which is not in the array it will be stored in the array.
This is what the app does when I click on random mode:
It always shows a random question but sometimes one questions are asked twice and more. And suddenly it stops (the app is loading the result page) but the stop does not come with a pattern. When I have 7 questions, each question is minimum asked once and sometimes it stops after 15, sometimes after 20 questions and so on.
Does someone know why?
Since I wanted to give an update to both of you, I posted an anwser. Thank you guys for the good input. It works now and this is how I got it working:
First I created an array:
public ArrayList<Integer> availableQuestions = new ArrayList<>();
Then i put integers in the array starting by 0 and ending maxQuestions-1 and I shuffled the values:
if (startNumber == -1) {
Integer i = 0;
do {
availableQuestions.add(i);
i++;
}while (i < maxQuestions);
Collections.shuffle(availableQuestions);
}
Then on every button click this function starts to work (j was declared as an integer with the value 0 before):
if (startNumber == -1) {
nQuestionNumber = availableQuestions.get(j);
j++;
}
Instead of keeping QuestionsDone, I suggest to keep QuestionAvailable (i.e. not yet answered), as indices of questions in the library
List<Integer> availableQuestions = null;
...................................................
if (startNumber == -1) {
if (availableQuestions.isEmpty()) {
finishQuiz();
availableQuestions = null;
} else {
if (availableQuestions == null) {
// Starting a new quiz
availableQuestions = new List<Integer>(maxQuestions);
for (int i=0; i<maxQuestons; i++) availableQuestions.Add(i);
}
int nQuestionOrder = (int) (Math.random() * availableQuestions.size());
nQuestionNumber = availableQuestions.get(nQuestionOrder);
availableQuestions.removeAt(nQuestionOrder);
}
}
I'm trying to generate a new unique identifier for each object in a class, without using a static nextID field to just increment. Using that will create complications when unloading and unloading the program.
I came up with a solution to loop through the objects in a static method checking them all but for some unknown reason to me, it won't exit the while-loop.
I have been testing it in ideone.com here trying to create 5 objects to begin with, though it won't even create one.
Without having to go to the link to view the whole testing code, below is the method I'm using.
public static int newRandomID() {
int randomID = 0;
boolean notUnique = true;
while (notUnique) {
randomID = (int) (Math.random() * 999999 + 1);
for (Example e : examples) {
if (e.ID == randomID) {
notUnique = true;
break;
}
notUnique = false;
}
}
return randomID;
}
Have I just made a stupid mistake that I'm too blind to see, or is there a reason that this isn't working?
If all you need is a unique identifier (that need not be sequential) and it dosn't have to be an integer, have a look at java.util.UUID
your notUnique is bit confusing and i think you are doing it wrong in here
if (e.ID == randomID) {
notUnique = true;
break;
}
you dont need to break the statement if the id exists. i changed you code may be this helps.
int randomID = 0;
boolean ContinueLoop = true;
while (ContinueLoop) {
randomID = (int) (Math.random() * 999999 + 1);
boolean exist = false;
for (Example e : examples) {
if (e.ID == randomID) {
exist = true;
}else{
exist = false;
break;
}
}
if(exist==false){
ContinueLoop = false;
}else{
ContinueLoop = true;
}
}
return randomID;
Tried to execute your code (from the link you sent):
After you created and printed 50 new ids, I tried to generate 150,000 more:
for (int i = 0; i < 150000; i++)
new Example();
and... it works perfectly fine! Just took it a minute or so (which makes sense).
If I try to create only 15,000 records it works in less than a second.
Which leads me to the conclusion that miss rate is exponentially high and starts to be unbearable once you reach 15% of the ids capacity.
Don't continue with this solution.
Use a different approach such as a stored sequential number (if you store the records). If you don't store the records, I don't see a reason why not to use a static int variable.
QUESTION:
How can I read the string "d6+2-d4" so that each d# will randomly generate a number within the parameter of the dice roll?
CLARIFIER:
I want to read a string and have it so when a d# appears, it will randomly generate a number such as to simulate a dice roll. Then, add up all the rolls and numbers to get a total. Much like how Roll20 does with their /roll command for an example. If !clarifying {lstThen.add("look at the Roll20 and play with the /roll command to understand it")} else if !understandStill {lstThen.add("I do not know what to say, someone else could try explaining it better...")}
Info:
I was making a Java program for Dungeons and Dragons, only to find that I have come across a problem in figuring out how to calculate the user input: I do not know how to evaluate a string such as this.
I theorize that I may need Java's eval at the end. I do know what I want to happen/have a theory on how to execute (this is more so PseudoCode than Java):
Random rand = new Random();
int i = 0;
String toEval;
String char;
String roll = txtField.getText();
while (i<roll.length) {
check if character at i position is a d, then highlight the numbers
after d until it comes to a special character/!aNumber
// so if d was found before 100, it will then highlight 100 and stop
// if the character is a symbol or the end of the string
if d appears {
char = rand.nextInt(#);
i + #'s of places;
// so when i++ occurs, it will move past whatever d# was in case
// d# was something like d100, d12, or d5291
} else {
char = roll.length[i];
}
toEval = toEval + char;
i++;
}
perform evaluation method on toEval to get a resulting number
list.add(roll + " = " + evaluated toEval);
EDIT:
With weston's help, I have honed in on what is likely needed, using a splitter with an array, it can detect certain symbols and add it into a list. However, it is my fault for not clarifying on what else was needed. The pseudocode above doesn't helpfully so this is what else I need to figure out.
roll.split("(+-/*^)");
As this part is what is also tripping me up. Should I make splits where there are numbers too? So an equation like:
String[] numbers = roll.split("(+-/*^)");
String[] symbols = roll.split("1234567890d")
// Rough idea for long way
loop statement {
loop to check for parentheses {
set operation to be done first
}
if symbol {
loop for symbol check {
perform operations
}}} // ending this since it looks like a bad way to do it...
// Better idea, originally thought up today (5/11/15)
int val[];
int re = 1;
loop {
if (list[i].containsIgnoreCase(d)) {
val[]=list[i].splitIgnoreCase("d");
list[i] = 0;
while (re <= val[0]) {
list[i] = list[i] + (rand.nextInt(val[1]) + 1);
re++;
}
}
}
// then create a string out of list[]/numbers[] and put together with
// symbols[] and use Java's evaluator for the String
wenton had it, it just seemed like it wasn't doing it for me (until I realised I wasn't specific on what I wanted) so basically to update, the string I want evaluated is (I know it's a little unorthodox, but it's to make a point; I also hope this clarifies even further of what is needed to make it work):
(3d12^d2-2)+d4(2*d4/d2)
From reading this, you may see the spots that I do not know how to perform very well... But that is why I am asking all you lovely, smart programmers out there! I hope I asked this clearly enough and thank you for your time :3
The trick with any programming problem is to break it up and write a method for each part, so below I have a method for rolling one dice, which is called by the one for rolling many.
private Random rand = new Random();
/**
* #param roll can be a multipart roll which is run and added up. e.g. d6+2-d4
*/
public int multiPartRoll(String roll) {
String[] parts = roll.split("(?=[+-])"); //split by +-, keeping them
int total = 0;
for (String partOfRoll : parts) { //roll each dice specified
total += singleRoll(partOfRoll);
}
return total;
}
/**
* #param roll can be fixed value, examples -1, +2, 15 or a dice to roll
* d6, +d20 -d100
*/
public int singleRoll(String roll) {
int di = roll.indexOf('d');
if (di == -1) //case where has no 'd'
return Integer.parseInt(roll);
int diceSize = Integer.parseInt(roll.substring(di + 1)); //value of string after 'd'
int result = rand.nextInt(diceSize) + 1; //roll the dice
if (roll.startsWith("-")) //negate if nessasary
result = -result;
return result;
}