Galton Box; Printing a histogram - java

Hey guys I'm writing a program for homework to display the path of a ball in a Galton box
My program so far picks how many balls you want to drop, and the amount of slots at the bottom of the box, and the shows you the random path the ball takes.
The problem I've run into is creating a histogram that depicts the end result.
One important piece of information that I found out, is that every time the ball falls to the right, it moves over one position. So if the print statement is LRLRLR it would be in the 3rd slot because of the 3 R's.
An example of a random histogram it could print:
public class Set_8_P6_21 {
public static void main(String[] args) {
// Declaring variables and calling scanner
int balls, slots;
System.out.println("Enter the amount of balls to drop: ");
Scanner input = new Scanner(System.in);
balls = input.nextInt();
System.out.println("Enter the amount of slots: ");
slots = input.nextInt();
char[] arrayslot = new char[slots-1];
int[] arraypattern = new int[slots-1];
// Nested loop that runs the amount of balls through the machine, and through the amount of slots.
for (int i = 0; i < balls; i++) {
System.out.println();
for (int j = 0; j < slots-1; j++) {
double k = Math.random();
if (k < 0.5) {
arrayslot[j] = 'L' ;
arraypattern[j] = 1; // This is where I am trying to make my histogram
}
else if (k >= 0.5) {
arrayslot[j] = 'R';
arraypattern[j] = 0; // This is where I am trying to make my histogram
}
System.out.print(arrayslot[j]);
}
}}}
If anyone has an idea of how could make this print with the information coming from the loop it would be very helpful, thank you for taking your time to read this.

First, there is no real need for you to keep the array arrayslot, because you print the array element right away, and you don't do anything with it afterwards. So you can just print the character:
if ( k < 0.5 ) {
System.out.print("L");
} else {
System.out.print("R");
}
As you notice, there is also no need for an else if. Either k is less than 0.5, or it is greater than it. So you can just use else.
In order to figure out which slot the ball will fall into, you need to count the Rs. To do so, you simply have an int that gets 0 at the beginning of each ball's simulation, and then you add to it when you roll an "R" above. So your loop expands to:
for (int i = 0; i < balls; i++) {
int ballSlot = 0;
for (int j = 0; j < slots - 1; j++) {
double k = Math.random();
if ( k < 0.5 ) {
System.out.print("L");
} else {
System.out.print("R");
ballSlot++;
}
}
System.out.println();
}
But of course, if we just do that, the value doesn't go anywhere and we lose it after we finish simulating the ball. What you want to do is keep an array which keeps the number of times we hit each slot. So at the end of each ball's simulation, when we know which slot it fell into, we add 1 to the given slot. If we hit the same slot 3 times, we'll have 3 in that spot in the array:
int[] frequencies = new int[slots];
// Nested loop that runs the amount of balls through the machine, and
// through the amount of slots.
for (int i = 0; i < balls; i++) {
int ballSlot = 0;
for (int j = 0; j < slots - 1; j++) {
double k = Math.random();
if ( k < 0.5 ) {
System.out.print("L");
} else {
System.out.print("R");
ballSlot++;
}
}
frequencies[ballSlot]++;
System.out.println();
}
Now, in order to print the histogram properly, you have to start from the tallest column, and work your way down until you reach the "floor" of the histogram, printing an O for every slot that has balls at that frequency. For example, if we have 3 balls in slots 4 and 5, and 1 ball in slot 2, you start from 3, the highest frequency:
For frequency 3, print O in the 4th and 5th positions.
For frequency 2, no new positions at this height, but you have to print O in 4th and 5th again, because otherwise you'll have an O only at the top of the column, instead of its whole height.
For frequency 1, you print O in the 2nd, 4th and 5th positions.
So in order to do this, we have to find out which is the highest frequency first. You can scan the array for that, but actually, you could calculate it while doing the simulations already:
int[] frequencies = new int[slots];
int maxFrequency = 0;
// Nested loop that runs the amount of balls through the machine, and
// through the amount of slots.
for (int i = 0; i < balls; i++) {
int ballSlot = 0;
for (int j = 0; j < slots - 1; j++) {
double k = Math.random();
if ( k < 0.5 ) {
System.out.print("L");
} else {
System.out.print("R");
ballSlot++;
}
}
frequencies[ballSlot]++;
if ( frequencies[ballSlot] > maxFrequency ) {
maxFrequency = frequencies[ballSlot];
}
System.out.println();
}
As you can see, if any frequency is greater than what we have currently as maxFrequency, we keep it as our new maxFrequency.
Now, the printing of the histogram:
for ( int i = maxFrequency; i > 0; i-- ) {
for ( int j = 0; j < slots; j++ ) {
if ( frequencies[j] >= i ) {
System.out.print( "O");
} else {
System.out.print( " ");
}
}
System.out.println();
}
For each position where we don't have a ball at this level, we print a space. For a position where we have a ball, we print an O.
The variable i represents the current level or height of the histogram we are drawing. So the condition if ( frequencies[j] >= i ) means If at this position, we have at least as many balls as the current height.
That's it. Add a System.out.println() before the simulation loop and before the histogram loop to space between the input, the simulation and the histogram, and you are done.

