Here's the example (counting black ones):
input:
output:
5 4 // 5 groups (4 squares each)
1 1 // 1 group containing 1 square
For Now, I can't think of anything better than a painfull for iteration. Would it be possible to get these groups in a recursive way?
Thanks
Set all black squares as nodes. Connection between black squares (if the squares are next to each other) will be an edge.
This gives you a graph.
A DFS in the graph will get you all the groups. Note that DFS is recursive by nature.
At the beginning, each cell be "unvisited".
I would iterate through the cells until you meet an "unvisited" black cell. Each white cell you hit up to that point
Once you hit a black cell, you "expand" it to all directions if possible (similar to "floodfilling"). You expand as long as you can and mark all the visited cells as "visited". After you did that, you count how many black cells you infected, and you know how big the group was. After detecting the group, you go on to the next "unvisited" black cell.
You can use algorithm for connected component labeling with 4-connectivity
Related
I'm designing a game in Scratch. The game is suppose to have a Spaceship travel through space, avoiding asteroids. These asteroids start at a fixed X position on the right side of the screen and go to the left, horizontally until they hit a fixed X position and they'll disappear. The asteroids will start in groups between 2-6 (it's a random number generated), and each set is about 1 second apart.
Assuming the game throws out up to 6 asteroids at once, I want to make sure each asteroid is distant from the next. I tried using two variables and comparing the distance, but this did not work. I can put the group of asteroids Y spawning position into a list. So say for instance in my list, I have:
0, 100, 5, 30, -20
As you can see, there are two items in that list that are close together. What I'm trying to do, is prevent this, so the third item would be something else, like -50, for instance, and then if a six item is generated, ensure it's also distant.
Can someone pseudocode how to achieve something like this? It doesn't matter what programming language it's in, I can probably translate the general idea into Scratch.
There is a way to do this without a trial-and-error loop.
Instead of picking random positions, pick random distances, then scale them to fit the screen.
Roughly, the approach is as follows.
The lists below represent the distances between neighboring asteroids (ordered by Y coordinate), as well as distances between the outermost asteroids and the edges of the screen.
For example, if a group contains 6 asteroids, then you need lists of 7 elements each.
Create a list L1 of minimal distances. Obviously, these are all fixed values.
Create a list L2 of random numbers. Take them from some arbitrary, fixed range with a positive lower bound, e.g. [1..100].
Calculate the total 'slack' = height of screen minus sum(L1).
Calculate a multiplication factor = slack divided by sum(L2).
Multiply every element of L2 with the multiplication factor.
Add every value from L1 to the value in L2 at the same index.
L2 now contains a list of distances that:
obey the minimal distances specified in L1
together equal the height of the screen
The final step is to position every asteroid relative to its neightbor, based on the distances in L2.
Note: if step 3 gives a negative number, then obviously there is not enough room on screen for all asteroids. What's worse, a naive 'trial-and-error' algorithm would then result in an infinite loop. The solution is of course to fix your parameters; you cannot fit 6 asteroids in 360 pixels with a minimal distance of 100.
To do this, you need to do through each previous entry in the array, compare that value to the new value, and if any element is too close change the value. This process needs to repeat until a suitable number is found. If this number is less then some minimum distance, then a variable tooClose is set to yes and the value will be reset. At the begining of the loop tooClose is set to yes so that at least one random number will be generated. Then, at the beginning of the loop, the value is randomized, and tooClose is set to no, then, I loop through all the previous entries with the value i, comparing each element and setting tooClose to yes if it is too close. The comparison between numbers is done with a subtraction, followed by an absolute value, which will ensure the result is positive, giving the difference between the two numbers as a positive value.
Here is a screenshot of the code:
And here is the project:
https://scratch.mit.edu/projects/408196031/
I'm trying to make a brick shooter game, where you have a board (2D array of int) and a set of bricks on each side. For example, I have bricks of 3 colors represented by numbers 1, 2, 3 and I put them in random locations on the board. When player shoots one brick from a side of the board it goes straight to the first brick it meets on the board or to the edge.
The problem is when 3 or more bricks of the same color are adjacent, they have to be deleted. I don't quite know how to implement that... Programming language you choose doesn't matter if it's possible to see the logic behind that code for a beginner like me.
...and also it is my first question on the site, so don't attack me if something's wrong.
I think what you are looking for, is an adjacency matrix, in which you will tell every block, which color has the adjacent block.
In that way will be easy for you to know if the blocks have the same color. If you don't know what an adjacency matrix is, I will put a link for you, in order to learn how they work.
https://www.sciencedirect.com/topics/computer-science/adjacency-matrix
This should help you, to overcome your problem.
One possible solution is to implement a flood fill algorithm. This will find all blocks attached to the hit block, and all the blocks attached to those, and all... etc.
Here, a cell is a discrete space in the array, e.g. position [n, m] in the array.
Insert into active, the seed cell (hit block)
Select any cell c from active
Insert c into closed, and remove from active
Insert into active the matching-value adjacent neighbours of c NOT in closed or active
If active has cells, move to step 2, else continue
All values in closed can be deleted
The premise of this problem is a sorted array of strings that's interspersed (in no particular order) with empty strings, like so:
["at", "", "", "", "ball", ""]
My algorithm came down to finding the midpoint, and arbitrarily running my pointer left (or right) until it landed on a non-empty string so that I can then execute a binary search.
The solutions recommended checking both left and right elements until we land on a non-empty string. Once we have a non-empty string, we can proceed with binary search.
The solutions way on average will land much quicker on a non-empty string, but it requires more calculations to get there. Consequently, I'm struggling to compare/contrast the time costs of each approach.
Which is the more optimal approach?
I guess the question is: when you land on an empty string, what algorithm visits less elements?
Suppose you have an sequence of N empty strings. With the suggested approach, if you land on the N/2th, you will visit N elements before finding a non empty string.
if you consider landing in the following positions, for each positions you end up visiting two less elements (one on the left and one on the right). So, your number of visited elements as a function of the landing position is:
{2, ... N-4, N-2, N, N-2, N-4, ...}.
If you visit only the element in a direction, your number of elements as a function of the position is {N, N-1, N-2...1}
Assuming that the probability of landing at any position in a range of empty string is the same, knowing that the sum of the first K number is
K*(K+1)
sum(1,K) = ------
2
and the average of the first K numbers is
K*(K+1)
avg(1,K) = ------ = K/2 + 1
2*K
The average in the first case is 2 * ((N/2)/2 + 1) = N/2 + 2
The average in the second case is is N/2 + 1
So, it seems to me in terms of complexity the two approaches are the same.
On a glimpse I would say that the strength of binary search is to always cut the array to search in half by querying the center element. With gaps, that is no longer possible as the center element can be a gap. So what we would want to do is find the closest non-gap element to the center. In order to do so we'd look alternatingly left and right.
position 1 2 3 4 5 6 7 8 9
value A B _ U _ _ _ T Z
Say we are looking for value B. We hit position 5 ( = (1+9)/10 ) which is a gap. If the algorithm were to always go right, then we'd walk on till position 8 and have the range to search restricted to 1-8 thus.
If on the other hand we had looked right, then left (etc.) then we'd have found position 4, which is much closer to the center and the range to search would be more restricted (1-4 in this example). Of course we can always make up an example where the always-look-right algorithm works better (e.g. when looking for T in above example :-), but generally it will be best to try to get as close to the center as possible, which is what the alternatingly-right-left solution does.
It was also suggested in a comment to remove gaps and you answered you'd have to read the whole array for this. This is true, but if you want to search the same range multiple times, that may be the fastest approach still, because you'd build that gapless arrray just once.
We'd build a new array containing the values and the original position and this array can be searched with pure binary search. Search this array several times and at one time it will pay to have built this new array.
position 1 2 3 4 5
orig. pos. 1 2 4 8 9
value A B U T Z
Even with empty strings, it is possible to perform a similar search as a binary search. When you visit an empty string, you should continue the binary search in one of the sides arbitrarily, then save that information in the stack, i.e. store whether this was a random direction or a wise direction. If at a certain point, the algorithm understands that was a wrong random direction, then tests the other direction with binary search and updates the stack of choice. If it was the right direction then just updates that stack and continues as normal binary search. This may lead to a linear time algorithm, however, depending on the distribution of the empty spaces, it may have an average of O (log n).
I currently use the following array formula to find the most common word or number in a range, ignoring any blank cells:
{=(INDEX(D1:D10,MODE(IF((D1:D10<>"")*ISNA(MATCH(D1:D10,$A$1:$A1,0)),MATCH(D1:D10,D1:D10,0)))))}
I am now looking to do something slightly different. I still want to find the most common word or number in a range, however I now have 2 lists: the first is a list of 'positive' words/numbers and the second is a list of 'negative' words/numbers.
To illustrate using an example: the colour green appears in the 'positive' list 4 times and the colour blue appears twice in the 'positive list', but green appears 3 times in the 'negative' list and blue does not appear at all in the 'negative' list. Using the above formula on the first list would return green as the most common word. However I now want it to take into account that green is not the most common word given the combined lists (i.e. 4 positives - 3 negatives = 1 green, and 2 positives - 0 negatives = 2 blue).
In the below image, using the formula under each list shows green to be the most common word. I would like to combine these lists and cancel out any instances where the colour appears on both instances - so 3 of the greens on the positive list would be cancelled out with the 3 greens on the negative list, leaving only one left.
In essence, I suppose I am trying to create a tally or ledger of some kind where rather than numbers that add or subtract I have words whose frequency is added or subtracted.
Thanks for the help, and apologies if I haven't been too clear in the task!
This should work:
=IF(SUMPRODUCT((MMULT(COUNTIF(OFFSET(B2:B11,,{0,1}),B2:B11),{1;-1})=MAX(MMULT(COUNTIF(OFFSET(B2:B11,,{0,1}),B2:B11),{1;-1})))/COUNTIF(B2:B11,B2:B11&""))>1,"No Favourite",INDEX(B2:B11,MATCH(MAX(MMULT(COUNTIF(OFFSET(B2:B11,,{0,1}),B2:B11),{1;-1})),MMULT(COUNTIF(OFFSET(B2:B11,,{0,1}),B2:B11),{1;-1}),0)))
And for non-contiguous, dynamically-defined ranges, assumed to be stored as Defined Names Positive and Negative, array formula**:
=IF(SUM((COUNTIF(Positive,Positive)-COUNTIF(Negative,Positive)=MAX(COUNTIF(Positive,Positive)-COUNTIF(Negative,Positive)))/COUNTIF(Positive,Positive&""))>1,"No Favourite",INDEX(Positive,MATCH(MAX(COUNTIF(Positive,Positive)-COUNTIF(Negative,Positive)),COUNTIF(Positive,Positive)-COUNTIF(Negative,Positive),0)))
Regards
**Array formulas are not entered in the same way as 'standard' formulas. Instead of pressing just ENTER, you first hold down CTRL and SHIFT, and only then press ENTER. If you've done it correctly, you'll notice Excel puts curly brackets {} around the formula (though do not attempt to manually insert these yourself).
First list your candidates in column D starting at D2
Then in E2 enter:
=COUNTIF(B$2:B$12,D2)-COUNTIF(C$2:C$12,D2)
and copy down.
Finally in F2 enter:
=INDEX(D:D,MATCH(MAX(E:E),E:E,0))
With your data:
Hello I need help with making algorithm with the following:
Let's say a 2d domain of space with xmax, xmin, ymin, ymax, with 'n~10,000' of points in the space.
Go through lists of points positions.
When there is maximum no,of points (lets say 10) in the box, the box split into 4 equal smaller boxes.
Then check again if the each of the smaller box has more than maximum no. of points. it will split again into 4 equal smaller boxes.... until the box has less than the maximum no.of points per box.
Any suggestions how I can make this algorithm? Please?
Cheers!
You should try to program this yourself and then ask again as soon as you run into problems.
To get you started here's an idea: create two arrays of indices that just go up from 0 to the number of points you have. Then use the x-values of the points to sort one index-array and the y-values to sort the other index-array. You can then read what you need by simply taking the n-th entry from each array and combine the x/y-maxima of the 2 points you got. (Also: To then get the next cross-point you dont need to sort again, just use the next n'th entries)