Java Reversi/Othello Program 2D array flip/get methods? - java

I'm hoping someone could help me understand my code probs. I'm trying to create a Reversi board game in Java but my game board will only stick to white pieces and refuse to do anything. Any suggestions would be great.
This is the part I have to do (hence marked TO DO). Honestly it should be 1 or 2 lines for each of them but I'm just not catching on. I'm definitely having trouble with my get() and flip() methods.
public class Simple2DArray implements Simple2DInterface
{
// TO DO: Your instance variables
private int[][] simpleArray = new int[8][8];
private int row = simpleArray.length;
private int column = simpleArray[0].length;
private int none = -1, white = 1, black = 0, value;
/**
* Constructor: Once a two dimensional array is constructed
* set all elements in the array to -1.
* #param aRow the number of rows of this Simple2DArray.
* #param aColumn the number of columns of this Simple2DArray.
*/
public Simple2DArray(int aRow, int aColumn)
{
// TO DO: Constructor
this.row = aRow;
this.column = aColumn;
for (int i = 1; i < simpleArray.length; i++)
{
for (int j = 1; j < simpleArray[i].length; j++)
{
simpleArray[i][j] = none;
}
}
}
/**
* Gets the number of rows of this Simple 2D Array.
* #return the number of rows of this Simple 2D array.
*/
public int getNumberOfRows()
{
// TO DO
return simpleArray.length;
}
/**
* Gets the number of columns of this Simple 2D Array.
* #return the number of columns of this Simple 2D array.
*/
public int getNumberOfColumns()
{
// TO DO
return simpleArray[1].length;
}
/**
* Reset every element to -1
*/
public void clear()
{
// TO DO
for (int i = 1; i < simpleArray.length; i++)
{
for (int j = 1; j < simpleArray[i].length; j++)
{
simpleArray[i][j] = none;
}
}
}
/**
* Sets the value at location row and column to 1.
* #param row the row number (start at 1).
* #param column the column number (start at 1).
*/
public void setToOne(int row, int column)
{
// TO DO
for (int i = 1; i < simpleArray.length; i++)
{
for (int j = 1; j < simpleArray[i].length; j++)
{
simpleArray[i][j] = white;
}
}
}
/**
* Sets the value at location row and column to 0.
* #param row the row number (start at 1).
* #param column the column number (start at 1).
*/
public void setToZero(int row, int column)
{
// TO DO
for (int i = 1; i < simpleArray.length; i++)
{
for (int j = 1; j < simpleArray[i].length; j++)
{
simpleArray[i][j] = black;
}
}
}
/**
* Reverse the value at row and column. If the value
* at row and column is 1, reverse it to 0. If the value
* at row and column is 0, reverse it to 1. If the value
* at row and column is -1, do nothing.
* #param row the row number (start at 1).
* #param column the column number (start at 1).
*/
public void flip(int row, int column)
{
// TO DO
value = simpleArray[row][column];
if (value == white)
{
value = black;
}
if(value == black)
{
value = white;
}
}
/**
* Gets the value at row and column.
* #param row the row number (start at 1).
* #param column the column number (start at 1).
* #return the value at row and column.
*/
public int get(int row, int column)
{
// TO DO
for (int i = 1; i < simpleArray.length; i++)
{
for (int j = 1; j < simpleArray[i].length; j++)
{
row = i;
column = j;
value = simpleArray[row][column];
}
}
return value;
}
}
And the rest of my files/interfaces/etc.:
public interface Simple2DInterface
{
/**
* Gets the number of rows of this Simple 2D Array.
* #return the number of rows of this Simple 2D array.
*/
public int getNumberOfRows();
/**
* Gets the number of columns of this Simple 2D Array.
* #return the number of columns of this Simple 2D array.
*/
public int getNumberOfColumns();
/**
* Reset every element to -1
*/
public void clear();
/**
* Sets the value at location row and column to 1.
* #param row the row number (start at 1).
* #param column the column number (start at 1).
*/
public void setToOne(int row, int column);
/**
* Sets the value at location row and column to 0.
* #param row the row number (start at 1).
* #param column the column number (start at 1).
*/
public void setToZero(int row, int column);
/**
* Reverse the value at row and column. If the value
* at row and column is 1, reverse it to 0. If the value
* at row and column is 0, reverse it to 1. If the value
* at row and column is -1, do nothing.
* #param row the row number (start at 1).
* #param column the column number (start at 1).
*/
public void flip(int row, int column);
/**
* Gets the value at row and column.
* #param row the row number (start at 1).
* #param column the column number (start at 1).
* #return the value at row and column.
*/
public int get(int row, int column);
}
public class Simple2DArrayTester
{
public static void main(String[] args)
{
int point = 0;
int numRows = 10;
int numColumns = 15;
boolean notEqualMinusOne = false;
Simple2DInterface s2d1 = new Simple2DArray(numRows,numColumns);
// Check that all locations are -1.
System.out.print("Testing that all locations must be -1: ");
for(int i = 1; i <= numRows; i++)
{
for(int j = 1; j <= numColumns; j++)
{
if(s2d1.get(i, j) != -1)
{
notEqualMinusOne = true;
}
}
}
if(notEqualMinusOne)
{
System.out.println("FAIL");
System.out.println("Not all locations contain -1.\n");
}
else
{
System.out.println("PASS");
point++;
}
System.out.println("Your current point is " + point + ".\n");
// Testing the method getNumberOfRows()
System.out.print("Testing the method getNumberOfRows: ");
if(s2d1.getNumberOfRows() != numRows)
{
System.out.println("FAIL");
System.out.println("The number of from your method getNumberOfRows should be " + numRows + ".");
System.out.println("But your method getNumberOfRows returns " + s2d1.getNumberOfRows() + ".\n");
}
else
{
System.out.println("PASS");
point++;
}
System.out.println("Your current point is " + point + ".\n");
// Testing the method getNumberOfColumns()
System.out.print("Testing the method getNumberOfColumns: ");
if(s2d1.getNumberOfColumns() != numColumns)
{
System.out.println("FAIL");
System.out.println("The number of from your method getNumberOfColumns should be " + numColumns + ".");
System.out.println("But your method getNumberOfColumns returns " + s2d1.getNumberOfColumns() + ".\n");
}
else
{
System.out.println("PASS");
point++;
}
System.out.println("Your current point is " + point + ".\n");
// Testing the method setToOne()
System.out.print("Testing the method setToOne(): ");
s2d1.setToOne(5, 9);
if(s2d1.get(5, 9) != 1)
{
System.out.println("FAIL");
System.out.println("After calling the method setToOne(5,9) the value at row 5 column 9 should be 1.");
System.out.println("But your method get(5,9) returns " + s2d1.get(5,9) + ".\n");
}
else
{
System.out.println("PASS");
point++;
}
System.out.println("Your current point is " + point + ".\n");
// setToZero()
System.out.print("Testing the method setToZero(): ");
s2d1.setToZero(9, 5);
if(s2d1.get(9, 5) != 0)
{
System.out.println("FAIL");
System.out.println("After calling the method setToZero(9,5) the value at row 9 column 5 should be 0.");
System.out.println("But your method get(9,5) returns " + s2d1.get(9,5) + ".\n");
}
else
{
System.out.println("PASS");
point++;
}
System.out.println("Your current point is " + point + ".\n");
// flip()
System.out.print("Testing flip from one to zero: ");
s2d1.flip(5, 9);
if(s2d1.get(5, 9) != 0)
{
System.out.println("FAIL");
System.out.println("After flipping by calling flip(5,9) the value at row 5 column 9 should be 0.");
System.out.println("But your method get(5,9) returns " + s2d1.get(5,9) + "\n.");
}
else
{
System.out.println("PASS");
point++;
}
System.out.println("Your current point is " + point + ".\n");
System.out.print("Testing flip from zero to one: ");
s2d1.flip(9, 5);
if(s2d1.get(9, 5) != 1)
{
System.out.println("FAIL");
System.out.println("After flipping by calling flip(9,5) the value at row 9 column 5 should be 1.");
System.out.println("But your method get(9,5) returns " + s2d1.get(9,5) + "\n.");
}
else
{
System.out.println("PASS");
point++;
}
System.out.println("Your current point is " + point + ".\n");
System.out.print("Testing flip -1: ");
s2d1.flip(1, 1);
if(s2d1.get(1, 1) != -1)
{
System.out.println("FAIL");
System.out.println("After flipping by calling flip(1,1), the value at row 1 column 1 should be -1.");
System.out.println("But your method get(1,1) returns " + s2d1.get(1,1) + ".\n");
}
else
{
System.out.println("PASS");
point++;
}
System.out.println("Your current point is " + point + ".\n");
// clear()
System.out.print("Testing the method clear(): ");
s2d1.clear();
notEqualMinusOne = false;
for(int i = 1; i <= numRows; i++)
{
for(int j = 1; j <= numColumns; j++)
{
if(s2d1.get(i, j) != -1)
{
notEqualMinusOne = true;
}
}
}
if(notEqualMinusOne)
{
System.out.println("FAIL");
System.out.println("After calling the method clear. Not all locations contain -1.\n");
}
else
{
System.out.println("PASS");
point++;
}
System.out.println("Your current point is " + point + ".\n");
if(point == 9)
{
System.out.println("Everything looks good one extra point :)");
point++;
}
System.out.println("Your final point is " + point + ".");
if(point == 10)
{
System.out.println("Contratulation! Your class Simple2DArray works perfectly (I guess).");
System.out.println("You can run OthelloFrame to see how Simple2DArray can be used in a program.");
}
else
{
System.out.println("There is one or more errors in your class.");
System.out.println("Fix your bugs to get more points.");
}
}
}
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.TitledBorder;
#SuppressWarnings("serial")
public class OthelloFrame extends JFrame
{
private int frameWidth = 600;
private int frameHeight = 600;
private JLabel msg;
private JButton switchPlayer;
private JPanel msgPanel;
private JPanel controlPanel;
private Simple2DInterface sa;
private OthelloComponent oc;
private boolean isWhite = false;
public static void main(String[] args)
{
JFrame frame = new OthelloFrame();
frame.setVisible(true);
}
public OthelloFrame()
{
sa = new Simple2DArray(8,8);
sa.setToOne(4, 4);
sa.setToZero(4, 5);
sa.setToZero(5, 4);
sa.setToOne(5, 5);
msg = new JLabel("Click on an empty space to put a disk or click on a disk to change color.");
oc = new OthelloComponent(sa);
controlPanel = new JPanel();
controlPanel.setLayout(new GridLayout(2,1));
switchPlayer = new JButton("Switch Color to White");
class SwitchButtonListener implements ActionListener
{
public void actionPerformed(ActionEvent arg0)
{
oc.switchColor();
isWhite = !isWhite;
if(isWhite)
{
switchPlayer.setText("Switch Color to Black");
}
else
{
switchPlayer.setText("Switch Color to White");
}
}
}
ActionListener sp = new SwitchButtonListener();
switchPlayer.addActionListener(sp);
controlPanel.add(switchPlayer);
msgPanel = new JPanel();
msgPanel.setBorder(new TitledBorder("Message"));
msgPanel.add(msg);
controlPanel.add(msgPanel);
setSize(frameWidth, frameHeight);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("Wanna be Othello");
add(oc);
add(controlPanel, BorderLayout.SOUTH);
setVisible(true);
}
}
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import javax.swing.JComponent;
#SuppressWarnings("serial")
public class OthelloComponent extends JComponent implements MouseListener
{
private Simple2DInterface grid;
private int numRows;
private int numColumns;
private int leftMargin = 10;
private int rightMargin = 10;
private int topMargin = 10;
private int bottomMargin = 10;
private int circleMargin = 5;
private double circleSize;
private int width;
private int height;
private int topLeftX;
private int topLeftY;
private int bottomRightX;
private int bottomRightY;
private double cellWidth;
private double cellHeight;
private double boardWidth;
private double boardHeight;
private boolean isWhite;
public OthelloComponent(Simple2DInterface a2DArray)
{
grid = a2DArray;
numRows = grid.getNumberOfRows();
numColumns = grid.getNumberOfColumns();
isWhite = false;
this.addMouseListener(this);
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
width = this.getWidth();
height = this.getHeight();
cellWidth = (double) (width - (leftMargin + rightMargin)) / numColumns;
cellHeight = (double) (height - (topMargin + bottomMargin)) / numRows;
if(cellWidth > cellHeight)
{
cellWidth = cellHeight;
}
else
{
cellHeight = cellWidth;
}
circleSize = cellWidth - (2 * circleMargin);
boardWidth = cellWidth * numColumns;
boardHeight = cellHeight * numRows;
topLeftX = (width - (int) boardWidth) / 2;
topLeftY = (height - (int) boardHeight) / 2;
bottomRightX = topLeftX + (int) boardWidth;
bottomRightY = topLeftY + (int) boardHeight;
Line2D.Double line = new Line2D.Double(0,0,0,0);
// Draw the Board
g2.setColor(Color.BLACK);
for(int i = 0; i <= numRows; i++)
{
line.setLine(topLeftX, topLeftY + (i * cellHeight), bottomRightX, topLeftY + (i * cellHeight));
g2.draw(line);
}
for(int i = 0; i <= numColumns; i++)
{
line.setLine(topLeftX + (i * cellWidth), topLeftY, topLeftX + (i * cellWidth), bottomRightY);
g2.draw(line);
}
// Draw circles
Ellipse2D.Double circle = new Ellipse2D.Double();
for(int row = 1; row <= numRows; row++)
{
for(int column = 1; column <= numColumns; column++)
{
if(grid.get(row, column) == 0)
{
g2.setColor(Color.BLACK);
int x = topLeftX + circleMargin + (int) ((column - 1) * cellWidth);
int y = topLeftY + circleMargin + (int) ((row - 1) * cellHeight);
circle.setFrame(x,y,circleSize,circleSize);
g2.fill(circle);
}
else if(grid.get(row, column) == 1)
{
int x = topLeftX + circleMargin + (int) ((column - 1) * cellWidth);
int y = topLeftY + circleMargin + (int) ((row - 1) * cellHeight);
circle.setFrame(x,y,circleSize,circleSize);
g2.setColor(Color.WHITE);
g2.fill(circle);
g2.setColor(Color.BLACK);
g2.draw(circle);
}
}
}
}
public void mouseClicked(MouseEvent arg0)
{
int column = getColumn(arg0.getX());
int row = getRow(arg0.getY());
if(row != 0 && column != 0)
{
if(grid.get(row, column) == -1)
{
if(isWhite)
{
grid.setToOne(row, column);
}
else
{
grid.setToZero(row, column);
}
}
else
{
if(isWhite && grid.get(row, column) == 0)
{
grid.flip(row, column);
}
else if(!isWhite && grid.get(row, column) == 1)
{
grid.flip(row, column);
}
}
}
repaint();
}
public void switchColor()
{
isWhite = !isWhite;
}
public int getColumn(int x)
{
int result = 0;
for(int column = 1; column <= numColumns; column++)
{
if(x > topLeftX + ((column - 1) * cellWidth) && x < topLeftX + (column * cellWidth))
{
result = column;
break;
}
}
return result;
}
public int getRow(int y)
{
int result = 0;
for(int row = 1; row <= numRows; row++)
{
if(y > topLeftY + ((row - 1) * cellHeight) && y < topLeftY + (row * cellHeight))
{
result = row;
break;
}
}
return result;
}
public void mouseEntered(MouseEvent arg0)
{
}
public void mouseExited(MouseEvent arg0)
{
}
public void mousePressed(MouseEvent arg0)
{
}
public void mouseReleased(MouseEvent arg0)
{
}
}

