Clickable Checkerboard applet - java

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));
}
}
}
}

Related

How do I get my multiplication table to have vertical lines?

I am trying to draw a multiplication table in Java. I can only seem to get the horizontal lines to print out. I'm new to coding and need help knowing where and what line of code I put in my for loop to make it run and look like a complete table.
public static void drawRow(int row, int size) {
g.drawLine(width, 3 + (row - 1) * height, 270, 3 + (row - 1) * height);
for (int col = 1; col <= size; ++col) {
g.drawString(pad(col), col * width, height);
System.out.printf("%4d", row * col);
g.drawString(pad(row * col), width * col, height * row);
}
g.drawLine(width, 3 + (row + 0) * height, 270, 3 + (row + 0) * height);
I tried to do a string above and below my for loop using g.drawLine.
To get an answer, a reproducible example is always a good place to start. I don't know what your code looks like exactly, but I think it might be something like this:
import java.awt.*;
import javax.swing.*;
public class App extends JFrame {
public static void main(String[] args) {
new App();
}
public App() {
super("Multiplication Table");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setMinimumSize(new Dimension(640, 480));
JPanel panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for(int row = 1; row <= 10; row++) drawRow(g, row, 10, 25, 25);
}
};
add(panel);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
public static void drawRow(Graphics g, int row, int size, int width, int height) {
g.drawLine(width, 3 + (row - 1) * height, 270, 3 + (row - 1) * height);
for (int col = 1; col <= size; ++col) {
g.drawString(pad(col), col * width, height);
System.out.printf("%4d", row * col);
g.drawString(pad(row * col), width * col, height * row);
}
g.drawLine(width, 3 + (row + 0) * height, 270, 3 + (row + 0) * height);
}
public static String pad(Integer value) {
return value.toString();
}
}
What could an answer look like then? Maybe like this:
import java.awt.*;
import javax.swing.*;
public class App extends JFrame {
public static void main(String[] args) {
new App();
}
public App() {
super("Multiplication Table");
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
setMinimumSize(new Dimension(640, 480));
JPanel panel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
drawTable(g, 10, 25, 20);
}
};
add(panel);
pack();
setLocationRelativeTo(null);
setVisible(true);
}
/**
* #param g - Graphics from eg paintComponent
* #param size - size of the table (eg 10 for 10x10)
* #param width - width of a cell in pixels
* #param height - height of a cell in pixels
*/
public void drawTable(Graphics g, int size, int width, int height) {
// set the top/left corner of the table
g.translate(20, 20);
// draw horizontal and vertical lines
for(int i = 0; i <= size; i++) {
g.drawLine(i * width, 0, i * width, height * size);
g.drawLine(0, i * height, width * size, i * height);
}
// calculate maximum width (eg width of "100" for size 10)
int maxWdth = g.getFontMetrics().stringWidth("" + size * size);
// draw the multiplications
for(int y = 1; y <= size; y++)
for(int x = 1; x <= size; x++) {
// calculate current width (eg width of "56" for 7x8)
String result = String.valueOf(x * y);
int resWdth = g.getFontMetrics().stringWidth(result);
// to align right, add (maxWdth - resWdth) to drawString x
g.drawString(result, (x - 1) * width + maxWdth - resWdth + 2, y * height - 2);
}
}

How to pause graphics of JPanel using Swing Timer?

