In: Computer Science
In Java please:
2) Part 2: Add a blankPos field
Dear Developer, It seems an overzealous programmer tried to create
a Fibonacci slider puzzle from our old code. This brought up the
fact there is a data integrity issue in our SlidingSquarePuzzle
class. It makes sense because the class’s data only consists of an
int[]. Since, you are new this is a good opportunity to get your
feet wet. I want you to change the offending code and help shore up
our security hole. I’ve attached their Driver and the GUI and
SlidingSquarePuzzle files. I’ve also commented out the offending
code. Sincerely, Your Boss P.S. You might as well include some
documentation while you’re at it. It’s been bugging me for the
longest time.
Part 2: Add a blankPos field
1. This replaces the blankPos field in GUI.
2. Add a field called blankPos. Initialize it in the Constructors.
3. Add a getter for blankPos.
4. Add a private update method for blankPos. This will be called anytime tileList changes.
5. Replace blankPos for ssp.getBlankPos().
6. Delete old code: a. For-loop from the newGame method in GUI
b. blankPos = newBlankPos; & ssp.getTileList()[blankPos] = 0; from the if (direction != 0) inside the GUI constructor.
=================
Driver.java:
public class Driver { public static void main(String[] args) { //change this number to how many tiles you want int numberOfTiles = 9; SlidingSquarePuzzle fibonaciSlider = new SlidingSquarePuzzle(numberOfTiles); // fibonaciSlider.getTileList()[0] = 1; // fibonaciSlider.getTileList()[1] = 1; // fibonaciSlider.getTileList()[2] = 2; // fibonaciSlider.getTileList()[3] = 3; // fibonaciSlider.getTileList()[4] = 5; // fibonaciSlider.getTileList()[5] = 8; // fibonaciSlider.getTileList()[6] = 13; // fibonaciSlider.getTileList()[7] = 21; GUI.init(fibonaciSlider); } }
=====================
GUI.java
import java.awt.*; import java.awt.event.*; import javax.swing.*; @SuppressWarnings("serial") public class GUI extends JPanel { private SlidingSquarePuzzle ssp; private final int sideLength; private final int tileSize; private int blankPos; private final int margin; private final int gridSize; private boolean gameOver; private GUI(SlidingSquarePuzzle ssp) { this.ssp = ssp; sideLength = (int) Math.floor(Math.sqrt(ssp.getTileList().length)); final int resolution = 640; margin = 40; tileSize = (resolution - 2 * margin) / sideLength; gridSize = tileSize * sideLength; setPreferredSize(new Dimension(resolution, resolution + margin)); setBackground(Color.WHITE); setForeground(new Color(0x006940)); setFont(new Font("SansSerif", Font.BOLD, 60)); gameOver = true; addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { if (gameOver) { newGame(); } else { int ex = e.getX() - margin; int ey = e.getY() - margin; if (ex < 0 || ex > gridSize || ey < 0 || ey > gridSize) return; int clickX = ex / tileSize; int clickY = ey / tileSize; int blankX = blankPos % sideLength; int blankY = blankPos / sideLength; int clickPos = clickY * sideLength + clickX; int direction = 0; if (clickX == blankX && Math.abs(clickY - blankY) > 0) { direction = (clickY - blankY) > 0 ? sideLength : -sideLength; } else if (clickY == blankY && Math.abs(clickX - blankX) > 0) { direction = (clickX - blankX) > 0 ? 1 : -1; } if (direction != 0) { do { int newBlankPos = blankPos + direction; ssp.getTileList()[blankPos] = ssp.getTileList()[newBlankPos]; blankPos = newBlankPos; } while (blankPos != clickPos); ssp.getTileList()[blankPos] = 0; } gameOver = ssp.isSolved(); } repaint(); } }); newGame(); } private void newGame() { ssp.shuffle(); gameOver = false; for (int i = 0; i < ssp.getTileList().length; i++) { if(ssp.getTileList()[i] != 0) continue; blankPos = i; break; } } private void drawGrid(Graphics2D g) { for (int i = 0; i < ssp.getTileList().length; i++) { int x = margin + (i % sideLength) * tileSize; int y = margin + (i / sideLength) * tileSize; if (ssp.getTileList()[i] == 0) { if (gameOver) { g.setColor(Color.GREEN); drawCenteredString(g, "\u2713", x, y); } continue; } g.setColor(getForeground()); g.fillRoundRect(x, y, tileSize, tileSize, 25, 25); g.setColor(Color.green.darker()); g.drawRoundRect(x, y, tileSize, tileSize, 25, 25); g.setColor(Color.WHITE); drawCenteredString(g, String.valueOf(ssp.getTileList()[i]), x, y); } } private void drawStartMessage(Graphics2D g) { if (gameOver) { g.setFont(getFont().deriveFont(Font.BOLD, 18)); g.setColor(getForeground()); String s = "click to start a new game"; int x = (getWidth() - g.getFontMetrics().stringWidth(s)) / 2; int y = getHeight() - margin; g.drawString(s, x, y); } } private void drawCenteredString(Graphics2D g, String s, int x, int y) { FontMetrics fm = g.getFontMetrics(); int asc = fm.getAscent(); int des = fm.getDescent(); x = x + (tileSize - fm.stringWidth(s)) / 2; y = y + (asc + (tileSize - (asc + des)) / 2); g.drawString(s, x, y); } @Override public void paintComponent(Graphics gg) { super.paintComponent(gg); Graphics2D g = (Graphics2D) gg; g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); drawGrid(g); drawStartMessage(g); } public static void init(SlidingSquarePuzzle ssp) { SwingUtilities.invokeLater(() -> { JFrame f = new JFrame(); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setTitle("Slidng Square Puzzle"); f.setResizable(false); f.add(new GUI(ssp), BorderLayout.CENTER); f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); }); } }
======================
SlidingSquarePuzzle.java
import java.util.Arrays; import java.util.Random; public class SlidingSquarePuzzle { private int [] tileList; public SlidingSquarePuzzle() { this(16); } public SlidingSquarePuzzle(int size) { tileList = size < 4 ? new int[4] : new int[(int) Math.pow(Math.floor(Math.sqrt(size)), 2)]; solve(); } public int[] getTileList() { return tileList; } public void solve() { for(int i = 0; i < tileList.length - 1; i++) { tileList[i] = i + 1; } } public boolean isSolved() { for(int i = 0; i < tileList.length - 1; i++) if (tileList[i] != i + 1) return false; return true; } /* * This looks at the puzzle and checks if it is solvable */ private boolean isSolvable() { int inversions = 0; int m = (int) Math.floor(Math.sqrt(tileList.length)); for(int i = 0; i < tileList.length; i++) for(int j = i + 1; j < tileList.length; j++) { if(tileList[i] == 0 || tileList[j] == 0) continue; if (tileList[j] < tileList[i]) inversions++; } if(m % 2 == 1) return inversions % 2 == 0; else { int blankIndex = 0; for(int i = 0; i < tileList.length; i++) if(tileList[i] == 0 ) { blankIndex = i; break; } if((blankIndex / m) % 2 == 0) return inversions % 2 == 1; else return inversions % 2 == 0; } } public void shuffle() { Random rand = new Random(); do { for(int i = tileList.length - 1; i > 0; i--) { int j = rand.nextInt(i + 1); int temp = tileList[j]; tileList[j] = tileList[i]; tileList[i] = temp; } }while(!this.isSolvable()); } }
=====================================SlidingSquarePuzzle.java=====================
import java.util.Arrays;
import java.util.Random;
public class SlidingSquarePuzzle {
private int [] tileList;
private int blankPos;
public void updateBlankPos(int
blankPos)
{
this.blankPos=blankPos;
}
public int getBlankPos()
{
return
blankPos;
}
public SlidingSquarePuzzle() {
this(16);
}
public SlidingSquarePuzzle(int size) {
this.blankPos=0;
tileList = size < 4
? new int[4]
: new int[(int) Math.pow(Math.floor(Math.sqrt(size)), 2)];
solve();
}
public int[] getTileList() {
return tileList;
}
public void solve() {
for(int i = 0; i < tileList.length - 1; i++) {
tileList[i] = i + 1;
}
}
public boolean isSolved() {
for(int i = 0; i < tileList.length - 1; i++)
if (tileList[i] != i + 1) return false;
return true;
}
/*
* This looks at the puzzle and checks if it is solvable
*/
private boolean isSolvable() {
int inversions = 0;
int m = (int) Math.floor(Math.sqrt(tileList.length));
for(int i = 0; i < tileList.length; i++)
for(int j = i + 1; j < tileList.length; j++)
{
if(tileList[i] == 0 || tileList[j] == 0) continue;
if (tileList[j] < tileList[i])
inversions++;
}
if(m % 2 == 1)
return inversions % 2 == 0;
else {
int blankIndex = 0;
for(int i = 0; i < tileList.length; i++)
if(tileList[i] == 0 ) {
blankIndex = i;
break;
}
if((blankIndex / m) % 2 == 0)
return inversions % 2 == 1;
else
return inversions % 2 == 0;
}
}
public void shuffle() {
Random rand = new Random();
do {
for(int i = tileList.length - 1; i > 0; i--) {
int j = rand.nextInt(i + 1);
int temp = tileList[j];
tileList[j] = tileList[i];
tileList[i] = temp;
}
}while(!this.isSolvable());
}
}
===========================GUI.java=============================
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
@SuppressWarnings("serial")
public class GUI extends JPanel {
private SlidingSquarePuzzle ssp;
private final int sideLength;
private final int tileSize;
// private int blankPos;
private final int margin;
private final int gridSize;
private boolean gameOver;
private GUI(SlidingSquarePuzzle ssp) {
this.ssp = ssp;
sideLength = (int)
Math.floor(Math.sqrt(ssp.getTileList().length));
final int resolution = 640;
margin = 40;
tileSize = (resolution - 2 * margin) / sideLength;
gridSize = tileSize * sideLength;
setPreferredSize(new Dimension(resolution, resolution +
margin));
setBackground(Color.WHITE);
setForeground(new Color(0x006940));
setFont(new Font("SansSerif", Font.BOLD, 60));
gameOver = true;
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
if (gameOver) {
newGame();
} else {
int ex = e.getX() - margin;
int ey = e.getY() - margin;
if (ex < 0 || ex > gridSize || ey < 0 || ey > gridSize)
return;
int clickX = ex / tileSize;
int clickY = ey / tileSize;
int blankX = ssp.getBlankPos() % sideLength;
int blankY = ssp.getBlankPos() / sideLength;
int clickPos = clickY * sideLength + clickX;
int direction = 0;
if (clickX == blankX && Math.abs(clickY - blankY) > 0)
{
direction = (clickY - blankY) > 0 ? sideLength :
-sideLength;
} else if (clickY == blankY && Math.abs(clickX - blankX)
> 0) {
direction = (clickX - blankX) > 0 ? 1 : -1;
}
if (direction != 0) {
do {
int newBlankPos = ssp.getBlankPos() + direction;
ssp.getTileList()[ssp.getBlankPos()] =
ssp.getTileList()[newBlankPos];
ssp.updateBlankPos(newBlankPos);
} while (ssp.getBlankPos() != clickPos);
ssp.getTileList()[ssp.getBlankPos()] = 0;
}
gameOver = ssp.isSolved();
}
repaint();
}
});
newGame();
}
private void newGame() {
ssp.shuffle();
gameOver = false;
for (int i = 0; i < ssp.getTileList().length; i++) {
if(ssp.getTileList()[i] != 0) continue;
ssp.updateBlankPos(i);
break;
}
}
private void drawGrid(Graphics2D g) {
for (int i = 0; i < ssp.getTileList().length; i++) {
int x = margin + (i % sideLength) * tileSize;
int y = margin + (i / sideLength) * tileSize;
if (ssp.getTileList()[i] == 0) {
if (gameOver) {
g.setColor(Color.GREEN);
drawCenteredString(g, "\u2713", x, y);
}
continue;
}
g.setColor(getForeground());
g.fillRoundRect(x, y, tileSize, tileSize, 25, 25);
g.setColor(Color.green.darker());
g.drawRoundRect(x, y, tileSize, tileSize, 25, 25);
g.setColor(Color.WHITE);
drawCenteredString(g, String.valueOf(ssp.getTileList()[i]), x,
y);
}
}
private void drawStartMessage(Graphics2D g) {
if (gameOver) {
g.setFont(getFont().deriveFont(Font.BOLD, 18));
g.setColor(getForeground());
String s = "click to start a new game";
int x = (getWidth() - g.getFontMetrics().stringWidth(s)) / 2;
int y = getHeight() - margin;
g.drawString(s, x, y);
}
}
private void drawCenteredString(Graphics2D g, String s, int x, int
y) {
FontMetrics fm = g.getFontMetrics();
int asc = fm.getAscent();
int des = fm.getDescent();
x = x + (tileSize - fm.stringWidth(s)) / 2;
y = y + (asc + (tileSize - (asc + des)) / 2);
g.drawString(s, x, y);
}
@Override
public void paintComponent(Graphics gg) {
super.paintComponent(gg);
Graphics2D g = (Graphics2D) gg;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
drawGrid(g);
drawStartMessage(g);
}
public static void init(SlidingSquarePuzzle ssp) {
SwingUtilities.invokeLater(() -> {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setTitle("Slidng Square Puzzle");
f.setResizable(false);
f.add(new GUI(ssp), BorderLayout.CENTER);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}
===========================Driver.java=====================
public class Driver {
public static void main(String[] args) {
//change this number to how many tiles you want
int numberOfTiles = 9;
SlidingSquarePuzzle fibonaciSlider = new
SlidingSquarePuzzle(numberOfTiles);
// fibonaciSlider.getTileList()[0] = 1;
// fibonaciSlider.getTileList()[1] = 1;
// fibonaciSlider.getTileList()[2] = 2;
// fibonaciSlider.getTileList()[3] = 3;
// fibonaciSlider.getTileList()[4] = 5;
// fibonaciSlider.getTileList()[5] = 8;
// fibonaciSlider.getTileList()[6] = 13;
// fibonaciSlider.getTileList()[7] = 21;
GUI.init(fibonaciSlider);
}
}