I'm trying to create a pyramid of circles to my game, looking similar to this :
alt text http://img266.imageshack.us/img266/3094/lab1213c.jpg
But I can't make it print properly. Constantly I'm getting really strange spirals but nothing close to this. Can anyone give me some tip on proper formula ? My window is 600x600, base of pyramid is 8 .
fields = new Field[BASE*(BASE/2)+4];
int line_count = BASE;
int line_tmp = line_count;
for(int i=0; i< fields.length; i++){
for( int j=line_tmp; j <= line_count; j++){
fields[i] = new Field(0, (150+(line_tmp*5)),(600+line_tmp*5));
}
line_count--;
line_tmp = line_count;
}
The mistakes I see are:
Incorrect array size formula.
Including line_tmp (which seems to be your column counter) in your y expression.
Having two variables, line_count and line_temp that are always equal.
Having your outer loop count by node rather than counting by row.
Having generally meaningless variable names and magic numbers strewn about.
// I use java.util.ArrayList because using its add(..) method is convenient here.
// The proper forumula for anticipated number of nodes is: base×(base+1)÷2
final List<Field> fields = new ArrayList<Field>(BASE*(BASE+1)/2);
// I use a java.awt.Point to store the (x,y) value of the first node of the row.
// This clarifies the meaning, rather than using ints or long inline expressions.
final Point rowStart = new Point(PANEL_WIDTH/2, DIAMETER);
// The number of rows equals the number of nodes on the final row.
for (int row = 1; row <= BASE; row++) {
// The nth row has n nodes.
for (int circle = 0; circle < row; circle++) {
// Each row starts at rowStart and each subsequent circle is offset to
// the right by two times the circle diameter.
fields.add(new Field(0, rowStart.x + circle*DIAMETER*2, rowStart.y));
}
// Each subsequent row starts a little down and to the left of the previous.
rowStart.x -= DIAMETER;
rowStart.y += DIAMETER;
}
Remember to only use this as reference for fixing your own code if this is homework.
Related
I have searched a number of posts here on SO as well as other resources online. Most of them provide a solution for finding the maximum area of a rectangle in a 2D matrix, which I understand. However, I am curious to know the way you find the number of rectangles in a 2D matrix where a rectangle is represented by 1s.
Update:
Apologize for not clarifying the scenario as to what classifies as a rectangle - it is considered a rectangle if the cells inside a certain perimeter are filled with 1s.
Some pseudo-code:
for x_0 in rows:
for x_1 > x_0 in rows: # symmetry-reduction: x_0 always "top"
for y_0 in columns:
for y_1 > y_0 in columns: # symmetry reduction: y_0 always "left"
if mat[x_0, y_0] == mat[x_0, y_1] == mat[x_1, y_0] == mat[x_1, y_1] == 1:
found rectangle!
Keep in mind: it's pseudo-code (partially based on python-style) and the boolean-evaluation does not work like that in most languages!
The symmetry-reduction is not only improving performance, but it's also important when you are counting. There are visually equal rectangles, where x_0 and x_1 just take different roles (left and right point). You have to decide how to count this.
Edit: After Ole V.V.'s comment above i realized that there are indeed very different interpretation's. Most of these can be realized with the pseudo-code above but with a different check on the inner-level. But that might be your work then (and there are more-tuned approaches possible then in some cases)!
Here i assume, a rectangle is just defined by 1's at the 4 corners!
Edit: After your new definition of a rectangle, the inner-check changes to:
if all(mat[x_0:x_1, y_0:y_1]) # python/numpy inspired pseudo-code!
So basically you might check all the values defined by the 4 border-points. That's easy and solves your problem.
But of course you could be much more efficient. It might be wise to add some binary-flag which indicates if the current rectangle (they are growing) is still filled with only 1's. Actually you would probably need 2 binary-flags, 1 for each dimension. Then you can do early-stopping if that's not the case.
Here is a non-optimized version that should give the correct result:
int sum = 0;
for (int row = 0; row < n; row++) {
for (int col = 0; col < m; col++) {
// count all rectangles with top left corner at (row,col)
int upperLimit = m; // this number sets the max width that rectangles with greater
// height can have (depends on the 1s in the rows above)
for (int r = row; r < n && matrix[r][col] == 1; r++) {
int c = col;
for (; c < upperLimit && matrix[r][c] == 1; c++)
sum++;
upperLimit = c;
}
}
}
I am trying to finish my code for an assignment I have, but I'm stuck on the last component. I need to create "stars" (small yellow square objects) in the "sky"... a grid of 5 rows of 10 stars. I am in a beginner java class, and I am supposed to being using methods such as star.moveHorizontal() or star.moveVertical(). All of the relevant posts I've searched for have been too complex or out of my comprehension.
I think that I would need to create an array? We haven't even covered that in class... And then have each "star" be x distance (the first star) + 30 units to the right. Then t continue that trend until there are 10 stars in a row. And then get four more rows of 10 stars.
Here is the code I've create for just one star (in the upper left of my window):
Square s1 = new Square();
s1.makeVisible();
s1.changeColor("yellow");
s1.changeSize(5);
s1.moveVertical(-100);
s1.moveHorizontal(-270);
Then I tried to create an array for a square class... I honestly have no idea if that's even legal.
Square[] starArray = new Square[10];
for ( int i=0; i<starArray.length; i++) {
starArray[i] = new Square();
But then I don't understand how I can call each star and make them appear... Please help. I feel so out of my depth. I've tried to research this and try new things for over 2.5 hours now. I will answer any questions you have to the best of my ability. Thank you
If you can make a single star appear and haven't learned about arrays yet, I don't think that is the answer your teacher is looking for. The point of an array is to be a container so you can reference the objects again. If you don't need to go back to the stars in the future, just create them and set their values in a loop.
// Set defaults for spacing and start positions
int horizontalStartPosition = 10;
int horizontalSpacing = 30;
int verticalStartPosition = 10;
int verticalSpacing = 30;
// Outer loop creates the 4 rows
for (int i = 0; i < 4; i++) {
// Inner loop creates each row
for (int j = 0; j < 10; j++) {
// Create the next star in the row
Square s = new Square();
s.makeVisible();
s.changeColor("yellow");
s.changeSize(5);
// Move the star to the correct vertical position for the current row
s.moveVertical(verticalStartPosition + i * verticalSpacing);
// Move the star to the correct horizontal spacing for the next star
s.moveHorizontal(horizontalStartPosition + j * horizontalSpacing);
}
}
You're on the right track. You can use a 2D array with 5 rows and 10 columns. Try something like this:
int numColumns = 10; //the number of columns in the array
int numRows = 5; // the number of rows in the array
Square[][] starArray = new Square[numRows][numColumns]; // the array itself
final int DIST_X = 10; //the distance between columns (use final because this value should not change)
final int DIST_Y = 10; // the distance between rows (use final because this value should not change)
int y = 0; // the initial row's vertical displacement
for ( int i=0; i<numRows; i++) {
int x = 0; // the initial columns horizontal displacement
for ( int j=0; j<numColumns; j++) {
starArray[i][j] = new Square(); //define the square
starArray[i][j].moveHorizontal(x); // move it x units horizontally
starArray[i][j].moveVertical(y); // move it y units vertically
starArray[i][j].makeVisible(); //show the square
x += DIST_X; //update your horizontal displacement so the next column shows up in the correct position
}
y += DIST_Y; //update your vertical displacement so the next row shows up in the correct position
}
Based on what I understand, you would want to call a method which would basically place a star in the grid for you.
I am not fully sure of what you mean, but here is what I can offer you:
You'll want to create a method for placing a star.
private static int X_SPACING = 30;
private static int Y_SPACING = 20;
public Square placeStar(int x, int y){
// This is the same code that you had before.
Square sq = new Square();
sq.changeColor("yellow");
sq.changeSize(5);
sq.moveVertical(-y); // Where Y is the distance from the TOP LEFT.
sq.moveHorizontal(-x);
return sq;
}
public ArrayList<Square> makeRow(int columnsAmount, int y, int startX){
ArrayList<Square> squares = new ArrayList<>();
for(int i = 0; i < columnsAmount; i++)
squares.add(placeStar(startX + (X_SPACING * i), y));
return squares;
}
public ArrayList<Square> makeGrid(int rowsAmount, int columnsAmount){
ArrayList<Square> rslt = new ArrayList<>();
for(int i = 0; i < rowsAmount; i++)
rslt.addAll(makeRow(columnsAmount, (i * Y_SPACING), 0);
return rslt;
}
Basically, calling "makeRow" should create a row of [rowsAmount] stars, which are all separated by [X_SPACING] pixels.
Then, makeGrid will call makeRow multiple times adjusting [y], and this will make you a grid. Feel free to adjust any value in the code.
EDIT: I've added a makeGrid function, and changed a few variables in the makeRow as I mistyped them. I made the functions return an ArrayList, but you shouldn't need them, only if your teachers later ask to modify them later, or something.
I hope this helps, don't hesitate to ask more questions.
Sneling.
I'm trying to create an iterative approach to a boggle game. The class contains fields for a 2d Array of Strings called "board" and has a 2d array of booleans called "haveVisit". The method that calls test 2 loops through the whole board, finding positions of the first character of the target string, then passes the coordinates into the test2 method, returning a list holding coordinates.
The return1Index method takes a 2D array coordinate at creates a int representative of the coordinates from a corresponding 1d array from it. The return2DIndex does the opposite and returns an int array holding the two coordinates.
public List<Integer> test2(int row1, int row2, String findMe){
String temp = findMe;
List<Integer> output = new ArrayList<Integer>();
if (board[row1][row2].charAt(0) != findMe.charAt(0))
return output;
haveVisit = new boolean[size][size];
int row = row1;
int column = row2;
output.add(return1DIndex(row, column));
haveVisit[row][column] = true;
//for each letter in the string
for(int j = 0; j < temp.length(); j++)
//for every column and row combination
for (int x = row - 1; x < row + 2 ; x++)
for (int y = column - 1; y < column + 2 ; y++)
//if index is valid and not visited
if (x > -1 && y > -1 && y < size && x < size && !haveVisit[x][y])
//if the output is the same size as string, return
if(output.size() == findMe.length())
return output;
//if the character in the board matches the char we're looking for
if(board[x][y].charAt(0) == temp.charAt(j))
{
haveVisit[x][y] = true;
output.add(return1DIndex(x, y));
//update row and column indices
row = x;
column = y;
}
}
}
return output;
}
For some reason this method works only 50% of the time. The method works fine with finding the letters when they're arranged left to right or top to bottom, but finding words from right to left or bottom to top never works except for one case: when you're searching for a string of length 1 or 2, where this method always works.
I have a working recursive solution but I wanted to try this way. Any thoughts as to why this wouldn't work?
Edit: Code now works from right to left, but still does not work when attempting to search upwards.
I don't know exactly what the problem is, but there are a few suspects:
You are updating row and column indices while checking their neighbors. This is like removing an element from an array while iterating through it: it's well defined, but has tricky semantics. I suggest either bailing out (greedy algorithm) or keeping a stack of matches (deeper search, requires saving stack of visited cells too).
The fors are missing opening braces, but the closing braces are there, suggesting missing code.
I'm not familiar with boggle, but isn't it possible for a letter to have two similar neighbors, like AXA? By just doing output.add(return1DIndex(x, y)); you may be outputting two ways to get the same letter. You may end up with output longer than findMe.
My suggestion is to follow a more standard format of depth-first search while you iron out the bugs. Wikipedia has a non-recursive pseudocode implementation, for example: https://en.wikipedia.org/wiki/Depth-first_search#Pseudocode .
I'm creating a voxel engine in Java using LWJGL just for practice, but I'm getting stuck on the chunk management system. More specifically, I'm trying to convert a Chunk, which is just a 3D array of integers for the block id, into an Octree for optimal rendering.
So far, I have the system working, but it's horribly inefficient.
Here's a screenshot of a 16*16*16 chunk with all positions below y=8 set to 1 (the red blocks)
https://raw.githubusercontent.com/ninthworld/Octree/master/screenshot0.png
I added a debugger to the OctNode generator code to find out how many times it needed to access the chunk array, and it came back with 8392704.
It accessed the chunk array over 8 million times just to generate 8 children nodes.
When I set the chunk array to only have blocks below y=4, the program has a blackscreen for almost 30 seconds, and the debugger returns 1623199744 array accesses.
Over 1.6 billion array calls just to generate 68 children nodes.
I obviously need to reduce the number of array calls, that much is certain, but I'm not sure how I would go about doing that. Here's the github page for the project if you'd like to see the entire source code.
Here are the important parts of my code:
Main.java
// Initialize Octree Object
// This is just an extended OctNode object
octree = new Octree(chunk);
octree.generate(lookup);
OctNode.java
public void generate(){
int value = -1;
// Loop through an area an area of width*width*width
for(int x=0; x<width; x++){
for(int y=0; y<width; y++){
for(int z=0; z<width; z++){
// Get the value from the master array based on the node's
// offset + the forloop'd area
int store = array[x+(int)offset.x][y+(int)offset.y][z+(int)offset.z];
// Basically sets the value variable to the value at
// 0, 0, 0 with respect to the offset
if(value < 0)
value = store;
// Then check if the current position's value is the
// same as the first one found (int value), if it's not,
// then this node needs to be subdivided
if(store != value){
// Create 8 children for this node
children = new OctNode[8];
// And for each of the children...
for(int i=0; i<children.length; i++){
// Set their offset equal to this node's offset +
// this node's width/2 all with respect to it's
// individual quadrant (which is related to i)
Vector3f offS = new Vector3f(offset.x + (width/2f)*(i%2), offset.y + (width/2f)*((int)Math.floor(i/2f)%2), offset.z + (width/2f)*((int)Math.floor(i/4f)%2));
// Initialize the new child node
children[i] = new OctNode(array, (int)(width/2f), offS);
// And now do the same thing (recursion), but
// for a smaller area
children[i].generate();
}
}
}
}
}
// This is only called if the node is completely made of one value
if(children == null){
data = value;
}
}
That's the best I can explain it unfortunately. If you could point out an easier, faster way to do the same thing that would be amazing.
You are partitioning the tree too frequently. If you have a 16x16x16 array with all different values, you are going to recurse at every cell except the first, so you will call generate (16x16x16-1) times at the top level, rather than just once; the value of the children array will be overwritten many times over; of course, you will repeat the doing of unnecessary work at the next level down etc.
You should move the decision to subdivide the current octree node outside the nested for loops. For example:
public void generate(){
// Assuming that width >= 1.
int minValue = Integer.MAX_VALUE;
int maxValue = Integer.MIN_VALUE;
// Loop through an area an area of width*width*width
// looking for min and max values in that area.
for(int x=0; x<width; x++){
for(int y=0; y<width; y++){
for(int z=0; z<width; z++){
int store = array[x+(int)offset.x][y+(int)offset.y][z+(int)offset.z];
minValue = Math.min(minValue, store);
maxValue = Math.max(maxValue, store);
}
}
}
if (minValue != maxValue) {
// Subdivide if the min and maxValues are different,
// as above.
children = new OctNode[8];
// etc.
} else {
data = minValue;
}
}
I am loading my level for a game through xml.
I have a loop that test the "name" and adds the sprite accordingly.
I have a map that has tiles that are 80by80 width and height. The maps rows and columns are 6x10.
I am trying to find a way to keep track of which row and column the level loader is on while it is loading the tiles, because i want to do specific things with the coordinates.
I have thought of using a 2d array for this but i am not sure how i would go about doing this in this situation.
Could anyone help me out with this?
EDIT:
Here is what i have tried.
Creating a row and column array
int row[] = new int[6];
int col[] = new int[10];
Now here is where i am stuck, im not sure how i can tell the code when to switch and use a different row. For example..
if (name.equals(TAG_ENTITY_ATTRIBUTE_TYPE_unwalkable)) {
tile = new Tile(x, y, this.tUnwalkable_tile,
activity.getVertexBufferObjectManager());
tileList.add(tile);
tile.setTag(1);
/*
* Body groundBody = PhysicsFactory.createBoxBody(this.mPhysicsWorld,
* tile, BodyType.StaticBody, wallFixtureDef);
*/
gameScene.getChildByIndex(SECOND_LAYER).attachChild(tile);
Log.e("Tile", "Unwalkable_Tile");
return;
} else if (name.equals(TAG_ENTITY_ATTRIBUTE_TYPE_Blue_Tile)) {
tile = new Tile(x, y, this.blue,
activity.getVertexBufferObjectManager());
tile.setTag(0);
this.tileList.add(tile);
gameScene.getChildByIndex(SECOND_LAYER).attachChild(tile);
return;
} else if (name.equals(TAG_ENTITY_ATTRIBUTE_TYPE_Red_Tile)) {
tile = new Tile(x, y, this.red, activity.getVertexBufferObjectManager());
tileList.add(tile);
tile.setTag(0);
gameScene.getChildByIndex(SECOND_LAYER).attachChild(tile);
return;
} else if (name.equals(TAG_ENTITY_ATTRIBUTE_TYPE_Pink_Tile)) {
tile = new Tile(x, y, this.pink,
activity.getVertexBufferObjectManager());
tileList.add(tile);
tile.setTag(0);
gameScene.getChildByIndex(SECOND_LAYER).attachChild(tile);
return;
} else if (name.equals(TAG_ENTITY_ATTRIBUTE_TYPE_Yello_Tile)) {
tile = new Tile(x, y, this.yellow,
activity.getVertexBufferObjectManager());
tileList.add(tile);
tile.setTag(0);
gameScene.getChildByIndex(SECOND_LAYER).attachChild(tile);
return;
}
How do i tell it to stay row[1] until the col[10] is reached?
Then switch to row[2] and stay there until col[10] is reached again?
From a design standpoint, your level loader should just be loading the level. Whatever magical transform you want to do on top of that can and most likely should be handled separately.
So just have your level loader create a 2d array of... whatever it's reading. Are you reading a flat set of tile elements? Then count the number of elements read. At any given point, your offset is:
x = count % 10;
y = count / 6;
If you have each row in an encapsulating element, count the rows, and the columns. Same idea.
Now you've got a 2d array (or some object encapsulating it). And you can do whatever transformations you want on it. If you want this in terms of screen space, instead multiply each count by 80.
Edit: from the edit above, it looks like you're declaring separate row and column arrays, which you probably don't want to do. It would more logically be something like:
int[][] tiles = new int[6][];
for (int i = 0; i < 6; i++) {
tiles[i] = new int[10];
}
Then, in your loader, define a counter somewhere (once).
int counter = 0;
You'll switch rows when:
counter > 0 && (counter++) % 10 == 0
But with a 2d array, you can really just think of it as having coordinates, as I mentioned above:
x = counter % 10;
y = counter / 6;
And in the end, you have one tiles[][] variable that holds all the tile data. So you can say:
tiles[x][y] = <whatever data you need to store>
And remember to increment the counter, once you're done.