I am building a Sudoku Solver visualizer that will solve the sudoku board and show the computer's steps as it tries each number in the available slots. I have been using the JFrame/JPanel framework to visualize this but have had problems updating the graphics to show the computer solving it and pausing the graphics in between each new attempt at each slot.
The solver works perfectly and correctly solves the board but I can only see the unsolved board and the solved board when I click the enter button.
Here is my class with the main method:
public class sudokuSolverVisualizer {
public static void main(String[] args) {
new GameFrame();
}
}
Here is the Game Frame class:
import javax.swing.*;
public class GameFrame extends JFrame {
GameFrame(){
this.add(new GamePanel());
this.setTitle("Sudoku Solver");
this.setResizable(false);
this.pack();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
}
And here is my JPanel class that solves the sudoku board and updates the graphics:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Line2D;
public class GamePanel extends JPanel implements ActionListener {
//region Variable Declaration
private static final int SIZE = 9;
static final int SCREEN_WIDTH = 270;
static final int SCREEN_HEIGHT = 270;
static final int UNIT_SIZE = SCREEN_WIDTH/SIZE;
static final int GAME_DELAY = 25;
static final int[][] board = {
{7, 0, 2, 0, 5, 0, 6, 0, 0},
{0, 0, 0, 0, 0, 3, 0, 0, 0},
{1, 0, 0, 0, 0, 9, 5, 0, 0},
{8, 0, 0, 0, 0, 0, 0, 9, 0},
{0, 4, 3, 0, 0, 0, 7, 5, 0},
{0, 9, 0, 0, 0, 0, 0, 0, 8},
{0, 0, 9, 7, 0, 0, 0, 0, 5},
{0, 0, 0, 2, 0, 0, 0, 0, 0},
{0, 0, 7, 0, 4, 0, 2, 0, 3}
};
static boolean solving = false;
static boolean solved = false;
static Timer timer;
//endregion
GamePanel(){
this.setPreferredSize(new Dimension(SCREEN_WIDTH, SCREEN_HEIGHT));
this.setBackground(Color.lightGray);
this.setFocusable(true);
this.addKeyListener(new MyKeyAdapter());
startGame();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
draw(g);
}
public void startGame(){
timer = new Timer(GAME_DELAY, this);
timer.start();
}
private static void draw(Graphics g) {
if (solving){
solveBoard(board, g);
}
Graphics2D g2 = (Graphics2D) g;
for (int row = 0; row < SIZE; row++){
if (row % 3 == 0 && row != 0){
g2.setStroke(new BasicStroke(5));
} else {
g2.setStroke(new BasicStroke(1));
}
g2.draw(new Line2D.Float(0, row * UNIT_SIZE, SCREEN_WIDTH, row * UNIT_SIZE));
for (int column = 0; column < SIZE; column++){
if (column % 3 == 0 && column != 0){
g2.setStroke(new BasicStroke(5));
} else {
g2.setStroke(new BasicStroke(1));
}
g2.draw(new Line2D.Float(column * UNIT_SIZE, 0, column * UNIT_SIZE, SCREEN_HEIGHT));
if (solved){
g.setColor(Color.green);
}
g2.drawString(String.valueOf(board[row][column]), column * UNIT_SIZE + 12, row * UNIT_SIZE + 22);
g.setColor(Color.black);
}
}
}
private static boolean isInRow(int[][] board, int num, int row){
for (int i = 0; i < SIZE; i++){
if (board[row][i] == num){
return true;
}
}
return false;
}
private static boolean isInColumn(int[][] board, int num, int column){
for (int i = 0; i < SIZE; i++){
if (board[i][column] == num){
return true;
}
}
return false;
}
private static boolean isInBox(int[][] board, int num, int row, int column){
int rowStart = row - row % 3;
int columnStart = column - column % 3;
for (int i = rowStart; i < rowStart + 3; i++){
for (int j = columnStart; j < columnStart + 3; j++) {
if (board[i][j] == num) {
return true;
}
}
}
return false;
}
private static boolean isValidPlace(int[][] board, int num, int row, int column){
return !isInRow(board, num, row) &&
!isInColumn(board, num, column) &&
!isInBox(board, num, row, column);
}
private static boolean solveBoard(int[][] board, Graphics g){
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.black);
for (int row = 0; row < SIZE; row++) {
for (int column = 0; column < SIZE; column++) {
if (board[row][column] == 0) {
for (int num = 1; num <= SIZE; num++) {
if (isValidPlace(board, num, row, column)) {
board[row][column] = num;
drawElements(g2, row, column, true);
if (solveBoard(board, g)) {
return true;
}
else{
board[row][column] = 0;
drawElements(g2, row, column, false);
}
}
}
return false;
}
}
}
solving = false;
solved = true;
draw(g);
return true;
}
private static void drawElements(Graphics2D g2, int row, int column, boolean correct){
if (correct) {
g2.setColor(Color.green);
} else {
g2.setColor(Color.red);
}
g2.clearRect(column * UNIT_SIZE, row * UNIT_SIZE, UNIT_SIZE, UNIT_SIZE);
g2.drawString(String.valueOf(board[row][column]), column * UNIT_SIZE + 12, row * UNIT_SIZE + 22);
g2.drawRect(column * UNIT_SIZE, row * UNIT_SIZE, UNIT_SIZE, UNIT_SIZE);
g2.setColor(Color.black);
}
private static void printBoard(int[][] board){
for (int row = 0; row < SIZE; row++){
if (row % 3 == 0 && row != 0){
System.out.println("-------------------");
}
for (int column = 0; column < SIZE; column++){
if (column % 3 == 0 && column != 0){
System.out.print("|");
}
System.out.print(board[row][column] + " ");
}
System.out.println();
}
}
#Override
public void actionPerformed(ActionEvent e) {
if (solving) {
repaint();
}
}
public class MyKeyAdapter extends KeyAdapter {
#Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()){
case KeyEvent.VK_ENTER:
solving = true;
break;
}
}
}
}
If you could help me find a way to pause the graphics in between each attempt at each slot or somehow repaint the graphics every time it tries a number, that would be great!
Visualising recursion like this is very hard, because what you need is control over the flow. Rather than the algorithm being allowed to run "freely", you need some way that you can control each iteration.
The first thing I did was adapted a non-recursive solver algorithm from Java | Recursive and non-recursive Sudoku solutions (Starter-friendly)
This allowed to create a step method which would move the solution along by a single (or close enough for the purpose) step.
This means that I can call step from Timer and control when the algorithm updates.
Important
This is NOT a Sudoku solution, this focus on how you might adopt a "recursive" style algorithm so it can be visualised, I take no responsibility for the accuracy of the algorithm 😉
Runnable example
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.Instant;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Stack;
import java.util.StringJoiner;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Main {
int[][] board = {
{7, 0, 2, 0, 5, 0, 6, 0, 0},
{0, 0, 0, 0, 0, 3, 0, 0, 0},
{1, 0, 0, 0, 0, 9, 5, 0, 0},
{8, 0, 0, 0, 0, 0, 0, 9, 0},
{0, 4, 3, 0, 0, 0, 7, 5, 0},
{0, 9, 0, 0, 0, 0, 0, 0, 8},
{0, 0, 9, 7, 0, 0, 0, 0, 5},
{0, 0, 0, 2, 0, 0, 0, 0, 0},
{0, 0, 7, 0, 4, 0, 2, 0, 3}
};
public static void main(String[] args) {
new Main();
}
public Main() {
// print(board);
SudokuSolver solver = new SudokuSolver(board);
// System.out.println();
print(solver.solve());
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
SudokuSolver solver = new SudokuSolver(board);
JFrame frame = new JFrame("Test");
frame.add(new MainPane(solver));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public void print(int[][] board) {
for (int[] row : board) {
StringJoiner joiner = new StringJoiner(" ", "", "\n");
for (int cell : row) {
joiner.add(String.format("%d", cell));
}
System.out.print(joiner.toString());
}
}
public class MainPane extends JPanel {
private SolverPane solverPane;
public MainPane(SudokuSolver solver) {
setLayout(new BorderLayout());
solverPane = new SolverPane(solver);
add(solverPane);
JButton startButton = new JButton("Go");
startButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
startButton.setEnabled(false);
solverPane.start(new SolverPane.Observer() {
#Override
public void didCompleteSolution() {
startButton.setEnabled(true);
}
});
}
});
add(startButton, BorderLayout.SOUTH);
}
}
public class SolverPane extends JPanel {
public interface Observer {
public void didCompleteSolution();
}
private SudokuSolver solver;
private Observer observer;
private Dimension preferredSize;
private int gap = 4;
public SolverPane(SudokuSolver solver) {
this.solver = solver;
solver.prepareSolution();
setFont(new Font("Monospaced", Font.PLAIN, 20));
}
#Override
public Dimension getPreferredSize() {
if (preferredSize == null) {
FontMetrics fm = getFontMetrics(getFont());
preferredSize = new Dimension(10 + ((fm.stringWidth("0") + gap) * 9), 10 + (fm.getHeight() * 9));
}
return preferredSize;
}
public void start(Observer observer) {
this.observer = observer;
solver.prepareSolution();
Instant startedAt = Instant.now();
Timer timer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (solver.step()) {
observer.didCompleteSolution();
((Timer) e.getSource()).stop();
Duration duration = Duration.between(Instant.now(), startedAt);
System.out.println(duration);
}
repaint();
}
});
timer.start();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
FontMetrics fm = g2d.getFontMetrics();
int gap = 4;
int cellWidth = fm.stringWidth("0") + 4;
int xPos = (getWidth() - (cellWidth * 9)) / 2;
int yPos = (getHeight() - (cellWidth * 9)) / 2;
g2d.translate(xPos, yPos);
Stack<SudokuSolver.Cell> solved = solver.getSolved();
if (solved != null) {
for (SudokuSolver.Cell cell : solver.getSolved()) {
int x = cell.getCol() * cellWidth;
int y = ((cell.getRow() - 1) * fm.getHeight());
g2d.drawString(Integer.toString(cell.getValue()), x, y);
}
}
g2d.dispose();
}
}
class SudokuSolver {
// Adapted from https://leetcode.com/problems/sudoku-solver/discuss/1392747/java-recursive-and-non-recursive-sodoku-solutions-starter-friendly
private int[][] board;
private LinkedList<Cell> unsolved;
private Stack<Cell> solved;
public SudokuSolver(int[][] originalBoard) {
this.board = originalBoard;
}
public LinkedList<Cell> getUnsolved() {
return unsolved;
}
public Stack<Cell> getSolved() {
return solved;
}
protected void prepareSolution() {
// all we need are just 1 stack, and 1 queue.
unsolved = new LinkedList<>(); // queue: all unconfirmed cells
solved = new Stack<>(); // stack: all cells which are confirmed temporarily
// init candidates
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (board[i][j] == 0) {
Cell cell = new Cell(i, j, board);
unsolved.addLast(cell);
} else {
Cell cell = new Cell(i, j);
cell.value = board[i][j];
solved.add(cell);
}
}
}
}
public boolean step() {
if (unsolved == null || solved == null) {
prepareSolution();
}
if (unsolved.peekFirst() == null) {
return true;
}
Cell curr = unsolved.removeFirst();
if (curr.isValidCandid()) {
solved.push(curr); // *
unsolved = excludeCandid(curr, unsolved);
} else { // MARK-s4
unsolved.addFirst(curr); // *
Cell prev = solved.pop(); // *
unsolved = revertCandid(prev, unsolved);
curr.resetCandid(); // restart selection
prev.nextCandid();
unsolved.addFirst(prev); // *
}
return unsolved.peekFirst() == null;
}
public int[][] solve() {
prepareSolution();
// try different combinations until all unsolved cells gone
Cell curr;
while (unsolved.peekFirst() != null) {
curr = unsolved.removeFirst();
if (curr.isValidCandid()) {
solved.push(curr); // *
unsolved = excludeCandid(curr, unsolved);
} else { // MARK-s4
unsolved.addFirst(curr); // *
Cell prev = solved.pop(); // *
unsolved = revertCandid(prev, unsolved);
curr.resetCandid(); // restart selection
prev.nextCandid();
unsolved.addFirst(prev); // *
}
}
int[][] solution = new int[board.length][board.length];
for (int row = 0; row < board.length; row++) {
for (int col = 0; col < board[row].length; col++) {
solution[row][col] = board[row][col];
}
}
// solutions back
while (!solved.empty()) {
confirm(solved.pop(), solution);
}
return solution;
}
void confirm(Cell solution, int[][] problem) {
problem[solution.row][solution.col] = solution.value;
}
// once some candidates are taken, we need to exclude them in related cells
LinkedList<Cell> excludeCandid(Cell target, LinkedList<Cell> before) {
LinkedList<Cell> after = new LinkedList<Cell>();
Cell curr;
while ((curr = before.peekFirst()) != null) {
before.removeFirst();
curr.excludeCandidate(target); // exclude the target candidate
// OPTIONAL, but win more about 70% time!
if (curr.isValidCandid()) // if there is conflict, handle it first
{
after.addLast(curr);
} else {
after.addFirst(curr);
}
}
return after;
}
// once the previous candidates were incorrectly taken, we need to revert/recover them in related cells
LinkedList<Cell> revertCandid(Cell target, LinkedList<Cell> before) {
LinkedList<Cell> after = new LinkedList<Cell>();
Cell curr = null;
while ((curr = before.peekFirst()) != null) {
before.removeFirst();
curr.enableCandidate(target);
after.addLast(curr);
}
return after;
}
// >> SOLUTION
// << STRUCT
public class Cell {
/**
*
* To solve sudoku, we can use one stack to save all temporarily
* confirmed cells, and one queue to save all unconfirmed ones, then
* repeatedly dequeue elements from queue and push them into the
* stack, analysing them at the same time, until queue is empty,
* then Sudoku is solved. If stack encounter EmptyStackException at
* some point of time, this method then is not capable to solve the
* given Sudoku. Note, analysing cells is simple and
* straightforward, just the "pointer" stuff, and the detail is
* shown below.
*
*
* ################################## ## "1 stack and 1 queue" model
* : ##################################
*
* ........................................................................
* .----------- (2,5) (2,4) (2,6) (2,0) .... |
* ........................................................................
* | (unsolved Queue/List) | | \/ | | | | | (2,3) | | .... | | ....
* | | .... | ---------- (solved Stack)
*
*
*
* ################################## ## "candidate pointer" model :
* ( cell(2,0) at any possible point of time )
* ##################################
*
* Characters: 1 2 3 4 5 6 7 8 9
*
* candidates: [-999999, 0 , 33 , -1 , 78 , 0 , 0 , -1 , 0 , -1] ^
* [Stage 1] ... 21 ^ [Stage 2] ... 21 23 22 25 ^(>9) [Stage 3]
*
* Explanations: [Stage 1] candidate pointer(cPtr), when at very
* beginning, and there are 3 possible values that can be chosen;
* [Stage 2] after '1' is selected by 21st cell, i.e. problem[2][2],
* cPtr moves to 5th; [Stage 3] at this point, the '1' was taken by
* 21st cell, '5' was by 23rd, '6' was by 22nd, '8' was by 25th,
* result in cPtr overflow, which means some of previous candidates
* were taken incorrectly, and getting back and retrying is needed.
* [Stage 4] details is shown in some place of codes, marked as
* "MARK-s4"
*
*
*
*/
private int row;
private int col;
private int[] candidates; // -1: confirmed 0: possible >0: be selected by others
private int value = -1; // [1,9] or 10,11,...
public Cell(int i, int j) {
row = i;
col = j;
candidates = new int[10];
candidates[0] = -999999;
}
public Cell(int i, int j, int[][] datasource) {
this(i, j);
initCandidates(datasource);
}
public int getRow() {
return row;
}
public int getCol() {
return col;
}
public int getValue() {
return value;
}
protected void initCandidates(int[][] datasource) {
// same row
for (int i = 0; i < 9; i++) {
if (datasource[row][i] != 0) {
candidates[datasource[row][i]] = -1;
}
}
// same col
for (int i = 0; i < 9; i++) {
if (datasource[i][col] != 0) {
candidates[datasource[i][col]] = -1;
}
}
// same 9-cell
int start_i = row / 3 * 3;
int start_j = col / 3 * 3;
for (int i = start_i; i < start_i + 3; i++) {
for (int j = start_j; j < start_j + 3; j++) {
if (datasource[i][j] != 0) {
candidates[datasource[i][j]] = -1;
}
}
}
// init candid ptr
resetCandid();
}
protected int getCurrCandid() { // [1-9] or -1
if (isValidCandid()) {
return value;
}
return -1;
}
private void resetCandid() {
// to left most 0
int i = 1;
for (; i < 10; i++) {
if (candidates[i] == 0) {
break;
}
}
value = i; // 1..9 or 10
}
private void nextCandid() {
int i = value + 1;
while (i < 10 && candidates[i] != 0) {
i++;
}
value = i; // 1..9 or 10,11,...
}
private void excludeCandidate(Cell by) {
int their = by.getCurrCandid();
if (candidates[their] == 0) {
int theirIdx = by.row * 9 + by.col + 1;
// same row
if (by.row == row) {
candidates[their] = theirIdx;
}
// same col
if (by.col == col) {
candidates[their] = theirIdx;
}
// same cell
if (by.row / 3 * 3 == row / 3 * 3 && by.col / 3 * 3 == col / 3 * 3) {
candidates[their] = theirIdx;
}
}
if (!isValidCandid()) {
nextCandid();
}
}
private void enableCandidate(Cell by) {
int their = by.getCurrCandid(); // must exist
int theirIdx = by.row * 9 + by.col + 1;
if (candidates[their] > 0 && candidates[their] == theirIdx) { // result from their
candidates[their] = 0; // >0 -> 0
if (value >= their) {
resetCandid(); // *
}
}
}
private int numOfCandidate() {
int num = 0;
for (int i = 1; i < 10; i++) {
if (candidates[i] == 0) {
num++;
}
}
return num;
}
private boolean isValidCandid() {
if (value < 1 || value > 9) {
return false;
}
return candidates[value] == 0;
}
public String toString() {
return String.format("%d,%d cptr:%d(%b) (%d)candids:%s\n", row, col, value, isValidCandid(), numOfCandidate(), Arrays.toString(candidates));
}
}
// >> STRUCT
}
}

