I'm writing an application to hide animage in another image using LSB. The encoding returns an image that differs from the image that was hidden and after searching the problem for quite some time now, i think i became seriously blind, when it comes to my code.
If somebody could take a look and give me a hint, I would be very thankful. The significant code below and the whole project (if somebody would want to test it) under the link: https://github.com/miassma/Steganography.git
public class SteganographyOperationsUtil {
/*checking if the image to hide can fit the hiding image
it returns the range of shades of gray that can be kept in the hiding image*/
public static int checkImages(ImageModel hiding, ImageModel toHide, ImageModel copyOfToHide){
int hidingSize = hiding.getWidth() * hiding.getHeight();
int toHideSize = toHide.getWidth() * toHide.getHeight();
int header = 40;
int value = 8;
while((toHideSize * value + header) > hidingSize){ //if doesnt fit, reducing one range, checking again
value--;
if(value==0){
break;
}
}
if(value == 0) return -1;
if(value<8) posterize(copyOfToHide, (int)pow(2, value)); //run the posterisation if needed
return (int)pow(2, value);
}
/* preparing the hiding image
we need zero on each LSB
*/
public static void prepareHidingImage(ImageModel imgModel){
for (int x = 0; x < imgModel.getWidth(); ++x) {
for (int y = 0; y < imgModel.getHeight(); ++y) {
int color = imgModel.getImage().getRaster().getPixel(x, y, new int[1])[0];
int temp = 254;
int newColor = color & temp;
int[] newColorPixel = {newColor};
imgModel.getImage().getRaster().setPixel(x, y, newColorPixel);
}
}
imgModel.imageChanged();
}
//fullfill by leading zeros with the lenght of the option
public static String fillString(String toFill, int option){
String zero = "0";
if (toFill.length() < option){
int temp = option - toFill.length();
do{
toFill = zero.concat(toFill);
}while(--temp >0);
}
return toFill;
}
/* fullfill the string to get the color matching the posterisation range
for example 1 will be 11111111 (2 ranges of gray)
101 will become 10110110 (3 ranges of gray)
1011 will become 10111011 (4 ranges of gray)
*/
public static String complete(String toComplete){
while (toComplete.length() < 9){
toComplete = toComplete+toComplete;
}
toComplete = toComplete.substring(0, 8);
return toComplete;
}
//hiding Image
public static void hidingOperation(ImageModel hiding, ImageModel toHide, int value){
prepareHidingImage(hiding);
String posterisation = Integer.toString(value-1, 2);
String hiddenWidth = Integer.toString(toHide.getWidth(), 2);
String hiddenHeight = Integer.toString(toHide.getHeight(), 2);
hiddenWidth = fillString(hiddenWidth, 16);
hiddenHeight = fillString(hiddenHeight, 16);
posterisation = fillString(posterisation, 8);
String header = hiddenWidth;
header = header.concat(hiddenHeight);
header = header.concat(posterisation);
int newColor;
int temp = 0;
int temp2 = 0;
int bitsToCheck = (int)logb(value, 2); //how many bits of each pixel we have to hide for given postarisation
int zero = 0;
int one = 1;
int i = 0;
int j = 0;
String colorOfToHideBinary = "";
outerLoop:
for (int x = 0; x < hiding.getWidth(); ++x) {
for (int y = 0; y < hiding.getHeight(); ++y) {
int color = hiding.getImage().getRaster().getPixel(x, y, new int[1])[0];
//filling header
if(temp < header.length()){
if(header.charAt(temp)== '0'){
newColor = color | zero;
}else{ newColor = color | one;
}temp++;
//hiding image
}else{
/*
getting the value of the next pixel of the image to hide, only if temp ==0,
what means that it is the first pixel or each needed bits by the posterisation range
has been already checked
*/
if(temp2 == 0){
int colorOfToHide = toHide.getImage().getRaster().getPixel(i, j, new int[1]) [0];
colorOfToHideBinary = Integer.toString(colorOfToHide, 2);
colorOfToHideBinary = fillString(colorOfToHideBinary, 8);
}
//i check each value of the color in binary, but only as much as needed by the posterisation range
if (colorOfToHideBinary.charAt(temp2) == '0'){
newColor = color | zero;
}else { newColor = color | one;}
temp2++;
if (temp2 == bitsToCheck){
temp2 = 0;
j++;
if(j == toHide.getHeight()){
j = 0;
i++;
}
}
}
int[] newColorPixel = {newColor};
hiding.getImage().getRaster().setPixel(x, y, newColorPixel);
if(i == toHide.getWidth()){
break outerLoop;
}
}
}
hiding.imageChanged();
}
//decrypting image
public static ImageModel encodingOperation(ImageModel imgModel){
int i = 0;
int j = 0;
String widthB = "";
String heightB = "";
String posterisationB = "";
int temp = 0;
int one = 1;
/* loop for taking values from the header, seems to work pretty fine */
outerLoop:
for (int x = 0; x < imgModel.getWidth(); ++x) {
for (int y = 0; y < imgModel.getHeight(); ++y) {
int color = imgModel.getImage().getRaster().getPixel(x, y, new int[1])[0];
if(temp<16){
if ((color & one) == one) widthB = widthB.concat("1");
else widthB = widthB.concat("0");
}else if(temp < 32){
if ((color & one) == one) heightB = heightB.concat("1");
else heightB = heightB.concat("0");
}else if(temp <40){
if ((color & one) == one) posterisationB = posterisationB.concat("1");
else posterisationB = posterisationB.concat("0");
}else{
break outerLoop;
}temp++; j++;
}i++;
}
int width = Integer.parseInt(widthB, 2);
int height = Integer.parseInt(heightB, 2);
int posterisation = Integer.parseInt(posterisationB, 2);
int bitsToCheck = (int)logb(posterisation+1, 2);
int temp2 = 0;
String colorInBinary = "";
//preparing the canvas for the encoded image, width and height from the header
ImageModel encryptedImage = ImageModel.fromHidden(width, height);
int a = 0;
int b = 0;
/* encoding the image
starting after the point after the header, saved in the variables i,j
*/
outerLoop:
for (int x = i; x < imgModel.getWidth(); ++x) {
for (int y = j; y < imgModel.getHeight(); ++y) {
int color = imgModel.getImage().getRaster().getPixel(x, y, new int[1])[0];
/* pixel by pixel reading color of the hidden image
temp2 checks, where to stop - how many LSB of the hiding image keeps information bout one pixel of the hidden img
*/
if ((color & one) == one) colorInBinary = colorInBinary.concat("1");
else colorInBinary= colorInBinary.concat("0");
temp2++;
if (temp2 == bitsToCheck){
temp2 = 0;
//fullfilling the color to the right by the given posterisation range
colorInBinary = complete(colorInBinary);
int newColor = Integer.parseInt(colorInBinary, 2);
colorInBinary = "";
int[] newColorPixel = {newColor};
encryptedImage.getImage().getRaster().setPixel(a, b, newColorPixel);
b++;
if(b == height){
a++;
b=0;
}if (a == width){
break outerLoop;
}
}
}
}
return encryptedImage;
}
public static double logb( double a, double b ){
return Math.log(a) / Math.log(b);
}
public static void posterize(ImageModel imgModel, int value) {
int[] lut = new int[256];
float param1 = 255.0f / (value - 1);
float param2 = 256.0f / (value);
for (int i = 0; i < 256; ++i) {
lut[i] = (int)((int)(i / param2) * param1);
}
useLUT(imgModel, lut);
}
public static void useLUT(ImageModel imgModel, int[] lut) {
for (int x = 0; x < imgModel.getWidth(); ++x) {
for (int y = 0; y < imgModel.getHeight(); ++y) {
int color = imgModel.getImage().getRaster().getPixel(x, y, new int[1])[0];
int[] newColorPixel = {lut[color]};
imgModel.getImage().getRaster().setPixel(x, y, newColorPixel);
}
}
imgModel.imageChanged();
}
Related
I have created a sample SWT application. I am uploading few images into the application. I have to resize all the images which are above 16x16 (Width*Height) resolution and save those in separate location.
For this reason I am scaling the image and saving the scaled image to my destination location. Below is the piece of code which I am using to do that.
Using getImageData() to get the image data and to save I am using ImageLoader save() method.
final Image mySampleImage = ImageResizer.scaleImage(img, 16, 16);
final ImageLoader imageLoader = new ImageLoader();
imageLoader.data = new ImageData[] { mySampleImage.getImageData() };
final String fileExtension = inputImagePath.substring(inputImagePath.lastIndexOf(".") + 1);
if ("GIF".equalsIgnoreCase(fileExtension)) {
imageLoader.save(outputImagePath, SWT.IMAGE_GIF);
} else if ("PNG".equalsIgnoreCase(fileExtension)) {
imageLoader.save(outputImagePath, SWT.IMAGE_PNG);
}
ImageLoader imageLoader.save(outputImagePath, SWT.IMAGE_GIF); is throwing the below exeception when I am trying to save few specific images (GIF or PNG format).
org.eclipse.swt.SWTException: Unsupported color depth
at org.eclipse.swt.SWT.error(SWT.java:4533)
at org.eclipse.swt.SWT.error(SWT.java:4448)
at org.eclipse.swt.SWT.error(SWT.java:4419)
at org.eclipse.swt.internal.image.GIFFileFormat.unloadIntoByteStream(GIFFileFormat.java:427)
at org.eclipse.swt.internal.image.FileFormat.unloadIntoStream(FileFormat.java:124)
at org.eclipse.swt.internal.image.FileFormat.save(FileFormat.java:112)
at org.eclipse.swt.graphics.ImageLoader.save(ImageLoader.java:218)
at org.eclipse.swt.graphics.ImageLoader.save(ImageLoader.java:259)
at mainpackage.ImageResizer.resize(ImageResizer.java:55)
at mainpackage.ImageResizer.main(ImageResizer.java:110)
Let me know If there is any other way to do the same (or) there is any way to resolve this issue.
Finally I got a solution by referring to this existing eclipse bug Unsupported color depth eclipse bug.
In the below code i have created a PaletteData with RGB values and updated my Image Data.
My updateImagedata() method will take the scaled image and will return the proper updated imageData if the image depth is 32 or more.
private static ImageData updateImagedata(Image image) {
ImageData data = image.getImageData();
if (!data.palette.isDirect && data.depth <= 8)
return data;
// compute a histogram of color frequencies
HashMap<RGB, ColorCounter> freq = new HashMap<>();
int width = data.width;
int[] pixels = new int[width];
int[] maskPixels = new int[width];
for (int y = 0, height = data.height; y < height; ++y) {
data.getPixels(0, y, width, pixels, 0);
for (int x = 0; x < width; ++x) {
RGB rgb = data.palette.getRGB(pixels[x]);
ColorCounter counter = (ColorCounter) freq.get(rgb);
if (counter == null) {
counter = new ColorCounter();
counter.rgb = rgb;
freq.put(rgb, counter);
}
counter.count++;
}
}
// sort colors by most frequently used
ColorCounter[] counters = new ColorCounter[freq.size()];
freq.values().toArray(counters);
Arrays.sort(counters);
// pick the most frequently used 256 (or fewer), and make a palette
ImageData mask = null;
if (data.transparentPixel != -1 || data.maskData != null) {
mask = data.getTransparencyMask();
}
int n = Math.min(256, freq.size());
RGB[] rgbs = new RGB[n + (mask != null ? 1 : 0)];
for (int i = 0; i < n; ++i)
rgbs[i] = counters[i].rgb;
if (mask != null) {
rgbs[rgbs.length - 1] = data.transparentPixel != -1 ? data.palette.getRGB(data.transparentPixel)
: new RGB(255, 255, 255);
}
PaletteData palette = new PaletteData(rgbs);
ImageData newData = new ImageData(width, data.height, 8, palette);
if (mask != null)
newData.transparentPixel = rgbs.length - 1;
for (int y = 0, height = data.height; y < height; ++y) {
data.getPixels(0, y, width, pixels, 0);
if (mask != null)
mask.getPixels(0, y, width, maskPixels, 0);
for (int x = 0; x < width; ++x) {
if (mask != null && maskPixels[x] == 0) {
pixels[x] = rgbs.length - 1;
} else {
RGB rgb = data.palette.getRGB(pixels[x]);
pixels[x] = closest(rgbs, n, rgb);
}
}
newData.setPixels(0, y, width, pixels, 0);
}
return newData;
}
To find minimum index:
static int closest(RGB[] rgbs, int n, RGB rgb) {
int minDist = 256*256*3;
int minIndex = 0;
for (int i = 0; i < n; ++i) {
RGB rgb2 = rgbs[i];
int da = rgb2.red - rgb.red;
int dg = rgb2.green - rgb.green;
int db = rgb2.blue - rgb.blue;
int dist = da*da + dg*dg + db*db;
if (dist < minDist) {
minDist = dist;
minIndex = i;
}
}
return minIndex;
}
ColourCounter Class:
class ColorCounter implements Comparable<ColorCounter> {
RGB rgb;
int count;
public int compareTo(ColorCounter o) {
return o.count - count;
}
}
I will use this algorithm for image rotation, however I realized that it only rotates squares, not rectangles.
Would anyone know why?
Main code-problem:
public static int[] rotate(double angle, int[] pixels, int width, int height) {
final double radians = Math.toRadians(angle);
final double cos = Math.cos(radians);
final double sin = Math.sin(radians);
final int[] pixels2 = new int[pixels.length];
for(int pixel = 0; pixel < pixels2.length; pixel++) {
pixels2[pixel] = 0xFFFFFF;
}
for(int x = 0; x < width; x++) {
for(int y = 0; y < height; y++) {
final int centerx = width / 2;
final int centery = height / 2;
final int m = x - centerx;
final int n = y - centery;
final int j = ((int) ( m * cos + n * sin ) ) + centerx;
final int k = ((int) ( n * cos - m * sin ) ) + centery;
if( j >= 0 && j < width && k >= 0 && k < height ){
pixels2[ ( y * width + x ) ] = pixels[ ( k * width + j ) ];
}
}
}
return pixels2;
}
Context application:
try {
BufferedImage testrot = ImageIO.read(new File("./32x32.png"));
int[] linearpixels = new int[testrot.getWidth() * testrot.getHeight()];
int c = 0;
for(int i = 0; i < testrot.getWidth(); i++){
for(int j = 0; j < testrot.getHeight(); j++){
linearpixels[c] = testrot.getRGB(i, j);
c++;
}
}
int[] lintestrot = rotate(50, linearpixels, 32, 32);
BufferedImage image = new BufferedImage(70, 70, BufferedImage.TYPE_INT_RGB);
c = 0;
for(int i = 0; i < 32; i++){
for(int j = 0; j < 32; j++){
image.setRGB(i, j, lintestrot[c]);
c++;
}
}
File outputfile = new File("test002.bmp");
ImageIO.write(image, "bmp", outputfile);
} catch (IOException e1) {
e1.printStackTrace();
}
If you alter to 33 width or height the result will be wrong (wrong image).
You algorithm actually does work. The problem is with your loops in your context application. Because the pixels are stored in raster order, the outer loop needs to iterate to the height and the inner loop iterates to the width, e.g:
for(int i = 0; i < testrot.getHeight(); i++){
for(int j = 0; j < testrot.getWidth(); j++){
linearpixels[c] = testrot.getRGB(j, i); //edit here, tested
c++;
}
}
Then if you change height to 40 for example:
int[] lintestrot = rotate(50, linearpixels, 32, 40);
The loops need to change like this:
c = 0;
for(int i = 0; i < 40; i++){
for(int j = 0; j < 32; j++){
image.setRGB(i, j, lintestrot[c]);
c++;
}
}
Note that the order is reversed in the loops (height then width) compared to the function call (width then height).
I made two methods for a class called Picture, the name is self explanatory. The getAverageColor() method gets the average color of all the pixels in a certain area of the image specified by the parameters passed in. In the pixelate() method, it uses getAverageColor() to pixelate the image. The whole thing works, however it takes upwards of 2 minutes to pixelate a single image. It takes even longer if the pixelSize parameter is made smaller and the image is larger. So I was wondering if there is a better algorithm for doing this by manipulating the pixels.
/**
* NOTE: The smaller the pixelSize the longer the pixelation process takes
*/
public void pixelate(int pixelSize)
{
Pixel[][] pixels = this.getPixels2D();
int blockSize = pixelSize;
Color averageColor = null;
for(int row = 0; row < pixels.length; row += blockSize)
{
for (int col = 0; col < pixels[row].length; col += blockSize)
{
if (!((col + blockSize > pixels[0].length) || (row + blockSize > pixels.length)))
{
averageColor = getAverageColor(row, col, row+blockSize, col+blockSize);
}
for (int row_2 = row; (row_2 < row + blockSize) && (row_2 < pixels.length); row_2++)
{
for (int col_2 = col; (col_2 < col + blockSize) && (col_2 < pixels[0].length); col_2++)
{
pixels[row_2][col_2].setColor(averageColor);
}
}
}
}
}
public Color getAverageColor(int startRow, int startCol, int endRow, int endCol)
{
Pixel[][] pixels = this.getPixels2D();
Color averageColor = null;
int totalPixels = (endRow - startRow)*(endCol - startCol);
int totalRed = 0;
int averageRed = 0;
int totalGreen = 0;
int averageGreen = 0;
int totalBlue = 0;
int averageBlue = 0;
for (int row = startRow; row < endRow; row++)
{
for (int col = startCol; col < endCol; col++)
{
totalRed += pixels[row][col].getRed();
totalGreen += pixels[row][col].getGreen();
totalBlue += pixels[row][col].getBlue();
}
}
averageRed = totalRed / totalPixels;
averageGreen = totalGreen / totalPixels;
averageBlue = totalBlue / totalPixels;
averageColor = new Color(averageRed, averageGreen, averageBlue);
return averageColor;
}
I'm writing the drawing system for a roguelike game based on ascii characters (graphics similar to dwarf fortress). I'm using the AsciiPanel from here. My problem is that when I draw entities on my map, they seem to blink, when they should be solid.
In this gif, the r characters in the top row are the entities.
This is the map's draw method that is called every frame.
public void draw(final Display display) {
for (int x = getViewportX(); x < getViewportX() + viewportWidthInTiles; x++) {
for (int y = viewportY; y < viewportY + viewportHeightInTiles; y++) {
final char character = background[x][y].getCharacter();
final Color foreground = background[x][y].getForeground();
final Color backgroundColor = background[x][y].getBackground();
final AsciiCharacterData data = new AsciiCharacterData(
character, foreground, backgroundColor);
display.setCharacterAt(x - getViewportX(), y - viewportY,
background[x][y].getDrawingLayer(), data);
}
}
display.clearLayer(DrawingLayer.PRIMARY);
for (int i = 0; i < entities.size(); i++) {
final Entity e = entities.get(i);
final char character = e.getCharacter();
final Color foreground = e.getForeground();
final Color backgroundColor = e.getBackground();
final AsciiCharacterData data = new AsciiCharacterData(character,
foreground, backgroundColor);
display.setCharacterAt(e.getX() - getViewportX(), e.getY()
- viewportY, e.getDrawingLayer(), data);
}
}
I think I know what causes the problem, because if I write display.clearLayer(DrawingLayer.BACKGROUND); (the layer the tiles are drawn to) before I draw the background tiles, it creates something even more ridiculous.
This is the Display class, where I think I am making some mistake.
public class Display {
private static final char TRANSPARENT_CHARACTER = ' ';
private final AsciiPanel displayPanel;
private final int widthInCharacters, heightInCharacters;
private final static int Z_LEVELS = DrawingLayer.values().length;
private final AsciiCharacterData[][][] characterMap;
public Display(final AsciiPanel panel) {
displayPanel = panel;
widthInCharacters = panel.getWidthInCharacters();
heightInCharacters = panel.getHeightInCharacters();
characterMap = new AsciiCharacterData[widthInCharacters][heightInCharacters][Z_LEVELS];
for (int x = 0; x < widthInCharacters; x++) {
for (int y = 0; y < heightInCharacters; y++) {
for (int z = 0; z < Z_LEVELS; z++) {
characterMap[x][y][z] = new AsciiCharacterData(
TRANSPARENT_CHARACTER,
displayPanel.getDefaultForegroundColor(),
displayPanel.getDefaultBackgroundColor());
}
}
}
}
public void setCharacterAt(final int x, final int y, final DrawingLayer z,
final AsciiCharacterData c) {
if (x < 0 || x >= widthInCharacters || y < 0 || y >= heightInCharacters)
return;
characterMap[x][y][z.layer] = c;
// if z is not the top level
if (z.layer != Z_LEVELS - 1) {
// check all levels above
for (int i = z.layer + 1; i < Z_LEVELS; i++) {
// if there is an opaque character
if (characterMap[x][y][i].character != TRANSPARENT_CHARACTER)
// we dont need to draw anything
return;
}
}
if (c.character == TRANSPARENT_CHARACTER) {
// loop through all characters under the transparent character
for (int i = z.layer - 1; i >= 0; i--) {
// if we find a non transparent character
if (characterMap[x][y][i].character != TRANSPARENT_CHARACTER) {
// display that one instead
displayPanel.write(characterMap[x][y][i].character, x, y,
characterMap[x][y][i].foregroundColor,
characterMap[x][y][i].backgroundColor);
return;
}
}
// if there were no non trasparent characters
displayPanel.write(TRANSPARENT_CHARACTER, x, y);
// if we are a highlighter, we draw the below character and then
// just draw on top
} else {
displayPanel.write(c.character, x, y, c.foregroundColor,
c.backgroundColor);
}
displayPanel.repaint();
}
public AsciiCharacterData getCharacterAt(final int x, final int y,
final DrawingLayer z) {
return characterMap[x][y][z.layer];
}
public int getWidth() {
return widthInCharacters;
}
public int getHeight() {
return heightInCharacters;
}
public void clearLayer(final DrawingLayer layer) {
for (int x = 0; x < widthInCharacters; x++) {
for (int y = 0; y < heightInCharacters; y++) {
setCharacterAt(x, y, layer,
new AsciiCharacterData(TRANSPARENT_CHARACTER,
displayPanel.getDefaultForegroundColor(),
displayPanel.getDefaultBackgroundColor()));
}
}
}
}
Solved! It was one line in the setCharacterAt method. I was repainting every time I set a character which (while inefficient) also creates that flicker.
Where do I put bounds checking so that program generates an entire maze?
The code should print a Grid with a maze drawn by breaking walls between Cells. However, much to my dismay, the Grid stops when it reaches index 0 or 24. I need the program to visit every cell before it stops (if it goes to a border, it moves back).
Here is the previous error that I'm getting:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
at Grid.genRand(Grid.java:73)
at Grid.main(Grid.java:35)
And here is the source code:
import java.awt.*;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.util.ArrayList;
public class Grid extends Canvas {
Cell[][] maze;
int size;
int pathSize;
double width, height;
ArrayList<int[]> coordinates = new ArrayList<int[]>();
public Grid(int size, int h, int w) {
this.size = size;
maze = new Cell[size][size];
for(int i = 0; i<size; i++){
for(int a =0; a<size; a++){
maze[i][a] = new Cell();
}
}
setPreferredSize(new Dimension(h, w));
}
public static void main(String[] args) {
Frame y = new Frame();
y.setLayout(new BorderLayout());
Panel r = new Panel();
r.setLayout(new BorderLayout());
Grid f = new Grid(25, 400, 400);
r.add(f, BorderLayout.CENTER);
y.add(r, BorderLayout.CENTER);
f.genRand();
f.repaint();
y.pack();
y.setPreferredSize(new Dimension(450, 450));
y.setVisible(true);
}
public void push(int[] xy){
coordinates.add(xy);
int i = coordinates.size();
coordinates.ensureCapacity(i++);
}
public int[] pop(){
int[] x = coordinates.get((coordinates.size())-1);
coordinates.remove((coordinates.size())-1);
return x;
}
public int[] top(){
return coordinates.get((coordinates.size())-1);
}
public void genRand(){
// create a CellStack (LIFO) to hold a list of cell locations [x]
// set TotalCells = number of cells in grid
int TotalCells = size*size;
// choose a cell at random and call it CurrentCell
int m = randomInt(size);
int n = randomInt(size);
while(m<1){
m = randomInt(size);
}
while(n<1){
n = randomInt(size);
}
Cell curCel = maze[m][n];
// set VisitedCells = 1
int visCel = 1;
int o = 0;
int p = 0;
int h;
int d;
int[] q;
// while VisitedCells < TotalCells
while( visCel < TotalCells){
d = 0;
// find all neighbors of CurrentCell with all walls intact
if(m!=0&&n!=0){
if(m<size&&n<size){
if(maze[m-1][n].countWalls() == 4)
{d++;}
if(maze[m+1][n].countWalls() == 4)
{d++;}
if(maze[m][n-1].countWalls() == 4)
{d++;}
if(maze[m][n+1].countWalls() == 4)
{d++;}
}
}
// if one or more found
if(d!=0){
Point[] ls = new Point[4];
ls[0] = new Point(m-1,n);
ls[1] = new Point(m+1,n);
ls[2] = new Point(m,n-1);
ls[3] = new Point(m,n+1);
// knock down the wall between it and CurrentCell
h = randomInt(3);
switch(h){
case 0: o = (int)(ls[0].getX());
p = (int)(ls[0].getY());
curCel.destroyWall(2);
maze[o][p].destroyWall(1);
break;
case 1: o = (int)(ls[1].getX());
p = (int)(ls[1].getY());
curCel.destroyWall(1);
maze[o][p].destroyWall(2);
break;
case 2: o = (int)(ls[2].getX());
p = (int)(ls[2].getY());
curCel.destroyWall(3);
maze[o][p].destroyWall(0);
break;
case 3: o = (int)(ls[3].getX());
p = (int)(ls[3].getY());
curCel.destroyWall(0);
maze[o][p].destroyWall(3);
break;
}
// push CurrentCell location on the CellStack
push(new int[] {m,n});
// make the new cell CurrentCell
m = o;
n = p;
curCel = maze[m][n];
// add 1 to VisitedCells
visCel++;
}
// else
else{
// pop the most recent cell entry off the CellStack
q = pop();
m = q[0];
n = q[1];
curCel = maze[m][n];
// make it CurrentCell
// endIf
}
// endWhile
}
}
public int randomInt(int s) { return (int)(s* Math.random());}
public void paint(Graphics g) {
int k, j;
width = getSize().width;
height = getSize().height;
double htOfRow = height / (size);
double wdOfRow = width / (size);
//checks verticals - destroys east border of cell
for (k = 0; k < size; k++) {
for (j = 0; j < size; j++) {
if(maze[k][j].checkWall(2)){
g.drawLine((int) (k * wdOfRow), (int) (j * htOfRow), (int) (k * wdOfRow), (int) ((j+1) * htOfRow));
}}
}
//checks horizontal - destroys north border of cell
for (k = 0; k < size; k++) {
for (j = 0; j < size; j++) {
if(maze[k][j].checkWall(3)){
g.drawLine((int) (k * wdOfRow), (int) (j * htOfRow), (int) ((k+1) * wdOfRow), (int) (j * htOfRow));
}}
}
}
}
class Cell {
private final static int NORTH = 0;
private final static int EAST = 1;
private final static int WEST = 2;
private final static int SOUTH = 3;
private final static int NO = 4;
private final static int START = 1;
private final static int END = 2;
boolean[] wall = new boolean[4];
boolean[] border = new boolean[4];
boolean[] backtrack = new boolean[4];
boolean[] solution = new boolean[4];
private boolean isVisited = false;
private int Key = 0;
public Cell(){
for(int i=0;i<4;i++){wall[i] = true;}
}
public int countWalls(){
int i, k =0;
for(i=0; i<4; i++) {
if (wall[i] == true)
{k++;}
}
return k;}
public boolean checkWall(int x){
switch(x){
case 0: return wall[0];
case 1: return wall[1];
case 2: return wall[2];
case 3: return wall[3];
}
return true;
}
public void destroyWall(int x){
switch(x){
case 0: wall[0] = false; break;
case 1: wall[1] = false; break;
case 2: wall[2] = false; break;
case 3: wall[3] = false; break;
}
}
public void setStart(int i){Key = i;}
public int getKey(){return Key;}
public boolean checkVisit(){return isVisited;}
public void visitCell(){isVisited = true;}
}
I overlooked you code very quickly:
you may got your exceptions while calling top() or pop() when coordinates is empty
--> coordinates.get(coordinates.size()-1) if size is 0 you try to adress index -1 -> BAM!
some methods do look very complex. you may split that functionallity in separate methods/functions
you do not mix AWT and SWING components because the do behave different
NEVER EVER do GUI stuff (showing, hiding, changing content, clicking, whatever in JFrame, JPanel etc.) out of the Event Dispatcher Thread (EDT) -> this may cause dead locks