Need help reducing triple for loop to increase efficiency - java

for (int i = 0; i < 3; ++i) {
for (int k = 0; k < 7; ++k) {
for (int h = i; h < 4 + i; ++h) {
result = state.getAt(k, h);
if (result == 1) {
++firstpl;
}
if (result == 2) {
++secondpl;
}
if (firstpl > 0 && secondpl > 0) {
break;
}
//y = k;
}
if (firstpl == 0 && secondpl == 0) {
break;
} else if (firstpl > secondpl) {
score += firstpl * firstpl;
//if(state.getHeightAt(y)-3 < 3) score += 3+firstpl*2;
} else {
score -= secondpl * secondpl;
//if(state.getHeightAt(y)-3 < 3) score -= 3+secondpl*2;
}
firstpl = 0;
secondpl = 0;
}
}
basically I have a 7 by 6 grid. I am going through 7 columns and looking at every 4 consecutive blocks vertically. Since there is 6 blocks upward. There is 3 four consecutive block for each column. State.getAt(k,h) takes in a x and y and returns a value.

I don't think you can improve on this, unless you can figure out an alternative representation for this "state" that allows this computation to be performed incrementally.
And since you have failed to properly explained what the state or the calculation actually mean, it is difficult for anyone but you to figure out whether an alternative approach is even feasible. (And I for one am not going to attempt to reverse engineer the meaning from your code.)
OK. For Connect4, the win / lose is a line of 4 checkers horizontally, vertically or diagonally in the 7x6 grid. So what you could do is represent the score-state as an array of counters, corresponding to each of the columns, rows and diagonals in which a winning line could be made. (7 + 5 + 4 + 4 = 20 of them => 20 counters) Then construct a static mapping from an (x,y) position to the indexes of lines that pass through that. When you add a checker at point (x,y) you look up the counters and increment them. When you remove a checker ... decrement.
I'm not sure how that relates to your existing scoring function ... but then I don't see how that function relates to a strategy that would win the game. Either way, you could potentially use the approach above to calculate scores incrementally.

Related

What's the easiest way to increment a value by x

I have a for loop with length 20.
I have a height of 800. I want to put a value 20 times separated by the same gap.
For example:
800 / 20 = 40
Every 40 I want to println the value. 40, 80, 120, 160... until 800.
I don't understand how to do this inside a loop. My approach is wrong and does not have the same gap between them.
for (int i = 0; i < array.size(); i++) {
int posY = (i != 0) ? 800/ i : 800;
println(posY);
}
you can use de Modulo Operador. more info
if(i % 40 == 0){
println(posY);
}
Math Explanation of Modulo here
Well there are imho three different aproaches. Which one depends on what else you need to do with i.
1) Use i directly:
for (int i = 40; i <= 800; i+=40) {
println(i);
}
This asumes that you don't need nothing else but the 20 numbers.
2) you need to count:
for (int i = 1; i <= 20; i++){
println(i*40);
}
2b) application eg. if 800 is in a variable:
for (int i = 1; i <= 800/40; i++){
println(i*40);
}
This assumes you need to track which step you are taking and want to do something with i.
3) you need the steps inbetween for something
for (int i = 1; i <= 800; i++) {
if(0 == i%40 ){ //if the rest of i/40 gives 0
println(i);
}
}
This last version prints the same numbers but still i goes over all values inbetween.
Plus if you have an array you need to iterate over:
replace the 800 with "array.length -1"
OR
replace the "<=" by "<" and use "array.length" above.
(And well there are a whole lot of variations of this)

Java output reply so slow