How to set object in center of frame?

I am new with programming. I am not sure how to put an object in the center of a frame. This is how far i got:
public class LetSee extends JPanel {
public void paintComponent(Graphics g) {
int row; // Row number, from 0 to 7
int col; // Column number, from 0 to 7
int x,y; // Top-left corner of square
for ( row = 0; row < 5; row++ ) {
for ( col = 0; col < 5; col++) {
x = col * 60;
y = row * 60;
if ( (row % 2) == (col % 2) )
g.drawRect(x, y, 60, 60);
else
g.drawRect(x, y, 60, 60);
}
} // end for row
}
}
public class LetSeeFrame extends JFrame {
public LetSeeFrame(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(1900, 1000);
setVisible(true);
LetSee let = new LetSee();
let.setLayout(new BorderLayout());
add(let,BorderLayout.CENTER);
setLocationRelativeTo(null);
}
public static void main(String[] args) {
LetSeeFrame l = new LetSeeFrame();
}
}
Actually your panel is centered in the frame, but what it draws isn't.
You should make use of the width and the height of the JPanel to center the drawing .
Also put your sizes and numbers into variables, it is less error-prone when you use them several times in your code .
Finally as #MadProgrammer said in the comments :
Don't forget to call super.paintComponent before you doing any custom
painting, strange things will start doing wrong if you don't. Also
paintComponent doesn't need to be public, no one should ever call it
directly
import java.awt.Graphics;
import javax.swing.JPanel;
public class LetSee extends JPanel {
public void paintComponent(final Graphics g) {
super.paintComponent(g);
int row; // Row number, from 0 to 7
int col; // Column number, from 0 to 7
int x, y; // Top-left corner of square
int maxRows = 5;
int maxCols = 5;
int rectWidth = 60;
int rectHeight = 60;
int maxDrawWidth = rectWidth * maxCols;
int maxDrawHeight = rectHeight * maxRows;
// this is for centering :
int baseX = (getWidth() - maxDrawWidth) / 2;
int baseY = (getHeight() - maxDrawHeight) / 2;
for (row = 0; row < maxRows; row++) {
for (col = 0; col < maxCols; col++) {
x = col * rectWidth;
y = row * rectHeight;
if ((row % 2) == (col % 2)) {
g.drawRect(baseX + x, baseY + y, rectWidth, rectHeight);
} else {
g.drawRect(baseX + x, baseY + y, rectWidth, rectHeight);
}
}
} // end for row
}
}

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

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.

