Last weeks I was developing a world generator (for a Minecraft mod). However, I wasn't looking for just Perlin noise, but rather something based on cell noise. I want to generate a sort of underground lab, existing of several rooms of different sizes.
To explain the problem I use 2D examples.
The noise generator takes a grid cell position (int x, int y), and returns an object with this stucture:
boolean top;
boolean right;
boolean down;
boolean left;
int roomType;
The 4 booleans represent the walls which are enabled or disabled:
The roomType represents the type of the room respectively.
The final result should be something like this:
Here, the background checkerboard pattern represents the base grid, and the black lines represent the walls. This is just a simple example that could generate, but in the real case, the grid is infinite in both x and y directions.
The problem I'm getting now is that the noise generator only takes in an x and y coordinate, which is the coordinate of the grid cell it should generate. There is a seed of which I can generate more random seeds for hash functions:
long seed = 0x75fd239de48;
Random r = new Random(seed);
int seed1 = r.nextInt();
int seed2 = r.nextInt();
// etc.
I could use a hash function: Hash.hash2D(int seed, int x, int y), which returns a random double for a coordinate, according to a seed.
That will give the ability to generate information for the surrounding cells.
To easily generate larger rooms, you could set a max size for a room, and check an area for rooms that try to be larger than 1x1. If they are there, and will span to the current room, the room will be an extension of another room. However, checking if a room will extend requires a check if it isn't already extending (otherwise, unwanted room extensions appear to room bases that extend another), which runs into an infinite loop.
In my case, there is a given table of room types, their sizes and their weights. Example:
name: size [weight]
room-1: 1x1 [128]
room-2: 1x1 [128]
room-3: 2x1 [16]
room-4: 1x2 [16]
room-5: 2x2 [8]
room-6: 3x1 [4]
room-7: 1x3 [4]
There are many others, coming with sizes up to 5x5, but I use this example list for my question. The max size in this example is 3x3 (just max-width by max-height).
Here I have an example class of some basic setup in Java:
public class RoomNoise {
private final long seed;
private final Random rand;
public RoomNoise( long seed ) {
this.seed = seed;
this.rand = new Random( seed );
}
public enum RoomTypes {
ROOM1( 1, 1, 128 ),
ROOM2( 1, 1, 128 ),
ROOM3( 2, 1, 16 ),
ROOM4( 1, 2, 16 ),
ROOM5( 2, 2, 8 ),
ROOM6( 1, 3, 4 ),
ROOM7( 3, 1, 4 );
public final int width;
public final int height;
public final int weight;
private RoomTypes( int w, int h, int weight ) {
width = w;
height = h;
this.weight = weight;
}
}
public static class Output {
public final RoomTypes roomType;
public final boolean upWall;
public final boolean rightWall;
public final boolean downWall;
public final boolean leftWall;
public Output( RoomTypes type, boolean u, boolean r, boolean d, boolean l ) {
roomType = type;
upWall = u;
rightWall = r;
downWall = d;
leftWall = l;
}
}
public Output generate( int x, int y ) {
// What should be here
}
}
I'm looking for the content of the generate method, for which I've tried many things, but every time I turned into an infinite loop or it didn't work.
Is there any way to generate this noise in O(N) with N less than infinity? And if there is a way, which way is that and how could I implement it? I've searched the internet and tried many things (for 3 weeks now) and still haven't found a solution.
I use Java 1.8, but I prefer any C-style language.
Again, I have this hash function:
Hash.hash2D( int seed, int x, int y );
Edit:
Expected result:
Blue lines are corridors, which are generated later on. Just forget them.
Note:
I'm not able to load and delete chunks (grid cells) manually, the base API (Minecraft) is doing that for me. It only gives me the coordinate (which depends on the player interaction) and I should give back a (part of a) room that fits the chunk at that coordinate. I also know that once a chunk is generated, it isn't generated again.
I'm not sure I perfectly understand the problem you're trying to solve, so please feel free to comment if this is short of the mark:
If you want to be able to generate an infinite grid, you're only going to be able to approximate infinite. I think you have two options:
Generate a "big enough" grid. This might be time / space intensive, but if there's an upper bound on how much you could need, and it's feasible to do it all at once, it's the simplest option. E.g. if the user couldn't possibly make it more than 1000 squares away from the center, generate 2000x2000.
OR:
Use lazy evaluation. This means, don't generate anything until you need it. If the user gets close to an area that has not yet been generated, generate it then. The flip side to this is you can also throw away old parts that the user isn't likely to return to, if you need to free up resources. For example: cut your area into squares (e.g. 20x20 or 1000x1000), and generate additional, adjacent squares, as the player gets close to them, or the map pans over in that direction, etc., as needed.
Ok, I think I've solved it myself.
This is the grid, not infinite here but it could be.
In this grid you have some cells that want to extend. This is directly defined by the hash function:
However, some extensions do overlap others. This is something we don't know actually.
Take for each cell a priority. You could do that in several ways:
Just use the hash function to give them a random priority
Give each possible room type / size a priority (e.g. larger rooms have higher priority).
The priority is only important on cells that want to extend. In my example, the bigger cells have higher priority.
Then we have the input coordinate, which is the blue cell:
Ok, knowing this, you have to do some steps. We know the maximum size is 3x3.
If the input cell doesn't want to extend
Check in the area of the maximum size if there is any cell that tries to extend to this cell:In this case it exists.
Knowing this, we need to check if one of the found cells could extend to this cell. To check that, check if this wants this cell to be an extension, then do the steps below and take the check cell as input coordinate. In the example, the extending cell is able to extend. We also know the extending cell will extend the input cell so the input cell is an extension.
Now we could easily check which walls exist and which not. In this case, every wall is gone because it is the center of this extending room:
Some other examples:
Input coordinates. None of them wants extension:
Check regions:
As you can see, one cell found an extension room, but that extension room doesn't extend that input cell. That makes all those rooms a 1x1 room:
If the input cell wants to extend
And how to check if a cell can extend
Do a hard check. The hard check checks the area of the extension (3x3 in this case) size right below the input cell for other cells trying to extend. If there is one, check if that one could extend. If it could, the input cell couldn't extend and go on with the steps for non-extending cells on your input cell. To save memory and time, you could skip checking if the found cells could extend (maybe this will run into an infinite loop), and just take an 1x1 cell directly (non-extending cell steps are not necessary then).
This is the extension area / hard check area in this case. There is no extending cell here so the cell could extend.
Now do a soft check. The soft check checks for extending cells in the maximum size area left below, and right above the cell:
Also here, you could check if they do extend, but that takes much memory and time.
For each found cell, check in their extension area right below them if they will extend to any of the extension cells the input cell will extend. This check if the two extension areas overlap. If they don't, your cell is able to extend and you could skip step 3 and go to step 4. If they do, go to step 3. In this case an overlap is found:
Here, the yellow cell with red outline is a found overlap.
You've found an overlap. Here the priority is going to play a role. Take the priority of the extension cell which area does overlap the input cell area. Also take the priority of the input cell itself. Compare them. If the priority of the input cell is larger that the other priority, the input cell can extend and you could go to step 4. If the input cell has lower priority, it couldn't extend and you could make it a 1x1 room (or you could do the non-extending cell steps, which is necessary if you validate found cells in the hard check). If the priorities are equal, take the cell with the highest X or Y coordinate, or something.
In my example, the input cell has the highest priority, because it is bigger.
The final step. The cell is guaranteed to extend. You could calculate which walls exist. Notice that the left and the top wall always exist, as the extension cells are always in the top left corner.
Our cell could extend and we get this result:
Another example
The input cell:
Do the hard check:
Oh, it found one, so it couldn't extend and turns into a 1x1 room:
That's it, actually. I hope I've been clear enough. Rather than using squares, you could use rectangles too, or more complex shapes like L-shaped rooms.
And this is the final result of my example:
Related
I'm working on a project and have some doubts about it's design.
How can I design the following problem the best (in JAVA):
Class A with the following attributes:
HashSet of Pixels where each pixel has x,y coordinates and value v between 0-1.
instance of class B.
Class B with the following function:
a function that gets a Pixel and returns its left neighbor.
When I'm in class A I want to use B.function on each pixel in A and add it to the HashSet only if it's not already there. The problem is that I don't want to send the HashSet to the function, how bad is it to return new instance of Pixel from the function if it might already exist (This function going to run on many pixels and will create many unused instances of Pixel).
What other options do I have?
Since you use Set<Pixel> you have to create new Pixel instance to check if it exists in set or not.
If set contains N elements after calling B.function method you will create extra N Pixel nodes. If all elements are new, you just add them to set, in other case Garbage Collection needs to sweep them. One of drawbacks is we need to create m (wheren m <= N - number of Pixel-s which already exists in set) and later we need to collect them by GC. How big is m/N ratio depends from your algorithm and what you are actually doing.
Lets calculate how many memory we need to consume for N = 1_000_000 pixels in set. We know that int is a 4 bytes and double is 8 bytes, lets add extra 8 bytes for an object and 8 bytes for a reference. It gives 32 bytes for every instance of Pixel object. We need to create N objects which gives 32MB. Let's assume that our ratio is 50% so, 16MB we allocated just to check it is not needed.
If this is a cost you can not pay you need to develop algorithm which allows you iterate over Set<Pixel> in an order from left-to-right. So, left neighbour of Pixel X is before X.
Assume that left neighbour of Pixel X(x, y) is pixel X'(x - 1, y). Pixel B(0, y) does not have left neighbour. You need to use TreeSet and implement Comparable<Pixel> interface in Pixel class. Simple implementation could look like this:
#Override
public int compareTo(Pixel o) {
return this.y == o.y ? this.x - o.x : this.y - o.y;
}
This allows you to iterate set in order from left to right: (0, 0), (1, 0), ...., (x - 1, y), (x, y), (x + 1, y), ... , (maxX, maxY). So, when you iterate it you can check whether previous element is a left neighbour of current Pixel. Example implementation could look like below:
void addNeighboursIfNeeded() {
Set<Pixel> neighbours = new HashSet<>(pixels.size());
Pixel last = null;
for (Pixel p : pixels) {
if (p.getX() == 0 || p.isLeftNeighbour(last)) {
// a left border pixel
// or last checked element is a left neighbour of current pixel.
last = p;
continue;
}
// last element was not our left-neighbour so we need to call b method
Pixel left = b.getLeft(p);
neighbours.add(left);
last = p;
}
// add all new neigbours
pixels.addAll(neighbours);
}
This should allow you to save this memory which is allocated for duplicated Pixel objects.
I can see here few concerns regarding object oriented programming.
Encapsulation violation: When you call function of B from A which operates on A's data (which you are avoiding by not sending HashMap), it violates encapsulation (If there is a reason, its acceptable though). Is it possible to move that function (operating on A's HashSet) to A? This will protect A's state from getting exposed.
Proliferation of classes: There is a possibility that there will be large number of objects of Point type. You can think of using Flyweight GOF design pattern, it will externalize the state of each point and will make it reusable. and will reduce number substantially.
Passing large collection of Points to method in B: If you can shift method from B to A, this point gets resolved. Anyway java will pass this collection by reference. But in that case its open for modifications from external classes (need to take care of this aspect).
Abstraction of type Point: If class Point has only state and no behavior, it will lead to violation of encapsulation. Can you shift the method getNeighbour() in to Point? as it will make Point immutable (which is essential). Off course actual algorithm can be delegated to another class (if its independently varying responsibility and has hierarchy of algorithms, think of GOF Strategy pattern here).
Uniqueness of points in collection: which your set will take care with due care about appropriate Hash and logical equality for class Point.
For my homework, I need to represents cells in a universe where ' * ' indicates a live cell and an empty space (' ') a dead cell. The following rules are used to determine the status of a particular cell in the next generations:
Any live cell with fewer than two live neighbors dies, as if caused by under population.
Any live cell with two or three live neighbors lives on to the next generation.
Any live cell with more than three live neighbors dies, as if caused by overpopulation.
Any dead cell with exactly three live neighbors becomes a live cell, as if caused by reproduction.
For example, considering the following arrays:
int[][] beehive = {{0,0,0,0,0,0}, {0,0,1,1,0,0}, {0,1,0,0,1,0},
{0,0,1,1,0,0}, {0,0,0,0,0,0}};
int[][] toad = {{0,0,0,0,0,0}, {0,0,1,1,1,0}, {0,1,1,1,0,0}, {0,0,0,0,0,0}};
getNextGenCell(beehive, 1, 3) returns 1, while getNextGenCell(beehive, 3, 1)
returns 0.
getNextGenCell(toad, 0, 3) returns 1, while getNextGenCell(toad, 2, 3)
returns 0.
I am confused on how to proceed with this code. Any suggestion?
My code has to have the following header where int x represents a sub-array and int y represents an element inside that sub-array. The code returns 1 if the cell is alive in the next generation or 0, otherwise.
// A method that gets the cell from the next generation
public static int getNextGenCell(int[][] validUniverse, int x, int y) {
}
You first must determine how you want the logic of your program to flow. In this case, you know there are 8 different cases when traversing the 2D array. These include:
The upper left-hand corner
The upper right-hand corner
The rest of the first row
The lower left-hand corner
The lower right-hand corner
The rest of the last row
The left and right-hand sides of the array
The rest of the array
You will need if statements for each of these cases. The following is an an example of the code for "the rest of the array" case:
if(x!=0&&y!=0&&x!=bees.length-1&&y!=bees[x].length-1&&bees[x][y+1]==1||bees[x][y-1]==1||bees[x+1][y]==1||bees[x-1][y]==1)
Now just finish the other 7 cases, count the amount of "alive" or "dead" cells and modify the array accordingly. Let me know if you have any questions.
I have a rectangle Object with x, y, width and height. I have a list of these rectangles which are displayed on a screen. It is guaranteed that none of them overlap. Given a user's click position (x and y coordinates), I want to see which of these rectangles were clicked (since they do not overlap, there is a maximum of one rect that can be clicked).
I can obviously look through all of them and check for each one if the user clicked it but this is very slow because there are many on the screen. I can use some kind of comparison to keep the rectangles sorted when I insert a new one into the list. Is there some way to use something similar to binary search in order to decrease the time it takes to find which rect was clicked?
Note: the rectangles can be any size.
Thanks:)
Edit: To get an idea of what I am making visit koalastothemax.com
It highly depends upon your application and details we're not quite aware of yet for what the best solution would be. BUT, with as little as I know, I'd say you can make a 2D array that points to your rectangles. That 2D array would map directly to the pixels on the screen. So if you make the array 10x20, then the coordinate x divided by screen width times 10 (casted to int) will be the first index and y divided screen height times 20 would be your y index. With your x and y index, you can map directly to the rectangle that it points to. Some indexes might be empty and some might point to more than one rectangle if they're not perfectly laid out, but that seems the easiest way to me without knowing much about the application.
I have tackled a very similar problem in the past when developing a simulation. In my case the coordinates were doubles (so no integer indexing was possible) and there could be hundreds of millions of them that needed to be searched.
My solution was to create an Axis class to represent each axis as a sequence of ranges. The ranges were guaranteed to go from a minimum to a maximum and the class was smart enough to split itself into pieces when new ranges were added. Each range has a single generic object stored. The class used a binary search to find a range quickly.
So roughly the class looks like:
class Axis<T> {
public Axis(double min, double max, Supplier<T> creator);
public Stream<T> add(double from, double to);
public T get(double coord);
}
The add method needs to return a stream because the added range may cover several ranges.
To store rectanges:
Axis<Axis<Rectangle>> rectanges = new Axis<>(0.0, 100.0,
() -> new Axis<>(0.0, 100.0, Rectangle::new));
rectangles.add(x, x + w).forEach(r -> r.add(y, y + h).forEach(Rectangle::setPresent));
And to find a rectangle:
rectangles.get(x).get(y);
Note that there's always an object stored so you need a representation such as Rectangle.NULL for 'not present'. Or you could make it Optional<Rectangle> (though that indirection eats a lot of memory and processing for large numbers of rectangles).
I've just given the high level design here rather than any implementation details so let me know if you want more info on how to make it work. Getting the logic right on the range splits is not trivial. But I can guarantee that it's very fast even with very large numbers of rectangles.
The fastest way I can come up with is definitely not the most memory efficient. This works by exploiting the fact that an amortized hash table has constant lookup time. It will map every point that a rectangle has to that rectangle. This is only really effective if your are using integers. You might be able to get it to work with floats if you use a bit of rounding.
Make sure that the Point class has a hash code and equals function.
public class PointCheck
{
public Map<Point, Rect> pointMap;
public PointCheck()
{
pointMap = new HashMap<>();
}
/**
* Map all points that contain the rectangle
* to the rectangle.
*/
public void addRect(Rect rect)
{
for(int i = rect.x; i < rect.x + rect.width; ++i)
{
for(int j = rect.y; j < rect.y + rect.height; ++i)
{
pointMap.put(new Point(i, j), rect);
}
}
}
/**
* Returns the rectangle clicked, null
* if there is no rectangle.
*/
public Rect checkClick(Point click)
{
return pointMap.get(click);
}
}
Edit:
Just thought I should mention this: All of the rectangles held in the value of the hash map are references to the original rectangle, they are not clones.
This is a question from a code competition, I am finding it unbelievably difficult to come up with any working algorithm to solve it. So I'm not really looking for the code but rather a step by step algorithm on how to solve it.
Stacking Tiles
Stacking tiles against the wall is one of Bongani's favourite pasttimes. His tiles all have the same thickness, but vary
in width and height. Bongani is given N tiles and has to use them in
the sequence given according to a set of rules. He can place a tile on
top of another only if it is narrower than the previously stacked
tile. Bongani is allowed to rotate the tiles by 90 degrees so that
width becomes height and height becomes width. He is also allowed to
discard a tile altogether. Given a list of tiles, help Bongani find
the highest stack he can build The example specifies tiles (3, 3),
(12, 5), (5, 8), (6, 10). To get the highest stack Bongani ignores the
first tile (3, 3) as it is smaller than the next tile. He uses the
next tile (12, 5) with 12 as the width and 5 as the height. He uses
the next two tiles with 8 as the width and 5 as the height followed by
6 as the width and 10 as the height.
The only thing I can possibly think of is getting every possible valid permutation of tiles and find the highest permutation.
The exact question can be found here http://www.olympiad.org.za/olympiad/wp-content/uploads/2013/01/2011PO-R2-Questions-0421.pdf (Question 5)
Here's an outline of dynamic programming solution:
You "move from left to right" and for each tile you figure out
how high tower can I build by using this tile unrotated
how high tower can I build by using this tile rotated
how high tower can I build by not using this tile
The first key observation is that each question can be answered recursively ("how high tower can I build for the remaining tiles if the current width is updated according to my current choice?"). Pseudo code:
maxHeight(tiles, currentWidth) {
// Base case
if (tiles.isEmpty())
return 0; // no tiles -> maxHeight == 0
int h = 0;
currentTile = tiles[0]
remainingTiles = tiles[1...]
// Compute maxHeight for the case when not using current tile
h = max(h, maxHeight(remainingTiles, currentWidth)
// Compute maxHeight when using current tile
if (currentWidth > currentTile.width)
subHeight = maxHeight(remainingTiles, currentTile.width)
h = max(h, subHeight + currentTile.height)
// Compute maxHeight when using current tile rotated
if (currentWidth > currentTile.height)
subHeight = maxHeight(remainingTiles, currentTile.height)
h = max(h, subHeight + currentTile.width)
return h
}
The second key observation is that many of the invocations of maxHeight have the same arguments, which means that previous computations can be reused. You can either use memoization or tabulation (both are variants of dynamic programming) If you choose to use a tabulation matrix, it would look like this:
M[tileN][width] = the height of the tower possible to build from
tileN onwards with width 'width'
(As you may note width does not have a clear upper bound. This can be solved by mapping all values to 1, 2, 3, ... before starting. Maximum width will then be 2N.)
Here is a quadratic time algorithm using dynamic programming. Let f(i) be the greatest height of a tower you can build using the ith block in the original orientation and no later blocks. Let g(i) be the greatest height of a tower you can build with the ith block rotated and no later blocks. Note that blocks can be omitted, so to compute f(i), you have to take 1 more than the maximum over all previous f and g values compatible with that orientation, and similarly for g(i). At the end, the answer is the maximum over all f(i) and g(i).
The following code shows code for f. Youc an write g similarly, or modify this to take another parameter for whether block i is in the original orientation.
public int f(int i)
{
if (i == 0)
return 1;
if (memoF[i] > 0)
return memoF[i];
int maxFound = 1; // using just this block is legal
for (int j = 0; j<i; j++){
if (widths[i] < widths[j])
maxFound = Math.max(f(j)+1,maxFound);
if (widths[i] < heights[j])
maxFound = Math.max(g(j)+1,maxFound);
}
memoF[i] = maxFound;
return memoF[i];
}
I think this is typical example for easy and effective solving using Backtracking.
You just go in sequence and try first things you can do, when you cant continue, you go back and try the one you did not try before. Just google "Sudoku Backtracking" there are a lot of pages explaing that.
The huge advantage of backtracking in this case is, it "cuts" off a lot scenariou which would make no sense, therefore it would be much more effective than trying to check every possible combination.
(like in sudoku, with backtracking, the most sudokus are solved in 1000-10000 steps, which is pretty good, given that the all possible combinations of numbers you can write are ~10^60)
Right now I have a project set up with 2 meshes, which are rendering correctly by themselves.
My Objective is to add lighting to one of them(a surface I want to display), which is made up from GL10_GL_TRIANGLES, but not the other(a helper grid), which is (obviously) made up from GL10.GL_LINES.
So far I managed to compile the 2 into renderables, like so:
grid.mesh.setVertices(gridMeshArray);
grid.meshPartOffset = 0;
grid.meshPartSize = grid.mesh.getNumIndices();
grid.primitiveType = GL10.GL_LINES;
grid.material = new Material();
grid.bones = null;
sampleSurface.mesh.setVertices(meshVArray);
sampleSurface.mesh.setIndices(meshIArray);
sampleSurface.meshPartOffset = 0;
sampleSurface.meshPartSize = sampleSurface.mesh.getNumIndices();
sampleSurface.primitiveType = GL10.GL_TRIANGLES;
sampleSurface.material = new Material();
sampleSurface.bones = null;
When I run the program, I see the sampleSurface, but not the grid.
Rendering is as follows:
MB.begin(cam.getCam());
MB.render(sampleSurface);
MB.render(grid);
MB.end();
It's propably worth to mention, that I'm not using any shaders right now, just the command:
cam.apply(Gdx.gl10);
Which is'nt the best practice, and I'm planning to replace it once I have the time to dwelve into the topic.
My guess is, the grids won't display, because I didn't specify an index array to them. That seems to be the only difference between the two renderables. (not counting the environment, since changing grid.environment didn't have any effect.)
Defining an index array seems highly illogical for the grid, since it doesn't really have overlapping vertices. I'm not sure what to do, or where lies the problem, since the 2 meshes draw perfectly by themselves. Any help is appreciated!
http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g3d/Renderable.html#meshPartSize
The #meshPartSize member of Renderable is used to specify the size (in vertices) of the part of the mesh to render. When not rendering a strip this the number of primitives multiplied by the number of vertices per primitive. So if you want to render 4 triangles (GL_TRIANGLES), then the size is 12 (4 triangles * 3 vertices = 12 vertices total). If you want to render 12 lines (GL_LINES), then the size is 24 (12 lines * 2 vertices = 24 vertices total).
In practice this means that, if the mesh is indexed, the size is equal to the number of indices you want to render. If the mesh isn't indexed, then it's equal to the number vertices you want to render. A mesh is considered indexed if the number of indices it contains is greater than zero (mesh.getNumIndices() > 0).
To be specifc: if indexed then glDrawElements will be used with the offset and count arguments as specified. Otherwise glDrawArrays will be used with the offset and count arguments as specified.
That being said: please note that some classes might require indexed meshes, also note that GLES1.x might not be fully supported. So in practice it is advised to use indexed meshes and GLES2.
After a refreshing beer and a walk I read #Xoppa's answer, and it made me see my error.
Simply changing
grid.meshPartSize = grid.mesh.getNumIndices();
to
grid.meshPartSize = grid.mesh.getNumVertices();
solved my problem, now it displays correctly.