How to Randomize Placement of a JLabel on a GridLayout of JButtons? - java

I am trying to make a chessboard, that will randomize the place of its pieces throughout the board.
Below is what I have so far
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
public class ChessBoard extends JFrame {
JLayeredPane layeredpane;
JPanel chessboard;
JButton[][] chessboardButtons;
Color black;
JLabel [][] chessboardLabels;
UIManager Ui;
ChessBoard() {
Dimension Size = new Dimension(600, 600);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
pack();
setResizable(true);
setLocationRelativeTo(null);
setVisible(true);
setSize(600, 600);
setTitle("Chess Board");
layeredpane = new JLayeredPane();
getContentPane().add(layeredpane);
layeredpane.setPreferredSize(Size);
chessboard = new JPanel();
layeredpane.add(chessboard, JLayeredPane.DEFAULT_LAYER);
chessboard.setLayout(new GridLayout(8, 8));
chessboard.setPreferredSize(Size);
chessboard.setBounds(0, 0, Size.width, Size.height);
Ui = new UIManager();
chessboardButtons = new JButton[8][8];
black = Color.black;
ButtonHandler handler = new ButtonHandler();
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
chessboardButtons[i][j] = new JButton();
chessboardButtons[i][j].setBorderPainted(false);
if ((i + j) % 2 != 0) {
chessboardButtons[i][j].setBackground(black);
chessboardButtons[i][j].setOpaque(true);
}
chessboard.add(chessboardButtons[i][j]);
chessboardButtons[i][j].addActionListener(handler);
}
}
chessboardLabels = new JLabel[8][8];
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
chessboardLabels[i][j] = new JLabel();
chessboardLabels[i][j].setFont(new Font("Ariel", Font.BOLD, 20));
chessboardLabels[i][j].setText("H");
chessboardLabels[i][j].setHorizontalAlignment(JLabel.CENTER);
chessboardLabels[i][j].setVerticalAlignment(JLabel.CENTER);
chessboardLabels[i][j].setOpaque(true);
chessboardButtons[i][j].add(chessboardLabels[i][j]);
if(chessboardButtons[i][j].getBackground() == Color.black) {
chessboardLabels[i][j].setBackground(Color.black);
chessboardLabels[i][j].setForeground(Color.white);
}
}
}
}
private class ButtonHandler implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == chessboardButtons[0][0]) {
System.out.println("Button 0,0");
}
if (e.getSource() == chessboardButtons[0][1]) {
System.out.println("Button 0,1");
}
}
}
}
Right now I have the letter H filling all my buttons. What I need it to do is to:
limit the number of "H"'s there are on the board to be 32, 16 "White" and 16 "black" and
randomize the placement throughout the board.
Any ideas will be helpful!

I tried exactly this years ago, and I ran into several problems. One of the biggest is that dragging a piece from one square (JComponent) to another hard to do, because each JComponent has its bounds, and its Graphics clipping prevents you from drawing outside of these bounds. There are workarounds, like adding an Image to a higher level in the JLayeredPane, but this is still very hard to get right.
You really want to make you GUI a custom JComponent/JPanel that draws the whole board and can get mouse events across the whole board.
But before that, the right place to start is by creating a ChessModel that encapsulates the logic of the game. If you do that first and test it thoroughly, adding a GUI on top of that is easier than the other way around.
public class ChessModel {
char[][] board = new char[8][8];
...
public Point[] getPossibleMoves(Point pieceLocation) {
...
}
}

Create an ArrayList with 64 Integers numbered from 0 - 63
Use Collections.shuffle(...) to shuffle the numbers randomly
Take the first 16 values from the ArrayList and add white pieces to the board based on the integer value.
Take the next 16 values from the ArrayList and add the black pieces to the board.

