RGBimage array and creating ppm file - java

This is part of university task
I'm given a class named RGBColor without private access(but with info on what each method/constructor does)
the object is (r,g,b): r for red, g for green, b for blue, each of them represent a number between 0-255
I need to write a new class named RBGImage based on RBGColor, and the class object is a two-dimensional array storing RGBColor objects.
My struggle is to create a ppm file in order to check the program and I have no idea how to do it. This is what I did so far:
public class RGBImage
{
RGBColor[][] _image;
public RGBImage(int rows , int cols){
_image=new RGBColor[rows][cols];
for(int i=0;i<rows;i++)
for(int j=0;j<cols;j++)
_image[i][j]=new RGBColor(_image[i][j]);
}
public RGBImage(RGBColor[][] pixels) {
int hight=pixels.length;
int width=pixels[0].length;
_image=new RGBColor[hight][width];
for(int i=0;i<hight;i++)
for(int j=0;j<width;j++)
_image[i][j] = new RGBColor(pixels[i][j]);
;
}
public RGBImage(RGBImage other)
{
_image = other._image;
}
public int getHeight()
{
int hight = _image.length;
return hight;
}
public int getWidth() {
int width = _image[0].length;
return width;
}
public RGBColor getPixel(int row,int col)
{
int _red = _image[row][col].getRed();
int _green = _image[row][col].getGreen();
int _blue = _image[row][col].getBlue();
return new RGBColor(_red,_green,_blue);
}
public void setPixel(int row,int col,RGBColor pixel)
{
int _red = pixel.getRed();
int _green = pixel.getGreen();
int _blue = pixel.getBlue();
// set if to do nothing
if(row <= _image.length && col <= _image[0].length)
_image[row][col].setRed(_red);
_image[row][col].setGreen(_green);
_image[row][col].setBlue(_blue);
}
public double[][] toGrayscaleArray() {
int width = _image[0].length;
int hight = _image.length;
double[][] grayScale = new double[hight][width];
for(int i=0;i<hight;i++)
for(int j=0;j<width;j++)
grayScale[i][j]=_image[i][j].convertToGrayscale();
return grayScale;
}
public boolean equals (RGBImage other)
{
if(_image == other._image)
return true;
return false;
}
Sorry I couldn't provide any documentation

Related

Android stop sprite from changing subimages when staying

Currently my sprite animates like it was in movement not only when is in movement but also when it stays in one place. Of course I want to stay still without animation when it stays in one place. How to solve that?
public abstract class GameMovingObject {
private static final int ROW_TOP_TO_BOTTOM = 0;
private static final int ROW_RIGHT_TO_LEFT = 1;
private static final int ROW_LEFT_TO_RIGHT = 2;
private static final int ROW_BOTTOM_TO_TOP = 3;
public boolean justSeen=true;
protected Bitmap image;
private final int rowCount, colCount;
protected final int WIDTH, HEIGHT;
private final int width, height;
private int x;
public int getX() { return this.x; }
public void setX(int x) { this.x = x; }
private int y;
public int getY() { return this.y; }
public void setY(int y) { this.y = y; }
// Row index of Image are being used.
private int rowUsing = ROW_LEFT_TO_RIGHT;
private int colUsing;
private Bitmap[] leftToRights;
private Bitmap[] rightToLefts;
private Bitmap[] topToBottoms;
private Bitmap[] bottomToTops;
// Velocity of game character (pixel/millisecond)
public float velocity = 0.15f;
public int getMovingVectorX() {
return movingVectorX;
}
public int getMovingVectorY() {
return movingVectorY;
}
public int movingVectorX = 0;
public int movingVectorY = 0;
public long lastDrawNanoTime =-1;
public GameSurface gs;
public GameMovingObject(GameSurface gs, Bitmap image, int rowCount, int colCount, int x, int y) {
this.gs = gs;
this.image = image;
this.rowCount = rowCount;
this.colCount = colCount;
this.x = x;
this.y = y;
this.WIDTH = image.getWidth();
this.HEIGHT = image.getHeight();
this.width = this.WIDTH / colCount;
this.height = this.HEIGHT / rowCount;
this.topToBottoms = new Bitmap[colCount]; // 3
this.rightToLefts = new Bitmap[colCount]; // 3
this.leftToRights = new Bitmap[colCount]; // 3
this.bottomToTops = new Bitmap[colCount]; // 3
for(int col = 0; col< this.colCount; col++ ) {
this.topToBottoms[col] = this.createSubImageAt(ROW_TOP_TO_BOTTOM, col);
this.rightToLefts[col] = this.createSubImageAt(ROW_RIGHT_TO_LEFT, col);
this.leftToRights[col] = this.createSubImageAt(ROW_LEFT_TO_RIGHT, col);
this.bottomToTops[col] = this.createSubImageAt(ROW_BOTTOM_TO_TOP, col);
}
}
public Bitmap[] getMoveBitmaps() {
switch (rowUsing) {
case ROW_BOTTOM_TO_TOP:
return this.bottomToTops;
case ROW_LEFT_TO_RIGHT:
return this.leftToRights;
case ROW_RIGHT_TO_LEFT:
return this.rightToLefts;
case ROW_TOP_TO_BOTTOM:
return this.topToBottoms;
default:
return null;
}
}
public void setMovingVector(int movingVectorX, int movingVectorY) {
this.movingVectorX= movingVectorX;
this.movingVectorY = movingVectorY;
}
public Bitmap getCurrentMoveBitmap() {
Bitmap[] bitmaps = this.getMoveBitmaps();
return bitmaps[this.colUsing];
}
public void draw(Canvas canvas) {
Bitmap bitmap = this.getCurrentMoveBitmap();
canvas.drawBitmap(bitmap,x, y, null);
// Last draw time.
this.lastDrawNanoTime= System.nanoTime();
}
public void update() {
this.colUsing++;
if(colUsing >= this.colCount) {
this.colUsing =0;
}
// Current time in nanoseconds
long now = System.nanoTime();
// Never once did draw.
if(lastDrawNanoTime==-1) {
lastDrawNanoTime= now;
}
// Change nanoseconds to milliseconds (1 nanosecond = 1000000 milliseconds).
int deltaTime = (int) ((now - lastDrawNanoTime)/ 777777 );
// Distance moves
float distance = velocity * deltaTime;
double movingVectorLength = Math.sqrt(movingVectorX* movingVectorX + movingVectorY*movingVectorY);
// Calculate the new position of the game character.
this.x = x + (int)(distance* movingVectorX / movingVectorLength);
this.y = y + (int)(distance* movingVectorY / movingVectorLength);
// When the game's character touches the edge of the screen, then change direction
if(this.x < 0 ) {
this.x = 0;
this.movingVectorX = - this.movingVectorX;
} else if(this.x > this.gs.getWidth() -width) {
this.x= this.gs.getWidth()-width;
this.movingVectorX = - this.movingVectorX;
}
if(this.y < 0 ) {
this.y = 0;
this.movingVectorY = - this.movingVectorY;
}
// rowUsing (obraca postać)
if( movingVectorX > 0 ){
if(movingVectorY > 0 && Math.abs(movingVectorX) < Math.abs(movingVectorY)) {
this.rowUsing = ROW_TOP_TO_BOTTOM;
}
else if(movingVectorY < 0 && Math.abs(movingVectorX) < Math.abs(movingVectorY)) {
this.rowUsing = ROW_BOTTOM_TO_TOP;
}
else {
this.rowUsing = ROW_LEFT_TO_RIGHT;
}
}
else
{
if(movingVectorY > 0 && Math.abs(movingVectorX) < Math.abs(movingVectorY)) {
this.rowUsing = ROW_TOP_TO_BOTTOM;
}
else if(movingVectorY < 0 && Math.abs(movingVectorX) < Math.abs(movingVectorY)) {
this.rowUsing = ROW_BOTTOM_TO_TOP;
}
else if(movingVectorX!=0 || movingVectorY!=0) {
this.rowUsing = ROW_RIGHT_TO_LEFT;
}
}
}
protected Bitmap createSubImageAt(int row, int col) {
// createBitmap(bitmap, x, y, width, height).
Bitmap subImage = Bitmap.createBitmap(image, col * width, row * height, width, height);
return subImage;
}
public int getHeight() {
return height;
}
public int getWidth() {
return width;
}
I was trying to add
if(movingVectorY!=0) this.topToBottoms[col] = this.createSubImageAt(ROW_TOP_TO_BOTTOM, col);
else this.topToBottoms[1] = this.createSubImageAt(ROW_TOP_TO_BOTTOM, 1);
but then sprite blinks and is without animation even when moving. I think I added everything you need to know. It there is anything you want me to add just ask me. Thank you in advance.

How to add a Title and legend in Processing(Java) and create diverging colors

I currently have a code to map poverty rates to states using processing. I want to add a Title above the map and a legend detailing colors. Currently I only have values in red, I also need help in creating diverging colors from green(low values) to red(High values).Link to files Below is my code:
PImage mapImage;
Table locationTable;
int rowCount;
Table dataTable;
float dataMin = MAX_FLOAT;
float dataMax = MIN_FLOAT;
int toggle = 0;
void setup( ) {
size(640, 400);
surface.setTitle("Poverty Rate by State");
surface.setResizable(true);
surface.setLocation(100, 100);
mapImage = loadImage("map.png");
locationTable = new Table("locations.tsv");
rowCount = locationTable.getRowCount( );
// Read the data table.
dataTable = new Table("poverty2017.tsv");
// Find the minimum and maximum values.
for (int row = 0; row < rowCount; row++) {
float value = dataTable.getFloat(row, 1);
if (value > dataMax) {
dataMax = value;
}
if (value < dataMin) {
dataMin = value;
}
}
}
void draw( ) {
background(255);
image(mapImage, 0, 0);
smooth( );
fill(192, 0, 0);
noStroke( );
for (int row = 0; row < rowCount; row++) {
String abbrev = dataTable.getRowName(row);
float x = locationTable.getFloat(abbrev, 1);
float y = locationTable.getFloat(abbrev, 2);
drawData(x, y, abbrev);
}
}
void drawData(float x, float y, String abbrev) {
float value = dataTable.getFloat(abbrev, 1);
float radius = 0;
if (value >= 0) {
radius = map(value, 0, dataMax, 1.5, 15);
fill(#FF4422); // Red
} else {
radius = map(value, 0, dataMin, 1.5, 15);
fill(#FF4422); // red
}
ellipseMode(RADIUS);
ellipse(x, y, radius, radius);
if (dist(x, y, mouseX, mouseY) < radius+2) {
fill(0);
textAlign(CENTER);
// Show the data value and the state abbreviation in parentheses.
text(value + " (" + abbrev + ")", x, y-radius-4);
}
}
With the following class to pull the data in as circles:
class Table {
String[][] data;
int rowCount;
Table() {
data = new String[10][10];
}
Table(String filename) {
String[] rows = loadStrings(filename);
data = new String[rows.length][];
for (int i = 0; i < rows.length; i++) {
if (trim(rows[i]).length() == 0) {
continue; // skip empty rows
}
if (rows[i].startsWith("#")) {
continue; // skip comment lines
}
// split the row on the tabs
String[] pieces = split(rows[i], TAB);
// copy to the table array
data[rowCount] = pieces;
rowCount++;
// this could be done in one fell swoop via:
//data[rowCount++] = split(rows[i], TAB);
}
// resize the 'data' array as necessary
data = (String[][]) subset(data, 0, rowCount);
}
int getRowCount() {
return rowCount;
}
// find a row by its name, returns -1 if no row found
int getRowIndex(String name) {
for (int i = 0; i < rowCount; i++) {
if (data[i][0].equals(name)) {
return i;
}
}
println("No row named '" + name + "' was found");
return -1;
}
String getRowName(int row) {
return getString(row, 0);
}
String getString(int rowIndex, int column) {
return data[rowIndex][column];
}
String getString(String rowName, int column) {
return getString(getRowIndex(rowName), column);
}
int getInt(String rowName, int column) {
return parseInt(getString(rowName, column));
}
int getInt(int rowIndex, int column) {
return parseInt(getString(rowIndex, column));
}
float getFloat(String rowName, int column) {
return parseFloat(getString(rowName, column));
}
float getFloat(int rowIndex, int column) {
return parseFloat(getString(rowIndex, column));
}
void setRowName(int row, String what) {
data[row][0] = what;
}
void setString(int rowIndex, int column, String what) {
data[rowIndex][column] = what;
}
void setString(String rowName, int column, String what) {
int rowIndex = getRowIndex(rowName);
data[rowIndex][column] = what;
}
void setInt(int rowIndex, int column, int what) {
data[rowIndex][column] = str(what);
}
void setInt(String rowName, int column, int what) {
int rowIndex = getRowIndex(rowName);
data[rowIndex][column] = str(what);
}
void setFloat(int rowIndex, int column, float what) {
data[rowIndex][column] = str(what);
}
void setFloat(String rowName, int column, float what) {
int rowIndex = getRowIndex(rowName);
data[rowIndex][column] = str(what);
}
// Write this table as a TSV file
void write(PrintWriter writer) {
for (int i = 0; i < rowCount; i++) {
for (int j = 0; j < data[i].length; j++) {
if (j != 0) {
writer.print(TAB);
}
if (data[i][j] != null) {
writer.print(data[i][j]);
}
}
writer.println();
}
writer.flush();
}
}
To add a title: just add some text to your draw loop.
void draw() {
AddTitle();
}
void AddTitle() {
fill(0);
textSize(20);
textAlign(CENTER);
text("Poverty Rate by State", width/2, 30);
}
To change the color of your red circles so states are on a scale from green (least poverty) to red (max poverty):
You're working in RGB (Red-Green-Blue). Each color is a mix of these. Those tree are calculated with numbers on a scale from 0 to 255. For an example, black would be (0, 0, 0), red would be (255, 0, 0). The lower the number the least of the specific color is in the mix.
color myColorRed = color(255, 0, 0);
So to make your fill dynamic, you have to find a way to increase the red part when your poverty rate increases, while lowering the green part at the same time. Here's a simple calcul which does exactly that:
float colorOffset = 255 * ((povertyRate - dataMin) / (dataMax - dataMin));
color(colorOffset, 255-colorOffset, 0);
You can just include this at the right place in your logic and it should do the trick. Beware, though: this calcul is based on the dataMin and dataMax. This means that the lowest number will be green and the highest will be red, not that 0% is green and 100% is red. You'll probably like it this way, but if you wanted something else you'll have to adapt this logic to what you want.
Now... something is bothering me here. At every iteration of the draw() loop, you re-calculate a lot of information. That's a lot of processing power wasted. Of course, with a good computer there will be no difference, but it would be good practice to avoid wasting resources like that. A good way to fix this would be to calculate everything you need to know to draw your map in the setup() method, and use it in the draw() loop.
Now, If you're not interested in what I just said, consider that you have your answer and you can skip the rest. If you'd like to improve a bit on your current algorithm, let's rock!
First, I gathered all the information you need in a nice new class:
class StateData {
public String name;
public PVector location; // I'll just use this to have nice x and y floats, but there's a lot of nice stuff available with this class (which I won't use here)
public float povertyRate;
public float radius;
public color fill;
StateData(String name, PVector location, float povertyRate) {
this.name = name;
this.location = location;
this.povertyRate = povertyRate;
this.radius = map(povertyRate, 0, dataMax, 1.5, 15);
float colorOffset = 255 * ((povertyRate - dataMin) / (dataMax - dataMin));
this.fill = color(colorOffset, 255-colorOffset, 0);
}
}
Naturally, I'll need to fill these and store this information somewhere. I created a global variable:
ArrayList<StateData> stateData;
I'll fill this global variable by using the following function in the setup() method, so I'll need to calculate all these things only once:
ArrayList<StateData> GetStateData() {
ArrayList<StateData> data = new ArrayList<StateData>();
for (int row = 0; row < rowCount; row++) {
String abbrev = dataTable.getRowName(row);
float value = dataTable.getFloat(abbrev, 1);
float x = locationTable.getFloat(abbrev, 1);
float y = locationTable.getFloat(abbrev, 2);
data.add(new StateData(abbrev, new PVector(x, y), value));
}
return data;
}
You'll notice that I'm mostly just recycling your code, here. That's because your code gets the job done. It's good work. It's just very inefficient, and this should help on this front.
By now, your setup() method should look like somthing like this:
void setup() {
size(640, 400);
smooth();
noStroke();
mapImage = loadImage("map.png");
locationTable = new Table("locations.tsv");
rowCount = locationTable.getRowCount( );
dataTable = new Table("poverty2017.tsv");
for (int row = 0; row < rowCount; row++) {
float value = dataTable.getFloat(row, 1);
if (value > dataMax) {
dataMax = value;
}
if (value < dataMin) {
dataMin = value;
}
}
stateData = GetStateData();
}
And your draw() loop like this:
void draw() {
background(255);
image(mapImage, 0, 0);
DrawStats();
AddTitle();
}
Wait...­ what's DrawStats()? That's a method which will loop in the stateData ArrayList and draw everything according to the data stored there while we were in the setup() method:
void DrawStats() {
// draw circles
for (StateData s : stateData) {
fill(s.fill);
ellipseMode(RADIUS);
ellipse(s.location.x, s.location.y, s.radius, s.radius);
}
// draw text (here so it's over the circles)
for (StateData s : stateData) {
if (dist(s.location.x, s.location.y, mouseX, mouseY) < s.radius+2) {
fill(0);
textAlign(CENTER);
textSize(10);
text(s.povertyRate + " (" + s.name + ")", s.location.x, s.location.y-s.radius-4);
}
}
}
Now, with these pointers and a little bit of refactoring, you should be able to give a nice quality boost to this program! I'll hang around in case you have further questions.
Have fun!

Drawing a dynamic custom view chess board in Android

I would like to draw an 8 by 8 chess board dynamically in android studio using the canvas and by overriding method onDraw, I almost have succeeded but I am running into a very annoying problem.
I already made a custom view, my goal is to make the parent layout match the size of it's child custom view, so my chessboard can cover the entire screen. ( in XML file both parent and child are set to match_parent)
I want the chess board to cover the full height of the screen as well.
Check the picture below here's the result I am getting, notice that huge gap in the lower area, my purpose is to stretch the chessboard vertically and make it cover the entire screen to eliminate that space.
Here's what I managed to write so far but it's not doing what I want :
Class ChessBoard:
public class ChessBoard extends View {
private static final String TAG = ChessBoard.class.getSimpleName();
private Rect rect;
private static final int COLS = 8;
private static final int ROWS = 8;
Tile tile;
private final Tile[][] mTiles;
private int x0 = 0;
private int y0 = 0;
private static final int DEF_SQUARE_SIZE=50;
private int squareSize=0;
private boolean flipped = false;
public ChessBoard(final Context context,AttributeSet attrs) {
super(context,attrs);
this.mTiles = new Tile[COLS][ROWS];
buildTiles();
rect=new Rect();
}
onDraw method:
protected void onDraw(final Canvas canvas)
{
int width = getWidth();
int height = getHeight();
squareSize=Math.min(getSquareSizeWidth(width),getSquareSizeHeight(height));
computeOrigins(width,height);
for (int c = 0; c < COLS; c++) {
for (int r = 0; r < ROWS; r++) {
final int xCoord = getXCoord(c);
final int yCoord = getYCoord(r);
mTiles[c][r].setTileRect(rect);
rect.left=xCoord;
rect.top=yCoord;
rect.right= rect.left+squareSize; // right
rect.bottom=rect.top + squareSize;
mTiles[c][r].draw(canvas);
}
}
Class Tile :
public final class Tile {
private static final String TAG = Tile.class.getSimpleName();
private final int col;
private final int row;
private final Paint squareColor;
private Rect tileRect;
public Tile(final int col, final int row) {
this.col = col;
this.row = row;
this.squareColor = new Paint();
squareColor.setColor(isDark() ? Color.BLACK : Color.WHITE);
squareColor.setAntiAlias(true);
}
public void draw(final Canvas canvas) {
canvas.drawRect(tileRect, squareColor);
}
public String getColumnString() {
switch (col) {
case 0: return "A";
case 1: return "B";
case 2: return "C";
case 3: return "D";
case 4: return "E";
case 5: return "F";
case 6: return "G";
case 7: return "H";
default: return null;
}
}
public String getRowString() {
// To get the actual row, add 1 since 'row' is 0 indexed.
return String.valueOf(row + 1);
}
public void handleTouch() {
Log.d(TAG, "handleTouch(): col: " + col);
Log.d(TAG, "handleTouch(): row: " + row);
}
public boolean isDark() {
return (col + row) % 2 == 0;
}
public boolean isTouched(final int x, final int y) {
return tileRect.contains(x, y);
}
public void setTileRect(final Rect tileRect) {
this.tileRect = tileRect;
}
public String toString() {
final String column = getColumnString();
final String row = getRowString();
return "<Tile " + column + row + ">";
}
}
onMeasure Mehtod:
protected void onMeasure(int widthMeasureSpec, int
heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
int height = getMeasuredHeight();
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
int sqSizeW = getSquareSizeWidth(width);
int sqSizeH = getSquareSizeHeight(height);
int sqSize = Math.min(sqSizeW, sqSizeH);
if (height > width) {
int p = getMaxHeightPercentage();
height = Math.min(getHeight(sqSize), height * p / 100);
} else {
width = Math.min(getWidth(sqSize), width * 65 / 100);
}
setMeasuredDimension(width, height);
}
Class ChessBoard methods:
protected int getWidth(int sqSize) {
return sqSize * 8;
}
protected int getHeight(int sqSize) {
return sqSize * 8;
}
private int getSquareSizeWidth(final int width) {
return (width)/ 8;
}
private int getSquareSizeHeight(final int height) {
return (height)/8;
}
private int getXCoord(final int x) {
return x0 + squareSize * (flipped ? 7 - x : x);
}
private int getYCoord(final int y) {
return y0 + squareSize * (flipped ? y : 7 - y);
}
private void computeOrigins(final int width, final int height) {
this.x0 = (width - squareSize *8)/2 ;
this.y0 = (height - squareSize *8)/2;
}
protected int getMaxHeightPercentage() {
return 75;
}
}
Kindly note that the onDraw method above is implemented in the Chess Board Class.
I am sure the solution for this problem lies in the onMeasure Method, I am thinking if I increase the height of each square then the chessboard will stretch horizontally and cover the whole screen ? Can anyone please tell me what I am doing wrong ?
Well, not quite sure what you want to achieve by having a non-square chessboard which is not how usually it is represented. In any case, just looking at your code somehow following lines looks a bit suspicious:
squareSize=Math.min(getSquareSizeWidth(width),getSquareSizeHeight(height));
and
rect.right= rect.left+squareSize; // right
rect.bottom=rect.top + squareSize;
So, your tile rect always seems to be setting to same width and height, which is minimum of width and height as per these lines.

Java: How to return object when I have its name as a string?

Suppose I am building a chess game and creating board space objects. I am creating objects like so, precisely 64 for all spaces on the chess board:
BoardSpace a1 = new BoardSpace("black", 1, 1, true);
Here is the class I've created for the BoardSpace object:
public class BoardSpace {
String color;
int x_pos;
int y_pos;
boolean occupied;
//constructor
public BoardSpace (String color, int x_pos, int y_pos, boolean occupied) {
this.color = color;
this.x_pos = x_pos;
this.y_pos = y_pos;
this.occupied = occupied;
}
}
I create all my BoardSpace objects prior to moving chess pieces on the board. My chess piece objects each have an x position and y position. What I want to do is convert their coordinates into a BoardPiece name, and then retrieve a previously-created BoardPiece object from that name.
This is what I want to do:
static String get_BoardSpace_color(int x_pos, int y_pos){
int modified_x = x_pos + 96; //adjusting for ASCII
char c = (char)(modified_x);
String space_name = ""+c+y_pos;
BoardSpace piece = (BoardSpace)(space_name); //PROBLEM AREA
return piece.color;
}
How can I, using the correct string representation of the already existing object's name, actually RETRIEVE THAT OBJECT?
Again, objects don't have names. Yes variables do, but the name of a variable is not a String, and variable names almost don't exist in compiled code. What you need is a way to get a reference to the object of interest, and there are various ways to do this including:
a Map<String, BoardSpace> such as a HashMap<String, BoardSpace>. This way you can associate a String with a unique object
A collection such as an ArrayList<BoardSpace> which allows you to get your object by an int index
a simple array of BoardSpace, such as BoardSpace[64]
A 2 dimensional nested collection, such as a List<List<BoardSpace>>
or a 2D array.
Since you appear to be making an 8 x 8 grid of BoardSpace, and since these dimensions likely will not change, simplest here is to create an 8x8 array of objects:
private BoardSpace[][] grid = new BoardSpace[8][8];
Then you can use your x and y (or row and column) indices to get the object of interest.
For example:
public class TestBoardSpace {
public static void main(String[] args) {
Board board = new Board();
for (int y = 0; y < Board.ROWS; y++) {
for (int x = 0; x < Board.COLS; x++) {
System.out.printf("%8s ", board.getBoardSpace(x, y).getColor());
}
System.out.println();
}
}
}
class Board {
public static final int ROWS = 8;
public static final int COLS = ROWS;
private BoardSpace[][] grid = new BoardSpace[ROWS][COLS];
public Board() {
for (int row = 0; row < grid.length; row++) {
for (int col = 0; col < grid[row].length; col++) {
MyColor color = row % 2 == col % 2 ? MyColor.BLACK : MyColor.WHITE;
grid[row][col] = new BoardSpace(color, col, row, false);
}
}
}
public BoardSpace getBoardSpace(int x, int y) {
// to get color, simply call getColor() on this
return grid[y][x];
}
}
// yes an enum here would be great and would protect against
// bad Strings
enum MyColor {
WHITE, BLACK
}
class BoardSpace {
private MyColor color;
private int x_pos;
private int y_pos;
private boolean occupied;
// constructor
public BoardSpace(MyColor color, int x_pos, int y_pos, boolean occupied) {
this.color = color;
this.x_pos = x_pos;
this.y_pos = y_pos;
this.occupied = occupied;
}
public boolean isOccupied() {
return occupied;
}
public void setOccupied(boolean occupied) {
this.occupied = occupied;
}
public MyColor getColor() {
return color;
}
public int getX_pos() {
return x_pos;
}
public int getY_pos() {
return y_pos;
}
}

2D arrays in Java not changing properly

In a Game Of Life project that I'm working on, I have a 2D array of bytes. The array represents a gameboard. The problem is that when I try to access the array, it returns all zeroes. But, in the function where I set a cell, changes save just fine.
Here's the class:
public class Game {
int boardW;
int boardH;
Board board;
public Game(int bW) {
boardW = bW;
boardH = bW;
this.board = new Board(boardH, boardW);
}
private byte updateCell(int x, int y) {
byte neighbors = 0;
// Loop through 8 neighbors and count them
for (byte offset_y = -1; offset_y < 2; offset_y++) {
for (byte offset_x = -1; offset_x < 2; offset_x++) {
// Make sure we don't check our current cell
if (offset_x != 0 || offset_y != 0) {
byte newY = (byte) (y + offset_y);
byte newX = (byte) (x + offset_x);
// Roll over edge of board
if (y + offset_y < 0) {
newY = (byte) (boardH - 1);
}
else if (y + offset_y >= boardH) {
newY = 0;
}
if (x + offset_x < 0) {
newX = (byte) (boardW - 1);
}
if (x + offset_x >= boardW) {
newX = 0;
}
neighbors += this.board.getState(newX, newY);
}
}
}
if (neighbors < 2) {return 0;}
if (neighbors > 3) {return 0;}
if (neighbors == 3) {return 1;}
return this.board.getState(x, y);
}
public Board gameTick() {
Board nextTick = new Board(boardH, boardW);
// Go through next iteration of cells
for (int h = 0; h < boardH; h++) {
for (int w = 0; w < boardW; w++) {
nextTick.setState(w, h, updateCell(w, h));
}
}
return nextTick;
}
public Board getBoard() {
return this.board;
}
public void toggleCell(int x, int y, byte state) {
this.board.setState(x, y, state);
}
}
class Board {
private final byte[][] board;
final int height;
final int width;
public Board(int h, int w) {
width = w;
height = h;
board = new byte[height][width];
}
public void setState(int x, int y, byte state) {
board[y][x] = state;
}
public byte getState(int x, int y) {
return board[y][x];
}
public byte[][] getData() {
return board;
}
public void setData(byte[][] newBoard) {
for (int x = 0; x<newBoard.length; x++) {
for (int y = 0; y<newBoard.length; y++) {
setState(x, y, newBoard[y][x]);
}
}
}
}
What is going on here?
EDIT: Turns out it was another problem in the code that accessed the board, which I solved. Thanks for all your help guys.
Change the design of your code completely. Have a wrapper class Board which encapsulates (and hides) the two-dimensional array (if it must be an array at all) inside.
public class Board {
private final byte[][] board;
public Board(int height, int width) {
board = new byte[height][width];
}
public void setState(int x, int y, byte state) {
board[y][x] = state;
}
public byte getState(int x, int y) {
return board[y][x];
}
}
Then create an instance of the Board class and access the state only via that one.
Thus you will have safe access to your data and your design is open for modifications in the future. You are e.g. free to start adding useful methods such as
boolean isRowEmpty(int x)
boolean isColumnEmpty(int y)
void resetRow(int x)
void resetColumn(int y)
void reset()
All of them will be nicely called on an instance of the Board class. You will not access the array directly from your business logic code, which is a nasty practice.
I would suggest that you make two different classes one main
and other for calling the function, In this from main class
pass the value you want , and call the method you want this will
surely solve the problem.
Try this:
public class YourClassName {
byte[][] board;
// Setters
public void setCell(int x, int y, byte state) {
System.out.println(board[y][x]);
board[y][x] = state;
}
// Getters
public byte[][] getBoard() {
return board;
}
}
This appears to be a scoping issue, so the solution is to make sure that board is defined in a scope that all your methods have access to. The cleanest way to do this is to define board as a class field (i.e. it is defined outside of any method), and then every time you want to modify or access board, you use this.board.
For example,
public class Board{
private byte[][] board;
public Board(int height, int width){
this.board = new byte[height][width];
}
public byte[][] getBoard(){
return this.board;
}
public void setCell(int x, int y, byte state){
System.out.println(this.board[y][x]);
this.board[y][x] = state;
}
}

Categories