Related

Simulated Annealing for Sudoku Solving

I'm trying to solve a 9x9 sudoku puzzle using Simulated Annealing, but my implementation doesn't seem to be working correctly. It does not even get closer to a lower-cost solution but instead keeps circling around results that cost between 60 and 80.
My cost function returns the sum of three things: Number of repeating digits in each row, column and block (3x3).
And the successor (neighbour) function i implemented changes two randomly selected digits from the 9x9 grid with random values.
And here is my SA function that doesn't work as expected:
public static void simulatedAnnealing() {
Sudoku neighbour; // candidate successor object
final Double temperature = 2.0; // initial temperature
final Double coolingFactor = 0.999; // cooling constant
final int maxIterations = 1000; // number of iterations
for(Double t = temperature; t>1; t*=coolingFactor) {
for(int i = 0; i < maxIterations; i++) {
neighbour = sudoku.generateSuccessor(); // set random neighbour
int delta = neighbour.cost() - sudoku.cost(); // calculate delta
if (delta <= 0) {
sudoku = neighbour; // always accept good step.
} else {
if (Math.exp(-delta / temperature) > Math.random()) { // Simulated annealing
sudoku = neighbour;
}
}
}
System.out.println(sudoku.cost());
if(sudoku.cost() == 0) { break; } // if puzzle is solved
} }
Function for generating successors:
public Sudoku generateSuccessor() {
int[][] newGrid = new int[9][9];
for(int o = 0; o < 9; o ++) { // cloning current grid array
for(int g = 0; g < 9; g ++) {
newGrid[o][g] = grid[o][g];
}
}
Sudoku rndm = new Sudoku(newGrid); // random Sudoku object.
for (int i = 0; i < 2; i++) { // will randomize 2 cells in 9x9 grid.
int rndmCell = rndmValue(); // random digit for randomizing.
int randomRow = rndm(); // random row that will be randomized
int randomCol = rndm(); // random column that will be randomized
// prevent randomizing given cells in sudoku (in problem definition)
boolean shouldContinue = false;
for (Coordinate c : SudokuSolver.concreteCoordinates) {
if (c.row == randomRow && c.col == randomCol) {
shouldContinue = true;
break;
}
}
if (shouldContinue) {
i--;
continue;
}
// prevention end.
rndm.grid[randomRow][randomCol] = rndmCell;
}
return rndm;
}
Cost function:
public int cost() {
if(hasZeros()) { // if grid is not totally filled with numbers don't calculate its cost.
return -1;
}
int cost = 0;
for(int i = 0; i< 9; i++) { // find total collusions in rows&columns.
cost += findNumberOfCollusions(grid[i]); // find collustions at row 'i'.
cost += findNumberOfCollusions(getColumn(grid,i)); // find collustions at column 'i'.
}
for(int r = 0; r < 9; r += 3) { //find total colusions in blocks (3x3).
for(int c = 0; c < 9; c += 3) {
int[] block = new int[9];
int ctr = 0;
for (int i = r; i < r + 3; i++) {
for (int y = c; y < c+ 3; y++) {
block[ctr] = grid[i][y];
ctr++;
}
}
cost += findNumberOfCollusions(block);
}
}
return cost;
}
When i run the program the output is costs between 60 and 80. After that the temperature goes below the limit and the program outputs a solution that costs around that interval. Can anyone tell me what am i doing wrong? Thanks in advance.
I also had a similar problem to the one you describe, my fitness remained stuck (actually though, my problem was with not copying lists in Python). I can't really assure why your code gets stuck, but if I had to guess: the neighbor generation (int rndmCell = rndmValue(); int randomRow = rndm(); int randomCol = rndm();) may be actually doing more harm than good. Imagine that you have a nearly complete sudoku, but out of the blue two of the correct cells that you had now change their value to a complete opposite one, which is not only wrong on the cell itself but also on the row, column and/or 3x3 square. I'm no mathematician, but logic tells me that the more fitting the sudoku is (i.e. the closer its fitness is to 0), the more chances there are to mess up the sudoku by randomly changing cells. This approach may get you stuck on a local minimum easily.
A more "informed" solution for this problem would be to keep one of the three basic restrictions of the sudoku puzzle fixed by, for instance, generating rows that are permutations of the values [1..9], swapping two cells of a random row (thus still fulfilling the restriction), and calculating the fitness only on the columns and on the 3x3 squares. This choice of neighbor generation is usually more effective. If you are interested, this idea comes from the paper Metaheuristics can solve Sudoku puzzles. I can say that this idea helped me a lot and now the algorithm completes sudokus that I provide :)

