I have a 2d array that contains polyominos of lengths 1 to 4, i want to shuffle their position AND rotation.
For example:
[0,0,1,0,0,0,0,0,0,0]
[0,0,1,0,0,0,0,0,0,0]
[0,0,1,1,0,0,0,0,0,0]
[0,0,0,0,0,0,0,0,0,0]
[0,0,X,0,0,0,0,3,0,0]
[0,0,0,0,0,0,0,0,0,0]
[0,0,0,2,2,0,0,0,0,0]
[0,0,0,2,0,0,0,X,0,0]
[0,0,0,0,0,0,0,0,0,0]
[0,0,0,0,0,0,0,0,0,0]
First, 0s are empty spaces, and numbers are polyominos. There are four of them: one tetromino "L" made by 1s, one tromino "L" made of 2s, and one monomino made by one 3. I want to shuffle this grid, changing their position and rotation without loosing their structure.
Second, though 0s are available spaces, Xs aren't and cant be shuffled.
I'd be happy if someone can help me solve the first part of the problem, but if there is anyone smart (or bored) enough to solve also the second part, it'll really appreciated because this stuff gets way over my head.
Edit:
The problem can also be seen as placing N polyominos in a 2d grid of fixed size.
I think that rather than having a board the way you have it, you should actually store a list of pieces, and their rotation and position on your board. The way you are storing it right now, it is much more difficult to manipulate because you have essentially finalized the data onto the board as a single data set.
If you like, you can store the board with a set of booleans (simply to take up less space in memory) where a true correlates to your "X" and a false correlates to an un-utilized space.
Then I would randomly choose a rotation for each piece before placement.
After you know the finalized randomized rotation, you can move through your LIST of pieces, generate a list of all placement locations possible, and simply choose one of those locations randomly. You will have to generate this potential placement list separately for each piece, as once a piece is placed, you will not be able to place another piece on top of it!
The trick here is to separate your board data from your pieces data so that you can manipulate the pieces more easily.
Related
I'm having a very difficult time determining how to translate a game state for a specific turn in a game I'm developing into a limited sequence of moves that represents the moves taken for that turn. I'd appreciate advice on how I can do this.
The rules for the game are relatively simple. There's a hex board, with hexes belonging to 2 players. On any given turn, pieces can already exist on the board, having been purchased on a previous turn, or they can be purchased onto the board (a yellow piece represents its being purchased onto the board this turn).
These pieces are "active", and can still be moved. Pieces can also be combined, and will still remain "active". They can be combined either by moving an existing piece onto another piece, or by purchasing a new piece onto an existing piece. When combined, an upgraded piece will exist on the target hex. Pieces can be of 3 strengths; X, Y, and Z. X combining with X gives Y, and X with Y gives Z.
Pieces can continue to be merged like this and remain "active". A piece can be moved to another hex in its own territory and remain "active". A piece stops being "active" when it is moved to capture the other player's hex. It cannot move after that, although it can still be combined with. Green below indicates an inactive piece.
A piece can also be summoned directly on top of another piece, resulting in an upgraded piece (if it was already active, it stays active; if it was inactive, it stays inactive):
Now, this is pretty easy to represent in game state; just update the state of the pieces and the board to reflect whatever's currently true. And it's quite easy to convert it into a sequence of moves as long as you theoretically allow for that sequence of moves to be unbounded; pieces could remain active and move to and fro ad infinitum. Of course, I want to keep the sequence of moves limited. This is where I'm having trouble. I have the following 2 moves:
Move piece to location
Summon piece to location
How can I convert the moves a player makes into a limited sequence of moves to represent what the player actually did, leading to the final state? I don't know if I'm missing something, but this seems to get almost impossibly complex to figure out. If you have pieces moving around within their own territory and remaining active, you might think you could just update the move in-place to the new coordinates instead of adding a new move to the new coordinates, but what if there is another move where a piece combines with that piece to form an upgraded piece, which relied upon the first piece moving to its first set of coordinates? Updating the move coordinates in-place now means that that second combination move becomes a regular move because it is now moving onto an empty hex, yet it should remain a combination move (the board state will in fact be the combined piece having moved to the new coordinates).
Conceptually, there should always be a limited sequence of moves that can represent any operation. However I am finding it extremely hard to figure out how to write an algorithm to do this automatically. I think an algorithm that would at least prevent the unbounded nature of the moves would be to say "a piece's most recent move is updated instead of adding the new move to the list if that most recent move is not a combine or capture operation". That should always result in the game state being correctly created by the move set, and prevent unlimited cycles. However that could still result in quite a lot of moves. For instance if you had 10 pieces in a territory, you could move all 1, capture with 1, move the remaining 9, combine one with another, move the remaining 8, etc. potentially resulting in over 60 moves from 10 pieces. It would be nice if there were an algorithm to get this down a bit, and I'm still not 100% sure that even this algorithm doesn't have some edge cases where it wouldn't work.
Am I missing a relatively straightforward way to solve this problem? The rules must stay the same but I'm open to suggestions about perhaps introducing new move types if that would help solve the problem, too.
From what I understand from your question and the comments, the problem seems to be the large amount of possible moves to be made in a single turn, including combinations. I couldn't think of a complete algorithm, but I think I can give you a pretty good starting point. In the end of the answer you will find the edge cases not contemplated here and possible solutions to them.
My suggestion is not to think in terms of movements, but in terms of events, and to check that each event is possible, according to the rules.
Previous assumptions and definitions.
The size of the board, the number of pieces and the number of purchasable pieces are finite.
Each piece is labelled with an ID of the form T_s, where T is the piece type (X, Y, Z) and s is a counter (1, 2, 3, 4...).
You have access to the information from the game state before the game turn and after it.
You can only purchase pieces of type X.
Possible events:
Piece moved
Piece purchased
No event of combination because it can always be translated to one or more events of movement. In other words: we can assume that if a piece is moved after being combined with another, there is an equivalent sequence of movements where both pieces just move to the final destination and get combined there. X_1 -> X_2 = Y_1; Y_1 -> NEWCELL equals to X_1 -> NEWCELL; X_2 -> NEWCELL
The algorithm
My algorithm is based on the fact that you can represent the game state as disjoint sets of labelled pieces. So the first thing to do is to use an inundation algorithm to compute the disjoint areas (area = set of cells) of the board in the initial state that belong to the player. Let's call these areas A_1, A_2, etc. It is not necessary to have this representation for the final state.
You also need to compute the difference of the initial pieces set and the final one, to determine the number of combinations and purchases made.
A. Let's call N_T_s to the number of pieces of type T in the starting state and N_T_f to the number of pieces of type T in the final state. You can calculate the number of purchased pieces like this: (N_X_f + 2*N_Y_f + 3*N_Z_f) - (N_X_s + 2*N_Y_s + 3*N_Z_s).
B. As the pieces are labelled, you can build a set NEW of pieces that were not present in the initial state. We will assume these are either the result of a purchase or a combination.
Prepare some variables:
Set a counter of PURCHASED with the initial value computed in the step 2A.
For each area A_i
Create a set of COMBINED_i with the pieces from A_i that are not present in the final state (as the only way for a piece to disappear is to be combined).
Define an area M_i as the union of A_i and all its adjacent cells.
For each area A_i and for each piece inside it:
A. If the piece is not inside NEW: its final position must be inside M_i. Given that a deactivated cell cannot move, it shouldn't move any further.
For each piece inside NEW:
The piece must be inside one of the M_i areas (otherwise the turn is invalid). Let's call it M_p.
A. If the piece is of type X: decrease the value of the counter PURCHASED. If the value is negative, the turn is not valid.
B. If the piece is of type Y:
If there exist two pieces X inside COMBINED_p, remove them from the set.
Else, if there exists a single X inside COMBINED_p remove it from the set and decrease the value of the counter PURCHASED.
Else, decrease twice the value of the counter PURCHASED.
C. If the piece is of type Z:
If there exist an X and a Y inside COMBINED_p, remove them from the set.
Else, if there exists an Y but no X inside COMBINED_p remove it from the set and decrease the value of the counter PURCHASED.
Else if there exist two X inside COMBINED_p remove them from the set and decrease the value of the counter PURCHASED.
Else if there exists a single X inside COMBINED_p remove it from the set and decrease twice the value of the counter PURCHASED.
Else, decrease thrice the value of the counter PURCHASED.
How to store events
In step 4A you can store the movement of the piece.
In step 5A you can store the purchase of the piece.
In steps 5B and 5C you can store the movements of the pieces you remove from the COMBINED_p (movement from their initial position to the position of the final combined piece) sets and the purchase of pieces each time you decrease the counter.
Observations
I didn't mention it but I guess you should remove from the areas M_i all the cells occupied by enemy pieces.
The order of if-elses in step 5 is very important. It is the greedy approach to the Change-making problem. Keep it in mind in case you added more combinations to the game.
You haven't told us where the currency for purchasing pieces comes from, but you can quickly check the validity of the purchases made in step 2A.
In case that the board was not finite (maybe it is automatically generated), then you could apply this algorithm to the finite surface defined by the presence of the pieces in both states.
Edge cases
The disjoint areas might not represent the true space where a piece can move, given that pieces are solid and can't be trespassed by other pieces without combining.
For example: I have an area that is just a row like this: #XY##. My algorithm would approve a final state ##YX#. A possible approach would be to check the existence of disjoint sub-areas and treat them separately.
In the final state, two initially disjoint areas could become joined thanks to a piece (let's call it a bridge) that moves into an intermediate cell that is adjacent to both areas at the same time. Precisely thanks to the first edge case, we don't need to worry about other existing pieces moving from one area to another through the bridge... but if we find that the bridge is a recently combined piece (in other words, it belongs to NEW), then we have to make extra checks and even backtracking to determine where did the combined pieces came from, because we can no longer assume they came from a single area plus possible purchases.
As you see, this is not a complete algorithm, but it may settle some working ground. The main contribution I attempt to make is the approach of the disjoint areas and the event focused analysis. If you want, I could try to elaborate further on the edge cases and try to find solutions and incorporate them in the whole algorithm.
In the end, given the flexibility of the ruleset, I had to come up with a different algorithm from the ones suggested. I came at the problem from the other end; instead of considering how to absolutely minimize the number of moves, what is it that allows the unbounded potential for number of moves? It's the fact that active pieces can move an unbounded number of times between empty hexes. Everything else is bounded quite nicely; a piece can move, then combine, but that's it; the combination removes it from the board and upgrades the underlying piece. It can move, then capture, but that ends its turn. So, to eliminate the unbounded nature of the moves list, I ended up with the following algorithm for validating a moves list:
Only one summon operation for a piece is allowed
For a move operation, any moves for a piece after it has captured are forbidden
Multiple non-combine/non-capture moves in a row for a piece are forbidden, if there are no moves between that piece's two moves that are combine/capture moves
When a piece is combined, it is removed from the board and the underlying piece is upgraded, meaning that that piece then can't move after the combine operation as it no longer exists on the board
This does mean that you can get a piece moving before a combine or capture operation, and a piece can even have multiple non-combine/non-capture moves in a turn if they are separated by other pieces being combined - which I think is somewhat necessary in case another piece is then moved on top of it for combination - but multiple such moves in a row are illegal, nicely limiting the bounds of how many moves may be submitted for a turn.
On the client side, it detects if a piece move is the piece moving twice in a row within its own territory. If it isn't, it just adds the move. If it is, it checks whether there is a move since the existing one with the same target coords. If there isn't, it just updates the existing move in-place. If there is, it splices that move out as well as the existing move for this piece, and inserts it at the end of the moves list, followed by this piece's move; this is needed to reflect the fact that this piece is now being combined with that piece, in the correct order.
This seems to work, but it's rather complicated and confusing. Seems to be the nature of the problem, though!
This is actually similar task as i.e. find what moves you need to do in chess to change from one state to another. It can even happen that the solution does not exist.
By default its O(x^n) issue, where x is possible moves and n number of moves. Yes, its growing quite rapidly. In general you have to check all possible moves in BFS way each turn until you find the solution.
Actually if you are successful with it, you are very close to implementing AI, you just add some scores to your moves and thats it.
To optimize it, you can use some heuristics (to i.e. prefer movement in correct direction or not expanding branches that does not make sense - i.e. when piece get combined and you know it is not possible). However there can be situations it will not be sufficient (i.e. piece needs to travel really far away around some enemy position to not be catched).
To get you further - google how to create AI for five-in-a-row or chess, your task will be very similar. Unless you want to create AI, I would strongly recommend to get all movements from client - even if you make a bit more movements than necessary.
I'll start directly with the example:
In a game, there is a bag that players will use to store their items (items has variable sizes) and the bag has a variable size also.
In a bag of 8x15 slots, I need to insert an item that occupies 2x2 slots, I can search space to actually check if there's enough space for this item to be stored - this is easy, but, what if I don't have enough space to store the requested item? This is the real problem.
I'm trying to find a way to actually rearranging all the current items in the current bag in order to release space for the new item.
Is there any algorithm that will help me doing that?
EDIT
Rules:
I cannot remove any of the current items in the bag, just rearrange them in order to store a new one if there's not enough space.
I think this unfortunately is an NP-hard problem, but you can use a greedy approximation algorithm. The approximation algorithm could work as follows:
Sort all items by item volume, descending.
Iterate trough the list and try to place the current item anywhere
If at any point the current item can't be fitted anywhere, decide that the item can't be picked up.
If all pieces are fitted, decide that the item can be picked up.
This is based on the intuitive thought that larger pieces are 'harder' to place than smaller pieces. Another thing you could do, if most items are 1x1, is a brute-force solution, which is quite feasible in such a small inventory. This would work as follows:
Try every single position for the current piece, where it still fits and for every such position:
Do this with the next unpositioned piece.
This will always solve your problem, but is way slower (though more accurate). This algorithm can be inproved by leaving out every 1x1 piece, placing them afterwards.
An elaboration on this question, but with more constraints.
The idea is the same, to find a simple, fast algorithm for k-nearest-neighbors in 2 euclidean dimensions. The bucketing grid seems to work nicely if you can find a grid size that will suitably partition your data. However, what if the data is not uniformly distributed, but has areas with both very high and very low density (for example, the US population), so that no fixed grid size could guarantee both enough neighbors and efficiency? Can this method still be salvaged?
If not, other suggestions would be helpful, though I hope for answers less complex than moving to kd-trees, etc.
If you don't have too many elements, just compare each with all the others. This can be a lot faster than you'd think; today's machines are fast. Unfortunately, the square factor will catch you sooner or later; I figure a linear search of a million objects won't take tooo long, so you may be okay with up to 1000 elements. Using a grid, or even stripes, might boost that number substantially.
But I think you're stuck with a quadtree (a specific form of k-d tree). Your whole map is one block, which can contain four subblocks (upper left, upper right, lower left, lower right). When a block fills up with more elements than you want to do a linear search on, break it into smaller ones and transfer the elements. (Only leaf nodes have elements.) It's easy to search within a given radius of a given point. Start at the top and if a part of a block is within range of the point, check out it's subblocks the same way if it has them. If it doesn't, check its elements.
(When searching for "closest", take care. The square grid means a nearer object might be in a farther block. You have to get everything within a given radius, then check 'em all. If you want the 10 closest and your radius of 20 only picked up 5, you need to try a larger radius. You may have a rejected item that proved to be 30 away and think you should grab it and a few others to make up your 10. However, there may be a few items at 25 away whose whole blocks were rejected, and you want them instead. There ought to be a better solution for this, but I haven't figured it out yet. I just make a guess at the radius and double it till I get enough.)
Quadtrees are fun. If you can set up your data and then access it, it's easy. The problems come when your mapped elements appear, disappear, and move while you are trying to figure out who's near what.
Have you looked at this?
http://www.cs.sunysb.edu/~algorith/major_section/1.4.shtml
kd-trees are quite simple to implement, there are standard java/c implementations.
Also:
You may want to post your question here:
https://cstheory.stackexchange.com/?as=1
I have an image separated into a 3x3 grid. The grid is represented by an array. Each column or row can be rotated through. E.g, the top row [1,2,3] could become [3,1,2] etc.
The array needs to end up as:
[1,2,3]
[4,5,6]
[7,8,9]
And would start from something like:
[5,3,9]
[7,1,4]
[8,6,2]
It will always be solvable, so this doesn't need to be checked.
I've tried a long handed approach of looking for '1' and moving left then up to its correct place, and so on for 2, 3,... but end up going round in circles for ever.
Any help would be appreciated, even if you can just give me a starting point/reference... I can't seem to think through this one.
your problem is that the moves to shift one value will mess up others. i suspect with enough set theory you can work out an exact solution, but here's a heuristic that has more chance of working.
first, note that if every number in a row belongs to that row then it's either trivial to solve, or some values are swapped. [2,3,1] is trivial, while [3,2,1] is swapped, for example.
so an "easier" target than placing 1 top left is to get all rows into that state. how might we do that? let's look at the columns...
if the column contains one number from each row, then we are in a similar state to above (it's either trivial to shift so numbers are in the correct rows, or it's swapped).
so, what i would suggest is:
for column in columns:
if column is not one value from each row:
pick a value from column that is from a duplicate row
rotate that row
for column in columns:
as well as possible, shift until each value is in correct row
for row in rows:
as well as possible, shift until each value is in correct column
now, that is not guaranteed to work, although it will tend to get close, and can solve some set of "almost right" arrangements.
so what i would then do is put that in a loop and, on each run, record a "hash" of the state (for example, a string containing the values read row by row). and then on each invocation if i detect (by checking if the hash was one we had seen already) that the state has already occurred (so we are repeating ourselves) i would invoke a "random shuffle" that mixes things up.
so the idea is that we have something that has a chance of working once we are close, and a shuffle that we resort to when that gets stuck in a loop.
as i said, i am sure there are smarter ways to do this, but if i were desperate and couldn't find anything on google, that's the kind of heuristic i would try... i am not even sure the above is right, but the more general tactic is:
identify something that will solve very close solutions (in a sense, find out where the puzzle is "linear")
try repeating that
shuffle if it repeats
and that's really all i am saying here.
Since the grid is 3x3, you can not only find the solution, but find the smallest number of moves to solve the problem.
You would need to use Breadth First Search for this purpose.
Represent each configuration as a linear array of 9 elements. After each move, you reach a different configuration. Since the array is essentially a permutation of numbers between 1-9, there would be only 9! = 362,880 different configurations possible.
If we consider each configuration as a node, and making each move is considered as taking an edge, we can explore the entire graph in O(n), where n is the number of configurations. We need to make sure, that we do not re-solve a configuration which we have already seen before, so you would need a visited array, which marks each configuration visited as it sees it.
When you reach the 'solved' configuration, you can trace back the moves taken by using a 'parent' array, which stores the configuration you came from.
Also note, if it had been a 4x4 grid, the problem would have been quite intractable, since n would equal (4x4)! = 16! = 2.09227899 × 10^13. But for smaller problems like this, you can find the solution pretty fast.
Edit:
TL;DR:
Guaranteed to work, and pretty fast at that. 362,880 is a pretty small number for today's computers
It will find the shortest sequence of moves.
lets say I have a very big matrix with 10000x10000 elements all having the value '0'. Lets say there are some big 'nests' of '1's. Those areas might even be connected, but very weekly connected by a 'pipe' of '1's.
I want to get an algorithm that very quickly (and dirty if necessary) finds these 'nests' of '1's. Here it shouldn't 'cut apart' two weekly connected 'nests'.
Any idea how I should do such an algorithm?
Maybe a pathfinding algorithm like A* (or something simpler like a BFS or DFS) may work in this case..
You can:
search starting point for your searches by finding small nests (ignoring pipes).. so at least a 3x3 block of 1's
then you should pathfind from there going through 1's until you end your "connected component" (poetic license) inside the matrix
repeat starting from another small 1's block
I would say it depends on how the data is needed. If, given two points, you need to check if they are in the same block of 1's, I think #Jack's answer is best. This is also true if you have some knowledge of where blocks are initially, as you can use those as starting points for your algorithm.
If you don't have any other information, maybe one of these would be a possibility:
If given a point, you wish to find all elements in the same block, a flood fill would be appropriate. Then you could cache each nest as you find it, and when you get another point first see if it's in a known nest, and if it isn't do a flood fill to find this nest then add it to the cache.
As an implementation detail, as you traverse the matrix each row should have available the set of nests present on the previous row. Then you would only need to check new points against those nests, rather than the complete set, to determine if a new point is in a known set or not.
Be sure that you use a set implementation with a very low lookup cost such as a hashtable or possibly a Bloom filter if you can deal with the probabilistic effects.
Turn the matrix into a black&white bitmap
Scale the matrix so that nests of size N become a single pixel (so if you look for 10x10 nests, scale by a factor of N=10).
Use the remaining pixels of the output to locate the nests. Use the center coordinate (multiplied by the factor above) to locate the same nest in the matrix.
Use a low-pass filter to get rid of all "pipes" that connect the nests.
Find the border of the nest with a contrast filter on the bitmap.
Create a bitmap which doesn't contain the nests (i.e. set all pixels of the nests to 0).
Use a filter that widens single pixels to grow the outline of the nests.
Bitwise AND the output of 7 and 5 to get the connection points of all pipes.
Follow the pipes to see how they connect the nests