First, I would start by decoupling parts of the system, this will provide you with a lot more flexibility.
For example, you want to decouple the "visual" from the "virtual". Components aren't managed in a "grid", instead, they are maintained in a list, so, you want some way you can quickly and easily ascertain the location of various components on the screen and how the relate to the "virtual" concept of the game or grid.
This is at the core concept of "model-view-controller", where the model represents a "grid" of "pieces" and the view is used to visually represent the model to the user. So you end up with a little bit of translation going on.
Now, you can do something like...
int row = (value / 8);
int col = (value % 8);
which, given a component index, will give you the row/col that they represent, but I'm also lazy 😉, so, I'm going to isolate the concept of a Piece...
public class Piece extends JPanel {
private JLabel label;
private Point cell;
public Piece(int index) {
setLayout(new GridBagLayout());
label = new JLabel(Integer.toString(index));
label.setForeground(Color.RED);
add(label);
setOpaque(false);
}
public void setCell(Point cell) {
this.cell = cell;
}
public Point getCell() {
return cell;
}
}
This does several things for me, first, it gives me a simple building block which can be used to represent a piece of data as well as maintain the "virtual" position of the piece, so I can easily look it up, independently.
It also divorces the piece from the board, which will make it easier to maintain (IMHO).
Next, I build the board...
setLayout(new GridLayout(8, 8));
int index = 0;
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) {
JPanel panel = new JPanel(new GridBagLayout()) {
#Override
public Dimension getPreferredSize() {
return new Dimension(50, 50);
}
};
// Indexed via x/y
cells[col][row] = panel;
if (index % 2 == 0) {
panel.setBackground(Color.WHITE);
} else {
panel.setBackground(Color.BLACK);
}
add(panel);
index++;
}
index++;
}
There's nothing really fancy here, it's just GridLayout with a bunch of color panels laid out on it.
The "fancy" part is the idea that, instead of using something complicated, like JLayeredPane, I'm simply going to add the Pieces directly to each cell.
Which leads us to the heart of the problem, how to randomise the position of the cells. Essentially, I'm going to create a list of numbers from 0 to 63 inclusive, randomise the list and then pop each number of off the list till I'm done.
Now, you could use an array, but filling an array with random numbers is not a simple task (especially if you want to guarantee uniqueness 😉)
// Fill a list of numbers
int totalCells = 8 * 8;
List<Integer> locations = new ArrayList<>(totalCells);
for (int value = 0; value < totalCells; value++) {
locations.add(value);
}
// Randomise the list
Collections.shuffle(locations);
// For al the white pieces, randomise their positions
for (index = 0; index < 16; index++) {
int value = locations.remove(0);
// Virtual coordinates
int row = (value / 8);
int col = (value % 8);
Point cell = new Point(col, row);
Piece piece = new Piece(index);
whitePieces[index] = piece;
piece.setCell(cell);
// Get the component offset by the value (physical)
JPanel cellPane = (JPanel) getComponent(value);
cellPane.add(piece);
}
// Now you can continue with the black pieces, just like above
// and because you've removed the "used" cell indexes from the
// list, you won't end up with duplicate positions
Now you're probably scratching your head over all this. But simply put, when you want to move a "piece", you simply remove it from it's current parent container, calculate the position ((row * 8) + col), get the new parent component (like above) and add it, simple.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Test extends JFrame {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JPanel[][] cells = new JPanel[8][8];
private Piece[] whitePieces = new Piece[16];
public TestPane() {
setLayout(new GridLayout(8, 8));
int index = 0;
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) {
JPanel panel = new JPanel(new GridBagLayout()) {
#Override
public Dimension getPreferredSize() {
return new Dimension(50, 50);
}
};
// Indexed via x/y
cells[col][row] = panel;
if (index % 2 == 0) {
panel.setBackground(Color.WHITE);
} else {
panel.setBackground(Color.BLACK);
}
add(panel);
index++;
}
index++;
}
int totalCells = 8 * 8;
List<Integer> locations = new ArrayList<>(totalCells);
for (int value = 0; value < totalCells; value++) {
locations.add(value);
}
Collections.shuffle(locations);
for (index = 0; index < 16; index++) {
int value = locations.remove(0);
int row = (value / 8);
int col = (value % 8);
Point cell = new Point(col, row);
Piece piece = new Piece(index);
whitePieces[index] = piece;
piece.setCell(cell);
JPanel cellPane = (JPanel) getComponent(value);
cellPane.add(piece);
}
}
}
public class Piece extends JPanel {
private JLabel label;
private Point cell;
public Piece(int index) {
setLayout(new GridBagLayout());
label = new JLabel(Integer.toString(index));
label.setForeground(Color.RED);
add(label);
setOpaque(false);
}
public void setCell(Point cell) {
this.cell = cell;
}
public Point getCell() {
return cell;
}
}
}
Oh, and just in case it's important, you can make use of component based drag-n-drop as well
How to make draggable components with ImageIcon
JLayeredPanel layout manager free moving objects
But, needs drives wants 😉

Related

How should I drag a JLabel from one JPanel in a JFrame onto a JTextField in another JPanel in the same JFrame?