i'm doing a exercise about a snail that climb a wall and i have to calculate how manys days it would take to reach the top, i already did my algorithm and it give me the expected output but it takes so long in a input case, basically what code have to do is given N M T N=how manys meter he climb a day M= how manys meters he fall in the night and T= what's the lenght of the wall this is my code any help will be useful this is my code PD it already work but it's too slow
int distance=0;
int[] up = { 2, 5 ,100};
int[] down= { 1,1 ,99};
int[] Top = {5,6 ,1000000000};
int days = 0;
for (int i = 0; i < up.length; )
{
distance += up[i];
if (Top[i] <= distance)
{
days++;
System.out.println(days);
i++;
days = 0;
distance = 0;
}
else
{
distance -= down[i];
days++;
}
}
the output are the next : case 1: 4
case 2: 2
case 3 :999999901
Your code can be refactored to simplify it. This is how Wikipedia describes refactoring:
Code refactoring is the process of restructuring existing computer code—changing the factoring—without changing its external behavior. Refactoring improves nonfunctional attributes of the software. Advantages include improved code readability and reduced complexity; these can improve source-code maintainability and create a more expressive internal architecture or object model to improve extensibility. Typically, refactoring applies a series of standardised basic micro-refactorings, each of which is (usually) a tiny change in a computer program's source code that either preserves the behaviour of the software, or at least does not modify its conformance to functional requirements.
So we're going to apply a set of micro-refactorings.
First, the two statements inside the else clause can be flipped.
} else {
days++; // Statement moved up
distance -= down[i];
}
When you do that, both the if block and the else block starts with days++;, so it can be moved outside.
for (int i = 0; i < up.length;) {
distance += up[i];
days++; // Statement moved outside
if (Top[i] <= distance) {
System.out.println(days);
i++;
days = 0;
distance = 0;
} else {
distance -= down[i];
}
}
Since the for loop doesn't modify i, it behaves like a forever-loop, as long as code inside the loop doesn't change i. So, we can add a forever-loop and break out of it when we change i. The effect is that nothing has changed, but it prepares for the next set of refactorings.
for (int i = 0; i < up.length;) {
for (;;) { // Forever-loop
distance += up[i];
days++;
if (Top[i] <= distance) {
System.out.println(days);
i++;
days = 0;
distance = 0;
break; // Break out, since we changed i
} else {
distance -= down[i];
}
}
}
Since the break statement is the only way to exit the forever-loop, we can move the code that is before the break to outside (i.e. after) the loop.
int distance = 0;
int days = 0;
for (int i = 0; i < up.length;) {
for (;;) {
distance += up[i];
days++;
if (Top[i] <= distance) {
break;
} else {
distance -= down[i];
}
}
System.out.println(days); // Moved outside forever-loop
i++; // Moved outside forever-loop
days = 0; // Moved outside forever-loop
distance = 0; // Moved outside forever-loop
}
Since days and distance are initialized to 0 before the outer loop, and reinitialized to 0 at the end of the loop, we can just do that at the start of the loop instead, and we can then declare them there. We can also move the i++ to the for loop.
for (int i = 0; i < up.length; i++) { // i++ moved here
int distance = 0; // Moved to top of loop and declared here
int days = 0; // Moved to top of loop and declared here
for (;;) {
distance += up[i];
days++;
if (Top[i] <= distance) {
break;
} else {
distance -= down[i];
}
}
System.out.println(days);
}
We will now do the opposite operation for the two statements that increment distance and days inside the forever-loop, i.e. do those two statement both before the loop, and at the end of the loop.
for (int i = 0; i < up.length; i++) {
int distance = 0;
int days = 0;
distance += up[i]; // Moved here
days++; // Moved here
for (;;) {
if (Top[i] <= distance) {
break;
} else {
distance -= down[i];
}
distance += up[i]; // Also moved here
days++; // Also moved here
}
System.out.println(days);
}
The initialization of distance and days can be combined with the incrementing done before the forever-loop. Also, since the break exits the loop, there is no need for else anymore.
for (int i = 0; i < up.length; i++) {
int distance = up[i]; // Combined =0 with +=up[i]
int days = 1; // Combined =0 with ++
for (;;) {
if (Top[i] <= distance)
break;
distance -= down[i]; // else clause eliminated
distance += up[i];
days++;
}
System.out.println(days);
}
distance is only used inside the forever loop, so we can move the declaration to the loop. The update of distance can be moved to the 3rd part of the forever loop. The if statement is at the top of the forever-loop, so it can become the loop condition instead, changing the forever-loop to a regular for loop.
for (int i = 0; i < up.length; i++) {
int days = 1;
for (int distance = up[i]; distance < Top[i]; distance += up[i] - down[i]) {
days++;
}
System.out.println(days);
}
See how much simpler your code is now, and we never changed the logic of the code. We just moved it around, i.e. refactored it.
Your performance issue is caused by the inner loop having to iterate almost a billion times for the 3rd use-case, but now that we can see a simple for loop, we can actually calculate how many times it will iterate.
To build that formula, consider a normal loop.
for (int value = start; value < stop; value += step)
How many times will that iterate? It will have to add step a total of x times until value reaches stop, so that means x = (stop - start) / step.
If stop - start is not an exact multiple of step, we need to make sure we always round up, so value will be >= stop. Using integer math, you do that by adding step - 1 before dividing, since integer division will truncate the result, leading to this formula: x = (stop - start + step - 1) / step
Applying that to our loop, we get:
x = (stop - start + step - 1) / step
x = (Top[i] - up[i] + (up[i] - down[i]) - 1) / (up[i] - down[i])
x = (Top[i] - down[i] - 1) / (up[i] - down[i])
days = 1 + x
days = 1 + (Top[i] - down[i] - 1) / (up[i] - down[i])
Since there is no need to assign result to a variable days anymore, your code becomes:
int[] up = { 2, 5, 100 };
int[] down = { 1, 1, 99 };
int[] Top = { 5, 6, 1000000000 };
for (int i = 0; i < up.length; i++)
System.out.println(1 + (Top[i] - down[i] - 1) / (up[i] - down[i]));
Output
4
2
999999901
Result is instantly calculated. No delays.
You can use a little maths to come up with a closed formula:
Math.ceil(((double)top - down) / (up - down))

