Making a simple Mine Sweeper game in Java - java

I'm working on creating a simple mine sweeper game in java using JButtons. So far I have a code that creates a 20x20 grid of JButtons, but I am unsure of how I can get my bombs randomly assigned to multimple JButtons durring the game.
Here is what I have written so far:
MineSweeper Class:
import javax.swing.*;
import java.awt.GridLayout;
public class MineSweeper extends JFrame {
JPanel p = new JPanel();
bombButton points[][]= new bombButton[20][20];
public static void main(String args[]){
new MineSweeper();
}
public MineSweeper(){
super("Mine Sweeper Version: Beta");
setSize(400,400);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
p.setLayout(new GridLayout(20,20));
int y=0;
int counter=0;
while(counter<20){
for(int x=0;x<20;x++){
points[x][y] = new bombButton();
p.add(points[x][y]);
}
y++;
counter++;
}
add(p);
setVisible(true);
}
}
bombButton Class:
import javax.swing.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.net.URL;
public class bombButton extends JButton implements ActionListener {
ImageIcon Bomb,zero,one,two,three,four,five,six,seven,eight;
public bombButton(){
URL imageBomb = getClass().getResource("Bomb.png");
Bomb= new ImageIcon(imageBomb);
URL imageZero = getClass().getResource("0.jpg");
zero= new ImageIcon(imageZero);
URL imageOne = getClass().getResource("1.jpg");
one= new ImageIcon(imageOne);
URL imageTwo = getClass().getResource("2.jpg");
two= new ImageIcon(imageTwo);
URL imageThree = getClass().getResource("3.jpg");
three= new ImageIcon(imageThree);
URL imageFour = getClass().getResource("4.jpg");
four= new ImageIcon(imageFour);
URL imageFive = getClass().getResource("5.jpg");
five= new ImageIcon(imageFive);
URL imageSix = getClass().getResource("6.jpg");
six= new ImageIcon(imageSix);
URL imageSeven = getClass().getResource("7.jpg");
seven= new ImageIcon(imageSeven);
URL imageEight = getClass().getResource("8.jpg");
eight= new ImageIcon(imageEight);
this.addActionListener(this);
}
public void actionPerformed(ActionEvent e){
switch(){
case 0:
setIcon(null);
break;
case 1:
setIcon(Bomb);
break;
case 2:
setIcon(one);
break;
case 3:
setIcon(two);
break;
case 4:
setIcon(three);
break;
case 5:
setIcon(four);
break;
case 6:
setIcon(five);
break;
case 7:
setIcon(six);
break;
case 8:
setIcon(seven);
break;
case 9:
setIcon(eight);
break;
}
}
int randomWithRange(int min, int max)
{
int range = Math.abs(max - min) + 1;
return (int)(Math.random() * range) + (min <= max ? min : max);
}
}
As you can see I already have a randomizer set up, I just don't know how I should implement it. Should I use (X,Y) cordinates? How do I assign my bombs to random JButtons?
Thnak you to all in advance!

Create an ArrayList<JButton>, fill it with all your buttons, call Collections.shuffle(..) on the list, and then select the first N buttons to add mines to.
Having said this, my real recommendation is to chuck all this and go the MVC route where your data model, including where the mines are located, and your GUI are completely distinct.
here are some of my prior musings on this problem from 2011.

