Can someone explain how to solve this? DeleteRows() method is not working as intended.
It's a Tetris game and I'm trying to delete rows. When the blocks move down, the blocks are still counted as 0 so new blocks go through them. But this occurs only in the top row of the moved blocks:
package application;
import java.util.*;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.scene.*;
import javafx.scene.input.*;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class Tetris extends Application {
public static final int MOVE_AMOUNT = 25;
public static final int SIZE = 25;
public static int XLIMIT = SIZE * 10;
public static int YLIMIT = SIZE * 24;
public static int[][] GRID = new int[XLIMIT/SIZE][YLIMIT/SIZE];
private static Pane group = new Pane();
private static Shape object;
private static Scene scene = new Scene(group, XLIMIT, YLIMIT);
public static void main(String[] args) { launch(args); }
#Override public void start(Stage stage) throws Exception {
for(int[] a: GRID){
Arrays.fill(a, 0);
}
for(int i = 0; i <= XLIMIT; i+= SIZE){
Line a = new Line(i, 0, i, YLIMIT);
group.getChildren().add(a);
}
for(int i = 0; i <= YLIMIT; i+= SIZE){
Line a = new Line(0, i, XLIMIT, i);
group.getChildren().add(a);
}
for(int i = 0; i <= YLIMIT; i+= SIZE){
Text a = new Text("" + i);
a.setY(i);
group.getChildren().add(a);
}
for(int i = SIZE; i < XLIMIT; i+= SIZE){
Text a = new Text("" + i);
a.setY(10);
a.setX(i);
group.getChildren().add(a);
}
Shape a = TetrisHolder.createRect();
group.getChildren().addAll(a.a, a.b, a.c, a.d);
moveOnKeyPress(scene, a.a, a.b, a.c, a.d);
object = a;
stage.setScene(scene);
stage.show();
Timer myTimer=new Timer();
TimerTask task =new TimerTask() {
#Override
public void run() {
Platform.runLater(new Runnable(){
public void run(){
CheckDown(object);
}
});
}
};
myTimer.schedule(task,0,300);
}
private void moveOnKeyPress(Scene scene, Rectangle rect, Rectangle rect2, Rectangle rect3, Rectangle rect4) {
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override public void handle(KeyEvent event) {
Shape shape = new Shape(rect, rect2, rect3, rect4);
switch (event.getCode()) {
case RIGHT:
TetrisHolder.CheckRight(shape);
break;
case DOWN:
CheckDown(shape);
break;
case LEFT:
TetrisHolder.CheckLeft(shape);
break;
case UP:
//TetrisHolder.CheckTurn(shape);
break;
}
}
});
}
private void CheckTurn(Shape shape){
}
private void DeleteRows(Pane pane){
ArrayList<Node> rects = new ArrayList<Node>();
ArrayList<Integer> lines = new ArrayList<Integer>();
int full = 0;
for(int i = 0; i < GRID[0].length; i++){
for(int j = 0; j < GRID.length; j++){
if(GRID[j][i] == 1)
full++;
}
if(full == GRID.length)
lines.add(i/*+lines.size()*/);
full = 0;
}
for(Node node: pane.getChildren()) {
if(node instanceof Rectangle) {
rects.add(node);
}
}
if(lines.size() > 0)
do{
for(Node node: rects){
Rectangle a = (Rectangle)node;
if(a.getY() == lines.get(0)*SIZE){
GRID[(int)a.getX()/SIZE][(int)a.getY()/SIZE] = 0;
pane.getChildren().remove(node);
}
if(a.getY() < lines.get(0)*SIZE){
GRID[(int)a.getX()/SIZE][(int)a.getY()/SIZE] = 0;
a.setY(a.getY() + SIZE);
GRID[(int)a.getX()/SIZE][(int)a.getY()/SIZE] = 1;
}
}
lines.remove(0);
rects.clear();
for(Node node: pane.getChildren()) {
if(node instanceof Rectangle) {
rects.add(node);
}
}
} while(lines.size() > 0);
}
private void CheckDown(Shape shape){
if((shape.c.getY() == YLIMIT - SIZE) || checkA(shape) || checkB(shape) || checkC(shape) || checkD(shape)){
GRID[(int)shape.a.getX()/SIZE][(int)shape.a.getY()/SIZE] = 1;
GRID[(int)shape.b.getX()/SIZE][(int)shape.b.getY()/SIZE] = 1;
GRID[(int)shape.c.getX()/SIZE][(int)shape.c.getY()/SIZE] = 1;
GRID[(int)shape.d.getX()/SIZE][(int)shape.d.getY()/SIZE] = 1;
DeleteRows(group);
Shape a = TetrisHolder.createRect();
object = a;
group.getChildren().addAll(a.a, a.b, a.c, a.d);
moveOnKeyPress(shape.a.getScene(), a.a, a.b, a.c, a.d);
}
if(shape.c.getY() + MOVE_AMOUNT < YLIMIT){
int checka = GRID[(int)shape.a.getX()/SIZE][((int)shape.a.getY()/SIZE) + 1];
int checkb = GRID[(int)shape.b.getX()/SIZE][((int)shape.b.getY()/SIZE) + 1];
int checkc = GRID[(int)shape.c.getX()/SIZE][((int)shape.c.getY()/SIZE) + 1];
int checkd = GRID[(int)shape.d.getX()/SIZE][((int)shape.d.getY()/SIZE) + 1];
if(checka == 0 && checka == checkb && checkb == checkc && checkc == checkd){
shape.a.setY(shape.a.getY() + MOVE_AMOUNT);
shape.b.setY(shape.b.getY() + MOVE_AMOUNT);
shape.c.setY(shape.c.getY() + MOVE_AMOUNT);
shape.d.setY(shape.d.getY() + MOVE_AMOUNT);
}
}
}
private boolean checkA(Shape shape){
return (GRID[(int)shape.a.getX()/SIZE][((int)shape.a.getY()/SIZE) + 1] == 1);
}
private boolean checkB(Shape shape){
return (GRID[(int)shape.b.getX()/SIZE][((int)shape.b.getY()/SIZE) + 1] == 1);
}
private boolean checkC(Shape shape){
return (GRID[(int)shape.c.getX()/SIZE][((int)shape.c.getY()/SIZE) + 1] == 1);
}
private boolean checkD(Shape shape){
return (GRID[(int)shape.d.getX()/SIZE][((int)shape.d.getY()/SIZE) + 1] == 1);
}
}
This is the code. The problem is at DeleteRows() method.
Related
I'm currently trying to implement Conway's Game of Life in Java. On a first glance the application seems to work as it either stalls in the states that are expected as stalling states (e.g. block, bee-hive and tub) or changes infinitely.
However, as I took a closer look I never actually saw a Blinker or Beacon nor a Loaf (for reference images of these states see here). So I decided to implement a drawing mode and a one-step-update method that gives me the possibility to analyze exactly what's going on.
The strange thing that I found was the following:
When entering Drawing Mode I reset all cells and all buffered cells on the board to dead. Then, I drew a vertical Blinker somewhere in the middle of the board and did one update step and checked for the update mechanism of all cells that are alive (which are only the 3 cells belonging to the Blinker). In the output however, all of them returned that the value to their bottom left was alive (which actually could not be the case because nothing is being logged for these cells).
I'm really confused about where I went wrong in my code because this just doesn't make any sense for me. The values for the next generation are being stored in a buffer and only written back after the next generation has been calculated entirely, so I don't think that this should be the issue.
For reproducibility, here is the code:
Main.java
import java.awt.EventQueue;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
public class Main {
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
createAndShowUI();
});
}
private static void createAndShowUI() {
AnimationPanel panel = new AnimationPanel();
JFrame frame = new JFrame("Game of Life");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(panel);
frame.setResizable(false);
frame.pack();
frame.setLocationRelativeTo(null);
frame.addKeyListener(new KeyAdapter() {
#Override
public void keyReleased(KeyEvent e) {
super.keyReleased(e);
if(e.getKeyCode() == e.VK_R) {
panel.reset();
panel.startAnimation();
}
if(e.getKeyCode() == e.VK_C) {
panel.clear();
}
if(e.getKeyCode() == e.VK_S) {
panel.startAnimation();
}
if(e.getKeyCode() == e.VK_SPACE) {
panel.stepAnimation();
}
}
});
frame.setVisible(true);
panel.populate();
panel.startAnimation();
}
}
AnimationPanel.java:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
import javax.swing.JPanel;
import javax.swing.Timer;
public class AnimationPanel extends JPanel implements ActionListener {
private static final long serialVersionUID = 4929258196354814855L;
private int width = 1920;
private int height = 1080;
private int gridSize = 10;
private Cell[][] cells;
private Cell[][] buffer;
private Timer timer;
private boolean drawingMode = false;
public AnimationPanel() {
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
if(drawingMode) {
int x = e.getX();
int y = e.getY();
int xIndex = (int)x / gridSize;
int yIndex = (int)y / gridSize;
cells[xIndex][yIndex].live = !cells[xIndex][yIndex].live;
repaint();
}
}
});
}
public void reset() {
timer.stop();
cells = null;
buffer = null;
populate();
}
public void clear() {
timer.stop();
for(Cell[] row : cells) {
for(Cell cell: row) {
cell.live = false;
}
}
for(Cell[] row : buffer) {
for(Cell cell: row) {
cell.live = false;
}
}
repaint();
drawingMode = true;
}
public void populate() {
Random random = new Random();
int horizontalCellCount = width / gridSize;
int verticalCellCount = height / gridSize;
cells = new Cell[horizontalCellCount][verticalCellCount];
buffer = new Cell[horizontalCellCount][verticalCellCount];
for(int i = 0; i < horizontalCellCount; i++) {
for(int j = 0; j < verticalCellCount; j++) {
double randVal = random.nextDouble();
boolean live = (randVal < 0.05) ? true : false;
int x = i * gridSize;
int y = j * gridSize;
cells[i][j] = new Cell(live, x, y, gridSize);
buffer[i][j] = new Cell(live, x, y, gridSize);
}
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for(Cell[] row : cells) {
for(Cell cell : row) {
cell.draw(g);
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
public void startAnimation() {
drawingMode = false;
timer = new Timer(250, this);
timer.start();
}
public void stepAnimation() {
update();
repaint();
}
#Override
public void actionPerformed(ActionEvent e) {
update();
repaint();
}
private void update() {
int horizontalCellCount = width / gridSize;
int verticalCellCount = height / gridSize;
boolean log = false;
for(int i = 0; i < horizontalCellCount; i++) {
for(int j = 0; j < verticalCellCount; j++) {
if(cells[i][j].live) {
log = true;
System.out.println("Cell: (" + i + "|" + j + ") " + cells[i][j].toString());
System.out.println("Row length: " + cells[i].length);
System.out.println("Column length: " + cells.length);
} else {
log = false;
}
int liveNeighours = 0;
for(int x = i - 1; x <= i + 1; x++) {
if(x < 0 || x == horizontalCellCount) {
continue;
}
for(int y = j - 1; y <= j + 1; y++) {
if(y < 0 || y == verticalCellCount || y == j && x == i) {
continue;
}
if(cells[x][y].live) {
liveNeighours++;
}
if(log) {
System.out.println("Cell at " + x + "|" + y + ": " + cells[x][y].live + " - liveNeighbours: " + liveNeighours);
}
}
}
Cell cell = cells[i][j];
if(liveNeighours > 3 || liveNeighours < 2) {
buffer[i][j].live = false;
} else if(!cell.live && liveNeighours == 3) {
buffer[i][j].live = true;
}
}
}
for(int i = 0; i < horizontalCellCount; i++) {
for(int j = 0; j < verticalCellCount; j++) {
cells[i][j] = buffer[i][j];
}
}
}
}
Cell.java
import java.awt.Color;
import java.awt.Graphics;
public class Cell {
public boolean live;
public int x;
public int y;
public int size;
public Cell(boolean live, int x, int y, int size) {
this.live = live;
this.x = x;
this.y = y;
this.size = size;
}
public void draw(Graphics g) {
if(live) {
g.setColor(Color.BLACK);
} else {
g.setColor(Color.WHITE);
}
g.fillRect(x, y, size, size);
}
#Override
public String toString() {
return "(" + x + " " + y + ") - Size: " + size;
}
}
Any help is really appreciated on this as I'm really confused what is wrong with the code.
I am making a basic platformer game and I need to make it so that every time you jump all the platforms that are below where you jumped disappear and every platform above moves down. It is still in development so just ignore some of the things that are commented out and the messy mode.
Basically, my problem is that when I try to clear all the platforms below the one that you clicked it works fine using this code:
for(int i = 0; i < platforms.length; i++) {
if(platforms[i] == null) {
continue;
}
if(parameters[i][1] > y) {
platforms[i].setVisible(false);
}
}
However later when I try to use .setvisible(true) on the platform that you clicked it doesn't work. Here is the full code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.math.*;
import java.util.*;
public class Main implements ActionListener {
static JFrame frame;
static JPanel panel;
//static JLabel title;
//static JLabel expl;
static JButton[] platforms;
static Random random;
static boolean playing;
static int[][] parameters;
static int platformsMade;
static int clicked;
static int preClicked;
static int score;
static int lives;
static int standing;
static int speed;
static double gravity;
static int jump;
static String action;
public Main(int seed) throws Exception {
frame = new JFrame("Snakes 'n' Adders");
panel = new JPanel(null);
//title = new JLabel("Snakes 'n' Adders", SwingConstants.CENTER);
//expl = new JLabel("");
platforms = new JButton[100000];
random = new Random();
parameters = new int[100000][5];
lives = 3;
speed = 10;
gravity = 9.81;
jump = 5;
action = "";
//panel.add(title);
//panel.add(expl);
frame.add(panel);
panel.setVisible(true);
frame.setVisible(true);
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
random.setSeed(seed);
panel.setBackground(Color.CYAN);
//title.setFont(new Font("Arial", Font.PLAIN, 50));
}
public void drawPlatform(int x, int y, int w, int h, int colour) {
platforms[platformsMade] = new JButton();
platforms[platformsMade].addActionListener(this);
platforms[platformsMade].setBounds(x, y, w, h);
switch(colour) {
case 0:
platforms[platformsMade].setBackground(Color.BLUE);
break;
case 1:
platforms[platformsMade].setBackground(Color.GREEN);
break;
case 2:
platforms[platformsMade].setBackground(Color.RED);
break;
case 3:
platforms[platformsMade].setBackground(Color.ORANGE);
break;
case 4:
platforms[platformsMade].setBackground(Color.GRAY);
break;
}
parameters[platformsMade][0] = x;
parameters[platformsMade][1] = y;
parameters[platformsMade][2] = w;
parameters[platformsMade][3] = h;
parameters[platformsMade][4] = colour;
panel.add(platforms[platformsMade]);
platforms[platformsMade].setVisible(true);
panel.repaint();
platformsMade++;
}
public void movePlatforms(int distance, int i) {
if(platforms[i] == null) {
NullPointerException end = new NullPointerException();
throw end;
}
//this.drawPlatform(parameters[i][0], parameters[i][1] + distance, parameters[i][2], parameters[i][3], parameters[i][4]);
//platforms[i].setVisible(false);
platforms[i].setBounds(parameters[i][0], parameters[i][1] + distance, parameters[i][2], parameters[i][3]);
parameters[i][1] = parameters[i][1] + distance;
}
#Override
public void actionPerformed(ActionEvent event) {
preClicked = clicked;
for(int i = 0; i < platforms.length; i++) {
if(event.getSource() == platforms[i]) {
clicked = i;
break;
}
}
int y = parameters[clicked][1];
for(int i = 0; i < platforms.length; i++) {
if(platforms[i] == null) {
continue;
}
if(parameters[i][1] > y) {
platforms[i].setVisible(false);
}
else {
this.movePlatforms(150, i);
}
this.movePlatforms(150, clicked);
}
for(int i = 0; i <= random.nextInt(2); i++) {
this.drawPlatform(random.nextInt(500), random.nextInt(500), 50, 50, random.nextInt(4));
}
/*for(int i = 0; i < platforms.length; i++) {
if(platforms[i] == null) {
continue;
}
if(platforms[i].getY() > frame.getY() - platforms[i].getHeight()) {
platforms[i].setVisible(false);
}
}*/
platforms[clicked].addActionListener(this);
platforms[clicked].setVisible(true);
standing = clicked;
for(int i = 0; i < platforms.length; i++) {
if(platforms[i] == null) {
continue;
}
if(clicked == i) {
platforms[i].setText("|");
}
else {
platforms[i].setText("");
}
}
}
public static void main(String[] args) throws Exception {
Main sna = new Main(7845);
//title.setVisible(true);
//expl.setVisible(false);
//Thread.sleep(5000);
//title.setVisible(false);
//expl.setVisible(true);
//Thread.sleep(40000);
for(int i = 0; i < 3; i++) {
sna.drawPlatform(random.nextInt(500), random.nextInt(500), 50, 50, random.nextInt(4));
}
int ticks = 0;
platforms[standing].setText("|");
}
}
This is implementation Lee's algorithm in Java. The problem is the deviation in the backtrace(on screenshots):
.
Please, any help?
import java.awt.Graphics;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.JComboBox;
public class Main {
JFrame frame;
//GENERAL VARIABLES
private int cells = 20;
private int delay = 30;
private int startx = -1;
private int starty = -1;
private int finishx = -1;
private int finishy = -1;
private int tool = 0;
private int checks = 0;
private int length = 0;
private int WIDTH = 850;
private final int HEIGHT = 650;
private final int MSIZE = 600;
private int CSIZE = MSIZE/cells;
//UTIL ARRAYS
private String[] tools = {"Start","Finish","Wall", "Eraser"};
//BOOLEANS
private boolean solving = false;
//UTIL
Node[][] map;
Algorithm Alg = new Algorithm();
Random r = new Random();
//SLIDERS
JSlider size = new JSlider(1,5,4);
JSlider speed = new JSlider(0,500,delay);
//LABELS
JLabel toolL = new JLabel("Toolbox");
JLabel sizeL = new JLabel("Size:");
JLabel cellsL = new JLabel(cells+"x"+cells);
JLabel delayL = new JLabel("Delay:");
JLabel msL = new JLabel(delay+"ms");
JLabel checkL = new JLabel("Checks: "+checks);
JLabel lengthL = new JLabel("Path Length: "+length);
//BUTTONS
JButton searchB = new JButton("Search");
JButton resetB = new JButton("Reset");
JButton clearMapB = new JButton("Clear");
//DROP DOWN
JComboBox toolBx = new JComboBox(tools);
//PANELS
JPanel toolP = new JPanel();
//CANVAS
Map canvas;
public static void main(String[] args) { //MAIN METHOD
new Main();
}
public Main() { //CONSTRUCTOR
clearMap();
initialize();
}
public void clearMap() { //CLEAR MAP
finishx = -1; //RESET THE START AND FINISH
finishy = -1;
startx = -1;
starty = -1;
map = new Node[cells][cells]; //CREATE NEW MAP OF NODES
for(int x = 0; x < cells; x++) {
for(int y = 0; y < cells; y++) {
map[x][y] = new Node(3,x,y); //SET ALL NODES TO EMPTY
}
}
reset(); //RESET SOME VARIABLES
}
public void resetMap() { //RESET MAP
for(int x = 0; x < cells; x++) {
for(int y = 0; y < cells; y++) {
Node current = map[x][y];
if(current.getType() == 4 || current.getType() == 5) //CHECK TO SEE IF CURRENT NODE IS EITHER CHECKED OR FINAL PATH
map[x][y] = new Node(3,x,y); //RESET IT TO AN EMPTY NODE
}
}
if(startx > -1 && starty > -1) { //RESET THE START AND FINISH
map[startx][starty] = new Node(0,startx,starty);
map[startx][starty].setHops(0);
}
if(finishx > -1 && finishy > -1)
map[finishx][finishy] = new Node(1,finishx,finishy);
reset(); //RESET SOME VARIABLES
}
private void initialize() { //INITIALIZE THE GUI ELEMENTS
frame = new JFrame();
frame.setVisible(true);
frame.setResizable(false);
frame.setSize(WIDTH,HEIGHT);
frame.setTitle("Lee Algorithm");
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
int space = 25;
int buff = 45;
toolP.setLayout(null);
toolP.setBounds(10,10,210,600);
searchB.setBounds(40,space, 120, 25);
toolP.add(searchB);
space+=buff;
resetB.setBounds(40,space,120,25);
toolP.add(resetB);
space+=buff;
clearMapB.setBounds(40,space, 120, 25);
toolP.add(clearMapB);
space+=40;
toolL.setBounds(40,space,120,25);
toolP.add(toolL);
space+=25;
toolBx.setBounds(40,space,120,25);
toolP.add(toolBx);
space+=buff;
sizeL.setBounds(15,space,40,25);
toolP.add(sizeL);
size.setMajorTickSpacing(10);
size.setBounds(50,space,100,25);
toolP.add(size);
cellsL.setBounds(160,space,40,25);
toolP.add(cellsL);
space+=buff;
delayL.setBounds(15,space,50,25);
toolP.add(delayL);
speed.setMajorTickSpacing(5);
speed.setBounds(50,space,100,25);
toolP.add(speed);
msL.setBounds(160,space,40,25);
toolP.add(msL);
space+=buff;
checkL.setBounds(15,space,100,25);
toolP.add(checkL);
space+=buff;
lengthL.setBounds(15,space,100,25);
toolP.add(lengthL);
frame.getContentPane().add(toolP);
canvas = new Map();
canvas.setBounds(230, 10, MSIZE+1, MSIZE+1);
frame.getContentPane().add(canvas);
searchB.addActionListener(new ActionListener() { //ACTION LISTENERS
#Override
public void actionPerformed(ActionEvent e) {
reset();
if((startx > -1 && starty > -1) && (finishx > -1 && finishy > -1))
solving = true;
}
});
resetB.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
resetMap();
Update();
}
});
clearMapB.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
clearMap();
Update();
}
});
toolBx.addItemListener(new ItemListener() {
#Override
public void itemStateChanged(ItemEvent e) {
tool = toolBx.getSelectedIndex();
}
});
size.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
cells = size.getValue()*5;
clearMap();
reset();
Update();
}
});
speed.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
delay = speed.getValue();
Update();
}
});
startSearch(); //START STATE
}
public void startSearch() { //START STATE
if(solving)
{
Alg.LeeAlg();
}
pause(); //PAUSE STATE
}
public void pause() { //PAUSE STATE
int i = 0;
while(!solving) {
i++;
if(i > 500)
i = 0;
try {
Thread.sleep(1);
} catch(Exception e) {}
}
startSearch(); //START STATE
}
public void Update() { //UPDATE ELEMENTS OF THE GUI
CSIZE = MSIZE/cells;
canvas.repaint();
cellsL.setText(cells+"x"+cells);
msL.setText(delay+"ms");
lengthL.setText("Path Length: "+length);
checkL.setText("Checks: "+checks);
}
public void reset() { //RESET METHOD
solving = false;
length = 0;
checks = 0;
}
public void delay() { //DELAY METHOD
try {
Thread.sleep(delay);
} catch(Exception e) {}
}
class Map extends JPanel implements MouseListener, MouseMotionListener{ //MAP CLASS
public Map() {
addMouseListener(this);
addMouseMotionListener(this);
}
public void paintComponent(Graphics g) { //REPAINT
super.paintComponent(g);
for(int x = 0; x < cells; x++) { //PAINT EACH NODE IN THE GRID
for(int y = 0; y < cells; y++) {
switch(map[x][y].getType()) {
case 0:
g.setColor(Color.GREEN);
break;
case 1:
g.setColor(Color.BLUE);
break;
case 2:
g.setColor(Color.BLACK);
break;
case 3:
g.setColor(Color.WHITE);
break;
case 4:
g.setColor(Color.GRAY);
break;
case 5:
g.setColor(Color.YELLOW);
break;
}
g.fillRect(x*CSIZE,y*CSIZE,CSIZE,CSIZE);
g.setColor(Color.BLACK);
g.drawRect(x*CSIZE,y*CSIZE,CSIZE,CSIZE);
}
}
}
#Override
public void mouseDragged(MouseEvent e) {
try {
int x = e.getX()/CSIZE;
int y = e.getY()/CSIZE;
Node current = map[x][y];
if((tool == 2 || tool == 3) && (current.getType() != 0 && current.getType() != 1))
current.setType(tool);
Update();
} catch(Exception z) {}
}
#Override
public void mouseMoved(MouseEvent e) {}
#Override
public void mouseClicked(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
#Override
public void mousePressed(MouseEvent e) {
resetMap(); //RESET THE MAP WHENEVER CLICKED
try {
int x = e.getX()/CSIZE; //GET THE X AND Y OF THE MOUSE CLICK IN RELATION TO THE SIZE OF THE GRID
int y = e.getY()/CSIZE;
Node current = map[x][y];
switch(tool) {
case 0: { //START NODE
if(current.getType()!=2) { //IF NOT WALL
if(startx > -1 && starty > -1) { //IF START EXISTS SET IT TO EMPTY
map[startx][starty].setType(3);
map[startx][starty].setHops(-1);
}
current.setHops(0);
startx = x; //SET THE START X AND Y
starty = y;
current.setType(0); //SET THE NODE CLICKED TO BE START
}
break;
}
case 1: {//FINISH NODE
if(current.getType()!=2) { //IF NOT WALL
if(finishx > -1 && finishy > -1) //IF FINISH EXISTS SET IT TO EMPTY
map[finishx][finishy].setType(3);
finishx = x; //SET THE FINISH X AND Y
finishy = y;
current.setType(1); //SET THE NODE CLICKED TO BE FINISH
}
break;
}
default:
if(current.getType() != 0 && current.getType() != 1)
current.setType(tool);
break;
}
Update();
} catch(Exception z) {} //EXCEPTION HANDLER
}
#Override
public void mouseReleased(MouseEvent e) {}
}
class Algorithm { // ALGORITHM CLASS
public void LeeAlg() {
ArrayList<Node> priority = new ArrayList<Node>(); //CREATE A PRIORITY QUE
priority.add(map[startx][starty]); //ADD THE START TO THE QUE
while (solving) {
if (priority.size() <= 0) { //IF THE QUE IS 0 THEN NO PATH CAN BE FOUND
solving = false;
break;
}
int hops = priority.get(0).getHops() + 1; //INCREMENT THE HOPS VARIABLE
ArrayList<Node> explored = exploreNeighbors(priority.get(0), hops); //CREATE AN ARRAYLIST OF NODES THAT WERE EXPLORED
if (explored.size() > 0) {
priority.remove(0); //REMOVE THE NODE FROM THE QUE
priority.addAll(explored); //ADD ALL THE NEW NODES TO THE QUE
Update();
delay();
} else { //IF NO NODES WERE EXPLORED THEN JUST REMOVE THE NODE FROM THE QUE
priority.remove(0);
}
}
}
public ArrayList<Node> exploreNeighbors(Node current, int hops) { //EXPLORE NEIGHBORS
ArrayList<Node> explored = new ArrayList<Node>(); //LIST OF NODES THAT HAVE BEEN EXPLORED
for(int a = -1; a <= 1; a++) {
for(int b = -1; b <= 1; b++) {
int xbound = current.getX()+a;
int ybound = current.getY()+b;
if((xbound > -1 && xbound < cells) && (ybound > -1 && ybound < cells)) { //MAKES SURE THE NODE IS NOT OUTSIDE THE GRID
Node neighbor = map[xbound][ybound];
if((neighbor.getHops()==-1 || neighbor.getHops() > hops) && neighbor.getType()!=2) { //CHECKS IF THE NODE IS NOT A WALL AND THAT IT HAS NOT BEEN EXPLORED
explore(neighbor, current.getX(), current.getY(), hops); //EXPLORE THE NODE
explored.add(neighbor); //ADD THE NODE TO THE LIST
}
}
}
}
return explored;
}
public void explore(Node current, int lastx, int lasty, int hops) { //EXPLORE A NODE
if(current.getType()!=0 && current.getType() != 1) //CHECK THAT THE NODE IS NOT THE START OR FINISH
current.setType(4); //SET IT TO EXPLORED
current.setLastNode(lastx, lasty); //KEEP TRACK OF THE NODE THAT THIS NODE IS EXPLORED FROM
current.setHops(hops); //SET THE HOPS FROM THE START
checks++;
if(current.getType() == 1) { //IF THE NODE IS THE FINISH THEN BACKTRACE TO GET THE PATH
backtrace(current.getLastX(), current.getLastY(),hops);
}
}
public void backtrace(int lx, int ly, int hops) { //BACKTRACE
length = hops;
while(hops > 1) { //BACKTRACE FROM THE END OF THE PATH TO THE START
Node current = map[lx][ly];
current.setType(5);
lx = current.getLastX();
ly = current.getLastY();
hops--;
}
solving = false;
}
}
class Node {
// 0 = start, 1 = finish, 2 = wall, 3 = empty, 4 = checked, 5 = finalpath
private int cellType = 0;
private int hops;
private int x;
private int y;
private int lastX;
private int lastY;
public Node(int type, int x, int y) { //CONSTRUCTOR
cellType = type;
this.x = x;
this.y = y;
hops = -1;
}
public int getX() {return x;} //GET METHODS
public int getY() {return y;}
public int getLastX() {return lastX;}
public int getLastY() {return lastY;}
public int getType() {return cellType;}
public int getHops() {return hops;}
public void setType(int type) {cellType = type;} //SET METHODS
public void setLastNode(int x, int y) {lastX = x; lastY = y;}
public void setHops(int hops) {this.hops = hops;}
}
}
That is, the shortest path on the map goes somewhere to the side, and should be in a straight line. What should be corrected in the code?
The problem is that according to the algorithm the answer is gave is as good as a strait line. Both the weird diagonal path and the strait desired path take 4 steps to reach the goal so they are both equal. To fix this you should add a weight. Instead of always incrementing hops by 1, increment it by 1.4 (sqrt(2)) when you move on a diagonal. This way there is a weighting for moving on a diagonal and the desired strait path would be the fastest (as it is in the real world).
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
For my binary tree program, I have been using JTextFields as nodes and I have managed to make it so when I click left button and select two of the JTextFields, it will draw a line between them. The problem is if I want to drag the JtextField around, I want the line to be following as well between two of the midpoints of the JTextField. I don't know if it's possible with using only paintComponent or not. I did try it but it's like a one off thing and it will leave a trail of all the previously drawn lines.
Here, is the code so far, there are other classes so some of the bits won't work. The code has been fiddled around a bit as well for testing.
public class BinaryTreeMainPnl extends JPanel {
public static Graphics g1;
public int Width = 75;
public int Height = 45;
public String tempNode1 = "";
public int tempNode1Pos = 0;
public int tempNode2Pos = 0;
public String tempNode2 = "";
public static boolean leftBtnSelected;
public static boolean rightBtnSelected;
private static int x1, y1 = 50;
private static int x2, y2 = 500;
JToggleButton leftBtn = new JToggleButton("Left");
JToggleButton rightBtn = new JToggleButton("Right");
JTextField[] myArray = new JTextField[60];
ArrayList<String> nodeNames = new ArrayList<String>();
JFrame MainFrame;
JTextField txtFld1 = new JTextField("Enter Questions here");
JButton btn1 = new JButton("Submit");
public BinaryTreeMainPnl(JFrame frame) {
super();
setSize(800, 700);
MainFrame = frame;
readInput();
leftBtn.setFont(new Font("Arial", Font.BOLD, 15));
leftBtn.setForeground(Color.blue);
leftBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
rightBtn.setSelected(false);
leftBtnSelected = leftBtn.getModel().isSelected();
rightBtnSelected = false;
System.out.println(leftBtnSelected);
System.out.println(rightBtnSelected);
}
});
add(leftBtn);
rightBtn.setFont(new Font("Arial", Font.BOLD, 15));
rightBtn.setForeground(Color.green);
rightBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
leftBtn.setSelected(false);
rightBtnSelected = rightBtn.getModel().isSelected();
leftBtnSelected = false;
System.out.println(leftBtnSelected);
System.out.println(rightBtnSelected);
}
});
add(rightBtn);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
updateLine(g);
}
public void readInput() {
btn1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
identifyNodeNames(txtFld1.getText());
displayNodes(nodeNames);
new TreeSorting().treeSort(nodeNames);
}
});
this.add(txtFld1);
this.add(btn1);
}
public void displayNodes(ArrayList<String> nodeNames) {
for (int i = 0; i < nodeNames.size(); i++) {
String currentSetText = nodeNames.get(i);
myArray[i] = new JTextField(currentSetText);
myArray[i].setEditable(false);
}
for (int i = 0; i < nodeNames.size(); i++) {
int I = i;
myArray[I].addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseDragged(MouseEvent evt) {
int x = evt.getX() + myArray[I].getX();
int y = evt.getY() + myArray[I].getY();
myArray[I].setBounds(x, y, myArray[I].getWidth(), myArray[I].getWidth());
System.out.println(myArray[I] + "dragged");
}
});
myArray[I].addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent evt) {
if (leftBtnSelected) {
if (tempNode1.equals("")) {
tempNode1 = myArray[I].getText();
System.out.println(tempNode1 + "clicked");
} else {
tempNode2 = myArray[I].getText();
System.out.println(tempNode2 + "Clicked as well");
leftBtn.setSelected(false);
leftBtnSelected = false;
x1 = 40;
y1 = 40;
x2 = 400;
y2 = 400;
updateLine(g1);
System.out.println("asdasd");
}
}
if (rightBtnSelected) {
}
}
public void moveComponent(MouseEvent evt) {
}
});
System.out.println("I " + I);
System.out.println(myArray[I].getText());
add(myArray[I]);
}
MainFrame.revalidate();
}
public int findMidPoint(JTextField temp) {
Point p = temp.getLocation();
Dimension d = temp.getSize();
return p.x + (d.width) / 2;
}
int coun = 0;
public void updateLine(Graphics g) {
g.drawLine(x1, x2, y1, y2);
x1 = x1 + 10;
y1 = y1 + 10;
y2 = y2 + 10;
x2 = x2 + 10;
System.out.println("Line Updated" + coun);
coun++;
}
public void identifyNodeNames(String answer) {
int arrayCounter = 0;
int lastNodePosition = 0;
for (int i = 0; i < answer.length(); i++) {
char c = answer.charAt(i);
if (c == ',') {
nodeNames.add(arrayCounter, answer.substring(lastNodePosition, i + 1).replaceAll(",", "").replaceAll(" ", ""));
lastNodePosition = i + 1;
arrayCounter++;
}
if (i == answer.length() - 1) {
nodeNames.add(arrayCounter, answer.substring(lastNodePosition, answer.length()).replaceAll(" ", ""));
}
}
}
}
import java.util.ArrayList;
public class TreeSorting {
public static int arrayLength;
String[][] Child;
String root = "";
boolean nodeSorted = false;
int parentCounter = 1;
public void treeSort(ArrayList<String> passedQuestions) {
// declaring nodes
arrayLength = passedQuestions.size();
System.out.println(arrayLength + "ARRAY LENGTH");
Child = new String[arrayLength][3];
for (int i = 0; i < arrayLength; i++) {
Child[i][0] = passedQuestions.get(i);
}
//initially calling the mainprocess with parentCounter 1;
root = Child[0][0];
mainProcess(1);
}
public void mainProcess(int parentCounter) {
if (parentCounter < Child.length) {
System.out.println(parentCounter);
sortingTree(Child[parentCounter][0], root, 0); //where the next node is passed on the tree is sorted recursively
for (int i = 0; i < Child.length; i++) {
System.out.println(Child[i][0]);
System.out.println(Child[i][1] + "," + Child[i][2]);
}
}
}
public void sortingTree(String CurrentNode, String PreviousNode, int PreviousPosition) {
nodeSorted = false;// node is not sorted in the beginning
if (isAfter(CurrentNode.toLowerCase(), PreviousNode.toLowerCase())) {
System.out.println(Child[PreviousPosition][2]);
if (Child[PreviousPosition][2] == null) { //checks if the right of the node is empty, if found empty the node is placed there.
Child[PreviousPosition][2] = CurrentNode;
nodeSorted = true; // if the node finds a position in the array node is sorted.
} else {
sortingTree(CurrentNode, Child[PreviousPosition][2], getPositionInArray(Child[PreviousPosition][2]));
//if the array position was not empty, the loop will process again this time with the item found in the filled position.
}
} else if (Child[PreviousPosition][1] == null) { // if the left of the node is empty, the item will be placed there
Child[PreviousPosition][1] = CurrentNode;
nodeSorted = true;
} else {
sortingTree(CurrentNode, Child[PreviousPosition][1], getPositionInArray(Child[PreviousPosition][1]));
//if the array position was not empty, the loop will process again this time with the item found in the filled position.
}
if (nodeSorted) { // if the node finds a position in the array, the nodeCounter increments and the next node in the question is processed.
parentCounter++;
mainProcess(parentCounter);
}
}
public int getPositionInArray(String node) {
int position = 0;
loop:
for (int i = 0; i < Child.length; i++) {
if (Child[i][0].equals(node)) {
position = i;
break loop;
}
}
return position;
}
public boolean isAfter(String CurrentNode, String PreviousNode) {
int loopLength = determineLoopLength(CurrentNode, PreviousNode);
boolean result = false;
String tempCheck = "";
loop:
for (int i = 0; i < loopLength; i++) {
if ((int) CurrentNode.charAt(i) > (int) PreviousNode.charAt(i)) {
result = true;
break loop;
}
if ((int) CurrentNode.charAt(i) < (int) PreviousNode.charAt(i)) {
result = false;
break loop;
} else if (CurrentNode.charAt(i) == PreviousNode.charAt(i) && CurrentNode.length() > PreviousNode.length()) {
System.out.println("I'm here");
tempCheck = tempCheck + CurrentNode.charAt(i) + "";
if (i == loopLength - 1 && tempCheck.equals(PreviousNode)) {
result = true;
break loop;
}
}
}
return result;
}
public int determineLoopLength(String CurrentNode, String PreviousNode) {
int loopLength = 0;
if (CurrentNode.length() < PreviousNode.length()) {
loopLength = CurrentNode.length();
}
if (PreviousNode.length() < CurrentNode.length()) {
loopLength = PreviousNode.length();
} else {
loopLength = CurrentNode.length();
}
return loopLength;
}
}
WTF, been working on this,.....
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class DragMyFields extends JPanel {
private static final int PREF_W = 1000;
private static final int PREF_H = 800;
private static final int COLS = 8;
private static final int DELTA_Y = 120;
private static final int MAX_DEPTH = 3;
private MySimpleTreeNode<JTextField> treeRoot = new MySimpleTreeNode<>();
private MyMouse myMouse = new MyMouse();
public DragMyFields() {
setLayout(null); // this is *** BAD ***
// much better would be to create a custom layout
JTextField field = new JTextField(COLS);
field.addMouseListener(myMouse);
field.addMouseMotionListener(myMouse);
field.setSize(field.getPreferredSize());
int x = (PREF_W - field.getPreferredSize().width) / 2;
int y = DELTA_Y;
field.setLocation(x, y);
add(field);
treeRoot.setNode(field);
recursiveCreateTree(treeRoot, MAX_DEPTH, x, y);
}
private void recursiveCreateTree(MySimpleTreeNode<JTextField> node, int depth, int x, int y) {
if (depth == 0) {
return;
}
JTextField leftField = new JTextField(COLS);
JTextField rightField = new JTextField(COLS);
MySimpleTreeNode<JTextField> leftNode = new MySimpleTreeNode<>(leftField);
MySimpleTreeNode<JTextField> rightNode = new MySimpleTreeNode<>(rightField);
node.setLeft(leftNode);
node.setRight(rightNode);
int multiplier = 4;
for (int i = 0; i < MAX_DEPTH - depth; i++) {
multiplier *= 2;
}
int xL = x - getPreferredSize().width / multiplier;
int xR = x + getPreferredSize().width / multiplier;
y += DELTA_Y;
leftField.setSize(leftField.getPreferredSize());
rightField.setSize(rightField.getPreferredSize());
leftField.setLocation(xL, y);
rightField.setLocation(xR, y);
leftField.addMouseListener(myMouse);
leftField.addMouseMotionListener(myMouse);
rightField.addMouseListener(myMouse);
rightField.addMouseMotionListener(myMouse);
add(leftField);
add(rightField);
recursiveCreateTree(leftNode, depth - 1, xL, y);
recursiveCreateTree(rightNode, depth - 1, xR, y);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
recursiveDraw(g, treeRoot);
}
private void recursiveDraw(Graphics g, MySimpleTreeNode<JTextField> node) {
MySimpleTreeNode<JTextField> left = node.getLeft();
MySimpleTreeNode<JTextField> right = node.getRight();
Point p = getNodeCenter(node);
if (left != null) {
Point p2 = getNodeCenter(left);
g.drawLine(p.x, p.y, p2.x, p2.y);
recursiveDraw(g, left);
}
if (right != null) {
Point p2 = getNodeCenter(right);
g.drawLine(p.x, p.y, p2.x, p2.y);
recursiveDraw(g, right);
}
}
private Point getNodeCenter(MySimpleTreeNode<JTextField> node) {
JTextField field = node.getNode();
Point location = field.getLocation();
Dimension size = field.getSize();
return new Point(location.x + size.width / 2, location.y + size.height / 2);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class MyMouse extends MouseAdapter {
Component source = null;
private Point pressedP;
private Point pressedLoc;
private Point parentP;
#Override
public void mousePressed(MouseEvent e) {
if (e.getButton() != MouseEvent.BUTTON1) {
return;
}
source = e.getComponent();
parentP = source.getParent().getLocationOnScreen();
pressedLoc = source.getLocationOnScreen();
pressedP = e.getLocationOnScreen();
}
#Override
public void mouseReleased(MouseEvent e) {
moveComponent(e);
source = null;
pressedP = null;
pressedLoc = null;
}
#Override
public void mouseDragged(MouseEvent e) {
if (source == null) {
return;
}
moveComponent(e);
}
private void moveComponent(MouseEvent e) {
Point p = e.getLocationOnScreen();
int x = pressedLoc.x + p.x - pressedP.x - parentP.x;
int y = pressedLoc.y + p.y - pressedP.y - parentP.y;
Point newP = new Point(x, y);
source.setLocation(newP);
repaint();
}
}
private static void createAndShowGui() {
DragMyFields mainPanel = new DragMyFields();
JFrame frame = new JFrame("DragMyFields");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
createAndShowGui();
});
}
}
class MySimpleTreeNode<T> {
private T node;
private MySimpleTreeNode<T> left;
private MySimpleTreeNode<T> right;
public MySimpleTreeNode() {
// default constructor
}
public MySimpleTreeNode(T node) {
this.node = node;
}
public void setNode(T node) {
this.node = node;
}
public T getNode() {
return node;
}
public MySimpleTreeNode<T> getLeft() {
return left;
}
public void setLeft(MySimpleTreeNode<T> left) {
this.left = left;
}
public MySimpleTreeNode<T> getRight() {
return right;
}
public void setRight(MySimpleTreeNode<T> right) {
this.right = right;
}
}
I am trying to make a puzzle game but the problem is that I can't do the EventHandler setOnMouseClicked.Also I want to know how to make possible that to re-arrange the puzzle so it shows random images in every-coordinate. This is how far I got.
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class eliss extends Application{
#Override
public void start(Stage primaryStage) {
ImageView view[][] = new ImageView[5][5];
Image imag = new Image("http://images.cdn.autocar.co.uk/sites/autocar.co.uk/files/styles/gallery_slide/public/ferrari-laferrari-zfye-059_1.jpg?itok=hfLNxUD9",600,600,false,true);
GridPane pane = new GridPane();
pane.setAlignment(Pos.CENTER);
pane.setVgap(2);
pane.setHgap(2);
PuzzleImage(view, imag, pane);
Scene scene = new Scene(pane,1100,1100);
primaryStage.setTitle("Elis");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] x)
{
launch(x);
}
public void PuzzleImage( ImageView view[][],Image imag,GridPane pane)
{
for(int i=0;i<5;i++)
{
for(int j=0;j<5;j++)
{
if(j==4 && i==4) view[i][j]=null;
else{
view[i][j]=new ImageView(imag);
Rectangle2D rect = new Rectangle2D(120*i,120*j,120,120);
view[i][j].setViewport(rect);
pane.add(view[i][j], i, j);
}
}
}
}
}
What you are asking is too much for a question on StackOverflow. However, I got a little bit of spare time, so I quickly drafted up some code to demonstrate what you need:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javafx.animation.PathTransition;
import javafx.application.Application;
import javafx.geometry.Rectangle2D;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.stage.Stage;
import javafx.util.Duration;
public class PuzzleGame extends Application {
private Image image = new Image("http://images.cdn.autocar.co.uk/sites/autocar.co.uk/files/styles/gallery_slide/public/ferrari-laferrari-zfye-059_1.jpg?itok=hfLNxUD9",600,600,false,true);
private static double SCENE_WIDTH = 1024;
private static double SCENE_HEIGHT = 768;
public static int TILE_ROW_COUNT = 5;
public static int TILE_COLUMN_COUNT = 5;
public static double TILE_SIZE = 120;
public static double offsetX = (SCENE_WIDTH - TILE_ROW_COUNT * TILE_SIZE) / 2;
public static double offsetY = (SCENE_HEIGHT - TILE_COLUMN_COUNT * TILE_SIZE) / 2;
List<Cell> cells = new ArrayList<>();
#Override
public void start(Stage primaryStage) {
// create grid
for (int x = 0; x < TILE_ROW_COUNT; x++) {
for (int y = 0; y < TILE_COLUMN_COUNT; y++) {
// create tile
ImageView tile = new ImageView(image);
Rectangle2D rect = new Rectangle2D(TILE_SIZE * x, TILE_SIZE * y, TILE_SIZE, TILE_SIZE);
tile.setViewport(rect);
// consider empty cell, let it remain empty
if (x == (TILE_ROW_COUNT - 1) && y == (TILE_COLUMN_COUNT - 1)) {
tile = null;
}
cells.add(new Cell(x, y, tile));
}
}
// shuffle cells
shuffle();
// create playfield
Pane pane = new Pane();
// put tiles on playfield, assign event handler
for (int i = 0; i < cells.size(); i++) {
Cell cell = cells.get(i);
Node imageView = cell.getImageView();
// consider empty cell
if (imageView == null)
continue;
// click-handler: swap tiles, check if puzzle is solved
imageView.addEventFilter(MouseEvent.MOUSE_CLICKED, mouseEvent -> {
moveCell((Node) mouseEvent.getSource());
});
// position images on scene
imageView.relocate(cell.getLayoutX(), cell.getLayoutY());
pane.getChildren().add(cell.getImageView());
}
Scene scene = new Scene(pane, SCENE_WIDTH, SCENE_HEIGHT);
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* Swap images of cells randomly
*/
public void shuffle() {
Random rnd = new Random();
for (int i = 0; i < 1000; i++) {
int a = rnd.nextInt(cells.size());
int b = rnd.nextInt(cells.size());
if (a == b)
continue;
// skip bottom right cell swap, we want the empty cell to remain there
if( cells.get(a).isEmpty() || cells.get(b).isEmpty())
continue;
swap( cells.get(a), cells.get(b));
}
}
public void swap( Cell cellA, Cell cellB) {
ImageView tmp = cellA.getImageView();
cellA.setImageView(cellB.getImageView());
cellB.setImageView(tmp);
}
public boolean checkSolved() {
boolean allSolved = true;
for (Cell cell : cells) {
if (!cell.isSolved()) {
allSolved = false;
break;
}
}
System.out.println("Solved: " + allSolved);
return allSolved;
}
public void moveCell(Node node) {
// get current cell using the selected node (imageview)
Cell currentCell = null;
for (Cell tmpCell : cells) {
if (tmpCell.getImageView() == node) {
currentCell = tmpCell;
break;
}
}
if (currentCell == null)
return;
// get empty cell
Cell emptyCell = null;
for (Cell tmpCell : cells) {
if (tmpCell.isEmpty()) {
emptyCell = tmpCell;
break;
}
}
if (emptyCell == null)
return;
// check if cells are swappable: neighbor distance either x or y must be 1 for a valid move
int steps = Math.abs(currentCell.x - emptyCell.x) + Math.abs(currentCell.y - emptyCell.y);
if (steps != 1)
return;
System.out.println("Transition: " + currentCell + " -> " + emptyCell);
// cells are swappable => create path transition
Path path = new Path();
path.getElements().add(new MoveToAbs(currentCell.getImageView(), currentCell.getLayoutX(), currentCell.getLayoutY()));
path.getElements().add(new LineToAbs(currentCell.getImageView(), emptyCell.getLayoutX(), emptyCell.getLayoutY()));
PathTransition pathTransition = new PathTransition();
pathTransition.setDuration(Duration.millis(100));
pathTransition.setNode(currentCell.getImageView());
pathTransition.setPath(path);
pathTransition.setOrientation(PathTransition.OrientationType.NONE);
pathTransition.setCycleCount(1);
pathTransition.setAutoReverse(false);
final Cell cellA = currentCell;
final Cell cellB = emptyCell;
pathTransition.setOnFinished(actionEvent -> {
swap( cellA, cellB);
checkSolved();
});
pathTransition.play();
}
private static class Cell {
int x;
int y;
ImageView initialImageView;
ImageView currentImageView;
public Cell(int x, int y, ImageView initialImageView) {
super();
this.x = x;
this.y = y;
this.initialImageView = initialImageView;
this.currentImageView = initialImageView;
}
public double getLayoutX() {
return x * TILE_SIZE + offsetX;
}
public double getLayoutY() {
return y * TILE_SIZE + offsetY;
}
public ImageView getImageView() {
return currentImageView;
}
public void setImageView(ImageView imageView) {
this.currentImageView = imageView;
}
public boolean isEmpty() {
return currentImageView == null;
}
public boolean isSolved() {
return this.initialImageView == currentImageView;
}
public String toString() {
return "[" + x + "," + y + "]";
}
}
// absolute (layoutX/Y) transitions using the pathtransition for MoveTo
public static class MoveToAbs extends MoveTo {
public MoveToAbs(Node node) {
super(node.getLayoutBounds().getWidth() / 2, node.getLayoutBounds().getHeight() / 2);
}
public MoveToAbs(Node node, double x, double y) {
super(x - node.getLayoutX() + node.getLayoutBounds().getWidth() / 2, y - node.getLayoutY() + node.getLayoutBounds().getHeight() / 2);
}
}
// absolute (layoutX/Y) transitions using the pathtransition for LineTo
public static class LineToAbs extends LineTo {
public LineToAbs(Node node, double x, double y) {
super(x - node.getLayoutX() + node.getLayoutBounds().getWidth() / 2, y - node.getLayoutY() + node.getLayoutBounds().getHeight() / 2);
}
}
public static void main(String[] args) {
launch(args);
}
}
You can use Collections.shuffle to generate a random permutation of a List This can be used to place the tiles in a random order:
private static final int COLUMN_COUNT = 5;
private static final int ROW_COUNT = 5;
private static void fillGridPane(GridPane pane, ImageView[][] view, Image imag) {
List<ImageView> images = new ArrayList<>(24);
for (int i = 0; i < COLUMN_COUNT; i++) {
for (int j = 0, end = i == (COLUMN_COUNT - 1) ? ROW_COUNT - 1 : ROW_COUNT; j < end; j++) {
ImageView iv = new ImageView(imag);
images.add(iv);
view[i][j] = iv;
Rectangle2D rect = new Rectangle2D(120 * i, 120 * j, 120, 120);
iv.setViewport(rect);
}
}
Collections.shuffle(images);
Iterator<ImageView> iter = images.iterator();
for (int i = 0; i < COLUMN_COUNT; i++) {
for (int j = 0, end = i == (COLUMN_COUNT - 1) ? ROW_COUNT - 1 : ROW_COUNT; j < end; j++) {
pane.add(iter.next(), i, j);
}
}
}
The onMouseClicked event handler can be attached to the GridPane and MouseEvent.getTarget can be used to get the node that was clicked:
pane.setOnMouseClicked(event -> {
if (move(event)) {
if (checkWin()) {
new Alert(Alert.AlertType.INFORMATION, "You Win!").show();
}
}
});
private int emptyTileX = 4;
private int emptyTileY = 4;
private boolean move(MouseEvent event) {
Object target = event.getTarget();
if (target instanceof ImageView) {
ImageView iv = (ImageView) target;
int row = GridPane.getRowIndex(iv);
int column = GridPane.getColumnIndex(iv);
int dx = Math.abs(column - emptyTileX);
int dy = Math.abs(row - emptyTileY);
if ((dx == 0 && dy == 1) || (dx == 1 && dy == 0)) {
// swap image and empty tile, if they are next to each other
GridPane.setConstraints(iv, emptyTileX, emptyTileY);
emptyTileX = column;
emptyTileY = row;
return true;
}
}
return false;
}
To check the winning condition, you can simply check the positions of the ImageViews in the GridPane
private boolean checkWin() {
for (int i = 0; i < COLUMN_COUNT; i++) {
for (int j = 0, end = i == (COLUMN_COUNT - 1) ? ROW_COUNT - 1 : ROW_COUNT; j < end; j++) {
ImageView iv = view[i][j];
if (GridPane.getColumnIndex(iv) != i || GridPane.getRowIndex(iv) != j) {
return false;
}
}
}
return true;
}