Pseudo-Random sequence generator based on seed - java

I managed to make a random sequence based on a seed, but now i am trying something else. basically, it generates a number(Based on a seed), then checks if that number is already in the array, then if it isn't in the array, it adds it to the array, and if it is, it goes on to the next one. However, my program works fine until it hits a 0, then it just keeps repeating 0. here is my code:
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.println("Enter a seed(One letter)");
String input = s.nextLine();
char a = input.charAt(0);
int b = ((int) a) - 96;
Random rnd1 = new Random(b);
int[] letters = new int[25];
boolean isSame = false;
for(int i = 0; i < 26; i++)
{
int c = rnd1.nextInt(26);
for(int x = 0; x < i; x++)
{
if(letters[x] == c)
{
isSame = true;
}
}
if(isSame == false)
{
letters[i] = c;
}
System.out.println(letters[i]);
}
}

Break the problem up in to parts, first a method to test for a value in letters between indices 0 and p like
private static boolean match(int[] letters, int p, int val) {
for (int i = 0; i < p; i++) {
if (letters[i] == val) {
return true;
}
}
return false;
}
Then a method to fill an int[] with a provided Random to a given length. Since you want the int[] to be unique, you can use an inner do while loop while the next symbol is already present. Like,
private static int[] fill(Random rnd1, int length) {
int[] letters = new int[length];
for (int i = 0; i < length; i++) {
int c;
do {
c = rnd1.nextInt(length);
} while (match(letters, i, c));
letters[i] = c;
}
return letters;
}
Then you can call that (and you might use Arrays.toString(int[])) to output the array like
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
System.out.println("Enter a seed(One letter)");
String input = s.nextLine();
char a = input.charAt(0);
int b = ((int) a) - 96;
Random rnd1 = new Random(b);
int[] letters = fill(rnd1, 26);
System.out.println(Arrays.toString(letters));
}

Two quick fixes:
1) The for loop is going up to index 25 which is ArrayIndexOutOfBoundsException as your array is of length 25.
for(int i = 0; i < 25; i++)
//Your code
}
2) Replace this code with something that can satisfy the condition as well generate a new random number and then assign it to array.
if (letters[x] == c) {
isSame = true;
}

It looks like you want to shuffle the numbers 0-25, that is, storing each number exactly once, but in a random position in the array. This is also known as generating a random permutation. Assuming this is the case, then there are two problems with your code:
isSame needs to be set to false when you pick a new random number, otherwise once a number is repeated, isSame is true for all subsequent numbers and nothing new is written to the array.
When a random number is picked that was already in the array (when isSame is found to be true), a new number needs to be found for that index. In your code, that index is skipped instead, and the value at that index will default to 0.
It is perhaps also worth mentioning that there are more efficient algorithms for this problem. This method will keep picking a lot of random numbers that are then just discarded, which is wasteful. The Fisher-Yates shuffle solves this (pseudocode from wikipedia):
for i from 0 to nāˆ’2 do
j ā† random integer such that i ā‰¤ j < n
exchange a[i] and a[j]

Related

Shuffle a specific number of strings in a String Array in Java