here are my Miseweeper Clone
package MWeeper;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
public class MMWeeper extends JFrame implements Runnable {
private JFrame mainFrame ;
private JPanel mainPanel;
private int boardX = 15;
private int boardY = 15;
private int bombs = 35;
private int bombsMarked;
private int cleanFields;
private int seconds;
private boolean gameOver = false;
private Map<Integer, Map<Integer, mweeperField>> boardMap;
private Map<Integer,position> bombMap;
private JPanel boardPanel;
private JPanel headPanel;
private JTextField bombsField;
#Override
public void run() {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
mainFrame = new JFrame("MMWEEEEEEPER");
int w = Toolkit.getDefaultToolkit().getScreenSize().width;
int h = Toolkit.getDefaultToolkit().getScreenSize().height;
mainFrame.setPreferredSize(new Dimension(350,390));
mainFrame.setResizable(true);
mainPanel = new JPanel(new BorderLayout());
init();
//setContent();
setPanel();
mainFrame.add(mainPanel);
mainFrame.setContentPane(mainFrame.getContentPane());
mainFrame.pack();
mainFrame.setLocationRelativeTo(null);
mainFrame.setVisible(true);
}
});
}
private void init() {
bombMap = new HashMap<Integer, MMWeeper.position>();
boardMap = new HashMap<Integer, Map<Integer,mweeperField>>();
bombsMarked = 0;
cleanFields = (boardX * boardY) - bombs;
seconds = 0;
for(int i = 1; i<= boardX; i++) {
boardMap.put(i, new HashMap<Integer, mweeperField>());
for(int j = 1; j <= boardY; j++) {
boardMap.get(i).put(j, new mweeperField(i, j ));
}
}
placeBombs();
}
private boolean placeBombs() {
Random pX = new Random();
Random pY = new Random();
int bombCount = 0;
//while( bombMap.size() < bombs ) {
while(bombCount < bombs) {
int x = (1 + pX.nextInt( boardX ) );
int y = (1 + pY.nextInt( boardY ) );
if(!boardMap.get(x).get(y).isBomb() ) {
boardMap.get(x).get(y).setBomb();
bombCount++;
bombMap.put(bombCount, new position(x, y));
}
}
return true;
}
private void setPanel() {
mainPanel.add(head(), BorderLayout.PAGE_START);
mainPanel.add(board(), BorderLayout.CENTER);
}
private JPanel head() {
headPanel = new JPanel(new BorderLayout());
bombsField = new JTextField(6);
bombsField.setEditable(true);
bombsField.setText( String.valueOf(bombs));
JButton start = new JButton("Start");
start.addActionListener( new mweeperAction(GameActions.START) );
headPanel.add(bombsField, BorderLayout.LINE_START);
headPanel.add(start, BorderLayout.LINE_END);
return headPanel;
}
private JPanel board() {
boardPanel = new JPanel();
GridLayout gLayout = new GridLayout(15, 15, 0, 0 );
boardPanel.setLayout(gLayout);
for( Integer x : boardMap.keySet()) {
for(Integer y : boardMap.get(x).keySet()) {
boardPanel.add( boardMap.get(x).get(y).getButton() );
}
}
return boardPanel;
}
private void gameOver() {
this.gameOver = true;
for( Integer x : boardMap.keySet()) {
for(Integer y : boardMap.get(x).keySet()) {
boardMap.get(x).get(y).trigger();
}
}
}
public class mweeperField implements mousePerformer {
private position pos;
private FieldStatus status = FieldStatus.HIDE_UNMARKED;
private boolean isBomb = false;
private int bombsAroundMe = 0;
private JButton but;
private boolean isTriggered = false;
public mweeperField( int x, int y ) {
this.pos = new position(x, y);
init();
}
public mweeperField( position p ) {
this.pos = p;
init();
}
public void resetField() {
status = FieldStatus.HIDE_UNMARKED;
isBomb = false;
bombsAroundMe = 0;
isTriggered = false;
but.setFont(new Font("Arial", Font.BOLD, 13));
but.setBackground(Color.LIGHT_GRAY);
but.setText(" ");
but.setEnabled(true);
}
public void setBomb() {
this.isBomb = true;
}
public boolean isBomb() {
return isBomb;
}
private void init() {
but = new JButton(" ");
but.setMaximumSize(new Dimension(16, 16));
but.setMinimumSize(new Dimension(16, 16));
but.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 1));
but.setMargin(new Insets(0, 0, 0, 0));
but.setBackground(Color.LIGHT_GRAY);
but.addMouseListener(new mweeperMouseListener(this.pos, this));
but.setFont(new Font("Arial", Font.BOLD, 14));
}
private void setButton() {
switch(status) {
case HIDE_MARKED:
//but.setForeground( new Color(224, 124, 168) );
but.setForeground( Color.RED);
but.setText("#");
but.setEnabled(true);
break;
case HIDE_UNMARKED:
but.setForeground(Color.BLACK);
but.setText(" ");
but.setEnabled(true);
break;
case OPEN_NOBOMB:
switch(this.bombsAroundMe) {
case 1:
case 2:
but.setForeground(Color.BLUE);
break;
case 3:
case 4:
but.setForeground(Color.MAGENTA);
break;
case 5:
case 6:
but.setForeground(Color.RED);
break;
case 7:
case 8:
but.setForeground(Color.PINK);
break;
}
String butText = " ";
if(this.bombsAroundMe > 0) {
butText = String.valueOf(this.bombsAroundMe);
}
but.setEnabled(false);
but.setText( butText );
break;
case OPEN_BOMB: // GAME OVER
but.setForeground(Color.BLACK);
but.setFont(new Font("Arial", Font.BOLD, 20));
but.setVerticalAlignment(SwingConstants.CENTER);
but.setHorizontalAlignment(SwingConstants.CENTER);
but.setText("*");
break;
}
// but.setEnabled(false);
but.validate();
but.repaint();
boardPanel.validate();
boardPanel.repaint();
mainPanel.repaint();
}
public JButton getButton() {
return but;
}
/*
+-----+-----+-----+
| x-1 | x | x+1 |
| y-1 | y-1 | y-1 |
+-----+-----+-----+
| x-1 | x/y | x+1 |
| y | | y |
+-----+-----+-----+
| x-1 | x | x+1 |
| y+1 | y+1 | y+1 |
+-----+-----+-----+
*/
private void scan() {
bombsAroundMe = 0;
for(Integer k : pos.posAroundMe.keySet() ) {
position p2 = pos.posAroundMe.get(k);
if(boardMap.get(p2.x).get(p2.y).isBomb()) {
bombsAroundMe++;
}
}
}
public void trigger() {
if(!isTriggered) {
isTriggered = true;
if(!isBomb) {
status = FieldStatus.OPEN_NOBOMB;
}else {
status = FieldStatus.OPEN_BOMB;
}
scan();
setButton();
if(bombsAroundMe == 0) {
// um mich herum triggern
for(Integer k : pos.posAroundMe.keySet() ) {
position p2 = pos.posAroundMe.get(k);
boardMap.get(p2.x).get(p2.y).trigger();
}
}
}
}
#Override
public void doClick(MouseEvent e, position pos) {
switch(e.getButton()) {
case 1: //Links Klick = triggern wenn nich markiert und hide
if(this.status.equals(FieldStatus.HIDE_UNMARKED)){
if(this.isBomb) {
// GAME OVER =8-(
status = FieldStatus.OPEN_BOMB;
but.setBackground(Color.RED);
gameOver();
}else {
trigger();
}
}
break;
case 3: // Rechtsklick
if(this.status.equals(FieldStatus.HIDE_UNMARKED)) {
// Mark Field
this.status = FieldStatus.HIDE_MARKED;
bombsMarked++;
}else {
// Umark Field
this.status = FieldStatus.HIDE_UNMARKED;
bombsMarked--;
}
setButton();
break;
}
}
}
public class position {
public int x = 0;
public int y = 0;
public Map<Integer, position> posAroundMe;
public position(int x, int y) {
this.x = x;
this.y = y;
posAroundMe = new HashMap<Integer, MMWeeper.position>();
setPosAroundMe();
}
public position(int x, int y, boolean setPos) {
posAroundMe = new HashMap<Integer, MMWeeper.position>();
this.x = x;
this.y = y;
}
private void setPosAroundMe() {
int c = 1;
for(int x2 = (x-1); x2 <= (x+1); x2++) {
for(int y2 = (y-1); y2 <= (y+1); y2++) {
if( ((x2 != x) || (y2 != y)) && ( x2>0 && x2<=boardX && y2>0 && y2<=boardY ) ){
posAroundMe.put(c++, new position(x2, y2, false));
}
}
}
}
}
public enum FieldStatus{
HIDE_UNMARKED,
HIDE_MARKED,
OPEN_NOBOMB,
OPEN_BOMB;
}
public enum GameActions{
START;
}
public class mweeperAction extends AbstractAction{
private GameActions gameAction;
public mweeperAction(GameActions ga ) {
this.gameAction = ga;
}
#Override
public void actionPerformed(ActionEvent ae) {
switch(gameAction) {
case START:
for( Integer x : boardMap.keySet()) {
for(Integer y : boardMap.get(x).keySet()) {
boardMap.get(x).get(y).resetField();;
boardMap.get(x).get(y).getButton().validate();
boardMap.get(x).get(y).getButton().repaint();;
}
}
int newBombCount = Integer.valueOf(bombsField.getText()) ;
if(newBombCount < 10) {
newBombCount = 10;
}
if(newBombCount > ((boardX * 2) + 20 ) ){
newBombCount = ((boardX * 2) + 20 );
}
bombs = newBombCount;
bombsField.setText(String.valueOf(bombs) );
placeBombs();
boardPanel.validate();
boardPanel.repaint();
mainPanel.repaint();
break;
}
}
}
public class mweeperMouseListener implements MouseListener{
private position pos;
mousePerformer performer;
public mweeperMouseListener(position pos, mousePerformer acPerf) {
this.pos = pos;
this.performer = acPerf;
}
#Override
public void mouseClicked(MouseEvent e) {
this.performer.doClick(e , pos );
}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
#Override
public void mousePressed(MouseEvent e) {}
#Override
public void mouseReleased(MouseEvent e) {}
}
public interface mousePerformer{
public void doClick(MouseEvent e, position pos );
}
public interface actionPerformer{
public void doAction(ActionEvent ae, GameActions ga );
}
}