Looking through the code there were a lot of things that I would change unrelated to the question so I just refactored your classes:
OthelloFrame.java:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.TitledBorder;
#SuppressWarnings("serial")
public class OthelloFrame extends JFrame {
private static final int FRAME_WIDTH = 600;
private static final int FRAME_HEIGHT = FRAME_WIDTH;
private OthelloComponent gridComponent;
private JButton switchPlayerButton;
public OthelloFrame() {
// create grid and add to frame
Simple2DInterface grid =
new Simple2DArray(Simple2DArray.DEFAULT_BOARD_DIMENSION, Simple2DArray.DEFAULT_BOARD_DIMENSION);
int halfWidth = grid.getNumberOfColumns() / 2;
int halfHeight = grid.getNumberOfRows() / 2;
grid.set(halfHeight - 1, halfWidth - 1, Simple2DArray.WHITE);
grid.set(halfHeight - 1, halfWidth, Simple2DArray.BLACK);
grid.set(halfHeight, halfWidth - 1, Simple2DArray.BLACK);
grid.set(halfHeight, halfWidth, Simple2DArray.WHITE);
gridComponent = new OthelloComponent(grid);
add(gridComponent);
// create control panel
JPanel controlPanel = new JPanel();
controlPanel.setLayout(new GridLayout(2,1));
// create and add switch player button to control panel
switchPlayerButton = new JButton("Switch Color to White");
ActionListener sp = new SwitchButtonListener();
switchPlayerButton.addActionListener(sp);
controlPanel.add(switchPlayerButton);
// create and add instructions to control panel
JPanel msgPanel = new JPanel();
msgPanel.setBorder(new TitledBorder("Message"));
msgPanel.add(new JLabel("Click on an empty space to put a disk or click on a disk to change color."));
controlPanel.add(msgPanel);
// add control panel to frame
add(controlPanel, BorderLayout.SOUTH);
// final setup
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(FRAME_WIDTH, FRAME_HEIGHT);
setTitle("Wanna be Othello");
setVisible(true);
}
public static void main(String[] args) {
JFrame frame = new OthelloFrame();
frame.setVisible(true);
}
private class SwitchButtonListener implements ActionListener {
public void actionPerformed(ActionEvent arg0) {
gridComponent.switchColor();
switchPlayerButton.setText("Switch Color to " + (gridComponent.whiteToPlay() ? "Black" : "White"));
}
}
}
OthelloComponent.java:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import javax.swing.JComponent;
#SuppressWarnings("serial")
public class OthelloComponent extends JComponent implements MouseListener {
private static final int MARGIN = 10;
private static final int CIRCLE_MARGIN = MARGIN / 2;
private static final int BOTTOM_MARGIN = MARGIN;
private static final int TOP_MARGIN = MARGIN;
private static final int LEFT_MARGIN = MARGIN;
private static final int RIGHT_MARGIN = MARGIN;
private Simple2DInterface grid;
private int numRows;
private int numColumns;
private double circleDiameter;
private double topLeftX;
private double topLeftY;
private double cellHeight;
private double cellWidth;
private double boardHeight;
private double boardWidth;
private int turn;
public OthelloComponent(Simple2DInterface a2DArray) {
grid = a2DArray;
numRows = grid.getNumberOfRows();
numColumns = grid.getNumberOfColumns();
turn = Simple2DArray.BLACK;
this.addMouseListener(this);
}
public int getColumn(int x) {
return (int) (Math.ceil((x - topLeftX) / cellWidth) - 1);
}
public int getRow(int y) {
return (int) (Math.ceil((y - topLeftY) / cellHeight) - 1);
}
public void mouseClicked(MouseEvent arg0) {
int column = getColumn(arg0.getX());
int row = getRow(arg0.getY());
// you can take this out if you want
System.out.println("r: " + row + ", c: " + column);
if (row >= 0 && column >= 0 && row < numRows && column < numColumns) {
grid.set(row, column, turn);
}
repaint();
}
public void mouseEntered(MouseEvent arg0) {}
public void mouseExited(MouseEvent arg0) {}
public void mousePressed(MouseEvent arg0) {}
public void mouseReleased(MouseEvent arg0) {}
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
cellHeight = ((double) getHeight() - (TOP_MARGIN + BOTTOM_MARGIN)) / numRows;
cellWidth = ((double) getWidth() - (LEFT_MARGIN + RIGHT_MARGIN)) / numColumns;
// make cells the largest possible squares
if (cellWidth > cellHeight) {
cellWidth = cellHeight;
} else {
cellHeight = cellWidth;
}
circleDiameter = cellWidth - (2 * CIRCLE_MARGIN);
boardHeight = cellHeight * numRows;
boardWidth = cellWidth * numColumns;
topLeftX = (getWidth() - boardWidth) / 2;
topLeftY = (getHeight() - boardHeight) / 2;
double bottomRightX = topLeftX + boardWidth;
double bottomRightY = topLeftY + boardHeight;
Line2D.Double line = new Line2D.Double(0,0,0,0);
// draw the lines on the board
g2.setColor(Color.BLACK);
for (int i = 0; i <= numRows; i++) {
line.setLine(topLeftX, topLeftY + i * cellHeight, bottomRightX, topLeftY + i * cellHeight);
g2.draw(line);
}
for (int i = 0; i <= numColumns; i++) {
line.setLine(topLeftX + i * cellWidth, topLeftY, topLeftX + i * cellWidth, bottomRightY);
g2.draw(line);
}
// draw circles
for (int row = 0; row < numRows; row++) {
for (int column = 0; column < numColumns; column++) {
if (grid.get(row, column) != Simple2DArray.NONE) {
Color fill = grid.get(row, column) == Simple2DArray.BLACK ? Color.BLACK : Color.WHITE;
drawCircle(row, column, fill, Color.BLACK, g2);
}
}
}
}
public void switchColor() {
turn = -turn;
}
public boolean whiteToPlay() {
return turn == Simple2DArray.WHITE;
}
private void drawCircle(int row, int column, Color fill, Color border, Graphics2D g2) {
Ellipse2D.Double circle = new Ellipse2D.Double();
double x = topLeftX + CIRCLE_MARGIN + column * cellWidth;
double y = topLeftY + CIRCLE_MARGIN + row * cellHeight;
circle.setFrame(x,y,circleDiameter,circleDiameter);
g2.setColor(fill);
g2.fill(circle);
g2.setColor(border);
g2.draw(circle);
}
}
Simple2DInterface.java:
public interface Simple2DInterface {
/** Reset every element to 0. */
public void clear();
/** Gets the value at row and column. */
public int get(int row, int column);
/** Gets the number of columns of this Simple2DInterface. */
public int getNumberOfColumns();
/** Gets the number of rows of this Simple2DInterface. */
public int getNumberOfRows();
/** Sets the value at location row and column to a certain color. */
public void set(int row, int column, int color);
}
Simple2DArray.java:
public class Simple2DArray implements Simple2DInterface {
public static final int DEFAULT_BOARD_DIMENSION = 8;
static final int BLACK = -1;
static final int NONE = 0;
static final int WHITE = 1;
private int[][] simpleArray;
/** Creates a blank Simple2DArray with the specified number of rows and columns. */
public Simple2DArray(int rows, int columns) {
simpleArray = new int[rows][columns];
}
/** Reset every element to 0 */
public void clear() {
simpleArray = new int[getNumberOfRows()][getNumberOfColumns()];
}
/** Gets the value at row and column. */
public int get(int row, int column) {
return simpleArray[row][column];
}
/** Gets the number of columns of this Simple 2D Array. */
public int getNumberOfColumns() {
return simpleArray.length != 0 ? simpleArray[0].length : 0;
}
/** Gets the number of rows of this Simple 2D Array. */
public int getNumberOfRows() {
return simpleArray.length;
}
/** Sets the value at location row and column to a certain color. */
public void set(int row, int column, int color) {
simpleArray[row][column] = color;
}
}
Next steps: tighten the bound checks a bit, signal the end of the game, clear button, automatically change all the opponents coins on each move, move validation.