In short, I want to set the text of a JLabel to be that of a JTextField in a JPanel (pnlUser) and then drag the JLabel across the screen from JPanel onto another JTextField in another JPanel (pnlGrid).
Here are the details.
I have written a "Solitaire Scrabble" program. The user can either position the text cursor in a grid cell (a JTextField in pnlGrid) and type a letter that is in the list of "User letters" (a JTextField in pnlUser) OR the user can simulate dragging a letter from "User letters" and dropping it into the destination grid cell in pnlGrid.
I say "simulate" because the selected letter is not actually dragged across the screen. I use the mouse pointer HAND_CURSOR to make the drag/drop as real as possible, but I haven't figured out how to make the HAND_CURSOR "grab" the letter and physically drag the letter across the board to its destination.
As it is, the letter is highlighted but left in the "User letters" area while the HAND_CURSOR moves along the grid during the drag operation. When it gets to the destination cell in pnlGrid and the mouse button is released, the letter is erased from "User letters" and suddenly appears in the grid cell.
So the letter is more or less "teleported" (beam me up, Scotty) from "User letters" to a grid cell. This is too abstract. I want the user letter to be at the tip of the HAND_CURSOR's pointing finger and be dragged along the grid into the grid cell where it will be dropped, as shown in the 3 pictures below.
I've successfully made it happen in a small test program (source below) using JLayeredPane, but I can't make it happen in the game. But I knew nothing about JLayeredPane until two days ago so I don't really know what I'm doing. (I adapted an Oracle tutorial program that demos JLayeredPane.)
I just read about the "glass pane" and thought it would maybe be easier to implement until I downloaded the source for that demo, which is quite long, so since it's totally new and will be even harder to adapt.
So I thought before I spend more hours in frustration I should ask:
Is a JLayeredPane or a setGlassPane approach appropriate? Is there an easier or better way to drag a JLabel from one JPanel onto another another JPanel?
(The approach in the program is to determine which "User letter" is being pointed at, store that letter in a JLabel, and then make sure that during mouseDragged the HAND_CURSOR fingertip is right at the bottom center of the letter.)
package mousemoveletter;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import static java.awt.Color.*;
import java.awt.event.*;
import static javax.swing.SwingUtilities.invokeLater;
public class LayeredPaneDemo extends JPanel
{
private static final int USER7 = 7;
static Cursor HAND = new Cursor(Cursor.HAND_CURSOR);
static Cursor ARROW = new Cursor(Cursor.DEFAULT_CURSOR);
private static JLayeredPane layeredPane;
private static JLabel lblToMove;
private static JPanel pnlUser;
private static JPanel pnlGrid;
private static final JTextField[] txtUser = new JTextField[USER7];
public LayeredPaneDemo() // constructor
{
pnlGrid = new JPanel();
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
layeredPane = new JLayeredPane();
layeredPane.setPreferredSize(new Dimension(240, 240));
pnlGrid.setSize(140, 140);
pnlGrid.setBorder(new EtchedBorder(RED, GREEN));
pnlGrid.setBackground(YELLOW);
lblToMove = new JLabel("XXX");
lblToMove.setSize(new Dimension(40,40));
layeredPane.add(pnlGrid, 0,0);
layeredPane.add(lblToMove, new Integer(0), -1);
add(layeredPane);
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("LayeredPaneDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent newContentPane = new LayeredPaneDemo();
newContentPane.setOpaque(true); //content panes must be opaque
frame.setContentPane(newContentPane);
makeUser();
frame.add(pnlUser);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
invokeLater(new Runnable()
{
public void run() {
createAndShowGUI();
}
});
}
private static void makeUser(){
pnlUser = new JPanel(new GridLayout(1,USER7));
pnlUser.setPreferredSize(new Dimension(225, 50));
pnlUser.setBackground(Color.green);
pnlUser.setBorder(BorderFactory.createLineBorder(Color.BLUE));
for(int k = 0; k < USER7; k++)
{
txtUser[k] = new JTextField("" + (char)(Math.random()*26+65));
txtUser[k].setName("" + k);
txtUser[k].setEditable(false);
txtUser[k].addMouseMotionListener(new MouseMotionAdapter()
{
public void mouseDragged(MouseEvent e)
{
lblToMove.setCursor(HAND);
int w = Integer.parseInt(e.getComponent().getName());
lblToMove.setText(txtUser[w].getText());
layeredPane.setLayer(lblToMove, 0, 0);
lblToMove.setLocation(e.getX() + (e.getComponent().getWidth())*w,
e.getY() + layeredPane.getHeight() - e.getComponent().getHeight()/2);
};
});
txtUser[k].addMouseListener(new MouseAdapter()
{
public void mouseReleased(MouseEvent e)
{
lblToMove.setCursor(ARROW);
}
});
pnlUser.add(txtUser[k]);
}
}
}
Thanks to #trashgod, I figured it out by following his links to this example and variation; I adapted the drag/drop of the chessboard found there to my own particular needs for "Scrabble".
The code below is not final code for my Solitaire Scrabble program, but proof-of-concept, possibly usable by others wishing to drag a cell from a 1xN grid onto a MxM grid.
package components;
import java.awt.*;
import static java.awt.BorderLayout.NORTH;
import static java.awt.BorderLayout.SOUTH;
import java.awt.event.*;
import static java.lang.Integer.parseInt;
import javax.swing.*;
import static javax.swing.WindowConstants.DISPOSE_ON_CLOSE;
import javax.swing.event.MouseInputAdapter;
public class ChessBoard //implements MouseListener, MouseMotionListener
{
static Point parentLocation;
int homeRow, homeCol; // where to restore moved user letter if dropped on occupied cell
static int N = 11; // NxN 'chessboard' squares
static int S = 44; // square dimensions: SxS
static int W ; // chessboard dimensions: WxW
static int USER7 = 7;
static Font dragFont;
static JFrame frame;
JLayeredPane layeredPane;
static JPanel gamePanel, // encompasses both pnlGrid and pnlUser
pnlGrid,
pnlUser;
JLabel userDragLetter = new JLabel(); // main item to drag around or restore if needed
int xAdjustment, yAdjustment; // how to locate drops accurately
String userLetters[] ;
public ChessBoard() // constructor
{
W = S*N;
dragFont = new Font("Courier", Font.PLAIN, S);
userLetters = new String[USER7];
for (int i = 0; i < USER7; i++)
userLetters[i] = "" + (char)(65 + Math.random()*26);
Dimension gridSize = new Dimension(W, W);
Dimension userSize = new Dimension(W, S);
Dimension gameSize = new Dimension(W, (W + S));
frame = new JFrame();
frame.setSize(new Dimension(gameSize)); // DO NOT USE PREFERRED
layeredPane = new JLayeredPane();
layeredPane.setPreferredSize( gameSize ); // NO PREFERRED => NO GRID!
gamePanel = new JPanel();
// **EDIT** LOSE THIS LINE gamePanel.setLayout(new BorderLayout());
gamePanel.setPreferredSize(gameSize);
pnlGrid = new JPanel();
pnlGrid.setLayout(new GridLayout(N, N));
pnlGrid.setPreferredSize( gridSize );
pnlGrid.setBounds(0, 0, gridSize.width, gridSize.height);
pnlUser = new JPanel();
pnlUser.setLayout(new GridLayout(1, N));
pnlUser.setPreferredSize(userSize);
pnlUser.setBounds(0, gridSize.height, userSize.width, userSize.height);
layeredPane.add(pnlGrid, JLayeredPane.DEFAULT_LAYER); // panels to drag over
layeredPane.add(pnlUser, JLayeredPane.DEFAULT_LAYER); // " "
for (int i = 0; i < N; i++){
for (int j = 0; j < N; j++){
JPanel square = new JPanel();
square.setBackground( (i + j) % 2 == 0 ? Color.red : Color.white );
pnlGrid.add( square );
}
}
for (int i = 0; i < N; i++) {
JPanel square = new JPanel(new BorderLayout());
square.setBackground(Color.YELLOW);
pnlUser.add(square);
}
for (int i = 0; i < USER7; i++)
addPiece(i, 0, userLetters[i]);
gamePanel.addMouseListener(new MouseInputAdapter()
{
public void mousePressed (MouseEvent e){mousePressedActionPerformed (e);}
public void mouseReleased(MouseEvent e){mouseReleasedActionPerformed(e);}
});
gamePanel.addMouseMotionListener(new MouseMotionAdapter()
{
public void mouseDragged(MouseEvent me){mouseDraggedActionPerformed(me);}
});
// **EDIT: LOSE THE NEXT TWO LINES AND REPLACE BY THE LINE AFTER THEM**
// gamePanel.add(layeredPane, NORTH);
// gamePanel.add(pnlUser, SOUTH);
gamePanel.add(layeredPane);
}
private void addPiece(int col, int row, String glyph) {
JLabel piece = new JLabel(glyph, JLabel.CENTER);
piece.setFont(dragFont);
JPanel panel = (JPanel) pnlUser.getComponent(col + row * N);
piece.setName("piece " + glyph + " # " + row + " " + col);
panel.add(piece);
}
void mousePressedActionPerformed(MouseEvent e)
{
userDragLetter = null; // signal that we're not dragging if no piece is in the square
gamePanel.setCursor(new Cursor(Cursor.HAND_CURSOR));
Component c = pnlGrid.findComponentAt(e.getX(), e.getY());
if(c != null)
return; // Illegal to click pnlGrid
c = pnlUser.findComponentAt(e.getX(), e.getY() - pnlGrid.getHeight());
if(c == null | c instanceof JPanel)
return; // letter already played; can't drag empty cell
parentLocation = c.getParent().getLocation();
xAdjustment = parentLocation.x - e.getX();
yAdjustment = parentLocation.y - e.getY() + gamePanel.getHeight() - pnlUser.getHeight();
userDragLetter = (JLabel)c;
userDragLetter.setPreferredSize(new Dimension(S, S)); // prevent 2 letters in a square
userDragLetter.setLocation(e.getX() + xAdjustment, e.getY() + yAdjustment);
layeredPane.add(userDragLetter, JLayeredPane.DRAG_LAYER);
homeRow = parseInt(userDragLetter.getName().substring(10,11)); // save restore location
homeCol = parseInt(userDragLetter.getName().substring(12,13));
}
void mouseDraggedActionPerformed(MouseEvent me)
{
if (userDragLetter == null)
return; // nothing to drag
int x = me.getX() + xAdjustment; // make sure grid cell will be chosen in-bounds
int xMax = layeredPane.getWidth() - userDragLetter.getWidth();
x = Math.min(x, xMax);
x = Math.max(x, 0);
int y = me.getY() + yAdjustment;
int yMax = layeredPane.getHeight() - userDragLetter.getHeight();
y = Math.min(y, yMax);
y = Math.max(y, 0);
if(y >= pnlGrid.getHeight())
return; // can't drag to location off grid
userDragLetter.setLocation(x, y);
}
void mouseReleasedActionPerformed(MouseEvent e)
{
//**EDIT: CHANGED NEXT LINE**
gamePanel.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
if (userDragLetter == null)
return; // nothing to drag; nothing to release
// Make sure the chess piece is no longer painted on the layered pane
userDragLetter.setVisible(false);
layeredPane.remove(userDragLetter);
userDragLetter.setVisible(true);
int xMax = layeredPane.getWidth() - userDragLetter.getWidth();
int x = Math.min(e.getX(), xMax);
x = Math.max(x, 0);
int yMax = layeredPane.getHeight()- userDragLetter.getHeight();
int y = Math.min(e.getY(), yMax);
y = Math.max(y, 0);
Component c = pnlGrid.findComponentAt(x, y); // find deepest nested child component
if(c == null) // then grid cell is unoccupied so ...
c = pnlUser.findComponentAt(x, y); // see if there's a letter there ...
if(c == null | (c instanceof JLabel)){ // and if illegal or there is one, put it back...
userDragLetter.setLocation(parentLocation.x + xAdjustment,
parentLocation.y + yAdjustment + gamePanel.getHeight());
userDragLetter.setVisible(true);
addPiece(homeCol, homeRow,userDragLetter.getName().substring(6,7));
layeredPane.remove(userDragLetter);
return;
}
else // but if NO letter ...
{
Container parent = (Container)c;
parent.add( userDragLetter ); // put one in the grid cell
parent.validate();
}
userDragLetter.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
public static void main(String[] args)
{
new ChessBoard();
frame.add(gamePanel);
frame.setDefaultCloseOperation( DISPOSE_ON_CLOSE );
// frame.setResizable( false );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
}

Finishing Keno Java code?

This is what I am having trouble with. I am making a Keno game out of a Crystals code I was given. So far, I have been able to choose 20 of the 80 and turn them red. However, I have the button set to when I press it it says "Game is a draw" and the window closes.
I am trying to put in a code where it will randomly draw 20 numbers without repeating, and then they turn yellow, however, if the CPU and the human match a number, it will turn green. I have no idea how to start this code or how to go about doing it. Here is what I have:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import java.util.*;
import java.lang.String;
public class Kenogame {
// constants
public static final int WIDTH = 4;
public static final int HEIGHT = 20;
public static final int INITIAL = 0;
public static final int RED = 1;
public static final int YELLOW = 3;
public static final int CHECKED = 4;
private int turn = RED; // to track which player should play next
private int[][] playerGrid; // to record each player's move
private int[][] shadowGrid; // to keep track of which atoms have been FOUND
private int[][] crystalGrid; // to extract a single crystal from playerGrid
private int row, column; // position of most recently added atom
private int lowX, lowY, highX, highY; // corner coordinates of current crystal
private int player1Score = 0;
private int player2Score = 0;
// GUI related fields
private JButton[] buttonArray;
// private JTextField scoreField1;
// private JTextField scoreField2;
// private JLabel labelRED; // Label "Red" on GUI
// private JLabel labelYELLOW; // Label "Yellow" on GUI
private JLabel labelTurn; // Label displays whose turn is next
private int numberToSelect = 20;
Kenogame() {
createGUIAndPlay();
}
private void createGUIAndPlay() {
final JFrame f = new JFrame();
// create the panels
JPanel topPanel = new JPanel(new BorderLayout());
JPanel buttonPanel = new JPanel(new GridLayout(WIDTH, HEIGHT));
JPanel labelPanel = new JPanel();
// represents the 2D grid of buttons on the GUI
buttonArray = new JButton[WIDTH * HEIGHT];
// stores the positions of atoms in both player's crystals
playerGrid = new int[WIDTH][HEIGHT];
// shadowGrid keeps track of which atoms have been found
shadowGrid = new int[WIDTH][HEIGHT];
// used to store a crystal to determine if it is a perfect crystal
crystalGrid = new int[WIDTH][HEIGHT];
JButton endGameButton = new JButton("Start Draw");
// labelRED = new JLabel("Red");
// scoreField1 = new JTextField(3);
// scoreField1.setEditable(false);
//labelYELLOW = new JLabel("Yellow");
labelTurn = new JLabel(Integer.toString(numberToSelect), Label.LEFT);
Dimension dim = labelTurn.getPreferredSize();
labelTurn.setPreferredSize(new Dimension(dim.width + 100, dim.height + 10));
// scoreField2 = new JTextField(3);
// scoreField2.setEditable(false);
// scoreField1.setText("0");
// scoreField2.setText("0");
// create the buttons on which players will make their moves
for (int i = 0; i < HEIGHT * WIDTH; i++) {
buttonArray[i] = new JButton(Integer.toString(i + 1));
buttonPanel.add(buttonArray[i]);
}
final Color buttColor = buttonArray[0].getBackground();
// add the action listener to the buttons
for (int i = 0; i < HEIGHT * WIDTH; i++) {
buttonArray[i].setActionCommand(Integer.toString(i));
buttonArray[i].addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JButton button = (JButton) e.getSource();
if (button.getBackground() == Color.RED) {
button.setBackground(buttColor);
numberToSelect++;
} else {
if (numberToSelect > 0) {
button.setBackground(Color.RED);
numberToSelect--;
}
}
// button.setEnabled(false);
int buttonIndex = Integer.valueOf(button.getActionCommand());
row = buttonIndex / WIDTH;
column = buttonIndex % WIDTH;
// playMove();
labelTurn.setText(Integer.toString(numberToSelect));
// updateGUI();
}
});
}
endGameButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String s;
// Need to add "ball draw here" for Keno
// 20 random numbers between 1 and 80
// each time a "ball" matches one selected on the Keno ticket add to a counter
// at end look up payout for the number of matches corresponding to the counter
if (player1Score > player2Score)
s = "RED wins the game";
else if (player1Score < player2Score)
s = "YELLOW wins the game";
else
s = "Game is a draw";
JOptionPane.showMessageDialog(f, s, "Game Over", JOptionPane.PLAIN_MESSAGE);
System.exit(1);
}
});
labelPanel.add(endGameButton);
labelPanel.add(labelTurn);
topPanel.add(labelPanel, BorderLayout.NORTH);
topPanel.add(buttonPanel, BorderLayout.CENTER);
f.add(topPanel);
f.setSize(1000, 400);
f.setTitle("Keno");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
private void playMove() {
playerGrid[row][column] = turn;
if (turn == RED) {
turn = YELLOW;
} else {
turn = RED;
}
}
private void initialize() {
highX = highY = Integer.MIN_VALUE;
lowX = lowY = Integer.MAX_VALUE;
for (int row = 0; row < HEIGHT; row++)
for (int column = 0; column < WIDTH; column++) {
crystalGrid[row][column] = INITIAL;
}
}
public static void main(String[] args) {
new Keno();
}
}
// green for a match, yellow for a no-match.
I have 4 lines towards the bottom where I am supposed to insert the code. I would really appreciate it if someone could give me a hand on this.
To draw 20 non-repeating numbers, you can do the following:
put your 80 numbers in a collection.
shuffle the collection
the elements are now in random order and you can loop over the collection to get the first 20 elements.
If you give me more details on what you are stuck, I can provide further information.