I have a long textfile and I need to shuffle all the words which are longer than 4 letters but the other words need to remain in the same place. This without using the Collections module.
I can manage to shuffle all the strings in the array, but I cant figure out for the life of me how to shuffle only a part.
public static String[] getScramble(String text) {
Random rgen=new Random();
String[] textArray=text.split(" ");
for(int i=0;i<textArray.length;i++){
int randPos=rgen.nextInt(textArray.length);
String temp=textArray[i];
if (textArray[i].length()>4){
textArray[i]=textArray[randPos];
textArray[randPos]=temp;
}else{
textArray[i]=textArray[i];
}
}
return textArray;
Thanks!
You only swap two words if both are larger than 4 characters, otherwise you keep them in the original position:
for(int i = 0; i < textArray.length; i++) {
int randPos = rgen.nextInt(textArray.length);
if (textArray[i].length() > 4 && textArray[randPos].length() > 4){
String temp = textArray[i];
textArray[i]=textArray[randPos];
textArray[randPos]=temp;
}
}
EDIT: if the number of long words is very small compared to the number of short words, this loop may behave badly (since it will fail to swap most of the long words), so you can improve it as follows:
for(int i=0;i<textArray.length;i++){
if (textArray[i].length() > 4) {
// find a long word to swap textArray[i] with
int randPos=rgen.nextInt(textArray.length);
while (textArray[randPos].length() <= 4){
randPos=rgen.nextInt(textArray.length);
}
// swap the two long words
String temp=textArray[i];
textArray[i]=textArray[randPos];
textArray[randPos]=temp;
}
}
When generating the random position for a word that is longer than 4 characters, you check to see if the new position also has a word with more than 4 characters. If not, you keep generating a new random position until you find one that works.
public static String[] getScramble(String text) {
Random rgen = new Random();
String[] textArray = text.split(" ");
for (int i = 0; i < textArray.length; i++) {
if( textArray[i].length() > 4) {
String temp = textArray[i];
int randPos = rgen.nextInt(textArray.length);
while( textArray[randPos].length() <= 4 ){
randPos = rgen.nextInt(textArray.length);
}
textArray[i] = textArray[randPos];
textArray[randPos] = temp;
}
}
return textArray;
}
A situation that might arise is if you have only one word with more than 4 characters, which means it's pointless to even try to randomize them, and you might waste a lot of time generating random positions to no avail. To optimize this, you can first check if you have less than 2 long words, and if so you don't need to do anything.
int longWordCount = 0;
for (int i = 0; i < textArray.length; i++) {
if( textArray[i].length() > 4 )
longWordCount++;
if( longWordCount == 2 )
break;
}
if( longWordCount > 1 ) {
for (int i = 0; i < textArray.length; i++) {
if (textArray[i].length() > 4) {
String temp = textArray[i];
int randPos = rgen.nextInt(textArray.length);
while (textArray[randPos].length() <= 4) {
randPos = rgen.nextInt(textArray.length);
}
textArray[i] = textArray[randPos];
textArray[randPos] = temp;
}
}
}
Here's a version that adapts Durstenfeld's algorithm. Note that ThreadLocalRandom is preferable to Random.
public static String[] getScramble(String text) {
ThreadLocalRandom rgen = ThreadLocalRandom.current();
String[] textArray = text.split(" ");
int[] indices = IntStream.range(0, textArray.length)
.filter(i -> textArray[i].length() > 4)
.toArray();
for (int i = indices.length; i > 1; --i) {
int j = indices[rgen.nextInt(i)];
int k = indices[i - 1];
if (j != k) {
String tmp = textArray[j];
textArray[j] = textArray[k];
textArray[k] = tmp;
}
}
return textArray;
}
The OP didn't say that Streams couldn't be used, only Collections. If that's a problem, one can replace the initialization of indices with a simple loop to initialize an array of int of the same size as textArray, using the variable i to keep track of the number of indices entered (so it would be declared and initialized before the main for loop).

Generate random numbers without duplicates using arrays only

I want to fill an array of size X with random integers from 0 to X with no duplicates. The catch is I must only use arrays to store the collections of int, no ArrayLists. How do I go about implementing this?
I don't understand why I can't seem to get this. But this is my most recent bit of code that fills the list but allows for duplicates.
System.out.print("Zero up to but excluding ");
int limit = scanner.nextInt();
// create index the size of the limit
int [] index = new int[limit];
for(int fill=0;fill<limit;fill+=1){
index[fill] = (limit);
}
int randomNumber = 0;
Random rand = new Random();
int [] randoms = new int[limit];
boolean flag = true;
// CODE TO NOT PRINT DOUBLES
for (int z=0;z<limit;z+=1){
randomNumber = rand.nextInt(limit);
int i=0;
while (i<limit){
if (index[i] == randomNumber){
flag = true;
}
else {
flag = false;
break;
}
i+=1;
}
if (flag == false){
randoms[z] = randomNumber;
index[z] = randomNumber;
}
}
System.out.println("Randoms: "+java.util.Arrays.toString(randoms));
Here's one way to do it:
Create an array of length N
Fill it from 0 to N-1
Run a for loop and swap randomly 2 indices
Code:
// Step 1
int N = 10;
int[] array = new int[N];
// Step 2
for(int i=0; i < N; i++)
array[i] = i;
// Step 3
for(int i=0; i < N; i++) {
int randIndex = (int) (Math.random() * N);
int tmp = array[i];
array[i] = array[randIndex];
array[randIndex] = tmp;
}
Why not rephrase the problem to shuffling an array of integers. First fill the array monotonically with the numbers 0 to X. Then use the Random() function to select one of the X numbers to exchange with the number in position 0. Repeat as many times as you may like. Done.
Here is your bug:
while (i<limit){
if (index[i] == randomNumber){
flag = true;
}
else {flag = false;break;} <--- rest of the array is skipped
i+=1;
}
after you generated a new number, you start to check for equality , however once you find that randomNumber!=index[i] (else statement) you break out of the while. look this: actual array is 3,4,5,1 your new number is 5, you compare it to 3 just to find out that they different so flag is set to false and break out happens.
Consider using another array filled with elements in order from 0 to X. Then, with this array, shuffle the elements around. How do you go about this? Use a loop to traverse through every single element of the array, and for each iteration, choose a random number from 0 to array.length - 1 and switch the elements at the index you're currently on and the random index. This is how it would look like,
In your main, you would have an array initialized by doing this,
int[] arr = new int[10];//10 can be interchangeable with any other number
for(int i = 0; i < arr.length; i++){
arr[i] = i;
}
shuffleArray(arr);
And the shuffle method would look like this,
public int[] shuffleArray(int[] arr){
Random rand = new Random();
for(int i = 0; i < arr.length; i++){
int r = rand.nextInt(arr.length);//generate a random number from 0 to X
int k = arr[i];
arr[i] = arr[r];
arr[r] = k;
}
}

Java Arrays: Finding Unique Numbers In A Group of 10 Inputted Numbers RE:

Java Arrays: Finding Unique Numbers In A Group of 10 Inputted Numbers
I have a problem that I have looked into Doestovsky's question but from his question, I need to know on how to make the part on finding duplicates into a function of it's own:
java.util.Scanner input = new java.util.Scanner(System.in);
int[] numbers = new int[10];
boolean[] usedBefore = new boolean[10];
// Insert all numbers
for (int i = 0; i < numbers.length; i++) {
// Read number from console
numbers[i] = input.nextInt();
// Check if number was inserted before
usedBefore[i] = false;
for(int k = 0; k < i; k++) {
if(numbers[k] == numbers[i]) {
usedBefore[i] = true;
break;
}
}
}
// Print all numbers that were not inserted before
for(int j = 0; j < numbers.length; j++) {
if(!usedBefore[i]) {
System.out.print(String.valueOf(numbers[j])+" ");
}
}
I have tried this part of this code and it worked but I need this to take the part that find duplicates into a function of it's own that is powered by arrays.
Credits to ThimoKl for creating this code.
Let's try something else, using Treeset, and let's get rid of that for for
import java.util.*;
public class duplicate {
private static TreeSet<Integer> numbers = new TreeSet<Integer>();
private static TreeSet<Integer> duplicates = new TreeSet<Integer>();
public static void main (String[] args) {
Scanner input = new Scanner(System.in);
int n=0;
int numberOfIntToRead=10;
for (int i = 0; i < numberOfIntToRead; i++) {
// Read number from console
n=input.nextInt();
// Check if number was inserted before
checkIfDuplicate(n);
}
// Print all numbers that were not inserted more than one time
for (Integer j : numbers) {
System.out.print(j+" ");
}
}
public static void checkIfDuplicate(int n){
if(!numbers.contains(n) && !duplicates.contains(n)){
numbers.add(n);
}else{
numbers.remove(n);
duplicates.add(n);
}
}
}
But if you really want to use arrays an not a Collection of any sort, then you need to declare your arrays as class members, that way you can put the "for" that checks for duplicates in a function a give it your i, and this way you can also put the "for" that does the printing in a function. and give to it numbers.length. That should do the trick.
You can make use of a Set to make finding duplicates easy:
List<Integer> dups = new ArrayList<>();
Set<Integer> set = new HashSet<>();
for (int i : numbers)
if (!set.add(i))
dups.add(i);
This works because Set#add() returns false if it doesn't change as a result if being called, which happens eggnog the set already contains the number - ie it's a dup.

finding the number of pairs of numbers in an array that add up to a number

I am trying to come up with a program that will search inside of an array that is given a length by the user that picks out whether there is a pair of numbers that sum to 7. The idea is that if there is k amount of dice being thrown, how many pairs of numbers out of those dice thrown add up to 7. So far this is all that I could come up with but I am very stuck.
This is the driver class for the program. I have to write a class that will make this driver function properly.
import java.util.Scanner;
public class SevenDriver{
public static void main(String[] args){
System.out.println("Enter number of dice to toss");
Scanner s = new Scanner(System.in);
int diceCount = s.nextInt();
SevenTally t = new SevenTally(diceCount);
int experiments = 1000000;
int wins = 0;
for(int j = 0; j < experiments; j++)
if(t.experiment()) wins++;
System.out.println((double)wins/experiments);
}
}
This is what I have so far. It does not currently work or compile. I am just looking for some ideas to get me going. Thanks!
public class SevenTally{
private int diceCount;
public SevenTally(int die){
diceCount = die;
}
public int genDice(){
return 1 + (int)(Math.random()*6);
}
public boolean experiment(){
boolean[] nums = new boolean[diceCount];
int ranNum;
int sum = 7;
for(int i = 0; i < nums.length; i++){
ranNum = genDice();
if (nums[ranNum] == sum){
return true;
}
}
int left = 0;
int right = nums.length - 1;
while(left<right){
int tempSum = nums[left] + nums[right];
if(tempSum == 7){
return true;
}
else if(tempSum>7){
right--;
}
return false;
}
}
First populate your array of length k with random int in [1;6]
The number of possible pairs in an array of length k is the number of 2-combinations in the array, which is (k-1)*k/2 (http://en.wikipedia.org/wiki/Combination)
You can test all the possible pairs (i,j) in your array like so:
int win = 0;
int tally = 7;
for(int i=0; i<k-1; i++){
for(int j=i+1; j<k; j++){
if(array[i]+array[j] == tally){
win++;
}
}
}
What this does is that it sets the first element of the pair to be the first element of the array, and sums it with the other elements one after the other.
It pairs array[0] with array[1] to array[k-1] at the first pass of the i for loop, that's k pairs.
Then k-1 pairs at second pass, and so on.
You end up with (k)+(k-1)+(k-2)+...+1 pairs, and that's exactly (k-1)*k/2 pairs.
done =]
edit: sorry, haven't read the whole thing. the method experiment() is supposed to return a boolean. you can return win>0?true:false; for example...
This Wiki page has some algorithms to do that. Its not a trivial problem...
You're generating a random number in ranNum, and then using it as an index into the array nums. Meanwhile, nums never gets filled, so no matter which box you index into, it never contains a 7.
What you want to do, if I understand your problem correctly, is fill each space in the array with the result of a die roll, then compare every two positions (rolls) to see if they sum to seven. You can do that using a nested for loop.
Essentially, you want to do this: (written in pseudocode as I'm not a java programmer)
int[] results[numrolls]
for (count = 0 to numrolls-1) { results[numrolls]=dieRoller() }
for (outer = 0 to numrolls-2)
for (inner = outer+1 to numrolls-1)
if (results[outer] + results[inner] == 7) return true
return false;
However, in this case there's an even easier way. You know that the only ways to get a sum of 7 on 2d6 are (1,6),(2,5),(3,4),(4,3),(5,2),(6,1). Set up a 6-length boolean array, roll your dice, and after each roll set res[result] to true. Then return (1-based array used for simplicity) ( (res[1] && res[6]) || (res[2] && res[5]) || (res[3] && res[4]) ).
ArrayIndexOutOfBoundsException means you are trying to access an element of the array that hasn't been allocated.
In your code, you create a new array d of length diceCount, but then you genDice() on always 6 elements.

Where does this program get its numbers from, and why is this caused by increasing 1 array size? (Java)

This program simply is supposed to eliminate duplicates from an array. However, the second for loop in the eliminate method was throwing an out of bounds exception. I was looking and couldnt see how that could be, so I figured I would increase the array size by 1 so that I would get it to work with the only downside being an extra 0 tacked onto the end.
To my surprise, when I increased tracker[]'s size from 10 to 11, the program prints out every number from 0 to 9 even if I dont imput most of those numbers. Where do those numbers come from, and why am I having this problem?
import java.util.*;
class nodupes
{
public static void main(String[] args)
{
int[] dataset = new int[10];
//getting the numbers
for (int i = 0; i <= 9 ; i++)
{
Scanner input = new Scanner(System.in);
System.out.println("Enter a one digit number");
dataset[i] = input.nextInt();
}
int[] answer = (eliminateduplicates(dataset));
System.out.println(Arrays.toString(answer));
}
public static int[] eliminateduplicates(int[] numbers)
{
boolean[] tracker = new boolean[11];
int arraysize = 1;
for(int k = 0; k <= 9; k++)
{
if(tracker[numbers[k]] == false)
{
arraysize++;
tracker[numbers[k]] = true;
}
}
int[] singles = new int[arraysize];
for(int l = 0; l <= arraysize; l++)
{
if(tracker[l] == true)
{
singles[l] = l;
}
}
return singles;
}
}
The exception was occuring at this part
if(tracker[l] == true)
but only when trackers size was 10. At 11 it just prints [0,1,2,3,4,5,6,7,8,9]
EDIT: The arraysize = 1 was a hold over from debugging, originally it was at 0
EDIT: Fixed it up, but now there is a 0 at the end, even though the array should be getting completely filled.
public static int[] eliminateduplicates(int[] numbers)
{
boolean[] tracker = new boolean[10];
int arraysize = 0;
for(int k = 0; k < numbers.length; k++)
{
if(tracker[numbers[k]] == false)
{
arraysize++;
tracker[numbers[k]] = true;
}
}
int[] singles = new int[arraysize];
int counter = 0;
for(int l = 0; l < arraysize; l++)
{
if(tracker[l] == true)
{
singles[counter] = l;
counter++;
}
}
return singles;
}
Since arrays start at 0, your arraysize will be one larger than the number of unique numbers, so your final loop goes through one too many times. In other words "l" (letter l -- try using a different variable name) will get to 11 if you have 10 unique numbers and tracker only has item 0-10, thus an out of bounds exception. Try changing the declaration to
int arraysize = 0;
Once again defeated by <=
for(int l = 0; l <= arraysize; l++)
An array size of 10 means 0-9, this loop will go 0-10
For where the numbers are coming from,
singles[l] = l;
is assigning the count values into singles fields, so singles[1] is assigned 1, etc.
Edit like 20 because I should really be asleep. Realizing I probably just did your homework for you so I removed the code.
arraySize should start at 0, because you start with no numbers and begin to add to this size as you find duplicates. Assuming there was only 1 number repeated ten times, you would've created an array of size 2 to store 1 number. int arraysize = 0;
Your first for loop should loop through numbers, so it makes sense to use the length of numbers in the loop constraint. for( int i = 0; i < numbers.length; i ++)
For the second for loop: you need to traverse the entire tracker array, so might as well use the length for that (tracker.length). Fewer magic numbers is always a good thing. You also need another variables to keep track of your place in the singles array. If numbers was an array of 10 9s, then only tracker[9] would be true, but this should be placed in singles[0]. Again, bad job from me of explaining but it's hard without diagrams.
Derp derp, I feel like being nice/going to bed, so voila, the code I used (it worked the one time I tried to test it):
public static int[] eliminateduplicates(int[] numbers)
{
boolean[] tracker = new boolean[10];
int arraysize = 0;
for(int k = 0; k < numbers.length; k++)
{
if(tracker[numbers[k]] == false)
{
arraysize++;
tracker[numbers[k]] = true;
}
}
int[] singles = new int[arraysize];
for(int l = 0, count = 0; l < tracker.length; l++)
{
if(tracker[l] == true)
{
singles[count++] = l;
}
}
return singles;
}
I feel you are doing too much of processing for getting a no duplicate, if you dont have the restriction of not using Collections then you can try this
public class NoDupes {
public static void main(String[] args) {
Integer[] dataset = new Integer[10];
for (int i = 0; i < 10; i++) {
Scanner input = new Scanner(System.in);
System.out.println("Enter a one digit number");
dataset[i] = input.nextInt();
}
Integer[] arr = eliminateduplicates(dataset);
for (Integer integer : arr) {
System.out.println(integer);
}
}
public static Integer[] eliminateduplicates(Integer[] numbers) {
return new HashSet<Integer>(Arrays.asList(numbers)).toArray(new Integer[]{});
}
}
To answer your question your final loop is going one index more than the size.
The range of valid indexes in an array in Java is [0, SIZE), ie. from 0 up to arraysize-1.
The reason you're getting the exception is because in your loop you're iterating from 0 to arraysize inclusively, 1 index too far:
for(int l = 0; l <= arraysize; l++)
Therefore when you get to if(tracker[l] == true) in the last iteration, l will equal arraysize and tracker[l] will be outside the bounds of the array. You can easily fix this by changing <= to < in your for loop condition.
The reason that the problem goes away when the size of your array is changed from 10 to 11 has to do with arraysize being incremented up to 10 in the for loop above the one causing the problems. This time, singles[10] is a valid element in the array since the range of indexes in your array is now [0, 11).
EDIT: Actually arraysize has the potential to be incremented to 11, I thought it was initialised to 0 in which case it would only get to 10. Either way the above is still valid; the last index you try and access in your array must be 1 less than the length of your array in order to avoid the exception you're getting, since arrays are zero-based. So yeah, long story short, <= should be <.

Categories