2D Array Scores

This is the original prompt:
Write program that declares a 2-dimensional array of doubles called scores with three rows and three columns. Use a nested while loop to get the nine (3 x 3) doubles from the user at the command line. Finally, use a nested for loop to compute the average of the doubles in each row and output these three averages to the command line.
Here is my code:
import java.util.Scanner;
public class Scorer {
public static void main(String[] args) {
Scanner scnr = new Scanner(System.in);
double [][] scores = new double[3][3];
double value = 0;
int i = 0;
int j;
while (i < 3) {
j = 0;
while (j < 3) {
System.out.print("Enter a number: ");
value = scnr.nextDouble();
scores[i][j] = value;
j++;
}
i++;
}
int average = 0;
for (i = 0; i < scores.length; i++) {
for (j = 0; j < scores[i].length; j++) {
average += value;
value = value / scores[i][j];
System.out.println(value);
}
}
}
}
The part that I need help on is the nested for loop at the bottom of the code. This code is supposed to compute the average of the numbers that are entered; however, I am confused on how to do that with the nested for loop.
you're almost there!
Here are the things you need to do:
1)you've to initialize the variable 'average' after the first for loop.
because average needs to be 0 i.e., reset after second for loop ends each time.
2)you've defined "value = value / scores[i][j]" . I don't know why you did that, but "value = scores[i][j]" must solve your problem.
3) you should print the average only thrice i.e., after calculating average of each row. so, print average at the end of second for loop.
Hope this makes it clear.
here's the code for your reference:
for (i = 0; i < 3; i++) {
int average = 0;
for (j = 0; j < 3; j++) {
value = scores[i][j];
average += value;
}
System.out.println(average/3);
}
Ever i represents a row, every j represents a column.
You need the average of every row, meaning that for every same i and every different j for that i you need to store the values and calculate the average.
Looks like homework code. We can give you hints but not write it for you :(

Weighted random numbers in 2D Array - Processing

I would like to fill a 3x3 2D array with values 1,2,3.
I need each number to appear for a given times.
For example:
1 to appear 2 times
2 to appear 4 times
3 to appear 3 times
What I need is to store this numbers to array in a random position.
For Example:
1,2,2
3,2,2
1,3,3
I already did this in a simple way using only 2 different numbers controlled by a counter. So I loop through the 2D array and applying random values of number 1 and number 2.
I'm checking if the value is 1 and add it in the counter and the same with number 2. if one of the counter exceeds the number I have set as the maximum appear times then it continues and applies the other value.
Is there any better approach to fill the 3 numbers in random array position?
See code below:
int [][] array = new int [3][3];
int counter1 =0;
int counter2 =0;
for (int i=0; i<3; i++) {
for (int j=0; j<3; j++) {
array[i][j] = (int)random(1, 3); //1,2
if (arrray[i][j]==1) {
counter1++;
} else if (array[i][j] ==2) {
counter2++;
}
//if it is more than 5 times in the array put only the other value
if (counter1>5) {
array[i][j] = 2;
}
//if it is more than 4 times in the array put only the other value
else if (counter2>4) {
array[i][j] = 1;
}
}
}
I finally did this according to this discussion:
How can I generate a random number within a range but exclude some?, with 1D array for tesing, but it does not always works.
Please see attached code:
int []values = new int[28];
int counter1=0;
int counter2=0;
int counter3=0;
for (int i=0; i<values.length; i++) {
if (counter1==14) {
ex = append(ex, 5);
}
if (counter2==4) {
ex =append(ex, 6);
}
if (counter3==10) {
ex =append(ex, 7);
}
values[i] = getRandomWithExclusion(5, 8, ex);
if (values[i]==5) {
counter1++;
} else if (values[i] ==6) {
counter2++;
} else if (values[i] ==7) {
counter3++;
}
}
int getRandomWithExclusion(int start, int end, int []exclude) {
int rand = 0;
do {
rand = (int) random(start, end);
}
while (Arrays.binarySearch (exclude, rand) >= 0);
return rand;
}
I would like to fill the 1D array with values of 5,6 or 7. Each one a specific number. Number 5 can be added 14 times. Number 6 can be added 4 times. Number 7 can be added 10 times.
The above code works most of the times, however somethimes it does not. Please let me know if you have any ideas
This is the Octave/Matlab code for your problem.
n=3;
N=n*n;
count = [1 2; 2 4; 3 3];
if sum(count(:,2)) ~= N
error('invalid input');
end
m = zeros(n, n);
for i = 1:size(count,1)
for j = 1:count(i,2)
r = randi(N);
while m(r) ~= 0
r = randi(N);
end
m(r) = count(i,1);
end
end
disp(m);
Please note that when you address a 2D array using only one index, Matlab/Octave would use Column-major order.
There are a ton of ways to do this. Since you're using processing, one way is to create an IntList from all of the numbers you want to add to your array, shuffle it, and then add them to your array. Something like this:
IntList list = new IntList();
for(int i = 1; i <= 3; i++){ //add numbers 1 through 3
for(int j = 0; j < 3; j++){ add each 3 times
list.append(i);
}
}
list.shuffle();
for (int i=0; i<3; i++) {
for (int j=0; j<3; j++) {
array[i][j] = list.remove(0);
}
}
You could also go the other way: create an ArrayList of locations in your array, shuffle them, and then add your ints to those locations.

Does this program use the Sieve of Eratosthenes?

I have an assignment as follows,
: Use the Sieve of Eratosthenes to locate and print out all prime numbers from 1 to 1000.
Follow a procedure similar to this:
Write down, in order, all number to be considered.
Cross out 1, since it is not considered prime.
Go to the next number not crossed out; leave it, but cross out all multiples of that number.
Repeat step 3 until you pas the number which is half of the largest number considered. At that point, all numbers not crossed out are the desired primes.
Your algorithm may vary slightly from the one above but speed is important.
I wrote this program out using the knowledge I have of math and arrays however as I was researching Sieve, I had no clue if this was the method.
public class PrimeSieve
{
public static void main( String[] args)
{
int max=1000;
calcPrimes( max );
}
public static void calcPrimes( int max )
{
// each boolean value indicates whether corresponding index
// position is composite (non-prime)
boolean[] array = new boolean[max +1 ];
// mark composites as true
for (int i = 2; i <= (int) Math.sqrt( max ); i++)
{
for (int j = i*i; j <= max; j += i) array [j ] = true;
{
// print indexes with corresponding false values
for (int k = 2;k <= max; k++)
{
if ( !array[ k ] )
System.out.format( k + "\n" );
}
}
}
}
}
Any help would be nice!
The problem is that you do not complete the process of marking off composites before printing out the results, possibly because your loops are nested in a confused sort of way.
public static void calcPrimes(int max) {
// each boolean value indicates whether corresponding index
// position is composite (non-prime)
boolean[] array = new boolean[max + 1];
// mark composites as true
for (int i = 2; i <= (int) Math.sqrt(max); i++) {
for (int j = i*i; j <= max; j += i) array[j] = true;
}
// print indexes with corresponding false values
for (int k = 2; k <= max; k++) {
if (!array[k]) System.out.println(k);
}
}
In this example, I have moved the code to print the primes outside of the loop that performs the sieve.

Finding repeats in a 2D array

I have made a program that outputs the number of repeats in a 2D array. The problem is that it outputs the same number twice.
For example: I input the numbers in the 2D array through Scanner: 10 10 9 28 29 9 1 28.
The output I get is:
Number 10 repeats 2 times.
Number 10 repeats 2 times.
Number 9 repeats 2 times.
Number 28 repeats 2 times.
Number 29 repeats 1 times.
Number 9 repeats 2 times.
Number 1 repeats 1 times.
Number 28 repeats 2 times.
I want it so it skips the number if it has already found the number of repeats for it. The output should be:
Number 10 repeats 2 times.
Number 9 repeats 2 times.
Number 28 repeats 2 times.
Number 29 repeats 1 times.
Number 1 repeats 1 times.
Here is my code:
import java.util.Scanner;
public class Repeat
{
static Scanner leopard = new Scanner(System.in);
public static void main(String [] args)
{
final int ROW = 10; //Row size
final int COL = 10; //Column size
int [][] num = new int[ROW][COL];
int size;
//Get input
size = getData(num);
//Find repeat
findRepeats(num, size);
}
public static int getData(int [][] num)
{
int input = 0, actualSize = 0; //Hold input and actualSize of array
System.out.print("Enter positive integers (-999 to stop): ");
//Ask for input
for(int i = 0; i < num.length && input != -999; i++)
{
for(int j = 0; j < num[i].length && input != -999; j++)
{
input = leopard.nextInt();
//Check if end
if(input != -999)
{
num[i][j] = input;
actualSize++;
}
}
}
System.out.println();
return actualSize;
}
public static void findRepeats(int [][] num, int size)
{
int findNum;
int total = 0, row = 0, col = 0;
for(int x = 0; x < size; x++)
{
//Set to number
findNum = num[row][col];
//Loop through whole array to find repeats
for(int i = 0; i < num.length; i++)
{
for(int j = 0; j < num[i].length; j++)
{
if(num[i][j] == findNum)
total++;
}
}
//Cycle array to set next number
if(col < num[0].length-1)
col++;
else
{
row++; //Go to next row if no more columns
col = 0; //Reset column number
}
//Display total repeats
System.out.println("Number " + findNum + " appears " + total + " times.");
total = 0;
}
}
}
I know why it is doing it, but I cannot figure out how to check if the number has already been checked for it to skip that number and go to the next number. I cannot use any classes or code that is not used in the code.
Since you cannot use anything other than this, lets say, basic elements of Java consider this:
Make another temporary 2D array with two columns (or just two separate arrays, personally I prefer this one). On the start of the algorithm the new arrays are empty.
When you take a number (any number) from the source 2D structure, first check if it is present in the first temporary array. If it is, just increment the value (count) in the second temporary array for one (+1). If it is not present in the first tmp array, add it to it and increase the count (+1) in the second at the same index as the newly added number in the first (which should be the last item of the array, basically).
This way you are building pairs of numbers in two arrays. The first array holds all your distinct values found in the 2D array, and the second one the number of appearances of the respective number from the first.
At the and of the algorithm just iterate the both arrays in parallel and you should have your school task finished. I could (and anyone) code this out but we are not really doing you a favor since this is a very typical school assignment.
It's counting the number two times, first time it appears in the code and second time when it appears in the code.
To avoid that keep a system to check if you have already checked for that number. I see you use check int array but you haven't used it anywhere in the code.
Do this,
Put the number in the check list if you have already found the count of it.
int count = 0;
check[count] = findNum;
count++;
Note: You can prefill you array with negative numbers at first in order to avoid for having numbers that user already gave you in input.
Next time in your for loop skip checking that number which you have already found a count for
for(int x = 0; x < size; x++) {
findNum = num[row][col];
if(check.containsNumber(findNUm)) { //sorry there is no such thing as contains for array, write another function here which checks if a number exists in the array
//skip the your code till the end of the first for loop, or in other words then don't run the code inside the for loop at all.
}
}
Frankly speaking I think you have just started to learn coding. Good luck! with that but this code can be improved a lot better. A piece of advice never create a situation where you have to use 3 nested for loops.
I hope that you understood my solution and you know how to do it.
All answers gives you some insight about the problem. I try to stick to your code, and add a little trick of swap. With this code you don't need to check if the number is already outputted or not. I appreciate your comments, structured approach of coding, and ask a question as clear as possible.
public static void findRepeats(int [][] num, int size)
{
int findNum;
int total = 1, row = 0, col = 0;
int [] check = new int[size];
while(row < num.length && col < num[0].length)
{
//Set to number
findNum = num[row][col];
//Cycle array to set next number
if(col < num[0].length-1)
col++;
else
{
row++; //Go to next row if no more columns
col = 0; //Reset column number
}
//Loop through whole array to find repeats
for(int i = row; i < num.length; i++)
{
for(int j = col; j < num[i].length; j++)
{
if(num[i][j] == findNum) {
total++;
//Cycle array to set next number
if(col < num[0].length-1)
col++;
else
{
row++; //Go to next row if no more columns
col = 0; //Reset column number
}
if(row < num.length - 1 && col < num[0].length -1)
num[i][j] = num[row][col];
}
}
}
//Display total repeats
System.out.println("Number " + findNum + " appears " + total + " times.");
total = 1;
}
}
you can use a HashMap to store the result. It Goes like this:
// Create a hash map
HashMap arrayRepeat = new HashMap();
// Put elements to the map
arrayRepeat.put(Number, Repeated);

Categories