Getting values of Grid's individual nodes (JAVA)

I want to create a program that can simulate the influence of a social structure of a matrix / grid. It's like an Erdos Renyi structure, but an nxn matrix where each node initially has a random value of +1 or -1. Each node has 4 neighbors (top, bottom, left, right) which also has values of +1 or -1. Thus, I can find the neighborhood of each node, which should be just a list / vector of the 4 values of those neighbors. The value of each node is then influenced by the neighbors' values, and the grid's values keep simulating and changing until an equilibrium is reached.
So far, I have a code which can create a grid with random -1 or +1 variables. Now, I am not sure how to get the values of each node (and its neighbors) inside the main method. I am a little confused as to how to go about this project so far, as in how to get the values.
In the main method, I cannot do like... int x = grid[0][1] etc. Sorry that I'm rusty in Java, but what topics can I look up in finding out the procedure to do this? I can't remember what it's called.
Also, is there a way that I can edit what each button (or node) on the grid says in the main method? Like, I can change it while it's looping, and I can also write what the values of its neighbors are? Thanks!
import javax.swing.JFrame;
import javax.swing.JButton;
import java.awt.GridLayout;
public class Grid {
JFrame frame = new JFrame(); // create frame
static JButton[][] grid;
// constructor
public Grid (int w, int l) {
frame.setLayout(new GridLayout(w, l));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
// create grid
grid = new JButton[w][l];
for (int y = 0; y < l; y++) {
int value = 0;
for (int x = 0; x < w; x++) {
// probability p
double p = 0.5;
// randomly allocate opinion
double random = Math.random();
if (random <= p)
value = -1;
else if (random > p)
value = 1;
grid[x][y] = new JButton("" + value);
frame.add(grid[x][y]);
}
}
}
public static void main (String[] args) {
// DIMENSION
// int d = 2;
// LENGTH
int l = 2;
// WIDTH
int w = 2;
new Grid(l,w); // create new Grid with parameters
}
}
I changed your approach a little bit, so it is more object-oriented. I hope this example makes clear, what you have to do. To get an basic understanding, google keywords like "encapsulation" or "object-orientation". There are many tutorials out there.
public class Grid {
private JFrame frame = new JFrame();
private JButton[][] grid; // Has to be a field of the object. static would make it to an field of the class
public Grid (int w, int l) {
frame.setLayout(new GridLayout(w, l));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
createGrid (w, l);
}
private void createGrid (int w, int l) {
// Your above implementation
}
public void stepInSimulation () {
// Your algorithm, you want to implement
}
public JButton[][] getGrid () {
return grid;
}
public static void main (String[] args) {
Grid grid = new Grid(2,2);
grid.getGrid ()[0][1]; // Access a value
grid.stepInSimulation (); // Do a step, call it in while loop, to do multiple steps
}
}
I hope this helps.

