Automate Logic using Loops? - java

I need to automate the below code snippet using loops. I need to get the max values even if the availpoints reaches infinite numbers
How can i achieve it within few lines of codes
if (availPoints < 500 ) {
pointsMax = 500;
MoneyMax = 25;
}
else if (availPoints < 1000 ) {
pointsMax = 1000;
MoneyMax = 50;
}
else if (availPoints < 1500 ) {
pointsMax = 1500;
MoneyMax = 75;
}
UPDATE:
Assume availPoint are the points a user score from 1 to 1000000(infinite too). Every 500 points is a Slot. If the points enter the next slot. The Max values pointMax has to be incremented by 500 & MoneyMax by 25.

It does not require loop.
for (int availPoints = 400; availPoints < 2000; availPoints += 200) {
int rank = availPoints / 500;
int pointsMax = (rank + 1) * 500;
int MoneyMax = (rank + 1) * 25;
System.out.printf("availPoints %d -> pointMax=%d MoneyMax=%d%n",
availPoints, pointsMax, MoneyMax);
}
result:
availPoints 400 -> pointMax=500 MoneyMax=25
availPoints 600 -> pointMax=1000 MoneyMax=50
availPoints 800 -> pointMax=1000 MoneyMax=50
availPoints 1000 -> pointMax=1500 MoneyMax=75
availPoints 1200 -> pointMax=1500 MoneyMax=75
availPoints 1400 -> pointMax=1500 MoneyMax=75
availPoints 1600 -> pointMax=2000 MoneyMax=100
availPoints 1800 -> pointMax=2000 MoneyMax=100