Finding all the number combos in array that add up to input number

Hey I'm working on figuring out an algorithm that takes a user-entered number and then goes through an array of size 50 filled with random numbers between 1 and 100 and finds all the combinations of numbers that add up to the input number.
For example, given an array of integers [3,6,1,9,2,5,12] and being passed the integer value 9, you would return [[3,6],[6,1,2],[9],[3,1,5]]. Order of returning the results in the array does not matter, though you should return unique sets (ie. [6,3] and [3,6] are the same and only one should be returned). Also, the individual results should be in the order they are found (ie [6,1,2] should be returned, not [1,2,6]).
As I've started writing code, the first solution that I came to seems extremely in-efficient. I'm currently trying to separate each combo into it's own array, and every time a number gets added to the array, a check is done to see if the numbers equal the input, are still less than, or go over it. It's not working properly, and I feel like this might be an inefficient way to do it:
for (int i = 0; i < list.length; i++) {
List<Integer> combo = new ArrayList<Integer>();
int counter = 0;
int current = list[i];
if (current == input){
System.out.println(i);
}
else if (current > input) {
continue;
}
else if (current < input) {
combo.add(current);
if (combo.size() >= 2) {
for (int j = 0; j < combo.size(); j++) {
counter += combo.get(j);
if (counter == input) {
System.out.println("Success");
break;
}
else if (counter < input) {
continue;
}
else if (counter > input) {
break;
}
}
}
}
}
This is an idea, I don't have a working code. Try to use recursion, test all combinations with the biggest possible number plus all the rest without it. Function like: Sums(Number, maxN), (maxN is maximum number which we can take - in first call it's 9)
For your example would be:
1. As suggested, sort them and cut bigger than input.
2. Check if the maxN is greater than the minimum required to make a sum, in your example it is 5 (can't make 9 from numbers smaller than 5 in your set); if it's not return (base case).
3. Is maxN equal tu input? (9 in first call)
a) Yes - first solution subset [9] + Sums(Number, dec(maxN)) (dec(maxN) will be 6 in first call)
b) No - recursively check if 'Number - maxN' could be built from numbers from your set, Sums(Number - maxN, dec(K) or max number of 'Number - maxN' (depends what is smaller)) + Sums(Number, dec(maxN)) - add the rest.
Here is code to count only, ways to write a number as sum of squares, it passed HackerRank tests:
import math
def minArgument(x):
s = 0
i = 1
while s < x:
s = s + i * i
i = i + 1
return i - 1
def maxPower(a):
return math.floor(math.sqrt(a))
def sumOfSquares(M, K, cnt):
if M < 1:
return cnt
lowerLimit = minArgument(M)
if K < lowerLimit:
return cnt
else:
if K * K == M:
return sumOfSquares(M, K - 1, cnt + 1)
else:
return sumOfSquares(M, K - 1,sumOfSquares(M - K * K,
min(maxPower(M - K * K), K - 1), cnt))
After easy change, this gives you number of solutions. I don't see how to build a list with combinations as a return value now...

Java Sudoku brute force solver, how does it work?

