I am working on a c++ project and I'm stuck. I am trying to generate a grid from a vector that holds what elements are in the grid. Originally, the vector will hold something like(3,3) and I would simply create a grid that looks like this XXX. If it were (3,2,1), it would be XX|X. The first number in the parenthesis represents the total number of X's that is in my Grid(even after an X has been removed) and the consequent number represents the number of X's for each column like shown above.
The problem I'm having is creating a grid that also keeps track of the removed X's so when I want to recreate it, the space for the removed X's is there and not overwritten.
For instance: Initial Grid = XXX|XX =>(5,3,2)
Later Grid = OOX|XX => (3,1,2)
Generating a grid from the "Initial Grid" is simple but generating later grids are hard(for me). For instance, My new vector would hold (3,1,2) for the "Later Grid". If I want to generate the "Later Grid" using the (3,1,2) representation, how should I do it. Any help is greatly appreciated.
This is not a homework, this is a side project that I'm working on.
Would a two-dimensional array not suffice for your program? Say you declare a two-dimensional array of your max map size, then use two independent variables to represent the max grid size there after?
char Map[15][15] = {//...}
int Width = 15;
int Height = 15;
//Map decreases in size...
Width--;
Height--;
//all calculations are now based off of width and height(not the initial size of the array)
if(xpos < Width)
//do stuff
sounds like you're working on a persistence problem. I may not fully understand what you are trying to do, but it sounds like you will be reading a series of tuples in the form (x:int, y:int, z:int)
where
x = total number of 'X'
y = 'X' before vertical bar
z = 'X' after vertical bar
then you want to pad missing 'X' with 'O'.
The problem it seems is that you are loosing information about the initial state of your grid and therefore don't know how many 'O' to pad with.
if I were you I would just add another value to keep track of the initial state. This value would never change and would be populated with the initial number of 'X' when the grid is first generated.
so in your example you have:
Initial Grid = XXX|XX =>(5,3,2) Later Grid = OOX|XX => (3,1,2)
instead try adding an initial state value to the tuple like this
Initial Grid = XXX|XX =>(5,3,2,5) Later Grid = OOX|XX => (3,1,2,5)
now you have a tuple in the form (x:int, y:int, z:int, n:int) where
x = total number of 'X'
y = 'X' before vertical bar
z = 'X' after vertical bar
n = 'X' in initial state
now we can determine the number of 'O' to pad with by evaluating
n - x = number of 'O' to pad with
assuming that the initial number of 'X' varies from tuple to tuple you would need to keep track of the initial 'X' state as well. keeping track the initial number of 'X' will allow you to always discern how many 'O' you need to pad with for every successive iteration of the grid
Related
Here we have a box that is 4 * 7 and it can be filled with rectangles that are either 1 * 2 or 2 * 1. This depiction is from the book Competitive Programmer's Handbook.
To solve this problem most efficiently, the book mentions using the parts that can be in a particular row:
Since there are 4 things in this set, the maximum unique rows we can have is 4^m, where m is the number of columns. From each constructed row, we construct the next row such that it is valid. Valid means we cannot have vertical fragments out of order. Only if all vertical "caps" in the top row correspond to vertical "cups" in the bottom row and vice versa is the solution valid. (Obviously for the horizontal fragments, their construction is restricted in row creation itself, so it is not possible for there to be inter-row discrepancy here.)
The book then mysteriously says this:
It is possible to make the solution more efficient by using a more
compact representation for the rows. It turns out that it is
sufficient to know which columns of the previous row contain the upper
square of a vertical tile. Thus, we can represent a row using only
characters upper square of a vertical tile and □, where □ is a combination of characters lower vertical square, left horizontal square and right horizontal square.
Using this representation, there are only 2^m distinct rows and the
time complexity is O(n2^(2m)).
Why does this simple square work? How would you know if there is a horizontal box underneath the top vertical fragment? How would you know left and right horizontal fragments are aligned? It breaks my mind why this is possible. Does anyone know?
Here is my ad hoc C++ implementation for 2 by n matrix, which would not work in this case, but I was trying to abstract it:
int ways[251];
int f(int n){
if (ways[n] != 1) return ways[n];
return (ways[n] = f(n-1) + f(n-2));
}
int main(){
ways[0] = 1;
ways[1] = 1;
for (int i = 2; i <= 250; i++){
ways[i] = -1;
cout << f(250) << '\n';
}
}
I want to remove numbers from a matrix that represents coordinates with the format 'x y z'. One example:
1.211 1.647 1.041
2.144 2.684 1.548
1.657 2.245 1.021
1.657 0.984 2.347
2.154 0.347 2.472
1.211 1.647 1.041
In this example the coordinates 1 and 6 are the same (x, y and z are the same) and I want to remove them but I do not want to remove cases with only one value equal as coordinates 3 and 4 for x-coordinate).
These values are in a text file and I want to print the coordinates without duplication in another file or even in the same one.
A very simple solution would be to treat each line as a string and use a set of strings. As you traverse the file line-wise, you check if the current line exists in the set and if not, you insert and print it.
Complexity: O(nlogn), extra memory needed: almost the same as your input file in the worst case
With the same complexity and exactly the worst case memory consumption as the previous solution, you can load the file in memory, sort it line-wise, and then easily skip duplicates while printing. The same can be done inside the file if you are allowed to re-order it, and this way you need very little extra memory, but be much slower.
If memory and storage is an issue (I'm assuming since you can't duplicate the file), you can use the simple method of comparing the current line with all previous lines before printing, with O(n^2) complexity but no extra memory. This however is a rather bad solution, since you have to read multiple times from the file, which can be really slow compared to the main memory.
How to do this if you want to preserve the order.
Read the coordinates into an array of structures like this
struct Coord
{
double x,y,z;
int pos;
bool deleted;
};
pos is the line number, deleted is set to false.
Sort the structs by whatever axis tends to show the greatest variation.
Run through the array comparing the value of the axis you were using in the sort from the previous item to the value in the current item. If the difference is less than a certain preset delta (.i.e. if you care about three digits after the decimal point you would look for a difference of 0.000999999 or so) you compare the remaining values and set deleted for any line where x,y,z are close enough.
for(int i=1;i<count;i++)
{
if(fabs(arr[i].x-arr[i-1].x)<0.001)
if(fabs(arr[i].y-arr[i-1].y)<0.001)
if(fabs(arr[i].z-arr[i-1].z)<0.001)
arr[i].deleted=true;
}
sort the array again, this time ascending by pos to restore the order.
Go through the array and output all items where deleted is false.
In c++, you can use the the power of STL to solve this problem. Use the map and store the three coordinates x, y and z as a key in the map. The mapped value to the key will store the count of that key.
Key_type = pair<pair<float,float>,float>
mapped_type = int
Create a map m with the above given key_type and mapped_type and insert all the rows into the map updating the count for each row. Let's assume n is the total number of rows.
for(i = 0; i < n; i++) {
m[make_pair(make_pair(x,y),z)]++;
}
Each insertion takes O(logn) and you have to insert n times. So,overall time complexity will be O(nlogn). Now, loop over all the rows of the matrix again and if the mapped_value of that row is 1, then it is unique.
I'm currently implementing a Transposition table in a Chinese Checkers minimax algorithm. In Chinese Checkers, no pieces are captured, and the board is functionally 81 spaces large. Players take turn moving pieces across the board.
Part of the process involves creating a hash for the board state. So far, I've got a functioning method that creates a (hopefully) unique hash for each board state:
myHash = 0;
//randoms[81][3] is an array filled completely with pseudorandom values
for (int x = 0; x < 81; x++) {
myHash ^= randoms[x][board[x]];
//board[x] is the piece at space x (1=player1 piece, 2=player2 piece, 0=empty)
}
More importantly, I do this incrementally in the applyMove function (and the undoMove function):
applyMove(int to, int from) {
//Undo the 'from' piece in the hash
myHash ^= randoms[from][board[from]];
// Apply the move
std::swap(board[from], board[to]);
//Add the 'to' piece to the hash
myHash ^= randoms[to][board[to]];
// Update whose turn it is
swapTurn();
}
This works because of the reversibility property of the XOR function.
The issue I have now, is that the hash function doesn't store whose turn it is. That is, you could have two identical game boards, but they would return different values in the minimax algorithm because one's trying to maximize the score, and the other is trying to minimize it.
Basically, my question is this: How can I store the player's turn in an incrementally generated hash function, while keeping the ability to reverse it perfectly (and preferably inexpensively)? Assuming the player's turn is an integer rather than a boolean, since the game will eventually have 6 players rather than two players.
You can use a turns[6] array filled with pseudorandom values:
unsigned n = 6; // number of players;
myHash ^= turns[active_player]; // 'undo' the old active player
active_player = (active_player + 1) % n; // new active player's index
myHash ^= turns[active_player]; // 'add' new active player
this is similar to the piece position incremental update and works for n ∈ [2, 6].
As a side note...
usually Zobrist hashing is done by scanning the location of pieces, excluding empty squares. The location of empty squares isn't explicitly hashed.
So you could use a smaller (more cache-friendly) array. Something like:
std::uint64_t randoms[81][2]; // two players
for (unsigned x(0); x < 81; ++x)
if (board[x])
myHash ^= randoms[x][board[x]];
For what it's worth, you could store the turn state as a bit at the beginning of the hash...
inline bool GetTurn(int hash){
return (bool)(hash & 1);
}
and have the Zobrist hash keys in the array all have 0 for their least significant bit, ex. [[0x2348dec2, 0x93857e34, ....] ...]
I am trying to make a simulation of a rabbit population. these rabbits are printed on a grid say 50x50 on a console app.
I have several questions which would really help.
If I want to keep a record of all the bunnehs with their individual characteristics, is a List the best way to record this data?
For random movement, I generate a random move (-1,0,+1) on the x-axis and on the y-axis.
If i want to avoid collision against other existing rabbits, is calculating the new x,y and comparing them against the list the only way.
like:
foreach(Bunny bunny2 in lst)
if (bunny2.x == newbunny.x && bunny2.y == newbunny.y)
then move newbunny again
Thank you for your time
Based on what you're talking about, I'd use a 2 dimensional to hold all of your bunnies. e.g.
Bunny[49][49] grid; //make a 2D array of bunny objects
This way you can have your data structure perfectly represent your system. Then you could actually use the indices (x, y) of the grid to map to the 2D array. For example this would get you the bunny at x = 3, y = 17:
Bunny myBunny = grid[2][16]
Also this would ease in collision detection, as you can just check if there is a bunny in the relevant grid space you want to move to, so if the bunny in the previous example wanted to go x-1 spaces, then you could check if that grid coordinate had a null value:
if(grid[1][16] == null) { //then bunny can go there
//code to move bunny
grid[2][16] = null //remove bunny from old grid space
} else { //buny can't go there
//code
}
NB! In order for this to work, you need to make sure you take the bunny OUT of the grid space it is moving from, as done in the previous example. That way you maintain where there are no bunnies versus where they are.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 5 years ago.
Improve this question
Are there algorithms to produce 3 dimensional mazes? Essentially the same as a 2D maze but the Z depth axis can be traversed? The idea is still the same though, to get from Start to End. Could backtracking still be used?
Which algorithm should I use to generate a 3D maze?
See here. I mean that you can go into the cube too, not just iterate the faces of it.
I made 2d mazes a few years ago using Kruskal's Algorithm here. There should be no reason this couldn't work with the 3d case you described. Basically you'd consider a cell a cube, and have a large array that has (for every cells), 6 walls in the +/- x, y, and z directions. The algorithm initially starts with all walls everywhere and randomly makes walls disappear until every cell in the maze is connected.
I have the code for generating a 2D maze in, of all things, RPGLE (something I did as a self-exercise while learning the language). Because of the way I wrote it, about the only changes necessary for the general alogrithm would be to add the Z dimension as an additional dimension...
The entire thing is 20 pages long (although this includes input/output), so here's some code. You should be able to translate this into whatever language you need: I translated it from spaghetti-code BASIC (gotos were way overused here, yeah. But it was a fun exercise).
//set out maximum maze size
maximumMazeSquareCounter = mazeHorizontalSize * mazeVerticalSize + 1;
// generate a starting horizontal positiongetRandomNumber(seed : randomNumber);
currentHorizontalPosition = %inth(randomNumber * (mazeHorizontalSize - 1)) + 1;
currentVerticalPosition = 1;
mazeSquareCounter = 1;
// generate the top row of the maze (with entrance)
mazeTopRow = generateEntrance(currentHorizontalPosition);
//write to the printer file
writeMazeDataLine(mazeTopRow);
mazeSquareCounter += 1;
//set the first position in the maze(the entry square
setPathPoint(currentHorizontalPosition : currentVerticalPosition);
//do until we've reached every square in the maze
dou mazeSquareCounter >= maximumMazeSquareCounter;
//get the next available random direction
mazeDirection = getNextRandomDirection(getNextAvailableDirection(currentHorizontalPosition : currentVerticalPosition));
//select what to do by the returned results
select;
//when FALSE is returned - when the maze is trapped
when mazeDirection = FALSE;
//if not at the horizontal end of the maze
if currentHorizontalPosition <> mazeHorizontalSize;
//add one to the position
currentHorizontalPosition += 1;
//else if not at the vertical end of the maze
elseif currentVerticalPosition <> mazeVerticalSize;
//reset the horizontal position
currentHorizontalPosition = 1;
//increment the vertical position
currentVerticalPosition += 1;
//otherwise
else;
//reset both positions
currentHorizontalPosition = 1;
currentVerticalPosition = 1;
endif;
//when 'N' is returned - going up (other directions removed)
when mazeDirection = GOING_NORTH;
//set the point above current as visited
setPathPoint(currentHorizontalPosition : currentVerticalPosition - 1);
//set the wall point to allow passage
setWallDirection(currentHorizontalPosition : currentVerticalPosition : GOING_NORTH);
//change the position variable to reflect change
currentVerticalPosition -= 1;
//increment square counter
mazeSquareCounter += 1;
endsl;
enddo;
//generate a random exit
// get a random number
getRandomNumber(seed : randomNumber);
// set to the horzontal position
currentHorizontalPosition = %inth(randomNumber * (mazeHorizontalSize - 1)) + 1;
//set the vertical position
currentVerticalPosition = mazeVerticalSize;
//set wall to allow for exit
setWallDirection(currentHorizontalPosition : currentVerticalPosition : GOING_SOUTH);
The entire thing is backed by two two-dimensional arrays (well, the RPG equivalent): One for the walls that occupy the 'square', and the other for whether or not that square has been visited. The maze is created after every square has been visited. Garuanteed one-path only, worm-turns maze.
To make this three-dimensional, make it use three-dimensional arrays, and add the necessary dimension index.
I designed an algorithm some time ago for 2D mazes on a square grid, there is no reason why this shouldn't also work for a 3D maze on a cubic grid.
Start with a 3D grid initially fully populated with wall cells.
...
Start an agent at an edge of the grid, the agent travels in a straight line in the X, Y, Z, -X, -Y or -Z direction clearing wall as she travels.
Action 'N' has a small chance of occurring each step.
Action 'M' occurs when the cell directly in front of the agent is wall and the cell in front of that is empty.
'N' is a random choice of:
removing that agent
turning left or right 90 degrees
and creating an agent on the same square turned 90 degrees left, right or both (two agents).
'M' is a random choice of:
removing that agent
removing the wall in front of that agent and then removing that agent
and doing nothing, carrying on
turning left or right 90 degrees.
and creating an agent on the same square turned 90 degrees left, right or both (two agents).
The mazes are distinctive, and their character is highly flexible by adjusting the trigger for 'M' (to do with valid junctions) and by also adjusting the chances of 1 to 8 occurring. You may want to remove an action or two, or introduce your own actions, for example one to make a small clearing or sidestep one step.
The trigger for 'N' can also be another sort of randomness, for example the example below can be used to create fairly branchy mazes that still have some long straight parts.
float n = 1;
while (random_0_to_1 > 0.15)
{
n *= 1.2;
}
return (int)n;
Some small adjustments will be needed from my simple description, for example trigger for action 'M' will need to check the cells adjacent to the cells it checks as well depending on what sort of junctions are desirable.
Either 5 or 6 are needed for the maze to contain cycles and at least one alternative 'M' action to 5 and 6 is required for the maze to contain dead ends.
Some choices of chances/actions and 'M' triggers will tend to make mazes that don't work, for example are unsolvable or full of empty or wall cells, but many will produce consistently nice results.