I need to get the max values even if the availpoints reaches infinite
numbers
Well this is really not good in Programming! You have to stop somewhere. Although if you have to loop until infinite (in my term, very big number), You can always use while(true){} LOOP with appropriate break statement.
If you could make it more clear that, for which kind of scenarios you want to support, then it can be more clear to us. Otherwise something like should work for you - (pseudo code - Don't try without understanding it properly )
long maxPoints = 0;
double MoneyMax = 0;
while(true) {
if((availPoints == REALLY BIG MAGIC NUMBER) || (SOME OTHER CONDITION)){
maxPoints += 500;
MoneyMax += 25;
}
}
Although as I said, you have to pick some condition based on which you will stop. If you this logic is never going to change thru out the application, you may store values in DB and play with them when needed.
Hope this helps.!

If you want to use incredibly large numbers, I suggest importing java.math.BigInteger
Here's some code that'll use a loop to find pointsMax and MoneyMax.
for (pointsMax = new BigInteger("500"), MoneyMax = new BigInteger("25");
pointsMax.compareTo(availPoints) != 1;) {
pointsMax = pointsMax.add(new BigInteger("500"));
MoneyMax = MoneyMax.add(new BigInteger("25"));
}
EDIT: Made it all into one loop. Also, make sure availPoints is also a BigInteger.
EDIT 2: Made it into a for loop.

Related

Calculating a number by experience point correlation

Looking at this RuneScape experience table: http://runescape.wikia.com/wiki/Experience/Table
You can see that an experience point amount correlates to a "level"
where:
if (xp < 83){
level = 0;
}
else if (xp >= 83 && xp < 174){
level = 1;
}
//etc
So when I save just the experience as a field for my player, how can I calculate the level they will be with their experience?
Without looping through 100 experience point integers.
i.e I don't want to do this: (Because a player will have many levels, meaning this will need to be looped many times)
for (int i =0; i < 100) {
if (playersExperience < experienceRequiredForLevel(i){
return i;
}
perhaps there is a faster way to do this?
Edit:
There is a formula to calculate the experience for level X here:
rsdo.net/rsdonline/guides/Experience%20formula.html
though I don't know how to reverse engineer that to find level instead
You can have a multiplier of X the experience levels. And you just take the integer part of division.
Ex if X=100: LVL1 = 100, LVL2 = 200; etc ...
In this case you just can just:
LVL = Experience / X;
Ex: 100 / 100 = 1 LVL, 200 / 100 = 2 ... etc
X can be any number.
Hope it helps.
You could use binary search to speed up things:
private static final int[] experiences={83, 174, ...};
int level(int experience) {
// boundary check
if (experience < experiences[0])
return 0;
if (experience >= experiences[experiences.length-1])
return experiences.length;
int minLevel = 0;
int maxLevel = experiences.length;
while (maxLevel - minLevel > 1) {
int chk = (maxLevel+minLevel)/2;
if (experience < experiences[chk])
maxLevel = chk;
if (experience >= experiences[chk])
minLevel = chk;
}
return maxLevel;
}

Number Search (Most efficient)

Given that N is a random number (range 1 to 1000). We need to guess the N and for each guess, one of the following feedbacks may be given:
The guess is correct;
The guess is too large, so you should guess a smaller number;
The guess is too small, so you should guess a larger number.
In case 3, the value of N will increase by P, where P is another random number(range 1 to 200).
If the initial value of N=800 and P=150. You guess in the following sequence:
Example
How do you code the following especially when it involves two number (N and P). I was thinking of using Binary Search but the it would be a problem if we do not know the value of P.
This is my code as of now :
myGuess=0;
checkCode=0;
int lower = 1, upper = 999;
myGuess = (lower+upper)/2;
do{
if (checkCode == 2) {
upper = myGuess - 1;
}
else if (checkCode == 3){
lower = myGuess + 1;
upper += ran.nextInt(200); //Need to guess the P value
}
myGuess = (lower+upper)/2;
}while(checkCode!=1);
The first step is to obtain a working guessing system. This code provides a rough guide to a binary search approach. The second step would the be to analyze how to improve efficiency. (note: can restore some of the S.O.P() to see progress)
private static int doGuess()
{
int lowerBound = 1;
int upperBound = 1000;
int numberToGuess = ThreadLocalRandom.current().nextInt(upperBound) + 1;
int guess = 0;
int steps = 0;
int increases = 0;
while (guess != numberToGuess) {
++steps;
guess = (lowerBound + upperBound) / 2;
// System.out.printf("[%5d] Guessing %d (is: %d)%n",
// steps,
// guess,
// numberToGuess);
if (guess == numberToGuess) {
System.out.printf("Guessed %d in %d steps (%d increases)%n",
numberToGuess,
steps,
increases);
continue;
}
else if (guess > numberToGuess) {
// System.out.println("Guess is too high!");
// adjust upper bound to be guess
upperBound = guess;
}
else {
// System.out.println("Guess is too low; changing number");
numberToGuess += ThreadLocalRandom.current().nextInt(200) + 1;
// adjust lower bound to this guess
lowerBound = guess;
// the number moved, so adjust upper bound by max range
upperBound += 200;
// track increases
++increases;
}
}
return steps;
}
public static void main(String[] args)
{
List<Integer> steps = new ArrayList<>();
int iterations = 10;
for (int i = 0; i < iterations; ++i) {
steps.add(doGuess());
}
IntSummaryStatistics stats =
steps.stream().collect(IntSummaryStatistics::new,
IntSummaryStatistics::accept,
IntSummaryStatistics::combine);
System.out.println(stats);
}
Output:
Guessed 8838 in 145 steps (83 increases)
Guessed 6301 in 106 steps (59 increases)
Guessed 3239 in 58 steps (30 increases)
Guessed 5785 in 109 steps (58 increases)
Guessed 2547 in 56 steps (27 increases)
Guessed 16071 in 300 steps (164 increases)
Guessed 3847 in 54 steps (31 increases)
Guessed 3125 in 42 steps (24 increases)
Guessed 6708 in 93 steps (57 increases)
Guessed 7433 in 143 steps (74 increases)
IntSummaryStatistics{count=10, sum=1106, min=42, average=110.600000, max=300}
[Note: based upon quick simulations, the average across multiple runs is about 115, so efficiency improvements should reduce on average from 115 steps]
[Note: the amount of change in the code is different with each guess that is too low; a comment by the OP might suggest the increase is randomly chosen once, in which case the increase in the number to guess in the above code would need to change]
Edit:
Logically if guessing low moves the the number one is to guess, then using some sort of bias towards picking higher would seem to be logical. As Holger has suggest in the various comments, there are some ways to make adjustments.
I had attempted some basic adjustments prior to seeing Holger's suggestion; I then also attempted to implement his algorithm. However, I have not found the adjustments to make a marked improvement (and some are worse).
Using 100,000 runs, the standard binary search averaged 127.7 steps (note: up slightly from my earlier estimate based upon a lower run count). Assuming I implemented Holger's algorithm correctly, at 100,000 the average was 126.6 steps.
As I lack the math skills (and unfortunately time at the moment) to investigate further, it seems that simple modifications do not seem to radically change the efficiency of the algorithm on average. I did not investigate worse cases. It would be interesting to ask the question over on the Math StackExchange to see if they could provide any definite input. I did do a quick Google search, but did not have time to read the academic papers that might give some improvement (again, with unknown trade-offs in speed and algorithmic complexity).
It is, of course, possible I did not implement Holgen's suggestion properly. Here is the code I used (replacing the change in the guess calculation if too low) based straight from the comment:
if (tryHolgen) {
double risc = 200.0/(upperBound-lowerBound);
if (risc <= 1) {
guess = (upperBound + lowerBound) /2;
}
else {
guess = upperBound -
Math.max((int)((upperBound - lowerBound)/risc/2),1);
}
else {
guess = (lowerBound + upperBound) / 2;
}
I am curious if others have a better implementation than the straight binary search.
It is interesting, though, that a 1..1000 range with a standard binary search would take 8 steps on average with O(log n) complexity. By allowing the guess to change, it moves the average by about 120 steps.
I reworked my solution once I understood what you were trying to do. This will give you some statistics. The current solution incorporates a random number between 0 and 13 for each guess, as well as adding the lower and upper bound together and divide them by 2. Why 13? It seems like it's a sweet spot for this exact task.
public static void main(String args[]) throws IOException {
int numTests = 1000000;
long averageTries = 0;
int maxAttempts = 0;
int minAttempts = Integer.MAX_VALUE;
for (int i = 0; i < numTests; i++) {
int numAttempts = 0;
int answer = (int) (Math.random() * 1000) + 1;
int lower = 1;
int upper = 1000;
int myGuess;
do {
myGuess = (int) (((lower + upper) / 2) + (Math.random() * 14));
numAttempts++;
if (myGuess > answer) {
upper = myGuess;
} else if (myGuess < answer) {
lower = myGuess;
upper += (lower + upper) / 2;
answer += (int) (Math.random() * 200) + 1;
}
} while (myGuess != answer);
averageTries += numAttempts;
if (numAttempts > maxAttempts) {
maxAttempts = numAttempts;
}
if (numAttempts < minAttempts) {
minAttempts = numAttempts;
}
}
System.out.println("Average attempts (of " + numTests + " tests): " + (averageTries / numTests));
System.out.println("Most attempts in one run: " + maxAttempts);
System.out.println("Least attempts in one run: " + minAttempts);
}
Output:
Average attempts (of 1000000 tests): 266
Most attempts in one run: 72228
Least attempts in one run: 1
You can try to do something similar to binary search. Just consider that binary search requires the input to be sorted. If the input is not sorted you have to sort it yourself.
Rather than guessing a random number, just guess the one exactly in the middle of the partition. However compared with binary search which halves each time, in this case it's a moving target, so the bounds of the search need to be adjusted for that.

Copying books using dynamic programming

I am implementing the dynamic programming solution for copying books problem. The idea for the solution is taken from here and here.
Problem statement:
Before the invention of book-printing, it was very hard to make a copy
of a book. All the contents had to be re-written by hand by so called
scribers. The scriber had been given a book and after several months
he finished its copy. One of the most famous scribers lived in the
15th century and his name was Xaverius Endricus Remius Ontius
Xendrianus (Xerox). Anyway, the work was very annoying and boring. And
the only way to speed it up was to hire more scribers.
Once upon a time, there was a theater ensemble that wanted to play
famous Antique Tragedies. The scripts of these plays were divided into
many books and actors needed more copies of them, of course. So they
hired many scribers to make copies of these books. Imagine you have m
books (numbered 1, 2, ...., m) that may have different number of pages
( p_1, p_2, ..., p_m) and you want to make one copy of each of them.
Your task is to divide these books among k scribes, k <= m. Each book
can be assigned to a single scriber only, and every scriber must get a
continuous sequence of books. That means, there exists an increasing
succession of numbers 0 = b_0 < b_1 < b_2, ... < b_{k-1} <= b_k = m$
such that i-th scriber gets a sequence of books with numbers between
bi-1+1 and bi. The time needed to make a copy of all the books is
determined by the scriber who was assigned the most work. Therefore,
our goal is to minimize the maximum number of pages assigned to a
single scriber. Your task is to find the optimal assignment.
I am able to obtain the optimal solution for the problem described iteratively, but unable to use that to find the required solution for the problem, that is:
Sample input:
2
9 3
100 200 300 400 500 600 700 800 900
5 4
100 100 100 100 100
Sample Output
100 200 300 400 500 / 600 700 / 800 900
100 / 100 / 100 / 100 100
Where 2 is the number of datasets, 9 is the number of books and 3 is the number of scribes to assign the books to.
Here is my output, for the respective inputs:
100 100 100
300 300 300
600 600 600
1000 700 700
1500 900 900
2100 1100 1100
2800 1300 1300
3600 1500 1500
4500 1700 1700
100 100 100 100
200 200 200 200
300 300 300 300
400 300 300 300
500 300 300 300
For the first solution set, I can use 1700 as the optimal number of page assignments to each user and keep on assigning the book pages until, Current scribe page sum >= 1700. However, the second solution does not have any pattern to it whatsoever?
Here is my code to generate the solution:
private void processScribes(){
int[][] bookScribe = new int[numOfBooks][numOfScribes];
//set first row to b1 page number
for (int j = 0; j < numOfScribes; ++j)
bookScribe[0][j] = bookPages[0];
//set first column to sum of book page numbers
for (int row = 1; row < numOfBooks; ++row)
bookScribe[row][0] = bookScribe[row - 1][0] + bookPages[row];
//calculate the kth scribe using dp
for (int i = 1; i < numOfBooks; ++i){
for (int j = 1; j < numOfScribes; ++j){
//calculate minimum of maximum page numbers
//from k = l + 1 to i
//calculate sum
int minValue = 1000000;
for (int k = 0; k < i - 1; ++k){
int prevValue = bookScribe[i - k][j - 1];
int max = 0;
int sumOflVals = 0;
for (int l = k + 1; l <= i; ++l){
sumOflVals = sumOflVals + bookPages[l];
}
if (prevValue > sumOflVals){
max = prevValue;
}
else
max = sumOflVals;
if (max < minValue )
minValue = max;
}
if (minValue == 1000000)
minValue = bookScribe[i][0];
//store minvalue at [i][j]
bookScribe[i][j] = minValue;
}
}
//print bookScribes
for (int i = 0; i < numOfBooks; ++i){
for (int j = 0; j < numOfScribes; ++j)
System.out.print(bookScribe[i][j] + " ");
System.out.println();
}
System.out.println();
}
Any pointers here? Is it the interpretation of solution or something is wrong with how I am translating the recurrence in my code?
Not sure of your solution but here is an intuitive recursive approach with memoization. Let there be n books with ith book having pages[i] pages. Also let there be m subscribers. Also let dp[i][j] be the answer to problem if we were given only books i,i+1.....n and there are only j subscribers to do the job. Following is a recursive pseudo code with memoization
//dp[][] is memset to -1 from main
// Assuming books are numbered 1 to n
// change value of MAX based on your constraints
int MAX = 1000000000;
int rec(int position , int sub )
{
// These two are the base cases
if(position > n)
{
if(sub == 0)return 0;
return MAX;
}
if(sub == 0)
{
if(position > n)return 0;
return MAX;
}
// If answer is already computed for this state return it
if(dp[position][sub] != -1)return dp[position][sub];
int ans = MAX,i,sum = 0;
for(i = position; i <= n;i++)
{
sum += pages[i];
// taking the best of all possible solutions
ans = min(ans,max(sum,rec(i+1,sub-1)));
}
dp[position][sub]=ans;
return ans;
}
//from main call rec(1,m) which is your answer
You can convert it to an iterative solution by dynamic programming it will be same complexity in time and space .Space is O(n.m) and time is O(n^2.m).
EDIT
Here have a look at running version of the code on your testcases Book Copying Code . It not only finds optimal answer but also prints the optimal assignment with it ( which I have not included in the pseudo code above). ( click on the top right corner fork and it would run on
your testcases, input format is same as yours ). Output will optimal answer followed by optimal assignment. Do comment if you have doubts regarding the code.

Using java to find Happy Numbers: Nested while loop loops indefinitely

My assignment asks for a command-line input to be put through nested while loops to find if a number is a happy number or not. So far I have this:
int i = 0;
int sum = 0;
int dig2, dig1, dig3, dig4, dig1next, dig2next, dig3next;
int digit1sum, digit2sum, digit3sum;
happyNumber = number;
while (i < 500){
while (happyNumber > 0){
while (sum!=1){
dig3 = happyNumber / 100;
dig2 = happyNumber % 10;
dig1 = happyNumber / 10;
dig2next = dig2 % 10;
dig1next = dig1 % 10;
dig3next = dig3 % 10;
digit1sum = dig1next * dig1next;
digit2sum = dig2next * dig2next;
digit3sum = dig3next * dig3next;
sum = digit1sum + digit2sum + digit3sum;
happyNumber = sum;
}
System.out.println("It is a happy number.");
System.exit(0);
}
i++;
System.out.println(i);
System.exit(0);
}
I set i<500 so when i++ reaches 500, the loop should stop. I've pretty much tried putting i++ in every section of the code possible, it never works. what am i doing wrong here?
also: i am not allowed to use for loops or do-while loops on this assignment. i have to use nested while loops only
Happy number: Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1(how long the loop will be: 500).
After a quick glance at your code:
while (sum!=1)
....
sum = digit1sum + digit2sum + digit3sum;
happyNumber = sum;
This while test is likely to be always true -> infinite loop -> stack overflow
You will never get out of your innermost while-loop in case of a number that loops endlessly (it is by no means stopped by the 500- limit and your logic is wrong here).
Secondly, something to think about:
digit1sum = dig1next*dig1next;
digit2sum = dig2next*dig2next;
digit3sum = dig3next*dig3next;
these (digitxsum) will always be positive.
sum = digit1sum + digit2sum + digit3sum;
sum will therefore always be positive
happyNumber = sum;
happynumber will always be positive
while (happyNumber > 0)
what is this for?

Determining an arrays value depending on another array

I'm currently working on one of my assignments, and am looking for some help with the logic for one of my functions.
First off I have a array of numbers to be categorized, then a number interval, this number determines in which position each of the numbers being plotted goes into array2.
ie.
int interval = 2;
for(int i = 0; i < array1.length; i++) {
if((array1[i] > 0) && (array1[i] < interval)) {
array2[0]++;
}
}
However, the number from array1 is 3. I would then need another if statement like so:
...
}else if((array1[i] > 2) && (array1[i] < interval * 2)) {
array2[1]++;
}else if((array1[i] >
As you can start to see the problem with this is that I would need to continue for an infinite range of numbers. So my question is what is an easier way of achieving this goal? Or is there already a library which I can utilize to do so?
I'm sorry if I didn't make this clear enough, also I would prefer if code wasn't given to me. I would appreciate if someone would be able to tell me a more effective way about going about this, thanks in advance!
EDIT:
Assuming that the interval is set to 2, and the numbers from array1 are between 0 and 10, I would need to create a code that would do such:
2 < numFromArray1 > 0 == array2[0]++
4 < numFromArray1 > 2 == array2[1]++
6 < numFromArray1 > 4 == array2[2]++
8 < numFromArray1 > 6 == array2[3]++
10 < numFromArray1 > 8 == array2[4]++
However, the numbers from array1 can be positive or negative, whole or decimal.
Use a nested loop. Obviously it's not infinitely many possibilities for interval because array2 has a fixed size. So if you loop through all the cells in array2, and then do some math to figure out what your conditions need to be... I won't give complete code (you asked me not to, but it would look something like:
for ( ... ) {
for ( ... ) {
if (array1[i] > /* do some math here */ && ... ) {
array2[/* figure out what this should be too */]++;
}
}
}
Hopefully you can figure it out from this.
By the way, if you aren't required to use an array for array2, consider learning about LinkedList<?>for a data structure that can grow in size as you need it to.
http://docs.oracle.com/javase/1.4.2/docs/api/java/util/LinkedList.html
http://www.dreamincode.net/forums/topic/143089-linked-list-tutorial/
Assuming I understood the question correct, and the interval would be 3, than occurrences of 0, 1 and 2 would increase array2[0], occurences of 3, 4 and 5 would increase array2[1] and so on, this would be a solution:
EDIT sorry, you did not want to see code. I can repost it, if you want. Think about a real easy way to determine which category a number will be in. I'll try to give a hint.
Interval = 3;
0,1,2 -> category 0
3,4,5 -> category 1
6,7,8 -> category 2
Once you know the category, it is easy to increment the desired number in array2.
It would look something like that:
for(int i = 0; i < array1.length; i++) {
int category = // determine category here
// increase correct position of array2
}
After some dicussion, here is my code:
for(int i = 0; i < array1.length; i++) {
int category = array1[i] / interval;
array2[category]++;
}
My solution won't work for negative numbers. Also it is not specified how to handle them
Here's what you can do to consider all cases: -
First find out what is the maximum value in your array: - array1.
Your range should be 0 to maxValueInArray1
Then inside your outer for loop, you can have another, that will run from 0 to the (maximum value) / 2. Because, you don't want to check for maximum value * 2 in your interval
And then for each value, you can check for the range, if it is in that range, use array2[j]
For E.G: -
for (...) // Outer loop {
for (int j = 0; j <= maximumValueinArray1 / 2; j++) {
// Make a range for each `j`
// use the `array2[j]` to put value in appropriate range.
}
}
In your inner loop, you might check for this condition, based on following reasoning: -
For interval = 2, and say maximumValueinArray1 is max, your range looks like: -
0 * interval ----- (1 * interval) --> in `array2[0]` (0 to 2)
1 * interval ----- (2 * interval) --> in `array2[1]` (2 to 4)
2 * interval ----- (3 * interval) --> in `array2[2]` (4 to 6)
and so on.
((max / 2) - 1) * interval ----- (max / 2) * interval (`max - 2` to max)
So, try relating these conditions, with the inner loop I posted, and your problem will be solved.
I'm not sure what exactly you're trying to do, but from your code snippets, I can come up with this inner for loop:
//OUTDATED CODE - please see code block in EDIT below
//for(int i = 0; i < array1.length; i++) {
// for (int j = 0; j < 100000; j++) { //or Integer.MAXVALUE or whatever
// if ((array1[i] > (j*2)) && (array1[i] < interval * ((j*2)==0?2:(j*2)) )) {
// array2[j]++;
// }
// }
//}
EDIT: Owing to your recent edit, this is more suitable and you don't have to run an inner loop!:
Loop through array1
For each element in array1, find array2 index by taking floor of element / interval
Add 1 to array2 element at found index.
DON'T LOOK AT THE CODE BELOW =)
for(int i = 0; i < array1.length; i++) {
int index = Math.floor(array1[i] / interval);
array2[index]++;
//the rest are actually not necessary as you just need to get the index
//and the element will be within range, left inclusive (lower <= value < upper)
//int lower_range = Math.floor(array1[i] / interval) * interval;
// //or int lower_range = index * interval;
//int upper_range = Math.ceil(array1[i] / interval) * interval;
//if ((array1[i] > lower_range) && (array1[i] < upper_range)) {
// array2[index]++;
//}
}
The relationships and pattern are hard to figure out. My attempt in interpreting what you want:
How about something like:
if ( array1[i] < interval * (interval - 2) ) {
array2[interval-2]++;
}

Categories