So you find the code below here. Most of the code I understand, but there is one bit I don't. The place where we create the boolean array called digits and the bit after that 3 * (x / 3).
I think it's used to check if each square in the sudoku has 9 unique numbers as well, but I'm not sure on how I can explain this to let's say someone next to me.
Why do I need the array of boolean here? Can someone explain to me what it is doing and why?
Kind regards!
public int[][] solvePuzzle(int[][] matrix) {
int x, y = 0;
boolean found = false;
// First we check if the matrix contains any zeros.
// If it does we break out of the for loop and continue to solving the puzzle.
for (x = 0; x < 9; x++) {
for (y = 0; y < 9; y++) {
if (matrix[x][y] == 0) {
found = true;
break;
}
}
if (found) {
break;
}
}
// If the puzzle doesn't contain any zeros we return the matrix
// We now know that this is the solved version of the puzzle
if (!found) {
return matrix;
}
boolean digits[] = new boolean[11];
for (int i = 0; i < 9; i++) {
digits[matrix[x][i]] = true;
digits[matrix[i][y]] = true;
}
int boxX = 3 * (x / 3), boxY = 3 * (y / 3);
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
digits[matrix[boxX + i][boxY + j]] = true;
}
}
// We loop over all the numbers we have to check if the next number fits in the puzzle
// We update the matrix and check recursively by calling the same function again to check if the puzzle is correct
// If it's not correct we reset the matrix field to 0 and continue with the next number in the for loop
for (int i = 1; i <= 9; i++) {
if (!digits[i]) {
matrix[x][y] = i;
if (solvePuzzle(matrix) != null) {
return matrix;
}
matrix[x][y] = 0;
}
}
// The puzzle can't be solved so we return null
return null;
}
I have added some explanation as comments inline:
//we need to know what digits are we still allowed to use
//(not used in this row, not used in this column, not used in
//the same 3x3 "sub-box")
boolean digits[] = new boolean[11];
//so we run through the rows/coumns around the place (x,y)
//we want to fill in this iteration
for (int i = 0; i < 9; i++) {
//take a used number from the row of x (matrix[x][i]) and mark it
// as used
digits[matrix[x][i]] = true;
//take a used number from the column of y (matrix[i][y]) and mark it
// as used
digits[matrix[i][y]] = true;
}
//find the top-left corner of the sub-box for the position (x,y) we
//want to fill in
//example: x is 8 -> 3 * 8/3 -> 6, so we start from 6
int boxX = 3 * (x / 3), boxY = 3 * (y / 3);
//iterate through the sub-box horizontally and vertically
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
//take a used number from the sub-box and mark it
// as used
digits[matrix[boxX + i][boxY + j]] = true;
}
}
There seem to be two issues you are unclear on:
The boolean array - this array is used to track which digits have been used already on a specific row or column. So imagine a row of tick boxes each with a digit written next to it (the array index) - these boxes are checked or unchecked to show a digit has been used or not.
The expressions 3* (x/3) and 3 * (y/3) - what you need to remember here is that this is integer division (that means the result of the division is always rounded down to an integer. For example if x=1 then 3 (x/3) is 3 (1/3) is 3 * (0) =0 (whereas if this was float division the result would be 3*(0.3333)=1. So these maths expressions essentially change you number to the next lowest multiple of three - that is 1 -> 0, 2 -> 0, 3 -> 3, 4 -> 3 etc.

For Loop help, checking prime numbers

for (int i = lo; i <= hi; i++)
{
boolean isPrime = true; // each value of i starts out assuming it IS prime
// Write a loop below that divides i by 2,3,4,5 etc upto i/2
// If at any time you find a divisor that evenly divides i
// Then set isPrime to false
/* your prime checking loop HERE */
for (int j = 2; j <= hi / 2; j++)
{
if (i % j == 0)
{
isPrime = false;
}
}
// DO NOT REMOVE OR MODIFY LINE BELOW
if ( isPrime )
System.out.print( i + " " );
}
Okay, here is the code I currently have and i'm assuming the problem lies within. The program takes a text input file and sets the first value as lo (in the text demo I have, the lo = 3 and hi = 73.) For whatever reason, the only numbers that are output as 'prime' start at 41 and then go totally fine after that. I have no idea why the first half of the numbers aren't being outputted at all.
Keep in mind I must use for loops for this project, methods and such are not in the 'vocabulary' at the moment. Trying to keep it simple. I'd appreciate the help guys.
Read the comment block again. It says to loop until i/2. You're looping until hi/2.
The issue is that you keep using modulus of the number on itself.
3 % 3 is zero, but 3 is prime.
the prime checking loop, choose one:
for (int j = 2; j < i / 2; j++)
or
for (int j = 2; j <= sqrt(i); j++)

Categories

Resources