memory game random color

Hey everybody I'm creating a memory game that uses a 4x4 2Darray.
I have the 4x4 filld with a pair of integers from 0-7 and they are randomly scattered. I want to assign a color to each pair, so when the mouse clicks over that square the assigned color will appear based on the integer and you will have to find the other integer based on it's corresponding matching color.
I've been running into some problems with this setColor method of mine. I'm going to include my whole code in case I messed up somewhere else and that was why. At the moment if I click every square once I use all 8 colors I assigned twice, but some of the colors don't match up to where the same integer is at on another tile. Also when I click the same tile multiple times it changes between 2-3 colors and I'm not sure what I'm doing wrong.
The parts I need advice on are the setColor method I have assigned and my logic behind it.
/*Sets the background of your memory board to black*/
public void init()
{
setSize(400,400);
setBackground(Color.BLACK);
buildBoard(4);
}
/*This is main in java applets
You may need to add (not
change) a couple things in this method
*/
public void paint(Graphics canvas)
{
if(firstRun) //for the first run we need to build our random board
{
print2DArray(board);
buildBoard(4);
firstRun = false;
}
else // once our board is built we will display the game
{
displayGame(canvas);
if (mouseClicked) // if the mouse has been clicked
{
displayHit(canvas);//find which box the user clicked
mouseClicked = false;
}
}
}
/*
DO NOT change this method
determines if the mouse has been pressed
sets x and y Mouse to the location of the mouse arrow
redraws the image
*/
public boolean mouseDown(Event e, int x, int y )
{
mouseClicked = true;
xMouse = x;
yMouse = y;
repaint();
return true;
}
/*DO NOT change this method
redraws the scene
*/
public void update ( Graphics g )
{
paint(g);
}
/*
pre: none
post: build an array that holds the memory values for a board of size x size
the board will hold two of each int from 0 to size randomly placed in the array
*/
public static void fillRect(Graphics g, int x, int y, int width, int length)
{
g.setColor(Color.BLACK);
width = 100;
length = 100;
x = (int)xMouse/100;
y = (int)yMouse/100;
}
public void buildBoard(int s)
{
int a = 4;
for (int row = 0; row < a; row++)
for (int column = 0; column < a; column++)
{
board[row][column] = count++ % 8;
}
for(int row = 0; row < 4; row++)
for(int column = 0; column < 4; column ++)
{
int x = (int)Math.floor(Math.random()*4);
int y = (int)Math.floor(Math.random()*4);
temp = board[row][column];
board[row][column] = board[x][y];
board[x][y] = temp;
}
}
public static void print2DArray(int[][] arr)
{
for (int row = 0; row < arr.length; row++)
{
for (int col = 0; col < arr[row].length; col++)
{
System.out.print(arr[row][col] + " ");
}
System.out.println();
}
}
public void displayGame(Graphics canvas)
{
canvas.setColor(Color.WHITE);
for(int i =0; i < 400; i+= WIDTH)
for(int j = 0; j < 400; j+= WIDTH)
canvas.drawRect(i, j, WIDTH, WIDTH);
}
/*
Pre: xMouse and yMouse have been initialized
Post: A circle is displayed in the correct box on the screen
Currently the circle is displayed at the mouse location
*/
public void displayHit(Graphics g)
{
/*int xGuess = (int)xMouse/100;
int yGuess = (int)yMouse/100;
board[xGuess][yGuess] = guess1;
int xGuess2 = (int)xMouse/100;
int yGuess2 = (int)yMouse/100;
board[xGuess2][yGuess2] = guess2;
if (guess1 == guess2)
{
setColor(g);
centerHit(xMouse, yMouse);
g.fillOval(xMouse, yMouse, 40, 40);
}
else
g.fillRect(guess1, guess2, width, length);
g.setColor(Color.BLACK);*/
setColor(g);
centerHit(xMouse, yMouse);
g.fillOval(xMouse, yMouse, 40, 40);
}
public void setColor(Graphics g)
{
centerClick(x1,y1);
//int x = xMouse;
//int y = yMouse;
colorIndex = board[row][column];
board[row][column] = board[x1][y1];
board[x1][y1] = colorIndex;
switch(colorIndex)
{
case 0: g.setColor(Color.RED);
break;
case 1: g.setColor(Color.GREEN);
break;
case 2: g.setColor(Color.BLUE);
break;
case 3: g.setColor(Color.ORANGE);
break;
case 4: g.setColor(Color.CYAN);
break;
case 5: g.setColor(Color.MAGENTA);
break;
case 6: g.setColor(Color.PINK);
break;
case 7: g.setColor(Color.YELLOW);
break;
}
}
public void centerHit(int centerX, int centerY)
{
{
if ((xMouse > 0) && (xMouse <=100))
xMouse = 33;
else if ((xMouse > 100) && (xMouse <=200))
xMouse = 133;
else if ((xMouse > 200) && (xMouse <=300))
xMouse = 233;
else if ((xMouse > 300) && (xMouse <=400))
xMouse = 333;
}
{
if ((yMouse > 0) && (yMouse <=100))
yMouse = 33;
else if ((yMouse > 100) && (yMouse <=200))
yMouse = 133;
else if ((yMouse > 200) && (yMouse <=300))
yMouse = 233;
else if ((yMouse > 300) && (yMouse <=400))
yMouse = 333;
}
}
public void centerClick(int centerX, int centerY)
{
{
if ((xMouse > 0) && (xMouse <=100))
x1 = 0;
else if ((xMouse > 100) && (xMouse <=200))
x1 = 1;
else if ((xMouse > 200) && (xMouse <=300))
x1 = 2;
else if ((xMouse > 300) && (xMouse <=400))
x1 = 3;
}
{
if ((yMouse > 0) && (yMouse <=100))
y1 = 0;
else if ((yMouse > 100) && (yMouse <=200))
y1 = 1;
else if ((yMouse > 200) && (yMouse <=300))
y1 = 2;
else if ((yMouse > 300) && (yMouse <=400))
y1 = 3;
}
}
}
to keep the colors from changing, change this code
colorIndex = board[row][column];
board[row][column] = board[x1][y1];
board[x1][y1] = colorIndex;
to
colorIndex = board[x1][y1];
the color matching issue is because youre building the board twice: first on the firstRun of the paint method where you print the array and then on the initmethod where the board gets overwritten so you see different values
to solve it you should build the board only once in the init method, and call print2DArray afterwards to check it, so
buildBoard(4);
print2DArray(board); //<-- add this line to verify colors
and you could omit the firstRun flag and all associated code.
comment or delete this code:
/*if(firstRun) //for the first run we need to build our random board
{
print2DArray(board);
buildBoard(4);
firstRun = false;
}
else // once our board is built we will display the game
{*/

Categories

Resources