Related

java swing reassign value in JButton[][]

I have this array of classes extending JButtons, and when one is clicked it registers that.
Then if another one gets clicked, they should 'switch' places. So my question is: How can i implement it that is swiches the buttons (so far i got before) and (the important part) how can i 'refresh' the GUI, so the user can see the chenge visually. Following the code:
import javax.swing.*; import Pieces.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Game extends JFrame {
private static final int width = 8;
private static final int height = 8;
private static Piece clicked;
public static Piece[][] fields = new Piece[width][height];
private JPanel main = new JPanel();
public static void init(JPanel g) {
for (int y = 0; y < fields.length; y++) {
for (int x = 0; x < fields[y].length; x++) {
if (y == 0) {
switch (x) {
case 0,7:
fields[y][x] = new Rook(x,y,1);
break;
case 1,6:
fields[y][x] = new Knight(x,y,1);
break;
case 2,5:
fields[y][x] = new Bishop(x,y,1);
break;
case 3:
fields[y][x] = new Queen(x,y,1);
break;
case 4:
fields[y][x] = new King(x,y,1);
break;
}
}
if (y == 1) fields[y][x] = new Pawn(x, y, 1);
else if (y >= 2 && y <= 5) fields[y][x] = new Empty(x,y,9);
else if (y == 6) fields[y][x] = new Pawn(x, y, 0);
else if(y == 7) {
switch (x) {
case 0,7:
fields[y][x] = new Rook(x,y,0);
break;
case 1,6:
fields[y][x] = new Knight(x,y,0);
break;
case 2,5:
fields[y][x] = new Bishop(x,y,0);
break;
case 3:
fields[y][x] = new Queen(x,y,0);
break;
case 4:
fields[y][x] = new King(x,y,0);
break;
}
}
fields[y][x].addActionListener(e -> {
var p = (Piece) e.getSource();
var pPos = p.getCell();
if(clicked == null) {
clicked = p;
System.out.println(fields[clicked.getCell().y][clicked.getCell().x]);
clicked.setForeground(Color.yellow.darker());
System.out.println("clicked " + pPos);
} else if (pPos == clicked.getCell()) {
clicked.setForeground(Color.white);
System.out.println("deselecting " + pPos);
clicked = null;
} else {
if (clicked.canMoveTo(fields, pPos)) {
fields[p.getCell().y][p.getCell().x] = clicked;
fields[clicked.getCell().y][clicked.getCell().x] = new Empty(clicked.getCell().x, clicked.getCell().y, 9);
System.out.println("moving " + clicked.getCell() + " to " + pPos);
clicked.setForeground(Color.white);
}
else System.out.println("canĀ“t move there, sry");
clicked = null;
}
SwingUtilities.updateComponentTreeUI(g);
});
g.add(fields[y][x]);
}
}
}
public Game() {
main.setBackground(Color.darkGray.darker());
main.setLayout(new GridLayout(8,8));
this.setSize(800,800);
init(main);
this.add(main);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
public static void main(String[] args) {
var g = new Game();
}
}
package Pieces;
import javax.swing.*;
import java.awt.*;
public abstract class Piece extends JButton {
private final int isWhite; //0 is false, 1 is true, 9 is undefined
private Point cell;
public Piece(int x, int y, int isWhite) {
cell = new Point(x, y);
this.isWhite = isWhite;
this.setForeground(Color.white);
this.setOpaque(false);
//this.setContentAreaFilled(false);
}
public Point getCell() {
return cell;
}
public int isWhite() {
return isWhite;
}
public boolean canMoveTo(Piece[][] fields, Point point) {
return true;
}
}
*all the pieces are setup like this
package Pieces;
public class Bishop extends Piece{
public Bishop(int x, int y, int isWhite) {
super(x, y, isWhite);
this.setText("Bishop");
}
}
(yee, this will hopefully be chess sometimes)

Sorting JPanels based on component

My program generates random numbers from 0 to 12 but if the result is 12 it would set dash as the text of JLabel, instead of the number generated.
Now, I wanted to sort my JPanel in ascending order based on the JLabel contents. In case of similarities in numbers, the black JPanels are placed on the left. It works fine except when there are dashes included, in which it doesn't sort properly. I would like to insert the JPanels containing dashes anywhere but it's not working as expected.
Screencaps from a shorter version of my program:
Pure numbers:
Dash included:
Here's the shorter version of my code (using the logic of integer sorting):
import java.awt.*;
import javax.swing.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;
import java.util.Comparator;
public class SortFrames extends JFrame
{
static ArrayList<JPanel> panels = new ArrayList<JPanel>();
JPanel panel = new JPanel();
JPanel sortPane = new JPanel();
int toWrite = 0;
int colorGen = 0;
int comparison = 0;
Random rand = new Random();
public SortFrames()
{
for(int i = 0; i<4;i++)
{
panels.add(new JPanel());
}
for(JPanel p: panels)
{
toWrite = rand.nextInt(13);
colorGen = rand.nextInt(2);
p.add(new JLabel());
JLabel lblToSet = (JLabel)p.getComponent(0);
if(colorGen == 0)
{
p.setBackground(Color.BLACK);
lblToSet.setForeground(Color.WHITE);
}
if(colorGen == 1)
{
p.setBackground(Color.WHITE);
lblToSet.setForeground(Color.BLACK);
}
if(toWrite != 12){lblToSet.setText("" +toWrite);}
if(toWrite == 12){lblToSet.setText("-");}
p.setPreferredSize(new Dimension(30, 30));
panel.add(p);
}
sortMethod();
for(JPanel p: panels)
{
panel.add(p);
panel.revalidate();
}
add(panel);
panel.setPreferredSize(new Dimension(300, 300));
setPreferredSize(new Dimension(300, 300));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
pack();
setLocationRelativeTo(null);
}
public void sortMethod()
{
for(int i = 0; i<(panels.size());i++)
{
for(int j = i+1; j<(panels.size());j++)
{
JLabel one = (JLabel)(panels.get(i)).getComponent(0);
JLabel two = (JLabel)(panels.get(j)).getComponent(0);
String lblOne = one.getText();
String lblTwo = two.getText();
if(!lblOne.equals("-") && !lblTwo.equals("-"))
{
int comp1 = Integer.parseInt(lblOne);
int comp2 = Integer.parseInt(lblTwo);
JPanel pnl1 = panels.get(i);
JPanel pnl2 = panels.get(j);
if(comp1 == comp2)
{
if(pnl1.getBackground() == Color.BLACK && pnl2.getBackground() == Color.WHITE)
{
panels.set(i, pnl1);
panels.set(j, pnl2);
}
if(pnl1.getBackground() == Color.WHITE && pnl2.getBackground() == Color.BLACK)
{
panels.set(i, pnl2);
panels.set(j, pnl1);
}
}
if(comp1 != comp2)
{
if(comp1>comp2)
{
panels.set(i, pnl2);
panels.set(j, pnl1);
}
}
}
if(lblOne.equals("-") && !lblTwo.equals("-"))
{
JPanel pnl1 = panels.get(i);
panels.set(rand.nextInt(panels.size()), pnl1);
}
if(!lblOne.equals("-") && lblTwo.equals("-"))
{
JPanel pnl2 = panels.get(j);
panels.set(rand.nextInt(panels.size()), pnl2);
}
}
}
}
public static void main(String args[])
{
new SortFrames();
}
}
I also have another method, which is by using Comparator class which also creates the same problem (this sorts equal numbers based on foreground but still the same as to sort equal numbers based on background so it has no effect on the said issue).
private static class JPanelSort implements Comparator<JPanel>
{
#Override
public int compare(JPanel arg0, JPanel arg1)
{
JLabel one = ((JLabel) arg0.getComponent(0));
JLabel two = ((JLabel) arg1.getComponent(0));
String firstContent = one.getText();
String secondContent = two.getText();
try
{
comparisonRes = Integer.compare(Integer.parseInt(firstContent), Integer.parseInt(secondContent));
if(comparisonRes == 0)
{
if(one.getForeground() == Color.BLACK && two.getForeground() == Color.WHITE)
{
comparisonRes = 1;
}
if(two.getForeground() == Color.BLACK && one.getForeground() == Color.WHITE)
{
comparisonRes = -1;
}
}
}
catch(NumberFormatException e)
{
comparisonRes = 0;
}
return comparisonRes;
}
}
Please tell me your ideas. Thank you.
It's much easier to sort data than to sort JPanels.
Here's mu GUI displaying your numbers.
So, lets create a Java object to hold the card data.
public class DataModel {
private final int number;
private final int colorNumber;
private final Color backgroundColor;
private final Color foregroundColor;
public DataModel(int number, int colorNumber, Color backgroundColor,
Color foregroundColor) {
this.number = number;
this.colorNumber = colorNumber;
this.backgroundColor = backgroundColor;
this.foregroundColor = foregroundColor;
}
public int getNumber() {
return number;
}
public int getColorNumber() {
return colorNumber;
}
public Color getBackgroundColor() {
return backgroundColor;
}
public Color getForegroundColor() {
return foregroundColor;
}
}
Pretty straightforward. We have fields to hold the information and getters to retrieve the information. We can make all the fields final since we're not changing anything once we set the values.
The sort class is pretty simple as well.
public class DataModelComparator implements Comparator<DataModel> {
#Override
public int compare(DataModel o1, DataModel o2) {
if (o1.getNumber() < o2.getNumber()) {
return -1;
} else if (o1.getNumber() > o2.getNumber()) {
return 1;
} else {
if (o1.getColorNumber() < o2.getColorNumber()) {
return -1;
} else if (o1.getColorNumber() > o2.getColorNumber()) {
return 1;
} else {
return 0;
}
}
}
}
Since we keep the color number, sorting by color is as easy as sorting a number.
Now that we've moved the data to it's own List, we can concentrate on creating the GUI.
package com.ggl.testing;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class SortFrames implements Runnable {
private List<DataModel> dataModels;
private JPanel[] panels;
private JLabel[] labels;
private Random random = new Random();
public SortFrames() {
this.dataModels = new ArrayList<>();
this.random = new Random();
for (int i = 0; i < 4; i++) {
int number = random.nextInt(13);
int colorNumber = random.nextInt(2);
Color backgroundColor = Color.BLACK;
Color foregroundColor = Color.WHITE;
if (colorNumber == 1) {
backgroundColor = Color.WHITE;
foregroundColor = Color.BLACK;
}
dataModels.add(new DataModel(number, colorNumber, backgroundColor,
foregroundColor));
}
Collections.sort(dataModels, new DataModelComparator());
}
#Override
public void run() {
JFrame frame = new JFrame("Sort Frames");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel mainPanel = new JPanel();
panels = new JPanel[dataModels.size()];
labels = new JLabel[dataModels.size()];
for (int i = 0; i < dataModels.size(); i++) {
DataModel dataModel = dataModels.get(i);
panels[i] = new JPanel();
panels[i].setBackground(dataModel.getBackgroundColor());
labels[i] = new JLabel(getDisplayText(dataModel));
labels[i].setBackground(dataModel.getBackgroundColor());
labels[i].setForeground(dataModel.getForegroundColor());
panels[i].add(labels[i]);
mainPanel.add(panels[i]);
}
frame.add(mainPanel);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
private String getDisplayText(DataModel dataModel) {
if (dataModel.getNumber() == 12) {
return "-";
} else {
return Integer.toString(dataModel.getNumber());
}
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new SortFrames());
}
public class DataModel {
private final int number;
private final int colorNumber;
private final Color backgroundColor;
private final Color foregroundColor;
public DataModel(int number, int colorNumber, Color backgroundColor,
Color foregroundColor) {
this.number = number;
this.colorNumber = colorNumber;
this.backgroundColor = backgroundColor;
this.foregroundColor = foregroundColor;
}
public int getNumber() {
return number;
}
public int getColorNumber() {
return colorNumber;
}
public Color getBackgroundColor() {
return backgroundColor;
}
public Color getForegroundColor() {
return foregroundColor;
}
}
public class DataModelComparator implements Comparator<DataModel> {
#Override
public int compare(DataModel o1, DataModel o2) {
if (o1.getNumber() < o2.getNumber()) {
return -1;
} else if (o1.getNumber() > o2.getNumber()) {
return 1;
} else {
if (o1.getColorNumber() < o2.getColorNumber()) {
return -1;
} else if (o1.getColorNumber() > o2.getColorNumber()) {
return 1;
} else {
return 0;
}
}
}
}
}
The lessons to be learned here are:
Separate the data from the view.
Focus on one part of the problem at a time. Divide and conquer.

Hello I am creating a TicTacToe game for myself to understand Java better

however I am not sure where I am supposed to enter the whoWins() method. Do I enter this method in the actionperformed Method of the buttons or do i need to something different. Please help.
public class TTT extends JFrame implements ActionListener {
private JButton buttons[] = new JButton[9];
private JButton exitButton;
public JLabel title;
public JPanel titlePanel, panel;
private int count = 0;
int symbolCount = 0;
private boolean win = false;
public TTT() {
title = new JLabel("Welcome to my Tic Tac Toe Game!");
titlePanel = new JPanel();
title.setFont(new Font(Font.SERIF, 0, 30));
titlePanel.add(title);
this.add(titlePanel, BorderLayout.NORTH);
panel = new JPanel(new GridLayout(3, 3));
for (int i = 0; i < buttons.length; i++) {
buttons[i] = new JButton();
panel.add(buttons[i]);
buttons[i].setEnabled(true);
buttons[i].addActionListener(this);
}
this.add(panel, BorderLayout.CENTER);
JPanel panel1 = new JPanel(new FlowLayout(FlowLayout.CENTER));
exitButton = new JButton("Quit");
panel1.add(exitButton);
this.add(panel1, BorderLayout.SOUTH);
exitButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(WIDTH);
}
});
}
public void whoWins() {
//Determines who wins using for the horizontal rows.
if (buttons[0].getText() == buttons[1].getText() && buttons[1].getText() == buttons[2].getText() && buttons[0].getText() != "") {
win = true;
} else if (buttons[3].getText() == buttons[4].getText() && buttons[4].getText() == buttons[5].getText() && buttons[3].getText() != "") {
win = true;
} else if (buttons[6].getText() == buttons[7].getText() && buttons[7].getText() == buttons[8].getText() && buttons[6].getText() != "") {
win = true;
} //Determines the verticles wins
else if (buttons[0].getText() == buttons[3].getText() && buttons[3].getText() == buttons[6].getText() && buttons[0].getText() != "") {
win = true;
} else if (buttons[1].getText() == buttons[4].getText() && buttons[4].getText() == buttons[7].getText() && buttons[1].getText() != "") {
win = true;
} else if (buttons[2].getText() == buttons[5].getText() && buttons[5].getText() == buttons[8].getText() && buttons[2].getText() != "") {
win = true;
}
// Diagnol Wins
else if (buttons[0].getText()==buttons[4].getText()&&buttons[4].getText()==buttons[8].getText()&& buttons[0].getText()!= "") {
win = true;
}else if (buttons[2].getText()==buttons[4].getText()&&buttons[4].getText()==buttons[6].getText()&& buttons[1].getText()!= "") {
win = true;
}else {
win = false;
}
//who won
if (win = true) {
JOptionPane.showMessageDialog(null, "wins");
}else if (count == 9 && win == false) {
JOptionPane.showMessageDialog(null, "Tie game");
}
}
public static void main(String[] args) {
TTT ref1 = new TTT();
ref1.setTitle("Tic Tac Toe");
ref1.setVisible(true);
ref1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ref1.setSize(500, 500);
ref1.setLocationRelativeTo(null);
// ref1.whoWins();
}
#Override
public void actionPerformed(ActionEvent e) {
count++;
for (JButton button : buttons) {
if (button == e.getSource()) {
if (symbolCount % 2 == 0) {
button.setText("X");
button.setEnabled(false);
} else {
button.setText("O");
button.setEnabled(false);
}
}
}
if (count >= buttons.length) {
JOptionPane.showMessageDialog(null, "End");
}
symbolCount++;
}
}
If you really want to do this right, then I suggest making some big changes, some M-V-C type changes:
First and foremost, separate out the logic of the game from the game GUI. This would mean that the code that determines who wins should not be in any code that contains GUI type code. This will be your "model"
Next you should never have GUI code implement listener interfaces, so try to get that out of the GUI and possibly have it go into its own class, the "Control" class.
Finally the GUI or "View" class will concern itself with displaying the model's state and getting input from the user and transmitting this input to the control.
For example,...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.Window;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.util.EnumMap;
import java.util.Map;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.SwingPropertyChangeSupport;
public class TicTacToeMain {
private static void createAndShowGui() {
TttView view = null;
try {
view = new TttView();
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
TttModel model = new TttModel();
new TttControl(model, view);
JFrame frame = new JFrame("Tic Tac Toe");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(view.getMainPanel());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
enum TttPiece {
EMPTY, X, O
}
class TttView {
public static final String IMAGE = "/imgFolder/TicTacToe.png";
private static final int GAP = 5;
private JPanel mainPanel = new JPanel();
private JPanel tttPanel = new JPanel();
private Map<TttPiece, Icon> iconMap = new EnumMap<>(TttPiece.class);
private JLabel[][] grid = new JLabel[TttModel.ROWS][TttModel.COLS];
private TttControl control;
public TttView() throws IOException {
BufferedImage img = ImageIO.read(getClass().getResourceAsStream(IMAGE));
Icon[] imgIcons = splitImg(img);
iconMap.put(TttPiece.X, imgIcons[0]);
iconMap.put(TttPiece.O, imgIcons[1]);
iconMap.put(TttPiece.EMPTY, createEmptyIcon(imgIcons[0]));
tttPanel.setLayout(new GridLayout(grid.length, grid[0].length, GAP, GAP));
tttPanel.setBackground(Color.black);
MyMouseAdapter mouseAdapter = new MyMouseAdapter();
for (int row = 0; row < grid.length; row++) {
for (int col = 0; col < grid[row].length; col++) {
grid[row][col] = new JLabel(iconMap.get(TttPiece.EMPTY));
grid[row][col].setOpaque(true);
grid[row][col].setBackground(Color.LIGHT_GRAY);
grid[row][col].addMouseListener(mouseAdapter);
tttPanel.add(grid[row][col]);
}
}
JPanel btnPanel = new JPanel(new GridLayout(1, 0, 5, 0));
btnPanel.add(new JButton(new ClearAction("Clear", KeyEvent.VK_C)));
btnPanel.add(new JButton(new ExitAction("Exit", KeyEvent.VK_X)));
int blGap = 2;
mainPanel.setLayout(new BorderLayout(blGap, blGap));
mainPanel.setBorder(BorderFactory.createEmptyBorder(blGap, blGap, blGap,
blGap));
mainPanel.add(tttPanel, BorderLayout.CENTER);
mainPanel.add(btnPanel, BorderLayout.SOUTH);
}
public void setControl(TttControl control) {
this.control = control;
}
public JComponent getMainPanel() {
return mainPanel;
}
private Icon createEmptyIcon(Icon icon) {
int width = icon.getIconWidth();
int height = icon.getIconHeight();
BufferedImage img = new BufferedImage(width, height,
BufferedImage.TYPE_INT_ARGB);
return new ImageIcon(img);
}
private Icon[] splitImg(BufferedImage img) {
int w = img.getWidth();
int h = img.getHeight();
int gap = 5;
Icon[] icons = new ImageIcon[2];
icons[0] = new ImageIcon(img.getSubimage(0, 0, w / 2 - gap, h / 2 - gap));
icons[1] = new ImageIcon(img.getSubimage(w / 2 + gap, 0, w / 2 - gap, h
/ 2 - gap));
return icons;
}
private class MyMouseAdapter extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
if (control == null) {
return;
}
for (int row = 0; row < grid.length; row++) {
for (int col = 0; col < grid[row].length; col++) {
if (grid[row][col] == e.getSource()) {
control.gridPress(row, col);
}
}
}
}
}
private class ClearAction extends AbstractAction {
public ClearAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent evt) {
if (control != null) {
control.clear();
}
}
}
private class ExitAction extends AbstractAction {
public ExitAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent evt) {
if (control != null) {
control.exit(evt);
}
}
}
public void setGridIcon(int row, int col, TttPiece tttPiece) {
grid[row][col].setIcon(iconMap.get(tttPiece));
}
}
class TttControl {
private TttModel model;
private TttView view;
public TttControl(TttModel model, TttView view) {
this.model = model;
this.view = view;
view.setControl(this);
model.addPropertyChangeListener(new ModelListener());
}
public void exit(ActionEvent evt) {
Window win = SwingUtilities
.getWindowAncestor((Component) evt.getSource());
win.dispose();
}
public void gridPress(int row, int col) {
try {
model.gridPress(row, col);
} catch (TttException e) {
// TODO: notify user
// e.printStackTrace();
}
}
public void clear() {
model.clear();
}
private class ModelListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (TttModel.GRID_POSITION.equals(evt.getPropertyName())) {
TttPiece[][] tttGrid = model.getTttGrid();
for (int row = 0; row < tttGrid.length; row++) {
for (int col = 0; col < tttGrid[row].length; col++) {
view.setGridIcon(row, col, tttGrid[row][col]);
}
}
}
}
}
}
class TttModel {
public static final int ROWS = 3;
public static final int COLS = ROWS;
public static final String GRID_POSITION = "grid position";
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(
this);
private TttPiece[][] tttGrid = new TttPiece[ROWS][COLS];
private TttPiece player = TttPiece.X;
private boolean gameOver;
public TttModel() {
clear();
}
public void setGridPosition(int row, int col, TttPiece piece)
throws TttException {
if (gameOver) {
return;
}
if (tttGrid[row][col] == TttPiece.EMPTY) {
tttGrid[row][col] = piece;
checkForWin(row, col, piece);
nextPlayer();
pcSupport.firePropertyChange(GRID_POSITION, null, tttGrid);
} else {
String message = "Invalid setGridPosition for row: %d, col: %d, piece: %s. "
+ "Spot already occupied by piece: %s";
message = String.format(message, row, col, piece, tttGrid[row][col]);
throw new TttException(message);
}
}
public TttPiece[][] getTttGrid() {
return tttGrid;
}
public void gridPress(int row, int col) throws TttException {
setGridPosition(row, col, player);
}
public void nextPlayer() {
player = player == TttPiece.X ? TttPiece.O : TttPiece.X;
}
private void checkForWin(int row, int col, TttPiece piece) {
// TODO finish
}
public void clear() {
for (int row = 0; row < tttGrid.length; row++) {
for (int col = 0; col < tttGrid[row].length; col++) {
tttGrid[row][col] = TttPiece.EMPTY;
}
}
player = TttPiece.X;
pcSupport.firePropertyChange(GRID_POSITION, null, tttGrid);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcSupport.removePropertyChangeListener(listener);
}
}
#SuppressWarnings("serial")
class TttException extends Exception {
public TttException() {
super();
}
public TttException(String message) {
super(message);
}
}
Using for my images:
With GUI looking like:
I am also interested in writing a Tic Tac Toe game, so I copied your code, and did a little modification, and it passed test, check following:
package eric.j2se.swing;
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Font;
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.JOptionPane;
import javax.swing.JPanel;
/**
* <p>
* Simple game of Tic Tac Toe.
* </p>
*
* #author eric
* #date Apr 16, 2014 11:03:48 AM
*/
#SuppressWarnings("serial")
public class TicTacToe extends JFrame implements ActionListener {
// 2 players
public static final char playerX = 'X';
public static final char playerO = 'O';
// null player
public static final char playerN = 'N';
// the winer, init to null player
private Character winner = playerN;
// indicate whether game over
private boolean gameOver = false;
// count of button used,
private int count = 0;
private Character buttonPlayers[] = new Character[9];
private JButton buttons[] = new JButton[9];
private JButton exitButton;
public JLabel title;
public JPanel titlePanel, panel;
public TicTacToe() {
// init buttonPlayers
for (int i = 0; i < 9; i++) {
buttonPlayers[i] = playerN;
}
// init title
title = new JLabel("Welcome to Tic Tac Toe!");
titlePanel = new JPanel();
title.setFont(new Font(Font.SERIF, 0, 30));
titlePanel.add(title);
this.add(titlePanel, BorderLayout.NORTH);
// init 9 button
panel = new JPanel(new GridLayout(3, 3));
for (int i = 0; i < buttons.length; i++) {
buttons[i] = new JButton();
panel.add(buttons[i]);
buttons[i].setEnabled(true);
buttons[i].addActionListener(this);
}
// init exit button
this.add(panel, BorderLayout.CENTER);
JPanel panel1 = new JPanel(new FlowLayout(FlowLayout.CENTER));
exitButton = new JButton("Quit");
panel1.add(exitButton);
this.add(panel1, BorderLayout.SOUTH);
exitButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(WIDTH);
}
});
}
public void whoWins() {
// determine winner - horizontal rows
if (!gameOver) {
for (int i = 0; i < 3; i++) {
if ((buttonPlayers[0 + i * 3] != playerN) && (buttonPlayers[0 + i * 3].equals(buttonPlayers[1 + i * 3]))
&& buttonPlayers[1 + i * 3].equals(buttonPlayers[2 + i * 3])) {
winner = buttonPlayers[0 + i * 3];
gameOver = true;
break;
}
}
}
// determine winner - vertical rows
if (!gameOver) {
for (int i = 0; i < 3; i++) {
if ((buttonPlayers[i + 0 * 3] != playerN) && (buttonPlayers[i + 0 * 3].equals(buttonPlayers[i + 1 * 3]))
&& buttonPlayers[i + 1 * 3].equals(buttonPlayers[i + 2 * 3])) {
winner = buttonPlayers[i + 0 * 3];
gameOver = true;
break;
}
}
}
// determine winner - diagonal rows
if (!gameOver) {
int winButtonIndex = -1;
if ((buttonPlayers[0] != playerN) && (buttonPlayers[0].equals(buttonPlayers[4])) && buttonPlayers[4].equals(buttonPlayers[8])) {
winButtonIndex = 0;
} else if ((buttonPlayers[2] != playerN) && (buttonPlayers[2].equals(buttonPlayers[4])) && buttonPlayers[4].equals(buttonPlayers[6])) {
winButtonIndex = 2;
}
if (winButtonIndex >= 0) {
winner = buttonPlayers[winButtonIndex];
gameOver = true;
}
}
// full
if (count == 9) {
gameOver = true;
}
if (gameOver) {
String tip = "";
switch (winner) {
case playerO:
tip = "Player O win!";
break;
case playerX:
tip = "Player X win!";
break;
default:
tip = "Draw game!";
break;
}
JOptionPane.showMessageDialog(null, tip);
}
}
#Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < buttons.length; i++) {
JButton button = buttons[i];
if (button == e.getSource()) {
Character currentPlayer = (count % 2 == 1 ? playerX : playerO);
button.setText(String.valueOf(currentPlayer));
buttonPlayers[i] = currentPlayer;
button.setEnabled(false);
break;
}
}
count++;
whoWins();
}
public static void main(String[] args) {
TicTacToe ref1 = new TicTacToe();
ref1.setTitle("Tic Tac Toe");
ref1.setVisible(true);
ref1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ref1.setSize(500, 500);
ref1.setLocationRelativeTo(null);
}
}
about when to call the win check:
check each time you click 1 of the 9 buttons,
about the flag:
I use 2 flag instead of 1 flag to indicate game over & winner, because in TTT game, draw game is very usual, after play several times, you always get draw game ...
a little suggestion to your code:
when compare string, use equals(), not ==,
define const values in variable, not write it in logic, e.g. 'O' 'X',
don't repeat code, try use logic control to make it short & easy to read & easy to maintain,

