My flood fill algorithm works, however, I cannot print the 6 main colors of my game. The Java function that allows me to print the 2-d array is in the class GameModel.java called toString():
import java.util.Random;
public class GameModel {
/**
* predefined values to capture the color of a DotInfo
*/
public static final int COLOR_0 = 0;
public static final int COLOR_1 = 1;
public static final int COLOR_2 = 2;
public static final int COLOR_3 = 3;
public static final int COLOR_4 = 4;
public static final int COLOR_5 = 5;
public static final int NUMBER_OF_COLORS = 6;
private static DotInfo[][] dots;
private int size;
private int currentColor;
private Random generator;
private int steps;
/**
* Constructor to initialize the model to a given size of board.
*
* #param size
* the size of the board
*/
public GameModel(int size) {
this.size = size;
dots = new DotInfo[size][size];
generator = new Random();
}
/**
* Resets the model to (re)start a game. The previous game (if there is one)
* is cleared up .
*/
public void reset(){
generator = new Random();
int color = 0;
for (int j=0;j<size;j++) {
for (int i=0;i<size;i++) {
dots[j][i] = new DotInfo(i, j, generator.nextInt(NUMBER_OF_COLORS)+1);
}
}
}
/**
* Getter method for the size of the game
*
* #return the value of the attribute sizeOfGame
*/
public int getSize(){
return size;
}
/**
* returns the current color of a given dot in the game
*
* #param i
* the x coordinate of the dot
* #param j
* the y coordinate of the dot
* #return the status of the dot at location (i,j)
*/
public int getColor(int i, int j){
return dots[j][i].getColor();
}
/**
* returns true is the dot is captured, false otherwise
*
* #param i
* the x coordinate of the dot
* #param j
* the y coordinate of the dot
* #return the status of the dot at location (i,j)
*/
public boolean isCaptured(int i, int j){
return dots[j][i].isCaptured();
}
/**
* Sets the status of the dot at coordinate (i,j) to captured
*
* #param i
* the x coordinate of the dot
* #param j
* the y coordinate of the dot
*/
public void capture(int i, int j){
dots[j][i] = new DotInfo(i, j, currentColor);
dots[j][i].setCaptured(true);
}
/**
* Getter method for the current number of steps
*
* #return the current number of steps
*/
public int getNumberOfSteps(){
return steps;
}
/**
* Setter method for currentSelectedColor
*
* #param val
* the new value for currentSelectedColor
*/
public void setCurrentSelectedColor(int val) {
currentColor = val;
}
/**
* Getter method for currentSelectedColor
*
* #return currentSelectedColor
*/
public int getCurrentSelectedColor() {
return currentColor;
}
/**
* Getter method for the model's dotInfo reference
* at location (i,j)
*
* #param i
* the x coordinate of the dot
* #param j
* the y coordinate of the dot
*
* #return model[i][j]
*/
public DotInfo get(int i, int j) {
return dots[j][i];
}
/**
* The metod <b>step</b> updates the number of steps. It must be called
* once the model has been updated after the payer selected a new color.
*/
public void step(){
steps++;
}
/**
* The metod <b>isFinished</b> returns true iff the game is finished, that
* is, all the dats are captured.
*
* #return true if the game is finished, false otherwise
*/
public boolean isFinished(){
boolean flag=true;
for (int y=0;y<size;y++) {
for (int x=0;x<size;x++) {
if (dots[y][x].isCaptured()==false) {
flag=false;
}
}
}
return flag;
}
/**
* Builds a String representation of the model
*
* #return String representation of the model
*/
public String toString(){
String rep = "";
for (int y=0;y<size;y++) {
for (int x=0;x<size;x++) {
rep += dots[y][x].getColor()+" ";
}
rep+="\n";
}
return rep;
}
}
The function where I am printing the array is in my GameController.java class with the call:
System.out.println(model)
.
import java.awt.*;
public class GameController /*implements ActionListener*/ {
private GameModel model;
private MyStack dots;
private int size;
/**
* Constructor used for initializing the controller. It creates the game's view
* and the game's model instances
*
* #param size
* the size of the board on which the game will be played
*/
public GameController(int size) {
this.size = size;
model = new GameModel(size);
dots = new MyStack(size*size);
}
/**
* resets the game
*/
public void reset(){
model.reset();
System.out.println(model);
}
/**
* Callback used when the user clicks a button (reset or quit)
*
* #param e
* the ActionEvent
*/
/*public void actionPerformed(ActionEvent e) {
}*/
/**
* <b>selectColor</b> is the method called when the user selects a new color.
* If that color is not the currently selected one, then it applies the logic
* of the game to capture possible locations. It then checks if the game
* is finished, and if so, congratulates the player, showing the number of
* moves, and gives two options: start a new game, or exit
* #param color
* the newly selected color
*/
public void selectColor(int color){
model.setCurrentSelectedColor(color);
capturePointAtZero();
sendCapturedToStack();
equalityCheck(color);
System.out.println(model);
}
private void capturePointAtZero() {
int x = 0, y = 0;
if (!model.isCaptured(x, y)) {
model.capture(x, y);
}
}
private void sendCapturedToStack() {
for (int j=0;j<size;j++) {
for (int i=0;i<size;i++) {
if (model.isCaptured(i, j)) {
model.capture(i,j);
dots.push(model.get(i,j));
}
}
}
}
private void equalityCheck(int newColor) {
while (!dots.isEmpty()) {
DotInfo dot = dots.pop();
int x = dot.getX();
int y = dot.getY();
if (model.getColor(x,y+1)==newColor && !model.isCaptured(x,y+1)) {
model.capture(x, y+1);
dots.push(model.get(x,y+1));
} if (model.getColor(x+1,y)==newColor && !model.isCaptured(x+1,y)) {
model.capture(x+1, y);
dots.push(model.get(x+1,y));
} if (model.getColor(x,y-1)==newColor && !model.isCaptured(x,y-1)) {
model.capture(x, y-1);
dots.push(model.get(x,y-1));
} if (model.getColor(x-1,y)==newColor && !model.isCaptured(x-1,y)) {
model.capture(x-1, y);
dots.push(model.get(x-1,y));
}
}
}
}
I am getting a IndexOutOfBoundsError when it approaches the end of the matrix.
If anyone could help that would be much appreciated.
There are too many issues with the code to fix all of them. Still here a few the I noticed after a quick look:
Yes, the reason why the matrix is filled with 0 is that currentColor is 0 becuase you don't call setCurrentSelectedColor
A deeper issue is with logic. Let's look at equalityCheck
if (model.getColor(x, y + 1) == newColor && !model.isCaptured(x, y + 1))
{
model.capture(x, y + 1);
dots.push(model.get(x, y + 1));
}
This code means that dot at (x, y+1) will be updated only if it already has the newColor. Obviously you want it to be updated if it matches the "old color" i.e. color of the (0,0) but you don't even try to save that color in your capturePointAtZero!
Code such as
public void capture(int i, int j){
for (int y=0;y<size;y++) {
for (int x=0;x<size;x++) {
if (x==i && y==j) {
dots[y][x] = new DotInfo(x, y, currentColor);
dots[y][x].setCaptured(true);
}
}
}
}
is rather inefficient. Why do you need loops if you still update only single DotInfo? It can be simplified
public void capture(int i, int j){
dots[j][i] = new DotInfo(i, j, currentColor);
dots[j][i].setCaptured(true);
}
Hope this helps.
Update
I understand your comments but now I am getting an arrayIndexOutOfBounds whenever i call a number that is at the end of my Matrix.
Exception most probably happens because you don't validate your indices in the equalityCheck. You can add a method isValidPosition such as:
public class GameModel
{
....
public boolean isValidPosition(int x, int y)
{
return (x >= 0) && (x < size) && (y >= 0) && (y < size);
}
}
and then
private void equalityCheck(int newColor)
{
...
if (model.isValidPosition(x, y+1) && model.getColor(x, y + 1) == newColor && !model.isCaptured(x, y + 1))
{
model.capture(x, y + 1);
dots.push(model.get(x, y + 1));
}
Note that it is important that isValidPosition is the first call in the compound if. This works because Java uses short-circuit evaluation for boolean statements.
You can hide isValidPosition inside your other methods in the GameModel and sometimes similar approach is the right thing to do. But I don't think this is the time because 1) it requires you to return some fake value from getColor (you now use 0 and I don't really like it) and 2) it hides from the reader the business-logic that the field is not unlimited.
Related
I wrote a Rectangle class that has length and width for the fields. setLength, setWidth, getLength, getWidth, getPerimeter, and getArea for the methods. In my main program, RectangleTest; when I run it; I am able to enter in the length and width. The program then displays the value that I entered in for length (which is correct), but when it displays the value that I entered in for width; it always displays 0.0. Please help. Here is the source code:
package com.delgado;
import javax.swing.JOptionPane;
import java.text.DecimalFormat;
public class RectangleTest {
public static void main(String[] args) {
double length;
double width;
String input;
DecimalFormat formatter = new DecimalFormat("#0.0");
input = JOptionPane
.showInputDialog("Please enter the length of the basketball court: ");
length = Double.parseDouble(input);
input = JOptionPane
.showInputDialog("Please enter the width of the basketball court: ");
width = Double.parseDouble(input);
Rectangle basketBall = new Rectangle(length, width);
JOptionPane.showMessageDialog(
null,
"You entered " + formatter.format(basketBall.getLength())
+ " for the length, and "
+ formatter.format(basketBall.getWidth())
+ " for the width.");
}
}
If you need the source code for the Rectangle class, please let me know. Thank you guys.
Here is the source code for the Rectangle class:
package com.delgado;
/* This Class creates an object that takes the length and width as arguments,
* and returns the perimeter and area of a rectangle.
*/
public class Rectangle {
private double length; // Holds the length.
private double width; // Holds the width.
/**
* This is a default constructor
*/
public Rectangle() {
}
/**
* This is a constructor that takes two arguments; len and w.
*
* #param len
* The length of the rectangle.
* #param w
* The width of the rectangle.
*/
public Rectangle(double len, double w) {
length = len;
w = width;
}
/**
* The method setLength sets the length of a rectangle.
*
* #param len
* The length of a rectangle.
*/
public void setLength(double len) {
length = len;
}
/**
* The method setWidth sets the width of a rectangle.
*
* #param w
* The width of a rectangle.
*/
public void setWidth(double w) {
width = w;
}
/**
* The method getLength returns the length of a rectangle.
*
* #return Returns the length of a rectangle.
*/
public double getLength() {
return length;
}
/**
* The method getWidth returns the width of a rectangle.
*
* #return Returns the width of a rectangle.
*/
public double getWidth() {
return width;
}
/**
* The method getArea returns the area of a rectangle.
*
* #return Returns the area of a rectangle.
*/
public double getArea() {
return length * width;
}
/**
* The method getPerimeter returns the perimeter of a rectangle.
*
* #return Returns the perimeter of a rectangle.
*/
public double getPerimeter() {
return (length * 2) + (width * 2);
}
}
I have to wonder if your JOptionPane is messing with your Scanner... can't tell til I test it, but regardless, I would simplify things even further. As long as you're showing JOptionPanes, who not show one that displays a message and gets input at the same time?
JOptionPane.showInputDialog(....)
Edit: Yikes
public Rectangle(double len, double w) {
length = len;
w = width;
}
You're setting the w parameter here, not the width field!!! Instead it should be:
width = w; //*********
Do you understand why?
I am developing a game in which the world is divided up into units called sectors, which the player passes through. Each of these sectors is a different size, and each is divided up into units called SubSectors, which can be different sizes and fill the sector completely. I made a quick drawing of how I would like the generation to work:
tiles http://jsydie.com/artlib/misc/tiles.gif
EDIT: I am not trying to draw random pictures like this. The SubSector object (represented by the squares above) knows where it's upper-left corner is, and how big it is. I am trying to fit these "squares" onto a grid the size of the parent Sector object.
I am trying to work on the generation for the sectors, but I don't know how to take the next step from here:
package world;
import java.util.ArrayList;
import java.util.Random;
public class Sector {
private static int size;
private static ArrayList<SubSector> sub;
public Sector(int par0) {
size = par0;
sub = this.generateSubs();
}
private ArrayList<SubSector> generateSubs() {
ArrayList<SubSector> out = new ArrayList<SubSector>();
int side = this.size;
int spaces = side * side;
boolean[][] available = new boolean[side][side];
Random r = new Random();
int subSide;
int loc;
SubSector a;
boolean anyAvailable = true;
while(anyAvailable) {
subSide = r.nextInt(1+side)-1;
System.out.println(subSide);
a = new SubSector(subSide);
loc = r.nextInt(4);
System.out.println(loc);
out.add(a);
if(loc == 0) {
for(int i=0; i<subSide; i++) {
for(int j=0; j<subSide; j++) {
available[i][j] = false;
}
}
}
if(loc == 1) {
for(int i=subSide; i>0; i--) {
for(int j=0; j<subSide; j++) {
available[i][j] = false;
}
}
}
if(loc == 2) {
for(int i=subSide; i>0; i--) {
for(int j=subSide; j>0; j--) {
available[i][j] = false;
}
}
}
if(loc == 3) {
for(int i=0; i<subSide; i++) {
for(int j=subSide; j>0; j--) {
available[i][j] = false;
}
}
}
breakloop:
for(int i=0; i<side; i++) {
for(int j=0; j<side; j++) {
if(available[i][j] == true) {
anyAvailable = true;
break breakloop;
}
else
anyAvailable = false;
}
}
}
return out;
}
}
I have no idea how to make it check what size SubSectors are now available to it in the remaining space, then create one and place it in a random location.
This is something I created for my own use, but it's modified for your square sub-sectors. It contains a class Sector which provides operations on its space and manages its sub-sectors, which are a SubSector class. I left the Javadoc in for you. You might want to add checks that the coordinate arguments are inside the sector's space.
public class Sector {
private final int SIZE;
private int[][] allocationTable;
private Set<SubSector> subSectors = new HashSet<>();
/**
* Creates a new <code>Sector</code> of the specified size.
* #param size the size of the sector
*/
public Sector (int size) {
SIZE = size;
allocationTable = new int[SIZE][SIZE];
}
/**
* Checks if a position in the grid is occupied by a {#link SubSector}.
* #param x the x coordinate
* #param y the y coordinate
* #return <code>true</code> if the position is occupied, <code>false</code> otherwise
*/
public boolean isAllocated(int x, int y) {
return (allocationTable[x][y] != 0);
}
/**
* Calculates the free space originating at the given coordinates. A {#link SubSector} of this
* maximum size or less can be allocated in this space.
* #param x the x coordinate origin of the space
* #param y the y coordinate origin of the space
* #return the length of contiguous non-allocated space
*/
public int getNonAllocatedSpaceAt(int x, int y) {
int space = Math.min(SIZE-x, SIZE-y);
for (int i = x; i < space +x ; i++) {
for (int j = y; j < space + y; j++) {
if (isAllocated(i, j))
return Math.max(i - x, j - y);
}
}
return space;
}
/**
* Gets the {#link SubSector} containing the specified coordinate.
* #param x the x coordinate
* #param y the y coordinate
* #return the <code>SubSecotr</code> to which this space is allocated. <code>null</code> if
* the space is not allocated.
*/
public SubSector getSubSectorAt(int x, int y) {
for (SubSector s : subSectors)
if (s.number == allocationTable[x][y])
return s;
return null;
}
/**
* Gets the {#link SubSector} specified by its number designation.
* #param subSector the number designation of the <code>SubSector</code>
* #return the designated <code>SubSector</code>. <code>null</code> if the <code>SubSector</code>
* does not exist.
*/
public SubSector getSubSector(int subSector) {
for (SubSector s : subSectors)
if (s.number == subSector)
return s;
return null;
}
/**
* Allocates the specified coordinate space to the specified {#link SubSector} and creates a new
* <code>SubSector</code>. The <code>SubSector</code> must not already exist.
* #param x the x coordinate origin of the space
* #param y the y coordinate origin of the space
* #param size the length of contiguous space to be allocated
* #param subSector the number designation of the <code>SubSector</code>
* #return <code>true</code> if the space was allocated, <code>false</code> otherwise
*/
public boolean allocate(int x, int y, int size, int subSector) {
if (getNonAllocatedSpaceAt(x, y) < size || !subSectors.add(new SubSector(x, y, size, subSector)))
return false;
for (int i = x; i < size + x; i++) {
for (int j = y; j < size + y; j++) {
allocationTable[i][j] = subSector;
}
}
return true;
}
/**
* Frees the space occupied by the specified {#link SubSector} and removes it.
* #param subSector the <code>SubSector</code> to be removed
* #return <code>true</code> if the space was deallocated, <code>false</code> otherwise
*/
public boolean deallocate(int subSector) {
return remove(getSubSector(subSector));
}
/**
* Frees the space occupied by the {#link SubSector} occupying the specified coordinates.
* #param x the x coordinate
* #param y the y coordinate
* #return <code>true</code> if the space was deallocated, <code>false</code> otherwise
*/
public boolean deallocate(int x, int y) {
return remove(getSubSectorAt(x, y));
}
private boolean remove(SubSector sub) {
if (!subSectors.remove(sub))
return false;
for (int i = sub.x; i < sub.size + sub.x; i++) {
for (int j = sub.y; j < sub.size + sub.y; j++) {
allocationTable[i][j] = 0;
}
}
return true;
}
/**
* Gets the allocation table for this <code>Sector</code>.
* #return the allocation table for this <code>Sector</code>
*/
public int[][] getAllocationTable() {
return allocationTable;
}
/**
* Gets the size of this <code>Sector</code>.
* #return the size of this <code>Sector</code>
*/
public int getSize() {
return SIZE;
}
/**
* Gets the (unsorted) {#link Set} of {#link SubSector}s in this <code>Sector</code>.
* #return the <code>Set</code> of <code>SubSector</code>s in this <code>Sector</code>.
*/
public Set<SubSector> getSubSectors() {
return subSectors;
}
/**
* A <code>SubSector</code> represents a square-shaped area in its parent {#link Sector}'s space.
* A <code>SubSector</code> is designated (named) by a number and each parent <code>Sector</code>
* can only contain one such <code>SubSector</code>.
* A <code>SubSector</code> can only be created (and removed) by its parent <code>Sector</code>
* and can never be modified (this prevents synchronizations issues with the allocation table),
* however, its fields can be accessed directly.
*/
public class SubSector {
/** The x coordinate origin of this <code>SubSector</code>. */
public final int x;
/** The y coordinate origin of this <code>SubSector</code>. */
public final int y;
/** The length of this <code>SubSector</code>. */
public final int size;
/** The designation of this <code>SubSector</code>. */
public final int number;
private SubSector(int x, int y, int size, int number) {
this.x = x;
this.y = y;
this.size = size;
this.number = number;
}
}
}
I'm learning about queues in school and an having an issue with one of our labs i believe the issue is here the problem is that it will not erase the circles after reaching 50
public void paint(Graphics g)
{
int incX = 5; // initial x increment for circle locations
int incY = 5; // initial y increment for circle locations
Coord temp = new Coord(0,0);
Queue<Coord> q = new LinkedList<Coord>();
Circle c = new Circle(g,circleSize,incX,incY,TIME_DELAY);
try
{
for(int i = 1; i <= TOTAL_NUM_CIRCLES; i++)
{
if(q.size() >= 50)
{
temp = q.remove();
c.eraseCircle(g,temp.getX(),temp.getY());
}
temp = new Coord(getX(),getY());
q.add(temp);
c.drawCircle(g);
c.hitEdge();
}
}
catch(InterruptedException e){}
}
if you need the whole thing to run or test here is all of it with comments saying what everything is and what I'm trying to do
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
/**
* Creates an instance of the GfxApp class, which uses the Circle class, Coord class, and
* a queue to create a screen saver.
* #param args not used
*/
public class ScreenSaver
{
public static void main(String args[])
{
GfxApp gfx = new GfxApp();
}
}
/**
* Creates a Screen Saver by placing Circle coordinates in a queue
*/
class GfxApp extends JFrame
{
private int circleCount, circleSize;
public static final int TIME_DELAY = 10; // controls the speed
public static final int TOTAL_NUM_CIRCLES = 1000; // controls how long it goes
/**
* Creates a GfxApp with 50 circles with diameter 30
*/
public GfxApp()
{
circleCount = 50;
circleSize = 30;
setSize(800,600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
/**
* Draws a stream of circleCount circles of size circleSize. Uses a queue to erase circles
* at the end of the stream. The total number of circles that will be drawn is 2000.
* #param g the Graphics object
*/
public void paint(Graphics g)
{
int incX = 5; // initial x increment for circle locations
int incY = 5; // initial y increment for circle locations
Coord temp = new Coord(0,0);
Queue<Coord> q = new LinkedList<Coord>();
Circle c = new Circle(g,circleSize,incX,incY,TIME_DELAY);
try
{
for(int i = 1; i <= TOTAL_NUM_CIRCLES; i++)
{
if(q.size() >= 50)
{
temp = q.remove();
c.eraseCircle(g,temp.getY(),temp.getX());
}
temp = new Coord(getX(),getY());
q.add(temp);
c.drawCircle(g);
c.hitEdge();
}
}
catch(InterruptedException e){}
}
}
/**
* A class to represent Circle objects. Circles can be drawn and erased.
*/
class Circle
{
private int tlX; // top-left X coordinate
private int tlY; // top-left Y coordinate
private int incX; // increment movement of X coordinate
private int incY; // increment movement of Y coordinate
private boolean addX; // flag to determine add/subtract of increment for X
private boolean addY; // flag to determine add/subtract of increment for Y
private int size; // diameter of the circle
private int timeDelay; // time delay until next circle is drawn
/**
* Creates a Circle with a specified Graphics, size, x increment, y increment and time delay
*/
public Circle(Graphics g, int s, int x, int y, int td)
{
incX = x;
incY = y;
size = s;
addX = true;
addY = false;
tlX = 400;
tlY = 300;
timeDelay = td;
}
/**
* returns the top left X of this circle
* #return tlX
*/
public int getTLX() { return tlX;}
/**
* returns the top left Y of this circle
* #return tlY
*/
public int getTLY() { return tlY;}
/**
* delays the program for a specified number of miliseconds
* #param n number of miliseconds
*/
public void delay(int n) throws InterruptedException
{
Thread.sleep(n);
}
/**
* draws a blue circle and sets the tlX and tlY for the next drawing
* #param g Graphics object
*/
public void drawCircle(Graphics g) throws InterruptedException
{
g.setColor(Color.blue);
g.drawOval(tlX,tlY,size,size);
delay(timeDelay);
if (addX)
tlX+=incX;
else
tlX-=incX;
if (addY)
tlY+=incY;
else
tlY-=incY;
}
/**
* Randomly sets a new direction for the circle by randomly setting
* the x increment and y increment
*/
public void newData()
{
incX = (int) Math.round(Math.random() * 7 + 5);
incY = (int) Math.round(Math.random() * 7 + 5);
}
/**
* Determines if any of the four edges have been hit, and if so, reverses the
* appropriate flags (addX and addY) and calls newData
*/
public void hitEdge()
{
boolean a = false;
if (tlX < incX)
{
addX = true;
a = true;
}
if (tlX > 800 - (30 + incX))
{
addX = false;
a = true;
}
if (tlY < incY + 30)
{
addY = true;
a = true;
}
if (tlY > 600 - (30 + incY))
{
addY = false;
a = true;
}
if (a)
newData();
}
// add an eraseCircle method
public void eraseCircle(Graphics g, int x, int y)
{
g.setColor(Color.black);
g.drawOval(x,y,size,size);
}
}
// Create a Coord class, so that coordinates of drawn circles can be placed in the queue.
// As coordinates are removed from the queue, circles are erased with eraseCircle.
class Coord
{
private int x;
private int y;
public Coord(int a, int b)
{
x=a;
y=b;
}
public int getX(){return x;}
public int getY(){return y;}
public int setX(int a){x=a; return x;}
public int setY(int b){y=b; return y;}
}
your coordinates are backwards:
-public void eraseCircle(Graphics g, int x, int y)
-c.eraseCircle(g,temp.getY(),temp.getX());
switch around x and y and it should work.
Edit:
Ok so the problem is the x and y in your coords are always 0 so I modified your drawCircle method to return the proper coordinates, and your paint method to store them, so this is what you get:
Paint:
public void paint(Graphics g)
{
int incX = 5; // initial x increment for circle locations
int incY = 5; // initial y increment for circle locations
Coord temp = new Coord(0,0);
Queue<Coord> q = new LinkedList<Coord>();
Circle c = new Circle(g,circleSize,incX,incY,TIME_DELAY);
try
{
for(int i = 1; i <= TOTAL_NUM_CIRCLES; i++)
{
if(q.size() >= 50)
{
temp = q.remove();
c.eraseCircle(g,temp.getX(),temp.getY());
}
temp = new Coord(getX(),getY());
//q.add(temp);
q.add(c.drawCircle(g));
c.hitEdge();
}
}
catch(InterruptedException e){}
}
drawCircle:
/**
* draws a blue circle and sets the tlX and tlY for the next drawing
* #param g Graphics object
* #return
*/
public Coord drawCircle(Graphics g) throws InterruptedException
{
g.setColor(Color.blue);
g.drawOval(tlX,tlY,size,size);
delay(timeDelay);
if (addX)
tlX+=incX;
else
tlX-=incX;
if (addY)
tlY+=incY;
else
tlY-=incY;
return new Coord(tlX, tlY);
}
To determine this I set a breakpoint in the paint method and viewed what temp's values were through eclipses debugger.
I'm trying to begin learning to use Perlin Noise to create a tile map. I'm just beginning so I found some source code online to create an array based on Perlin Noise. So I have an array of good data right now (as far as I know) but I don't understand what kinds of methods can be used to convert this from an array into a tile map.
Does anybody have any examples or sources of any methods to do this?
Here is the code I'm using the generate the array.
package perlin1;
import java.util.Random;
public class ImageWriter {
/** Source of entropy */
private Random rand_;
/** Amount of roughness */
float roughness_;
/** Plasma fractal grid */
private float[][] grid_;
/** Generate a noise source based upon the midpoint displacement fractal.
*
* #param rand The random number generator
* #param roughness a roughness parameter
* #param width the width of the grid
* #param height the height of the grid
*/
public ImageWriter(Random rand, float roughness, int width, int height) {
roughness_ = roughness / width;
grid_ = new float[width][height];
rand_ = (rand == null) ? new Random() : rand;
}
public void initialise() {
int xh = grid_.length - 1;
int yh = grid_[0].length - 1;
// set the corner points
grid_[0][0] = rand_.nextFloat() - 0.5f;
grid_[0][yh] = rand_.nextFloat() - 0.5f;
grid_[xh][0] = rand_.nextFloat() - 0.5f;
grid_[xh][yh] = rand_.nextFloat() - 0.5f;
// generate the fractal
generate(0, 0, xh, yh);
}
// Add a suitable amount of random displacement to a point
private float roughen(float v, int l, int h) {
return v + roughness_ * (float) (rand_.nextGaussian() * (h - l));
}
// generate the fractal
private void generate(int xl, int yl, int xh, int yh) {
int xm = (xl + xh) / 2;
int ym = (yl + yh) / 2;
if ((xl == xm) && (yl == ym)) return;
grid_[xm][yl] = 0.5f * (grid_[xl][yl] + grid_[xh][yl]);
grid_[xm][yh] = 0.5f * (grid_[xl][yh] + grid_[xh][yh]);
grid_[xl][ym] = 0.5f * (grid_[xl][yl] + grid_[xl][yh]);
grid_[xh][ym] = 0.5f * (grid_[xh][yl] + grid_[xh][yh]);
float v = roughen(0.5f * (grid_[xm][yl] + grid_[xm][yh]), xl + yl, yh
+ xh);
grid_[xm][ym] = v;
grid_[xm][yl] = roughen(grid_[xm][yl], xl, xh);
grid_[xm][yh] = roughen(grid_[xm][yh], xl, xh);
grid_[xl][ym] = roughen(grid_[xl][ym], yl, yh);
grid_[xh][ym] = roughen(grid_[xh][ym], yl, yh);
generate(xl, yl, xm, ym);
generate(xm, yl, xh, ym);
generate(xl, ym, xm, yh);
generate(xm, ym, xh, yh);
}
/**
* Dump out as a CSV
*/
public void printAsCSV() {
for(int i = 0;i < grid_.length;i++) {
for(int j = 0;j < grid_[0].length;j++) {
System.out.print(grid_[i][j]);
System.out.print(",");
}
System.out.println();
}
}
/**
* Convert to a Boolean array
* #return the boolean array
*/
public boolean[][] toBooleans() {
int w = grid_.length;
int h = grid_[0].length;
boolean[][] ret = new boolean[w][h];
for(int i = 0;i < w;i++) {
for(int j = 0;j < h;j++) {
ret[i][j] = grid_[i][j] < 0;
}
}
return ret;
}
/** For testing */
public static void main(String[] args) {
ImageWriter n = new ImageWriter(null, 1.0f, 250, 250);
n.initialise();
n.printAsCSV();
}
}
The resulting array is all amounts between 0 and 1.
Again, I'm just looking for how this array can be converted into a tile map.
Any help is appreciated. Thanks
public static final int SQUARE = 0,
LINE = 1,
S_FIGURE = 2,
Z_FIGURE = 3,
RIGHT_ANGLE_FIGURE = 4,
LEFT_ANGLE_FIGURE = 5,
TRIANGLE = 6;
Here above is my Tetris midlet/J2ME code for the block. But i don't know how to explain these parameters. can anyone give me advice? Let me know if you need the full code to work.
this is my full code:
public class Block {
public static final int SQUARE = 0,
LINE = 1,
S_FIGURE = 2,
Z_FIGURE = 3,
RIGHT_ANGLE_FIGURE = 4,
LEFT_ANGLE_FIGURE = 5,
TRIANGLE = 6;
public int kind;
public int color;
/**
* The horizontal figure position on the board. This value has no
* meaning when the figure is not attached to a square board.
*/
public int xPos = 0;
/**
* The vertical figure position on the board. This value has no
* meaning when the figure is not attached to a square board.
*/
public int yPos = 0;
/**
* The figure orientation (or rotation). This value is normally
* between 0 and 3, but must also be less than the maxOrientation
* value.
*
* #see #maxOrientation
*/
private int orientation = 0;
public int maxOrientation;
public int[] shapeX, shapeY;
private GameCanvas board = null;
public Block(int k) {
shapeX = new int[4];
shapeY = new int[4];
initialize(k);
this.kind = k;
}
private void initialize(int kind) {
switch (kind) {
case SQUARE :
maxOrientation = 1;
color = 0x0000ff; // blau
shapeX[0] = -1;
shapeY[0] = 0;
shapeX[1] = 0;
shapeY[1] = 0;
shapeX[2] = -1;
shapeY[2] = 1;
shapeX[3] = 0;
shapeY[3] = 1;
break;
case LINE :
maxOrientation = 2;
color = 0xff0000; // rot
shapeX[0] = -2;
shapeY[0] = 0;
shapeX[1] = -1;
shapeY[1] = 0;
shapeX[2] = 0;
shapeY[2] = 0;
shapeX[3] = 1;
shapeY[3] = 0;
break;
case S_FIGURE :
maxOrientation = 2;
color = 0xff00ff; // lila
shapeX[0] = 0;
shapeY[0] = 0;
shapeX[1] = 1;
shapeY[1] = 0;
shapeX[2] = -1;
shapeY[2] = 1;
shapeX[3] = 0;
shapeY[3] = 1;
break;
case Z_FIGURE :
maxOrientation = 2;
color = 0x008000; // grĂ¼n
shapeX[0] = -1;
shapeY[0] = 0;
shapeX[1] = 0;
shapeY[1] = 0;
shapeX[2] = 0;
shapeY[2] = 1;
shapeX[3] = 1;
shapeY[3] = 1;
break;
case RIGHT_ANGLE_FIGURE :
maxOrientation = 4;
color = 0x800080; // violett
shapeX[0] = -1;
shapeY[0] = 0;
shapeX[1] = 0;
shapeY[1] = 0;
shapeX[2] = 1;
shapeY[2] = 0;
shapeX[3] = 1;
shapeY[3] = 1;
break;
case LEFT_ANGLE_FIGURE :
maxOrientation = 4;
color = 0x000000; // schwarz
shapeX[0] = -1;
shapeY[0] = 0;
shapeX[1] = 0;
shapeY[1] = 0;
shapeX[2] = 1;
shapeY[2] = 0;
shapeX[3] = -1;
shapeY[3] = 1;
break;
case TRIANGLE :
maxOrientation = 4; // gelb
color = 0xCECE00;
shapeX[0] = -1;
shapeY[0] = 0;
shapeX[1] = 0;
shapeY[1] = 0;
shapeX[2] = 1;
shapeY[2] = 0;
shapeX[3] = 0;
shapeY[3] = 1;
break;
}
}
/**
* Checks if this figure is attached to a square board.
*
* #return true if the figure is already attached, or
* false otherwise
*/
public boolean isAttached() {
return board != null;
}
public boolean attach(GameCanvas board, boolean center) {
int newX;
int newY;
int i;
// Check for previous attachment
if (isAttached()) {
detach();
}
// Reset position (for correct controls)
xPos = 0;
yPos = 0;
// Calculate position
newX = board.getBoardWidth() / 2;
if (center) {
newY = board.getBoardHeight() / 2;
} else {
newY = 0;
for (i = 0; i < shapeX.length; i++) {
if (getRelativeY(i, orientation) < 0 && getRelativeY(i, orientation)<newY) {
newY = Math.abs(getRelativeY(i, orientation))+1;
}
}
}
// Check position
this.board = board;
if (!canMoveTo(newX, newY, orientation)) {
this.board = null;
return false;
}
// Draw figure
xPos = newX;
yPos = newY;
paint(color);
board.repaint();
return true;
}
/**
* Checks if the figure is fully visible on the square board. If
* the figure isn't attached to a board, false will be returned.
*
* #return true if the figure is fully visible, or
* false otherwise
*/
public boolean isAllVisible() {
if (!isAttached()) {
return false;
}
for (int i = 0; i < shapeX.length; i++) {
if (yPos + getRelativeY(i, orientation) < 0) {
return false;
}
}
return true;
}
/**
* Detaches this figure from its square board. The figure will not
* be removed from the board by this operation, resulting in the
* figure being left intact.
*/
public void detach() {
board = null;
}
/**
* Checks if the figure has landed. If this method returns true,
* the moveDown() or the moveAllWayDown() methods should have no
* effect. If no square board is attached, this method will return
* true.
*
* #return true if the figure has landed, or false otherwise
*/
public boolean hasLanded() {
return !isAttached() || !canMoveTo(xPos, yPos + 1, orientation);
}
/**
* Moves the figure one step to the left. If such a move is not
* possible with respect to the square board, nothing is done. The
* square board will be changed as the figure moves, clearing the
* previous cells. If no square board is attached, nothing is
* done.
*/
public void moveLeft() {
if (isAttached() && canMoveTo(xPos - 1, yPos, orientation)) {
paint(-1);
xPos--;
paint(color);
board.repaint();
}
}
/**
* Moves the figure one step to the right. If such a move is not
* possible with respect to the square board, nothing is done. The
* square board will be changed as the figure moves, clearing the
* previous cells. If no square board is attached, nothing is
* done.
*/
public void moveRight() {
if (isAttached() && canMoveTo(xPos + 1, yPos, orientation)) {
paint(-1);
xPos++;
paint(color);
board.repaint();
}
}
/**
* Moves the figure one step down. If such a move is not possible
* with respect to the square board, nothing is done. The square
* board will be changed as the figure moves, clearing the
* previous cells. If no square board is attached, nothing is
* done.
*/
public void moveDown() {
if (isAttached() && canMoveTo(xPos, yPos + 1, orientation)) {
paint(-1);
yPos++;
paint(color);
board.repaint();
}
}
/**
* Moves the figure all the way down. The limits of the move are
* either the square board bottom, or squares not being empty. If
* no move is possible with respect to the square board, nothing
* is done. The square board will be changed as the figure moves,
* clearing the previous cells. If no square board is attached,
* nothing is done.
*/
public void moveAllWayDown() {
int y = yPos;
// Check for board
if (!isAttached()) {
return;
}
// Find lowest position
while (canMoveTo(xPos, y + 1, orientation)) {
y++;
}
// Update
if (y != yPos) {
paint(-1);
yPos = y;
paint(color);
board.repaint();
}
}
/**
* Returns the current figure rotation (orientation).
*
* #return the current figure rotation
*/
public int getRotation() {
return orientation;
}
/**
* Sets the figure rotation (orientation). If the desired rotation
* is not possible with respect to the square board, nothing is
* done. The square board will be changed as the figure moves,
* clearing the previous cells. If no square board is attached,
* the rotation is performed directly.
*
* #param rotation the new figure orientation
*/
public void setRotation(int rotation) {
int newOrientation;
// Set new orientation
newOrientation = rotation % maxOrientation;
// Check new position
if (!isAttached()) {
orientation = newOrientation;
} else if (canMoveTo(xPos, yPos, newOrientation)) {
paint(-1);
orientation = newOrientation;
paint(color);
board.repaint();
}
}
/**
* Rotates the figure clockwise. If such a rotation is not
* possible with respect to the square board, nothing is done.
* The square board will be changed as the figure moves,
* clearing the previous cells. If no square board is attached,
* the rotation is performed directly.
*/
public void rotateClockwise() {
if (maxOrientation == 1) {
return;
} else {
setRotation((orientation + 1) % maxOrientation);
}
}
/**
* Rotates the figure counter-clockwise. If such a rotation
* is not possible with respect to the square board, nothing
* is done. The square board will be changed as the figure
* moves, clearing the previous cells. If no square board is
* attached, the rotation is performed directly.
*/
public void rotateCounterClockwise() {
if (maxOrientation == 1) {
return;
} else {
setRotation((orientation + 3) % 4);
}
}
/**
* Checks if a specified pair of (square) coordinates are inside
* the figure, or not.
*
* #param x the horizontal position
* #param y the vertical position
*
* #return true if the coordinates are inside the figure, or
* false otherwise
*/
private boolean isInside(int x, int y) {
for (int i = 0; i < shapeX.length; i++) {
if (x == xPos + getRelativeX(i, orientation)
&& y == yPos + getRelativeY(i, orientation)) {
return true;
}
}
return false;
}
/**
* Checks if the figure can move to a new position. The current
* figure position is taken into account when checking for
* collisions. If a collision is detected, this method will return
* false.
*
* #param newX the new horizontal position
* #param newY the new vertical position
* #param newOrientation the new orientation (rotation)
*
* #return true if the figure can be moved, or
* false otherwise
*/
private boolean canMoveTo(int newX, int newY, int newOrientation) {
int x;
int y;
for (int i = 0; i < 4; i++) {
x = newX + getRelativeX(i, newOrientation);
y = newY + getRelativeY(i, newOrientation);
if (!isInside(x, y) && !board.isSquareEmpty(x, y)) {
return false;
}
}
return true;
}
/**
* Returns the relative horizontal position of a specified square.
* The square will be rotated according to the specified
* orientation.
*
* #param square the square to rotate (0-3)
* #param orientation the orientation to use (0-3)
*
* #return the rotated relative horizontal position
*/
public int getRelativeX(int square, int orientation) {
switch (orientation % 4) {
case 0 :
return shapeX[square];
case 1 :
return -shapeY[square];
case 2 :
return -shapeX[square];
case 3 :
return shapeY[square];
default:
return 0; // Should never occur
}
}
/**
* Rotates the relative vertical position of a specified square.
* The square will be rotated according to the specified
* orientation.
*
* #param square the square to rotate (0-3)
* #param orientation the orientation to use (0-3)
*
* #return the rotated relative vertical position
*/
public int getRelativeY(int square, int orientation) {
switch (orientation % 4) {
case 0 :
return shapeY[square];
case 1 :
return shapeX[square];
case 2 :
return -shapeY[square];
case 3 :
return -shapeX[square];
default:
return 0; // Should never occur
}
}
/**
* Paints the figure on the board with the specified color.
*
* #param color the color to paint with, or -1 for clearing
*/
private void paint(int color) {
int x, y;
for (int i = 0; i < shapeX.length; i++) {
x = xPos + getRelativeX(i, orientation);
y = yPos + getRelativeY(i, orientation);
board.setSquareColor(x, y, color);
}
}
}
First of all, I think what you're looking for is an enum:
public enum Tetrimonos{
SQUARE , LINE, S_FIGURE, Z_FIGURE ,
RIGHT_ANGLE_FIGURE, LEFT_ANGLE_FIGURE , TRIANGLE
}
Using constants is a bad idea, relic from old languages.
Secondly, what do you mean 'explain these parameters'? Explain the tetris structure of each thing you named? In this case you should go to the relevant literature: a tetris piece is called tetrimono, and each one is called by a letter. Take a look here:
http://en.wikipedia.org/wiki/Tetris#Gameplay
You might like to link to this in your documentation as well.