GridLayout stacks all JPanels on first cell

I am trying to create a map for a game I am making with a JPanel that uses gridLayout. In my first tests I use a 5x5 grid and create my small panels which are a subclass of JPanel. My program creates them fine but when I add all of the panels into the larger panel and display it, only the first square shows up and the rest is blank. Why does it do that?
Here is my code for the MapSpace(smaller panel):
import javax.swing.*;
import java.awt.*;
public class MapSpace extends JPanel{
private int ownerTag;
private int xPos, yPos;
public MapSpace(){
xPos = 0;
yPos = 0;
ownerTag = 0;
setBackground(Color.WHITE);
}
public MapSpace(MapSpace m){
xPos = m.getX();
yPos = m.getY();
ownerTag = m.getID();
setBackground(m.getColor());
}
and here is my code for the Map:
import javax.swing.*;
import java.awt.*;
import java.util.*;
public class Map extends JPanel{
private int cols, rows;
private int randCol, randRow;
private MapSpace[][] spaces;
Random gen = new Random();
public Map(int w, int h){
cols = h;
rows = w;
setLayout(new GridLayout(cols, rows));
setBackground(Color.WHITE);
spaces = new MapSpace[cols][rows];
for(int i = 0; i < cols; i++){
for(int j = 0; j < rows; j++){
MapSpace panel = new MapSpace(i, j);
spaces[i][j] = panel;
}
}
assignSpaces(3);
setColors();
for(int i = 0; i < cols; i++){
for(int j = 0; j < rows; j++){
MapSpace spot = new MapSpace(spaces[i][j]);
add(spot);
}
}
setSize(400, 400);
}
the second nested for loop is where all the mapSpaces are added but when I put the map in a JFrame and display it in a GUI window only one small square in the top left corner appears.
Why are you trying to create a MapSpace with an instance of MapSpace?
Just create the MapSpace with the parameters you want and then add the MapSpace to your Array and the panel at the same time.
and display it in a GUI window only one small square in the top left corner appears.
Probably because you don't give a preferredSize() size to your MapSpace class so it defaults to (10, 10) which is the size for a panel using a FlowLayout with no components added to it. So since you create a 5x5 grid you probably see a (50, 50) white square.
Override the getPreferredSize() of your MapSpace class to return the default Dimension for each square.

Custom JButton not sizing properly?

I am creating a matching game using Netbeans, but not the GUI editor (it sucks). So, basically, I created a new class, called Card, that extends the JButton class. Upon construction, the button's size is set to 100px by 100px and an icon is set. When I add the button to a JPanel in a GridBagLayout, it is not the intended size.
Here is some of my code:
JFRAME CLASS:
package matchinggame;
... imports ...
public class MatchingGameWindow extends JFrame {
Card[] cards = new Card[16]; //16 game cards
public MatchingGameWindow() {
...
//Create new game panel (for the cards)
JPanel gamePanel = new JPanel(new GridBagLayout());
//gamePanel.setSize(500,500); removed as it is not needed.
...
this.add(gamePanel, BorderLayout.CENTER);
//Create 16 card objects
cards = createCards();
//Create new grid bag constraints
GridBagConstraints gbc = new GridBagConstraints();
//Add the cards to the game panel
int i=0;
for (int y = 0; y < 4; y++) {
gbc.gridy = y;
for (int x = 0; x < 4; x++) {
gbc.gridx = x;
gamePanel.add(cards[i], gbc);
i++;
}
}
}
public final Card[] createCards() {
Card[] newCards = new Card[16];
//New choices array
ArrayList<Integer> choices = new ArrayList();
int[] choiceValues = {0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7};
//Add the initial choice values to the arraylist
for (int i=0; i < choiceValues.length; i++) {
choices.add(choiceValues[i]);
}
//Create 16 cards
for (int i=0; i < 16; i++) {
//Initial value of -1 for error checking
int iconIndex = -1;
//Loop until card is created
while (iconIndex == -1) {
//Get a random number from 0 - 7
Random r = new Random();
int rInt = r.nextInt(8);
//If the random number is one of the choices
if (choices.contains(rInt)) {
//the icon # will be the random number
iconIndex = rInt;
//Get rid of that choice (it is used up)
choices.remove(new Integer(rInt));
//Create a new Card in the Card[]
newCards[i] = new Card(i,iconIndex);
//If all the choices are gone
} else if (choices.isEmpty()){
iconIndex = -1; //done creating this card (breaks out of loop)
}
}
}
//Return the created cards
return newCards;
}
}
CARD CLASS:
package matchinggame;
import javax.swing.ImageIcon;
import javax.swing.JButton;
public class Card extends JButton {
final static ImageIcon defaultIcon = new ImageIcon("cardback.jpg");
ImageIcon secretIcon;
boolean isRevealed = false;
...
public Card(final int cardIndex, int secretIconIndex) {
//Size is 100px by 100px
setSize(100, 100);
//Default icon is card back image
setIcon(defaultIcon);
//Get the secret icon behind the back of the card
secretIcon = icons[secretIconIndex];
}
}
And using this code I get a result of this:
Any ideas as to what I am doing wrong here?
EDIT:
I overrided the getPreferredSize method like Hovercraft Full Of Eels said, and it worked!
I added this code in the Card class:
#Override
public Dimension getPreferredSize() {
return new Dimension(100,100);
}
and got my desired result:
Now I must be doing something wrong with the icons, as they are not showing up as they should.
You should not use setSize(...) in the class's constructor but rather override the class's getPreferredSize() method to return a Dimension(100, 100). And in fact you should have setSize(...) no-where in your program. Instead use decent layout managers, call pack() on the JFrame after adding all components and before setting it visible, and let the layout managers size the GUI appropriately.

Categories