Java Applet - For Loop to decrement a stack of components

I've created an Applet that creates a row of buttons, up to 15 buttons, when you push the "add to queue" button. I now want to decrement that row using a for loop. I want it to decrement from left to right. I can only get it to decrement from right to left. I know it has to do with the code in my "Remove" method, but I can't seem to figure out how to fix it. As a newbie I would appreciate any help you can provide.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
public class Main extends javax.swing.JApplet {
private final int width = 60;
private final int height = 24;
private final int maxItems = 15;
private int x = 40 + width;
private int y = 260;
private int count = 1;
private JButton jAdd;
private JButton jRemove;
Vector<JButton> stack = new Vector<JButton>();
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
Main inst = new Main();
frame.getContentPane().add(inst);
((JComponent) frame.getContentPane()).setPreferredSize(inst
.getSize());
frame.pack();
frame.setVisible(true);
}
});
}
public Main() {
super();
initGUI();
}
private void initGUI() {
try {
this.setSize(719, 333);
getContentPane().setLayout(null);
{
jAdd = new JButton();
getContentPane().add(jAdd);
jAdd.setText("Add to Queue");
jAdd.setBounds(43, 300, 150, 24);
jAdd.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
jAddActionPerformed(evt);
}
});
}
{
jRemove = new JButton();
getContentPane().add(jRemove);
jRemove.setText("Remove from queue");
jRemove.setBounds(950, 300, 150, 24);
jRemove.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
jRemoveActionPerformed(evt);
}
});
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void jAddActionPerformed(ActionEvent evt) {
if (count > maxItems) {
JOptionPane.showMessageDialog(null, "The queue is full");
return;
}
JButton b = new JButton();
stack.add(0, b);
getContentPane().add(b);
int textCount = count;
b.setText("" +textCount++);
b.setBounds(x, y, width, height);
x = x + width;
count++;
}
private void jRemoveActionPerformed(ActionEvent evt) {
if (stack.isEmpty()) {
JOptionPane.showMessageDialog(null, "The queue is empty");
return;
}
JButton b = stack.remove(0);
this.remove(b);
for(int originalX = 880; originalX < 880; originalX--){
x = 880 - width;
}
repaint();
count--;
}
}
The issue is this:
stack.add(0, b);
You are always adding the new one to the start of the Vector (index 0). Remove that and you will see the behavior you want.
stack.add(b);