Related

Java drawImage method

I am trying within exercise to put into ArrayList a set of Picture objects, then shuffle them randomly and display them as a grid of 3x3. However, the shuffle method does not work correctly for me. Or perhaps I am doing anything wrong within draw or drawImage methods, I don't know.
I am always getting picture displayed from 9 pieces in their original order, not randomly shuffled.
See below my PicturePiece class as well as the main class.
package lab;
import java.awt.Graphics2D;
import java.awt.Image;
import java.io.File;
import javax.imageio.ImageIO;
public class PicturePiece {
private int IMAGE_X = 266;
private int IMAGE_Y = 224;
private final int row;
private final int col;
private Image img;
private static int count = 0;
private int id = 0;
public PicturePiece(int row, int col, File f) {
try {
this.img = ImageIO.read(f);
} catch (Exception e) {
e.printStackTrace();
}
this.row = this.IMAGE_X * row;
this.col = this.IMAGE_Y * col;
PicturePiece.count++;
this.id = PicturePiece.count;
}
public void draw(Graphics2D g2) {
g2.drawImage(this.img, this.row, this.col, null);
}
public void setPosition(int row, int col) {
this.IMAGE_X = row;
this.IMAGE_Y = col;
}
public int getXposition() {
return this.IMAGE_X;
}
public int getYposition() {
return this.IMAGE_Y;
}
public int getRow() {
return this.row;
}
public int getCol() {
return this.col;
}
public String getImage() {
return this.img.toString();
}
public static int getPictureCount() {
return PicturePiece.count;
}
public int getId() {
return this.id;
}
}
And here is my main class:
/*
Find a pretty image from the Internet and use an image editor to break it down
into 9 pieces (for example, you can use the application Paint in Windows).
Display the 9 images in a 3×3 grid in a random order. Add a mouse listener.
Allow the user to swap two images by clicking on them.
The goal of the game is to re-create the original image.
Display an appropriate message when the user wins.
*/
package lab;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.util.*;
public class Puzzle {
public static void main(String[] args) throws Exception {
MyFrame frame = new MyFrame();
frame.setSize(1000, 1000);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
class MyFrame extends JFrame {
MyPanel p;
public MyFrame() {
p = new MyPanel();
add(p);
setVisible(true);
}
}
class MyPanel extends JPanel {
private ArrayList<PicturePiece> images = new ArrayList<PicturePiece>();
public MyPanel() {
this.setFocusable(true);
try {
int j = 0, k = 0, pocet = 0;
for (int i = 1; i <= 9; i++) {
//g2.drawImage(images.get(i), (IMAGE_X * (j)), (IMAGE_Y * (k)), null);
images.add(new PicturePiece(j, k, new File(("/home/ivo/Pictures/domcek/domcek" + i + ".jpg"))));
pocet++;
//System.out.println("j = " + (j - 1) + "; k = " + (k - 1) + "; i = " + i + "; pocet = " + pocet);
if ((pocet % 3) == 0) {
j = 0;
k++;
} else {
j = j + 1;
}
}
} catch (Exception e) {
}
//Random rnd = new Random();
//rnd.setSeed(400);
//Collections.shuffle(images, rnd);
Collections.shuffle(images);
}
public void draw(Graphics2D g2) {
try {
for (int i = 0; i <= images.size(); i++) {
images.get(i).draw(g2);
}
} catch (Exception my) {
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
draw(g2);
}
}
Your error arises because you are setting the row/column (j and k) in the MyPanel function.
So the shuffle only changes the order of the PicturePiece in the list, not the j/k that you use for the position.
In order to achieve the behavior you would like I would generate the row/column from the order in the list.
the problem is that you draw the image based in init coordinates, even if you suffle them, the coordinates remain the same in the PicturePiece objects.
short solution:
change in PicturePiece:
public void draw(Graphics2D g2, int i, int j) {
g2.drawImage(this.img, this.IMAGE_X *i, this.IMAGE_Y * j, null);
}
change in Puzzle:
public void draw(Graphics2D g2) {
try {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
System.out.println(i*3+j);
images.get(i*3+j).draw(g2, i ,j);
}
}
} catch (Exception my) {
}
}
this way you will get images in the same order from the array, but if they are shuffled inside the array, the image will be different at each execution.
Note: this is a hardcoded version (ok only for 3x3 matrix) but I hope you got the ideea. There are many other solutions to this but this is the shortest one I could think of.
Instead of drawing, on to the JPanel/JComponent, it would be wise to use a JLabelfor this purpose, which will make your work a bit easier, as you only have to worry about the index positions.
Here is one example:
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.util.*;
import javax.imageio.ImageIO;
import javax.swing.*;
public class TestingImages {
private static final String IMAGE_HEADER = "/images/windowicon/windowicon";
private GUIView guiView;
private void performTask () {
try {
guiView = new GUIView (IMAGE_HEADER);
} catch (Exception exp) {
exp.printStackTrace ();
}
Runnable runnable = new Runnable () {
#Override
public void run () {
guiView.displayGUI ();
}
};
EventQueue.invokeLater (runnable);
}
public static void main (String[] args) {
new TestingImages ().performTask ();
}
}
class GUIView {
private static final int ROWS = 3;
private static final int COLUMNS = 3;
private static final int GAP = 5;
private static final int TOTAL_IMAGES = 9;
private JLabel originalImageLabel;
private JLabel[] splitImageLabel;
private int counter;
private int[] imageMap;
private int previousIndex;
private int currentIndex;
private MouseAdapter labelAdapter = new MouseAdapter () {
private int counter = 0;
#Override
public void mouseClicked (MouseEvent me) {
JLabel label = (JLabel) me.getSource ();
if (counter == 0) {
/*
* On first click, we simply keeping track of on which label
* the user clicked in the first place
*/
previousIndex = findLabelIndex (label);
System.out.println("Previous Index: " + previousIndex);
counter = 1;
} else if (counter == 1) {
/*
* On second click, firstly we will get the location of the JLabel
* on which the user clicked, then we will simply swap the icon as
* well as the Name of this JLabel with the JLabel at previousIndex
*/
currentIndex = findLabelIndex (label);
System.out.println("Current Index: " + currentIndex);
ImageIcon tempIcon = (ImageIcon) splitImageLabel[previousIndex].getIcon ();
splitImageLabel[previousIndex].setIcon (splitImageLabel[currentIndex].getIcon ());
splitImageLabel[currentIndex].setIcon (tempIcon);
String labelName = splitImageLabel[previousIndex].getName ();
splitImageLabel[previousIndex].setName (splitImageLabel[currentIndex].getName ());
splitImageLabel[currentIndex].setName (labelName);
prepareModel ();
counter = 0;
}
if (hasWon()) {
System.out.println("CONGRATULATIONS you won :-)");
}
}
};
public GUIView (String imageHeader) throws IOException {
imageMap = new int[TOTAL_IMAGES];
counter = 0;
originalImageLabel = new JLabel ();
originalImageLabel.setIcon (new ImageIcon (
ImageIO.read (GUIView.class.getResource (
imageHeader + ".jpg"))));
splitImageLabel = new JLabel[TOTAL_IMAGES];
for (int i = 0; i < ROWS; ++i) {
for (int j = 0; j < COLUMNS; ++j) {
splitImageLabel[counter] = new JLabel ();
String indexValue = "" + counter;
/*
* Since JLabel[] is a 1-D Array, hence we simply giving
* each JLabel, at each index a name, as 0 1 2 3 and so on
*/
splitImageLabel[counter].setName (indexValue);
splitImageLabel[counter].setIcon (new ImageIcon (ImageIO.read (
GUIView.class.getResource (imageHeader + i + "-" + j + ".png"))));
splitImageLabel[counter].addMouseListener (labelAdapter);
++counter;
}
}
}
public void displayGUI () {
JFrame frame = new JFrame("Testing Images");
frame.setDefaultCloseOperation (JFrame.DISPOSE_ON_CLOSE);
JPanel contentPane = new JPanel ();
contentPane.setBorder (BorderFactory.createEmptyBorder (GAP, GAP, GAP, GAP));
contentPane.setLayout (new GridLayout (2, 1, GAP, GAP));
JPanel headerPanel = new JPanel ();
headerPanel.setBorder (BorderFactory.createEmptyBorder (GAP, GAP, GAP, GAP));
headerPanel.add (originalImageLabel);
contentPane.add (headerPanel);
JPanel footerPanel = new JPanel ();
footerPanel.setBorder (BorderFactory.createEmptyBorder (GAP, GAP, GAP, GAP));
footerPanel.setLayout (new GridLayout (ROWS, COLUMNS, GAP, GAP));
/*
* This will Shuffle the JLable[] array
*/
Collections.shuffle (Arrays.asList (splitImageLabel));
prepareModel ();
for (int i = 0; i < TOTAL_IMAGES; ++i) {
footerPanel.add (splitImageLabel[i]);
}
contentPane.add (footerPanel);
frame.setContentPane (contentPane);
frame.pack ();
frame.setLocationByPlatform (true);
frame.setVisible (true);
}
private int findLabelIndex (JLabel label) {
int index = 0;
for (int i = 0; i < TOTAL_IMAGES; ++i) {
if (label.getName ().equals(splitImageLabel[i].getName ())) {
index = i;
break;
}
}
return index;
}
/*
* hasWon() is used to simply check, if the array has values
* 0 1 2 3 4 till TOTAL_IMAGES, i.e. in increasing order, then it
* means, that the image has been rightly placed, by the user.
* Hence, the GAME is OVER
*/
private boolean hasWon () {
boolean flag = true;
for (int i = 0; i < TOTAL_IMAGES; ++i) {
if (imageMap[i] != i) {
flag = false;
}
}
return flag;
}
/*
* PrepareModel() is used to assign values to imageMap[] array,
* in the same sequence, in which the JLabel is placed inside
* JLabel[] array. Say JLabel[] array has JLabels with names in
* this order 1 5 4 3 and so on, thus imageMap[] will contain
* values 1 5 4 3 and so on, once they are in sorted order, then
* we can easily check for winning condition
*/
private void prepareModel () {
System.out.println("Preparing MODEL");
for (int i = 0; i < TOTAL_IMAGES; ++i) {
imageMap[i] = getIntValue(splitImageLabel[i].getName ());
System.out.println("i: " + i + " Name: " + splitImageLabel[i].getName ());
}
System.out.println("Exiting MODEL");
}
private int getIntValue (String text) {
int value = 0;
try {
value = Integer.parseInt (text);
} catch (Exception exp) {
exp.printStackTrace ();
}
return value;
}
}
OUTPUT:
IMAGES USED:
ORIGINAL IMAGE: http://i.imgur.com/GNIZRQy.jpg
To SPLIT, I used this site: http://imagesplitter.net/
let me first thank you for your time and effort.
I wrote my application/lab this way:
package lab;
import java.awt.Graphics2D;
import java.awt.Image;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class PicturePiece extends JPanel {
private Image img;
private int id = 0;
public PicturePiece(int id) {
this.id = id;
}
public void setImage(File f) {
try {
this.img = ImageIO.read(f);
} catch (Exception e) {
}
}
public String getImage() {
return this.img.toString();
}
public int getId() {
return this.id;
}
public void draw(Graphics2D g2, int row, int col) {
g2.drawImage(this.img, row, col, null);
}
}
/**
* Find a pretty image from the Internet and use an image editor to break it
* down into 9 pieces (for example, you can use the application Paint in
* Windows). Display the 9 images in a 3×3 grid in a random order. Add a mouse
* listener. Allow the user to swap two images by clicking on them. The goal of
* the game is to re-create the original image. Display an appropriate message
* when the user wins.
*/
package lab;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Rectangle2D;
import java.io.File;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.util.*;
public class Puzzle {
public static void main(String[] args) throws Exception {
MyFrame frame = new MyFrame();
frame.setSize((266 * 3) + 10, (224 * 3) + 10);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
class MyFrame extends JFrame {
MyPanel p;
public MyFrame() {
p = new MyPanel();
add(p);
setVisible(true);
}
}
class MyPanel extends JPanel implements MouseListener {
public static final int IMAGE_X = 266;
public static final int IMAGE_Y = 224;
public static final int PAD = 5;
private int counter = 0;
private int previouspicture = -1;
private int currentpicture = -1;
private boolean won = false;
private ArrayList<PicturePiece> images = new ArrayList<PicturePiece>();
public MyPanel() {
this.setFocusable(true);
for (int i = 0; i < 9; i++) {
images.add(new PicturePiece(i));
}
Random rnd = new Random();
rnd.setSeed(40000);
Collections.shuffle(images, rnd);
try {
for (int i = 0; i < images.size(); i++) {
images.get(i).setImage(new File(("src/chapter/domcek/domcek" + (images.get(i).getId() + 1) + ".jpg")));
}
} catch (Exception e) {
}
addMouseListener(this);
}
public void draw(Graphics2D g2) {
int j = 0, k = 0, pocet = 0;
for (int i = 0; i < 9; i++) {
images.get(i).draw(g2, j * (IMAGE_X + PAD), k * (IMAGE_Y + PAD));
pocet++;
if ((pocet % 3) == 0) {
j = 0;
k++;
} else {
j = j + 1;
}
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
validate();
draw(g2);
if (won == true) {
showMessage("You won!!!", g2);
}
}
/**
* checks whether user clicked on two different pictures and if yes, changes
* their order
*
* #param e - event object
*/
#Override
public void mouseClicked(MouseEvent e) {
int picturepiece_id;
if (counter == 0) {
previouspicture = getPicturePiece(e.getX(), e.getY());
counter = 1;
} else if (counter == 1) {
counter = 0;
currentpicture = getPicturePiece(e.getX(), e.getY());
if ((previouspicture != currentpicture) && (previouspicture != -1) && (currentpicture != -1)) {
swap(previouspicture, currentpicture);
repaint();
int j = 0;
int i = 0;
i = 0;
while ((j == i) && (i < images.size()) && (j < images.size())) {
i++;
j = images.get(i).getId();
if ((j == 8) && (i == 8)) {
won = true;
removeMouseListener(this);
repaint();
break;
}
}
}
}
}
/**
* prints message on winning
*
* #param s - message to print
* #param g2 - graphical context
*/
public void showMessage(String s, Graphics2D g2) {
Font myFont = new Font(" SansSerif ", Font.BOLD, 100);
g2.setFont(myFont);
g2.setColor(Color.BLUE);
Rectangle2D textBox = myFont.getStringBounds(s, g2.getFontRenderContext());
g2.drawString(s, (int) (getWidth() / 2 - textBox.getWidth() / 2), (int) (getHeight() / 2 - textBox.getHeight()));
}
/**
* returns order number of picture within 3x3 grid where user clicked
*
* #param x - X coordinate
* #param y - Y coordinate
* #return
*/
private int getPicturePiece(int x, int y) {
if ((x <= IMAGE_X) && (y <= IMAGE_Y)) {
return 0;
} else if (((x > IMAGE_X) && (x <= IMAGE_X * 2)) && (y <= IMAGE_Y)) {
return 1;
} else if (((x > IMAGE_X) && (x <= IMAGE_X * 3)) && (y <= IMAGE_Y)) {
return 2;
} else if ((x <= IMAGE_X) && ((y > IMAGE_Y) && (y <= (IMAGE_Y * 2)))) {
return 3;
} else if (((x > IMAGE_X) && (x <= (IMAGE_X * 2))) && ((y > IMAGE_Y) && (y <= (IMAGE_Y * 2)))) {
return 4;
} else if (((x > IMAGE_X) && (x <= (IMAGE_X * 3))) && ((y > IMAGE_Y) && (y <= (IMAGE_Y * 2)))) {
return 5;
} else if ((x <= IMAGE_X) && ((y > IMAGE_Y) && (y <= (IMAGE_Y * 3)))) {
return 6;
} else if (((x > IMAGE_X) && (x <= (IMAGE_X * 2))) && ((y > IMAGE_Y) && (y <= (IMAGE_Y * 3)))) {
return 7;
} else if (((x > IMAGE_X) && (x <= (IMAGE_X * 3))) && ((y > IMAGE_Y) && (y <= (IMAGE_Y * 3)))) {
return 8;
} else {
return -1;
}
}
/**
* swaps two clicked different pictures
*
* #param previouspic - first picture
* #param currentpic - second picture
*/
public void swap(int previouspic, int currentpic) {
int temp = 0;
int a = previouspic;
int b = currentpic;
PicturePiece p = images.get(a);
PicturePiece p2 = images.get(b);
images.set(a, p2);
images.set(b, p);
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}

Clickable Checkerboard applet

currently trying to correct some errors (maybe due to my misunderstanding of some concepts) for a clickable checkerboard applet.
using an array to indicate whether a square of the checkerboard was selected (1 = selected, 0 = not selected) with mouse click listener
add a white border to the square if mouse clicked (selected), without border if clicked again, or stay with a border if I click another square
attention was given to exclude coordinate (0, 0), as I don't want any square to be selected at the beginning, which was the case if I include (0, 0)
Errors:
- the array values changed but the repaint does not behaved as intended, border/ without border
- if I select a square next to another selected square, the selection of the other square disappears
Advices on how I can move forward with this would be much appreciated.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class ClickableCheckerboard extends Checkerboard implements MouseListener {
#Override
public void init() {
initSelectionRecord();
addMouseListener(this);
}
private static int
selectedRow, selectedCol, // row and col of checkerboard
x, y; // coordinates of a mouse click
// Selection state of each square of the Checkerboard board.
private static int selectionRecord[][]; // 8 x 8 array (0 to 7, row x col), 0 = not selected, 1 = selected
// Initialise selection state of each square of the Checkerboard board.
public void initSelectionRecord() {
int row, col;
selectionRecord = new int[8][8]; // Allocate memory for the array, otherwise end up with NullPointerException
for (row = 0; row < 8; row++) {
for (col = 0; col < 8; col++) {
selectionRecord[row][col] = 0;
}
}
}
#Override
public void mouseClicked(MouseEvent e) {
x = e.getX();
y = e.getY();
selectedRow = getRow(y);
selectedCol = getCol(x);
if (selectedRow != -1 && selectedCol != -1) {
repaint(selectedCol * 20, selectedRow * 20, 19, 19);
repaint(0, 161, 300, 300);
}
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
/**
* Returns the column of the checkerboard for an integer x coordinate.
*
* #param x
* #return col if inside checkerboard, or -1 if outside checkerboard
*/
public int getCol(int x) {
int col = -1;
if (x <= 160 && x != 0) {
col = (int) (x / 20);
}
return col;
}
/**
* Returns the row of the checkerboard for an integer y coordinate.
*
* #param y
* #return row if inside checkerboard, or -1 if outside checkerboard
*/
public int getRow(int y) {
int row = -1;
if (y <= 160 && y != 0) {
row = (int) (y / 20);
}
return row;
}
/**
* Returns the selection state of a square of the checkerboard
*
* #param row
* #param col
* #return i - 1 if selected, 0 if unselected, -1 if not applicable
*/
public static int getSelectionRecord(int row, int col) {
int i = -1;
if (row < 8 && col < 8){
i = selectionRecord[row][col];
}
return i;
}
/**
* Select a square by adding a white border to it, or unselect it by clearing the border
*
* #param row
* #param col
* #param g
*/
public void toggleSelection(int row, int col, Graphics g) {
int evenRow, evenCol, width, height;
evenRow = row % 2;
evenCol = col % 2;
width = 19;
height = 19;
if (getSelectionRecord(row, col) == 0) {
selectionRecord[row][col] = 1;
g.setColor(Color.white);
g.drawRect(col * 20 , row * 20 , width, height);
} else if (getSelectionRecord(row, col) == 1) {
selectionRecord[row][col] = 0;
if (evenRow == 0 && evenCol == 0) {
g.setColor(Color.red);
g.fillRect(col * 20, row * 20, width, height);
} else if (evenRow != 0 && evenCol != 0) {
g.setColor(Color.red);
g.fillRect(col * 20, row * 20, width, height);
} else if (evenRow == 0 && evenCol != 0) {
g.setColor(Color.black);
g.fillRect(col * 20, row * 20, width, height);
} else if (evenRow != 0 && evenCol == 0) {
g.setColor(Color.black);
g.fillRect(col * 20, row * 20, width, height);
}
} else if (getSelectionRecord(row, col) == -1) {
}
}
public void paint(Graphics g) {
super.paint(g);
g.drawString("x is " + x + ". y is " + y + ".", 2, 180);
if (x != 0 && y != 0 && x <=160 && y <= 160) {
if (selectedRow != -1 && selectedCol != -1) {
toggleSelection(selectedRow, selectedCol, g);
}
}
g.drawString("Selection state of toggled square is " + getSelectionRecord(selectedRow, selectedCol), 2, 200);
int i, j;
for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) {
g.drawString(getSelectionRecord(i, j) + " ", (2 + j * 20), (220 + i * 20));
}
}
}
}

twosorts is only giving me an issue

it keeps making the selection sort off by at least 1,
it sorts the insertion sort fine,
but it seems like the selection sort needs more time,
i cant figure it out...
its not doing a proper sort of the selection sort method.i think that my error is either in the reorderselection method.
import java.awt.*;
import java.applet.*;
import java.awt.event.*;
import java.util.Random;
public class TwoSorts extends Applet {
private final int APPLET_WIDTH = 800, APPLET_HEIGHT = 600; // to make the applet size
private final int colNum = 15; // how many columns
int[] insertion = new int[colNum]; //insertion array for column heights
int[] selection = new int[colNum]; // selection array for column heights
public Random generator; // random numbers class
public int randomNum; // random number
public Button butn1 = new Button("Sort Arrays"); // buttons
public int selectionCount = 0; // how many times press the sort button
boolean selectionFlag, insertionFlag; // to stop looping when done
//**********************************************************************
//* initiates everything
//**********************************************************************
public void init()
{
setBackground (Color.black);
setSize(APPLET_WIDTH, APPLET_HEIGHT);
generator = new Random();
for (int column = 0; column < colNum; column++) // Creates the two arrays
{
randomNum = generator.nextInt(100) + 15;
insertion[column] = randomNum;
selection[column] = randomNum;
}
butn1.addActionListener(new Butn1Handler());
butn1.setBackground(Color.blue);
add(butn1);
}
//*************************************************************************
// Draws the columns
//************************************************************************
public void paint(Graphics g)
{
g.setColor(Color.white); // debugging code
g.drawString ("Count: " + selectionCount, 100, 495);
g.drawString("Selection Sort", 25, 220);
g.drawString("Insertion Sort", 25, 420);
int xs = 50, ys = 100, width = 40, heights = 0; // for the loops
int xi = 50, yi = 300, heighti = 0;
if ( insertionFlag == false && selectionFlag == false)
{
for (int count = 0; count < colNum + 1; count++ )
{
g.setColor(Color.green);
heights = selection[count];
heighti = insertion[count];
g.fillRect(xs, ys, width, heights);
g.fillRect(xi, yi, width, heighti);
xs = xs + width + 2;
xi = xi + width + 2;
}
}
else
{
g.setColor(Color.white);
g.drawString ("Sort is Done!", 5, 495);
for (int count = 0; count < colNum + 1; count++ )
{
g.setColor(Color.gray);
heights = selection[count];
heighti = insertion[count];
g.fillRect(xs, ys, width, heights);
g.fillRect(xi, yi, width, heighti);
xs = xs + width + 2;
xi = xi + width + 2;
}
}
}
//*****************************************************************************
//* Method to sort the array by Selection method
//******************************************************************************
public void reorderSelection()
{
int min = selectionCount;
int temp = 0;
for (int scan = (selectionCount); scan < selection.length; scan++)
{
if (selection[scan] < selection[min])
min = scan;
temp = selection[min];
selection[min] = selection[selectionCount];
selection[selectionCount] = temp;
}
}
//*****************************************************************************
//* Method to sort the arrary by Insertion method
//******************************************************************************
public void reorderInsertion()
{
int key = insertion[selectionCount];
int position = selectionCount;
while (position > 0 && key < (insertion[position-1]))
{
insertion[position] = insertion[position-1];
position--;
}
insertion[position] = key;
}
//-----------------------------------------------------
// Button 1 Listener and instructions
//-----------------------------------------------------
public class Butn1Handler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
reorderSelection();
reorderInsertion();
repaint();
selectionCount++;
if (selectionCount > 14)
selectionFlag = true;
if (selectionCount > 15)
insertionFlag = true;
}
}
}
Your selection sort method is incorrect. You need an inner loop.
public void reorderSelection()
{
int min = selectionCount;
int temp = 0;
for( int scan = selectionCount ; scan < selection.length - 1 ; scan++ )
{
min = scan;
for(int i = scan + 1; i < selection.length ; i++)
{
if(selection[min] > selection[i]) min = i;
}
if(min != scan)
{
temp = selection[scan];
selection[scan] = selection[min];
selection[min] = temp;
}
}
}

Java Tetris - Confused on grid[row][col] and coordinates (x, y)

I'm making Tetris in java for fun... I pretty much had everything working... but later found out that when I wanted to change the dimensions so it was square ([10 row][10 col] matrix, but instead a [12 row][10 col] matrix), that I started getting Index Out of Bound exceptions... see here: Java Tetris - weird row clearing issue
So I tried fixing everything so that the rows and columns weren't flip flopped... But am now getting hung up on the fact that the grid takes [row][col], but I’m moving around the tiles as (x, y) coordinates…
What’s confusing me is that row = y and col = x… which is reversed… so when I pass in coordinates I’m not sure when to swap them.
I know it’s a simple thing, but it’s confusing the hell out of me and I keep getting out of bounds exceptions whenever I think I have it right.
I'm not sure where the exact issue is, so I'm posting a full Sscce of my program... I think the issue is in the Board class...
Here, the block should still be able to move down... but if it tries to go down further than this...
I get:
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 10
at Board.getTileAt(Board.java:177)
at Tile.collision(Tile.java:31)
at Piece.isCollision(Piece.java:172)
at Board.collisionCheck(Board.java:192)
at Piece.movePieceCheck(Piece.java:87)
at Board.keyPressed(Board.java:160)
Sscce:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MainSscce extends JPanel {
static MainSscce runMe;
BoardSscce gameBoard, scoreBoard;
public MainSscce() { //creates a new frame window and sets properties
JFrame f = new JFrame("Tetris");
//width (height), length, tilesize
gameBoard = new BoardSscce(12, 10, 35);
// scoreBoard = new BoardSscce(10, 10, 35);
f.add(gameBoard);
f.setSize(gameBoard.getWidth(), gameBoard.getHeight());
f.setVisible(true);
f.setResizable(false);
f.setVisible(true);
f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize();
//set j frame location to appear in middle of screen
f.setLocation( (screensize.width - f.getWidth())/2,
(screensize.height - f.getHeight())/2-100 );
}
public static void main(String[] args) {
runMe = new MainSscce();
}
}
import java.awt.Graphics;
import java.awt.Color;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.event.*; // for ActionListener and ActionEvent
import java.util.Random;
public class BoardSscce extends JPanel implements KeyListener {
private TileSscce grid[][];
private int totalRows, totalCols, tilesize, level, totalScore;
private final int changeLevelMultiplier;
private PieceSscce newPiece, nextPiece;
private String randomPiece;
private boolean gameLost;
public BoardSscce(int r, int c, int ts) {
totalRows = r;
totalCols = c;
tilesize = ts;
//set grid size to [# rows][# columns], aka [height][width]
grid = new TileSscce[totalRows][totalCols];
gameLost = false;
System.out.println("TotalRows: " + totalRows + ", " + "TotalCols: " + totalCols);
//multiplier to determine what score the level changes, which is:
//level * changeLevelMultiplier;
changeLevelMultiplier = 40;
//initialize score to 0
totalScore = 0;
//initialize level to 0
level = 0;
newPiece = new PieceSscce(this, randomPiece(), getColor());
addKeyListener(this);
setFocusable(true);
//getTranspose();
timer();
}
public String randomPiece() {
String[] Pieces = {"L", "O", "Z", "RevZ", "Bar", "T", "RevL"};
int rand = (int) (Math.random() * Pieces.length);
randomPiece = Pieces[rand];
return randomPiece;
}
public Color getColor() {
Color color;
if (randomPiece.equals("L"))
color = new Color(17, 255, 0);
else if(randomPiece.equals("O"))
color = new Color(117, 168, 255);
else if(randomPiece.equals("Z"))
color = new Color(255, 187, 82);
else if(randomPiece.equals("RevZ"))
color = new Color(206, 27, 72);
else if(randomPiece.equals("Bar"))
color = new Color(50, 216, 219);
else if(randomPiece.equals("T"))
color = new Color(252, 148, 240);
else
color = new Color(255, 255, 52);
//Random rand = new Random();
//float r = rand.nextFloat();
//float g = rand.nextFloat();
//float b = rand.nextFloat();
//Color randomColor = new Color(r, g, b);
return color;
}
//dimensions of board = width * tilesize
public int getWidth() {
return totalCols * tilesize;
}
public int getHeight() {
return totalRows * tilesize;
}
public int getTileSize() {
return tilesize;
}
public void paintComponent(Graphics g) {
g.setColor(Color.black);
g.fillRect(0, 0, getWidth(), getHeight());
for(int row = 0; row < grid.length; row++) {
for(int col = 0; col < grid[row].length; col++) {
//System.out.println(row + ", " + col);
g.drawString("[" + row + "][" + col + "]", col * tilesize, row * tilesize+10);
System.out.println(row + ", " + col);
//if there is a non-null space, that is a Tetris piece... fill it
if(grid[row][col] != null) {
g.setColor(grid[row][col].getColor());
g.fillRect(row * tilesize, col * tilesize, tilesize, tilesize);
g.setColor(Color.WHITE);
}
}
}
// g.drawString("Level: " + level, this.getWidth()/2, this.getHeight()/2-130);
// g.drawString("Score: " + totalScore, this.getWidth()/2, this.getHeight()/2-100);
if (gameLost == true) {
g.drawString("Way to go, loser...", this.getWidth()/2, this.getHeight()/2);
messageTimer();
}
}
//Auto move piece
public void timer () {
int interval;
switch (level) {
//each level increases drop speed by .10 seconds
case 1: interval = 800;
break;
case 2: interval = 700;
break;
case 3: interval = 600;
break;
case 4: interval = 500;
break;
default: interval = 1000;
break;
}
Timer t = new Timer(interval, new ActionListener() {
public void actionPerformed(ActionEvent e) {
//newPiece.autoMove();
//repaint();
}
});
t.start();
}
public void messageTimer() {
Timer t = new Timer(5000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
gameLost = false;
}
});
t.start();
}
//move piece on key input
public void keyPressed(KeyEvent e) {
newPiece.movePieceCheck(e.getKeyCode());
repaint();
}
public void keyReleased(KeyEvent e) {
}
public void keyTyped(KeyEvent e) {
}
public boolean isValidCoordinate(int x, int y) {
return x >= 0 && y >= 0 && x < totalCols && y < totalRows;
}
// returns the tile at (x, y) or null if empty
public Tile getTileAt(int x, int y) {
if(isValidCoordinate(x, y))
return grid[x][y];
return null;
}
// sets the tile at (x, y) to tile
public void setTileAt(Tile tile, int x, int y) {
if(isValidCoordinate(x, y))
grid[x][y] = tile;
}
public boolean isOpen(int x, int y) {
return isValidCoordinate(x, y) && (getTileAt(x, y) == null);
}
public void collisionCheck() {
if (newPiece.isCollision()){
newPiece = new PieceSscce(this, randomPiece(), getColor());
}
}
public void changeLevel () {
int max = (level+1)*changeLevelMultiplier;
if (totalScore >= max) {
System.out.println(max + "reached... next level");
level++;
totalScore = 0;
timer();
}
}
public int tallyScore(int totalLines) {
int score = 0;
switch (totalLines) {
case 1: score = 40 * (level + 1);
break;
case 2: score = 100 * (level + 1);
break;
case 3: score = 300 * (level + 1);
break;
case 4: score = 1200 * (level + 1);
break;
default: break;
}
return score;
}
//loop through all rows starting at bottom (12 rows)
public void checkBottomFull() {
int lines = 0;
for(int row = 12; row > 0; row--) {
/* while (isFull(row)) {
lines++;
// clearRow(row);
}*/
}
totalScore += tallyScore(lines);
//check if level needs to be changed based on current score...
changeLevel();
//reset lines after score has been incremented
lines=0;
}
//loop through all columns in that row (10 columns)
public boolean isFull(int row) {
for (int col = 0; col <= 10; col++) {
System.out.println(row + ", " + col);
if(grid[row][col] == null) {
return false;
}
}
return true;
}
public void clearRow(int rowToClear) {
for(int row = rowToClear; row > 0; row--) {
for(int col = 0; col < grid[row].length; col++) {
grid[col][row] = grid[col][row-1];
}
}
}
public void checkEndGame(int x, int y) {
//if currPiece y location = 0 AND the space below is filled...
if (y <= 2 && !isOpen(x, y+1)) {
gameLost = true;
level = 0;
totalScore = 0;
//reset timer
timer();
for(int row = 0; row < grid.length; row++) {
for(int col = 0; col < grid[row].length; col++) {
grid[row][col] = null;
}
}
}
}
}
import java.awt.Color;
import java.awt.event.KeyEvent;
public class PieceSscce {
public int[] pieceCoordinates;
public String shape, currRotation;
public Color color;
public BoardSscce board;
public int rotationsCounter;
public TileSscce tile[];
public int[] newPositionX, newPositionY, currPositionX, currPositionY;
//don't need to pass in board because I'm already utilizing the Tiles class, which knows about the board
public Piece(Board b, String randomPiece, Color randomColor) {
shape = randomPiece;
color = randomColor;
board = b;
newPositionX = new int[4];
newPositionY = new int[4];
currPositionX = new int[4];
currPositionY = new int[4];
pieceCoordinates = new int[8];
//set pieceCoordinates global variable
getShape(shape);
tile = new TileSscce[4];
int counterX = 0, counterY = 1;
System.out.print("\"" + shape + "\" Coordinates: ");
//generate 4 new Tiles at specified coordinates that will compose the Piece
for (int i = 0; i < tile.length; i++) {
tile[i] = new TileSscce(board, pieceCoordinates[counterX], pieceCoordinates[counterY]);
System.out.print("(" + pieceCoordinates[counterX] + ", " + pieceCoordinates[counterY] + ") ");
//increment by 2 because x,y values are next to each other in array
counterX+=2;
counterY+=2;
}
System.out.println("\n");
for (int i = 0; i < tile.length; i++) {
tile[i].setColor(color);
}
}
public void calcNewPosition(int newX, int newY, int currTile) {
newPositionX[currTile] = newX;
newPositionY[currTile] = newY;
}
public void clearCurrPosition() {
for (int i = 0; i < tile.length; i++) {
currPositionX[i] = tile[i].getX();
currPositionY[i] = tile[i].getY();
board.setTileAt(null, currPositionX[i], currPositionY[i]);
}
}
public void autoMove() {
for (int i = 0; i < tile.length; i++) {
calcNewPosition(tile[i].getX(), tile[i].getY()+1, i);
}
clearCurrPosition();
for (int i = 0; i < tile.length; i++) {
board.checkEndGame(tile[i].getX(), tile[i].getY());
System.out.println("Checking..." + tile[i].getX() + ", " + tile[i].getY());
}
board.checkBottomFull();
board.collisionCheck();
move();
}
public void movePieceCheck(int keycode) {
if (keycode == KeyEvent.VK_DOWN) {
for (int i = 0; i < tile.length; i++) {
calcNewPosition(tile[i].getX(), tile[i].getY()+1, i);
}
clearCurrPosition();
for (int i = 0; i < tile.length; i++) {
board.checkEndGame(tile[i].getX(), tile[i].getY());
System.out.println("Checking..." + tile[i].getX() + ", " + tile[i].getY());
}
board.checkBottomFull();
board.collisionCheck();
move();
}
if (keycode == KeyEvent.VK_RIGHT) {
for (int i = 0; i < tile.length; i++) {
calcNewPosition(tile[i].getX()+1, tile[i].getY(), i);
}
clearCurrPosition();
move();
}
if (keycode == KeyEvent.VK_LEFT) {
for (int i = 0; i < tile.length; i++) {
calcNewPosition(tile[i].getX()-1, tile[i].getY(), i);
}
clearCurrPosition();
move();
}
//rotate left
if (keycode == KeyEvent.VK_A) {
int[] rotatedCoords = calcRotation("left");
clearCurrPosition();
rotate(rotatedCoords, "left");
}
//rotate right
if (keycode == KeyEvent.VK_D) {
int[] rotatedCoords = calcRotation("right");
clearCurrPosition();
rotate(rotatedCoords, "right");
}
}
public boolean movePieceValid() {
boolean valid = true;
for (int i = 0; i < tile.length; i++) {
if(!tile[i].checkNewLocation(newPositionX[i], newPositionY[i]))
valid = false;
}
return valid;
}
public boolean validRotation(int[] rotatedCoordinates) {
boolean valid = true;
int counterX = 0, counterY = 1;
for (int i = 0; i < tile.length; i++) {
if(!tile[i].checkNewLocation(rotatedCoordinates[counterX], rotatedCoordinates[counterY]))
valid = false;
counterX +=2;
counterY +=2;
}
return valid;
}
public void move() {
if (movePieceValid()) {
for (int i = 0; i < tile.length; i++) {
tile[i].setLocation(newPositionX[i], newPositionY[i]);
}
} else {
for (int i = 0; i < tile.length; i++) {
tile[i].setLocation(currPositionX[i], currPositionY[i]);
}
}
}
public void rotate(int[] rotatedCoordinates, String rotation) {
int counterX = 0, counterY = 1;
if (validRotation(rotatedCoordinates)) {
for (int i = 0; i < tile.length; i++) {
tile[i].setLocation(rotatedCoordinates[counterX], rotatedCoordinates[counterY]);
counterX+=2;
counterY+=2;
}
//else, if not valid move set the original location
} else {
for (int i = 0; i < tile.length; i++) {
tile[i].setLocation(currPositionX[i], currPositionY[i]);
}
}
}
public boolean isCollision() {
boolean collision = false;
for (int i = 0; i < tile.length; i++) {
if(tile[i].collision(newPositionX[i], newPositionY[i])) {
collision = true;
}
}
return collision;
}
//calc curr coordinates, send them to getRotation... which will create new piece based on coords
public int[] calcRotation(String direction) {
for (int i = 0; i < tile.length; i++) {
currPositionX[i] = tile[i].getX();
currPositionY[i] = tile[i].getY();
System.out.println("Current position: (" + currPositionX[i] + "," + currPositionY[i]+")");
}
return getRotation(currPositionX, currPositionY, direction);
}
public int[] getRotation (int coordinatesX[], int coordinatesY[], String direction) {
int[] rotationDirection;
int[] coordinates = new int[8];
int[] origin = new int[2];
int[] newCoordinates = new int[8];
int[] resultCoordinates = new int[8];
int[] finalCoordinates = new int[8];
int vectorMatrix[][] = new int[2][4];
//set either R(90) or R(-90) rotation matrix values:
if (direction.equals("right")) {
rotationDirection = new int[] {0, -1, 1, 0};
}
else {
rotationDirection = new int[] {0, 1, -1, 0};
}
int counterX = 0, counterY = 1, x = 0;
while (counterY < coordinates.length) {
//add arrays coordinatesX and coordinatesY into a single array: coordinates
coordinates[counterX] = coordinatesX[x];
coordinates[counterY] = coordinatesY[x];
counterX+=2;
counterY+=2;
x++;
}
//set origin so it rotates around center...
if (shape.equals("RevZ")) {
origin[0] = coordinates[6];
origin[1] = coordinates[7];
}
else if (shape.equals("T")) {
origin[0] = coordinates[4];
origin[1] = coordinates[5];
}
else {
origin[0] = coordinates[2];
origin[1] = coordinates[3];
}
//subtract origin from vectors
System.out.println();
counterX = 0;
counterY = 1;
while (counterY < newCoordinates.length) {
//System.out.println(coordinates[counterX] + ", " + coordinates[counterY]);
newCoordinates[counterX] = coordinates[counterX] - origin[0];
newCoordinates[counterY] = coordinates[counterY] - origin[1];
System.out.println("Translated coordinates: (" + newCoordinates[counterX] + ", " + newCoordinates[counterY] + ")");
counterX+=2;
counterY+=2;
}
System.out.println();
System.out.println("vector matrix:");
//fill up vectorMatrix with coordinates
int k = 0;
for (int col = 0; col < 4; col++) {
for (int row = 0; row < 2; row++) {
vectorMatrix[row][col] = newCoordinates[k++];
}
}
//print vectorMatrix:
for (int i = 0; i < vectorMatrix.length; i++) {
System.out.print("[");
for (int j = 0; j < vectorMatrix[i].length; j++) {
System.out.print(vectorMatrix[i][j]);
}
System.out.println("]");
}
int rotationMatrix[][] = new int[2][2];
//fill up rotationMatrix
System.out.println();
System.out.println("multiplicative matrix:");
k = 0;
for (int row = 0; row < 2; row++) {
System.out.print("[");
for (int col = 0; col < 2; col++) {
rotationMatrix[row][col] = rotationDirection[k++];
System.out.print(rotationMatrix[row][col]);
}
System.out.println("]");
}
//perform matrix multiplication
int[][] result = multiplyMatrices(rotationMatrix, vectorMatrix);
//print resulting matrix
System.out.println();
System.out.println("result matrix:");
for (int i = 0; i < result.length; i++) {
System.out.print("[");
for (int j = 0; j < result[i].length; j++) {
System.out.print(result[i][j]);
}
System.out.println("]");
}
//load new matrix coordinates back into array
k = 0;
for (int col = 0; col < 4; col++) {
for (int row = 0; row < 2; row++) {
resultCoordinates[k] = result[row][col];
k++;
}
}
System.out.println();
System.out.println("result coordinates:");
counterX = 0;
counterY = 1;
while (counterY < resultCoordinates.length) {
finalCoordinates[counterX] = resultCoordinates[counterX] + origin[0];
finalCoordinates[counterY] = resultCoordinates[counterY] + origin[1];
System.out.print("("+finalCoordinates[counterX] + ", " + finalCoordinates[counterY]+")");
counterX+=2;
counterY+=2;
}
return finalCoordinates;
}
public int[][] multiplyMatrices(int rotationMatrix[][], int vectorMatrix[][]) {
int mA = rotationMatrix.length;
int nA = rotationMatrix[0].length;
int mB = vectorMatrix.length;
int nB = vectorMatrix[0].length;
if (nA != mB) throw new RuntimeException("Illegal matrix dimensions.");
int[][] C = new int[mA][nB];
for (int i = 0; i < mA; i++) {
for (int j = 0; j < nB; j++) {
for (int k = 0; k < nA; k++) {
C[i][j] += (rotationMatrix[i][k] * vectorMatrix[k][j]);
}
}
}
return C;
}
public int[] getShape(String shape) {
if (shape.equals("L")) {
//pieceCoordinates = new int[] {0, 1, 0, 2, 1, 2, 2, 2};
pieceCoordinates = new int[] {4, 0, 4, 1, 5, 1, 6, 1};
}
else if (shape.equals("O")) {
pieceCoordinates = new int[] {0, 1, 1, 1, 0, 2, 1, 2};
}
else if (shape.equals("Z")) {
pieceCoordinates = new int[] {0, 1, 1, 1, 1, 2, 2, 2};
}
else if (shape.equals("RevZ")) {
pieceCoordinates = new int[] {1, 1, 2, 1, 0, 2, 1, 2};
}
else if (shape.equals("Bar")) {
//pieceCoordinates = new int[] {0, 1, 1, 1, 2, 1, 3, 1};
pieceCoordinates = new int[] {0, 1, 1, 1, 2, 1, 3, 1};
}
else if (shape.equals("T")) {
pieceCoordinates = new int[] {1, 1, 0, 2, 1, 2, 2, 2};
}
else if (shape.equals("RevL")) {
pieceCoordinates = new int[] {0, 2, 1, 2, 2, 2, 2, 1};
}
return pieceCoordinates;
}
}
import java.awt.Color;
import java.util.Random;
public class TileSscce {
private BoardSscce board;
private int currX, currY;
private Color color;
public TileSscce(BoardSscce b, int x, int y) {
board = b;
//when Tile is instantiated, set its position
setLocation(x, y);
}
public int getX() {
return currX;
}
public int getY() {
return currY;
}
public boolean checkNewLocation(int newX, int newY) {
boolean newLocationOK = board.isOpen(newX, newY);
return newLocationOK;
}
public boolean collision(int newX, int newY) {
boolean collision = this.getY() == ((board.getHeight()/board.getTileSize()))-2 || board.getTileAt(newX, newY) != null;
return collision;
}
public void setLocation(int newX, int newY) {
// board.setTileAt(null, currX, currY);
currX = newX;
currY = newY;
board.setTileAt(this, currX, currY);
}
public Color getColor() {
return setColor(color);
}
public Color setColor(Color myColor) {
color = myColor;
return color;
}
}
Thanks!
EDIT----------
I've tried implementing both ValarDohaeris and Svend Hansen's suggestions... Now the block is moving right when I press down, up when I press left, and down when I press right...
It seems to have to do with these methods in Board class which get and set tile locations...
// returns the tile at (x, y) or null if empty
public Tile getTileAt(int row, int col) {
System.out.println("getTileAt: " + row + ", " + col);
if(isValidCoordinate(row, col))
return grid[row][col];
return null;
}
// sets the tile at (x, y) to tile
public void setTileAt(Tile tile, int row, int col) {
System.out.println("setTileAt: " + row + ", " + col);
if(isValidCoordinate(row, col))
grid[row][col] = tile;
}
And in Piece class... movements are defined as:
public void movePieceCheck(int keycode) {
if (keycode == KeyEvent.VK_DOWN) {
for (int i = 0; i < tile.length; i++) {
calcNewPosition(tile[i].getRow()+1, tile[i].getCol(), i);
}
clearCurrPosition();
for (int i = 0; i < tile.length; i++) {
board.checkEndGame(tile[i].getRow(), tile[i].getCol());
}
board.checkBottomFull();
if (isCollision()) board.createNewPiece();
move();
}
if (keycode == KeyEvent.VK_RIGHT) {
for (int i = 0; i < tile.length; i++) {
calcNewPosition(tile[i].getRow(), tile[i].getCol()+1, i);
}
clearCurrPosition();
move();
}
if (keycode == KeyEvent.VK_LEFT) {
for (int i = 0; i < tile.length; i++) {
calcNewPosition(tile[i].getRow(), tile[i].getCol()-1, i);
}
clearCurrPosition();
move();
}
You have
grid = new TileSscce[totalRows][totalCols];
So when you want to access grid[x][y], you should check
x >= 0 && y >= 0 && x < totalRows && y < totalCols
in isValidCoordinate(x, y).
Emm... Quite interesting question. So to find out where the problem(s) may be I'll try to analyze your code a little bit...
You paste stack trace as
Exception in thread "AWT-EventQueue-0" java.lang.ArrayIndexOutOfBoundsException: 10
at Board.getTileAt(Board.java:177)
...
and at the same time the getTileAt()
// returns the tile at (x, y) or null if empty
public Tile getTileAt(int row, int col) {
System.out.println("getTileAt: " + row + ", " + col);
if(isValidCoordinate(row, col))//isValidCoordinate()?
return grid[row][col];
return null;
}
public boolean isValidCoordinate(int x, int y) {
return x >= 0 && y >= 0 && x < totalCols && y < totalRows;
}
... so the isValidCoordinate method return terms as
x >= 0 && y >= 0 && x < totalCols && y < totalRows
...the method doesn't allow to avoid array out-of-bounds problems; Seems like you put wrong array element indexes.
A. As I can notice, you trying to put a classic math matrix on Java [][] arrays as
public void clearRow(int rowToClear) {
for(int row = rowToClear; row > 0; row--) {
for(int col = 0; col < grid[row].length; col++) {//<-- ?
grid[col][row] = grid[col][row-1];
}
}
}
... and here I must say that you should know that in [][] arrays x,y are backwards and it is y,x because :
y (or classic i) - sub-array index (vertical)
x (or classic j) - sub-array's element index (horizontal)
so you should use array index something this way grid[y][x] or grid[i][j]
As a useful tip, I recommend you to analyze your code for logic errors in this field...
B. According to your app screenshot as
... it seems like the x,y problem takes place here too because you trying to control y (vertical) coordinates but (in real) you control x (horizontal) coordinates only :S It is still because of the row,col instead of a classic Java (col,row or y,x) [][] array index positions.
C. And again concerning to the wrong directions...
...up when I press left, and down when I press right...
if (keycode == KeyEvent.VK_RIGHT) {
for (int i = 0; i < tile.length; i++) {
calcNewPosition(tile[i].getRow(), tile[i].getCol()+1, i);
}
clearCurrPosition();
move();
}
Here I'll try to analyze the event as (you press right but move down)...
OK... according to one of your tasks you need to move by x coordinate (horizontally) but look closer... you make tile[i].getCol()+1 so it is newY and, of course, it moves vertically :S In your case it really moves down because you make increment as y++ ...
public void calcNewPosition(int newX, int newY, int currTile) {
newPositionX[currTile] = newX;
newPositionY[currTile] = newY;
}
public void clearCurrPosition() {
for (int i = 0; i < tile.length; i++) {
currPositionX[i] = tile[i].getX();
currPositionY[i] = tile[i].getY();
board.setTileAt(null, currPositionX[i], currPositionY[i]);
}
}
public void move() {
if (movePieceValid()) {
for (int i = 0; i < tile.length; i++) {
tile[i].setLocation(newPositionX[i], newPositionY[i]);//<-- !
}
} else {
for (int i = 0; i < tile.length; i++) {
tile[i].setLocation(currPositionX[i], currPositionY[i]);
}
}
}
...as a conclusion, I may recommend to change code (move right) something this way...
if (keycode == KeyEvent.VK_RIGHT) {
for (int i = 0; i < tile.length; i++) {
calcNewPosition(tile[i].getRow()+1, tile[i].getCol(), i);
}
clearCurrPosition();
move();
}
I hope my tips will help you to figure out what to look closer. Anyway, if you have some additional information please do comment my answer
Report if that helped you
This is based on x corresponds to columns and y corresponds to rows.
However grid is indexed by [row][col].
TileSscce grid[][] = new TileSscce[totalRows][totalCols]; // 12 => totalRows, 10 => totalCols
public int getWidth() {
return totalCols * tilesize;
}
public int getHeight() {
return totalRows * tilesize;
}
Following changes (based on your initial code - Sscce: - without later edits) will get rid of the exception and allow drawing till bottom of the board.
public void paintComponent(Graphics g) {
for (int row = 0; row < grid.length; row++) {
for (int col = 0; col < grid[row].length; col++) {
if (grid[row][col] != null) {
g.setColor(grid[row][col].getColor());
g.fillRect(col * tilesize, row * tilesize, tilesize, tilesize); // changed, check below snippet from fillRect documentation
g.setColor(Color.WHITE);
}
}
}
}
public TileSscce getTileAt(int x, int y) {
if (isValidCoordinate(x, y))
return grid[y][x]; // changed to [y][x] as grid is indexed by [row][col]
return null;
}
public void setTileAt(TileSscce tile, int x, int y) {
if (isValidCoordinate(x, y))
grid[y][x] = tile; // changed to [y][x] as grid is indexed by [row][col]
}
From fillRect documentation.
public abstract void fillRect(int x, int y, int width, int height)
The left and right edges of the rectangle are at x and x + width - 1.
The top and bottom edges are at y and y + height - 1.
This is correct.
public boolean isValidCoordinate(int x, int y) {
return x >= 0 && y >= 0 && x < totalCols && y < totalRows;
}

Is it possible to force JButton to always be square?

I'm coding a minesweeper clone and what I have problem with right now is the ratio of buttons on my grid - I want to allow users to resize the window as they please but I'd love the buttons to keep the same 1:1 width/height ratio rather than becoming pancakes or prison bars under some circumstances :) Is there some way to easily force the JButton to always remain square without giving it a fixed width and height?
You can write a custom LayoutManager e.g. GridLayout extension and set the children sizes.
import javax.swing.*;
import java.awt.*;
public class SquareButtonsTestApp extends JFrame {
public static void main ( String[] args ) {
new SquareButtonsTestApp();
}
public SquareButtonsTestApp() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
getContentPane().setLayout(new MyGridLayout(10, 20));
for (int i=0; i<10; i++) {
for (int j=0; j<20; j++) {
getContentPane().add(new JButton(" "));
}
}
setSize(800,600);
setLocationRelativeTo(null);
setVisible(true);
}
class MyGridLayout extends GridLayout {
public MyGridLayout(int rows, int cols) {
super(rows, cols);
}
public void layoutContainer(Container parent) {
synchronized (parent.getTreeLock()) {
Insets insets = parent.getInsets();
int ncomponents = parent.getComponentCount();
int nrows = getRows();
int ncols = getColumns();
boolean ltr = parent.getComponentOrientation().isLeftToRight();
if (ncomponents == 0) {
return;
}
if (nrows > 0) {
ncols = (ncomponents + nrows - 1) / nrows;
} else {
nrows = (ncomponents + ncols - 1) / ncols;
}
// 4370316. To position components in the center we should:
// 1. get an amount of extra space within Container
// 2. incorporate half of that value to the left/top position
// Note that we use trancating division for widthOnComponent
// The reminder goes to extraWidthAvailable
int totalGapsWidth = (ncols - 1) * getHgap();
int widthWOInsets = parent.getWidth() - (insets.left + insets.right);
int widthOnComponent = (widthWOInsets - totalGapsWidth) / ncols;
int extraWidthAvailable = (widthWOInsets - (widthOnComponent * ncols + totalGapsWidth)) / 2;
int totalGapsHeight = (nrows - 1) * getVgap();
int heightWOInsets = parent.getHeight() - (insets.top + insets.bottom);
int heightOnComponent = (heightWOInsets - totalGapsHeight) / nrows;
int extraHeightAvailable = (heightWOInsets - (heightOnComponent * nrows + totalGapsHeight)) / 2;
int size=Math.min(widthOnComponent, heightOnComponent);
widthOnComponent=size;
heightOnComponent=size;
if (ltr) {
for (int c = 0, x = insets.left + extraWidthAvailable; c < ncols ; c++, x += widthOnComponent + getHgap()) {
for (int r = 0, y = insets.top + extraHeightAvailable; r < nrows ; r++, y += heightOnComponent + getVgap()) {
int i = r * ncols + c;
if (i < ncomponents) {
parent.getComponent(i).setBounds(x, y, widthOnComponent, heightOnComponent);
}
}
}
} else {
for (int c = 0, x = (parent.getWidth() - insets.right - widthOnComponent) - extraWidthAvailable; c < ncols ; c++, x -= widthOnComponent + getHgap()) {
for (int r = 0, y = insets.top + extraHeightAvailable; r < nrows ; r++, y += heightOnComponent + getVgap()) {
int i = r * ncols + c;
if (i < ncomponents) {
parent.getComponent(i).setBounds(x, y, widthOnComponent, heightOnComponent);
}
}
}
}
}
}
}
}

Categories

Resources