Trying to learn the ins and outs of javax.swing

So I've been trying to get the handle of javax.swing and am having some trouble. I am attempting to implement the '8 puzzle', where there are 8 tiles and one open spot set up in a 3x3 grid, when a tile adjacent to the open spot is clicked it trades spaces with the open spot. My structure consists of a JFrame, which contains a JPanel, and the JPanel contains the 9 tiles as JComponents, however only the JPanel renders, and the tiles are nowhere to be found. Any help with this problem would be greatly appreciated.
import javax.swing.*;
public class MainFrame{
public static void main(String[] args){
JFrame frame = new JFrame("8 Puzzle");
frame.setVisible(true);
frame.setSize(600, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
PieceManager pm = new PieceManager();
frame.add(pm);
}
}
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Random;
import javax.swing.*;
Second class
public class PieceManager extends JPanel{
int[] possmoves;
GameTile[] pieces;
int openSpot;
public PieceManager(){
this.setSize(600,600);
this.setBackground(new Color(255,255,255));
this.setLayout(new GridLayout(3,3));
pieces = new GameTile[9];
this.init();
this.addMouseListener(new ClickAction());
}
public void init(){
ArrayList<Integer> nums = new ArrayList<Integer>();
Random rand = new Random();
for(int i=0;i<9;i++){
nums.add(i);
}
for(int i=0,j=8;i<8;i++,j--){
int p = rand.nextInt(j);
GameTile x = new GameTile(i,nums.remove(p));
pieces[i]=x;
nums.removeAll(Collections.singleton(null));
}
GameTile z = new GameTile(8,nums.get(0));
pieces[8]=z;
possmoves = new int[4];
boolean found = false;
for(int i=0;i<9||found;i++){
if(pieces[i].getID()==0){
openSpot = pieces[i].getPos();
}
}
setOpenSpot();
paint();
}
public void paint(){
this.removeAll();
for(int i=0;i<9;i++){
this.add(pieces[i]);
pieces[i].setVisible(true);
}
}
public void setOpenSpot(){
Arrays.fill(possmoves,-1);
if(openSpot==0){
possmoves[0]=1;
possmoves[1]=3;
} else if(openSpot==1){
possmoves[0]=0;
possmoves[1]=2;
possmoves[3]=4;
} else if(openSpot==2){
possmoves[0]=1;
possmoves[1]=5;
} else if(openSpot==3){
possmoves[0]=0;
possmoves[1]=4;
possmoves[2]=6;
} else if(openSpot==4){
possmoves[0]=1;
possmoves[1]=3;
possmoves[2]=5;
possmoves[3]=7;
} else if(openSpot==5){
possmoves[0]=2;
possmoves[1]=4;
possmoves[3]=8;
} else if(openSpot==6){
possmoves[0]=3;
possmoves[1]=7;
} else if(openSpot==7){
possmoves[0]=6;
possmoves[1]=4;
possmoves[2]=8;
} else if(openSpot==8){
possmoves[0]=5;
possmoves[1]=7;
}
}
public void checkCorrect(){
}
public class ClickAction implements MouseListener{
#Override
public void mouseClicked(MouseEvent e) {
int x = e.getX();
int y = e.getY();
int pX=(int)Math.floor(x/200);
int pY=(int)Math.floor(y/200);
int piecepressed=(pY*3)+pX;
boolean moveable = false;
int toBeMoved = -1;
for(int i=0;i<4;i++){
if(piecepressed==possmoves[i]){
moveable=true;
toBeMoved=possmoves[i];
}
}
if(moveable){
GameTile saved=pieces[openSpot];
pieces[openSpot]=pieces[toBeMoved];
pieces[toBeMoved]=saved;
openSpot=toBeMoved;
setOpenSpot();
paint();
checkCorrect();
}
}
#Override
public void mouseEntered(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseExited(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mousePressed(MouseEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void mouseReleased(MouseEvent arg0) {
// TODO Auto-generated method stub
}
}
}
Tile Class (3rd and final)
import java.awt.*;
import javax.swing.JComponent;
public class GameTile extends JComponent{
private int id;
private int position;
public GameTile(int id, int initpos){
if(id==0){
this.id=id;
this.position=initpos;
} else{
this.id=id;
this.position = initpos;
String label = Integer.toString(id);
setSize(200,200);
setBackground(new Color(0,0,0));
Label l = new Label(label,Label.CENTER);
this.add(l);
l.setVisible(true);
}
}
public void setPos(int position){
this.position=position;
}
public int getPos(){
return position;
}
public int getID(){
return id;
}
}
Use of a JComponent is fine, but you'll probably want to set it to be opaque.
Also
Don't mix AWT (i.e., Label) with Swing components.
Don't setSize(...). Instead deal with preferredSize. Best to override getPreferredSize() and return an appropriate Dimension. I've used setPreferredSize(...) in a pinch, but at the risk of the wrath of kleopatra.
Don't override a JComponent or any of its children's (JPanel included) paint method without good reason (you don't have one). Instead override paintComponent. Edit: I see that your paint method is not a true override, so this is OK -- sorry for the misunderstanding on my part.
You almost never call paint or paintComponent directly. Instead you call repaint() and let the JVM call the painting methods for you. Edit: ditto for this as this was my misunderstanding of your code. You will want to call 'revalidate()andrepaint()` after removing and replacing components in your JPanel.
You can see that your JComponents are present and accounted for if you give them borders.
Edit 2: You will need to give your JComponents a layout if you want to have components added to them easily placed and visualized. In this example I gave mine a BorderLayout.
I've combined a bunch of classes into one file for ease with compilation.
I've indicated key changes with // !! comments.
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Random;
import javax.swing.*;
public class MainFrame {
public static void main(String[] args) {
JFrame frame = new JFrame("8 Puzzle");
frame.setVisible(true);
frame.setSize(600, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
PieceManager pm = new PieceManager();
frame.add(pm);
}
}
class PieceManager extends JPanel {
int[] possmoves;
GameTile[] pieces;
int openSpot;
public PieceManager() {
this.setSize(600, 600);
this.setBackground(new Color(255, 255, 255));
this.setLayout(new GridLayout(3, 3));
pieces = new GameTile[9];
this.init();
this.addMouseListener(new ClickAction());
}
public void init() {
ArrayList<Integer> nums = new ArrayList<Integer>();
Random rand = new Random();
for (int i = 0; i < 9; i++) {
nums.add(i);
}
for (int i = 0, j = 8; i < 8; i++, j--) {
int p = rand.nextInt(j);
GameTile x = new GameTile(i, nums.remove(p));
pieces[i] = x;
nums.removeAll(Collections.singleton(null));
}
GameTile z = new GameTile(8, nums.get(0));
pieces[8] = z;
possmoves = new int[4];
boolean found = false;
for (int i = 0; i < 9 || found; i++) {
if (pieces[i].getID() == 0) {
openSpot = pieces[i].getPos();
}
}
setOpenSpot();
paint();
}
public void paint() {
this.removeAll();
for (int i = 0; i < 9; i++) {
this.add(pieces[i]);
pieces[i].setVisible(true);
}
revalidate(); // !!
repaint(); // !!
}
public void setOpenSpot() {
Arrays.fill(possmoves, -1);
if (openSpot == 0) {
possmoves[0] = 1;
possmoves[1] = 3;
} else if (openSpot == 1) {
possmoves[0] = 0;
possmoves[1] = 2;
possmoves[3] = 4;
} else if (openSpot == 2) {
possmoves[0] = 1;
possmoves[1] = 5;
} else if (openSpot == 3) {
possmoves[0] = 0;
possmoves[1] = 4;
possmoves[2] = 6;
} else if (openSpot == 4) {
possmoves[0] = 1;
possmoves[1] = 3;
possmoves[2] = 5;
possmoves[3] = 7;
} else if (openSpot == 5) {
possmoves[0] = 2;
possmoves[1] = 4;
possmoves[3] = 8;
} else if (openSpot == 6) {
possmoves[0] = 3;
possmoves[1] = 7;
} else if (openSpot == 7) {
possmoves[0] = 6;
possmoves[1] = 4;
possmoves[2] = 8;
} else if (openSpot == 8) {
possmoves[0] = 5;
possmoves[1] = 7;
}
}
public void checkCorrect() {
}
public class ClickAction implements MouseListener {
#Override
public void mouseClicked(MouseEvent e) {
int x = e.getX();
int y = e.getY();
int pX = (int) Math.floor(x / 200);
int pY = (int) Math.floor(y / 200);
int piecepressed = (pY * 3) + pX;
boolean moveable = false;
int toBeMoved = -1;
for (int i = 0; i < 4; i++) {
if (piecepressed == possmoves[i]) {
moveable = true;
toBeMoved = possmoves[i];
}
}
if (moveable) {
GameTile saved = pieces[openSpot];
pieces[openSpot] = pieces[toBeMoved];
pieces[toBeMoved] = saved;
openSpot = toBeMoved;
setOpenSpot();
paint();
checkCorrect();
}
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mousePressed(MouseEvent arg0) {
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
}
}
class GameTile extends JComponent {
private int id;
private int position;
public GameTile(int id, int initpos) {
setBorder(BorderFactory.createTitledBorder("" + id)); // !!
setLayout(new BorderLayout()); // !! so the added JLabel will show
if (id == 0) {
this.id = id;
this.position = initpos;
} else {
this.id = id;
this.position = initpos;
String label = Integer.toString(id);
// !! setSize(200, 200);
setOpaque(true); // !!
setPreferredSize(new Dimension(200, 200)); // !!
setBackground(new Color(0, 0, 0));
// !! Label l = new Label(label, Label.CENTER);
JLabel l = new JLabel(label, SwingConstants.CENTER); // !!
this.add(l);
l.setVisible(true);
}
}
public void setPos(int position) {
this.position = position;
}
public int getPos() {
return position;
}
public int getID() {
return id;
}
}
There's probably a lot more to say, but this is all I've seen so far.

Categories