MineSweeper game array - java

I have the same problem as some guy who asked this.
I want to code some basic stuff for a little minesweeper game.
Now I have the problem that my code
public class Minesweeper1 {
public static int[][] makeRandomBoard(int s, int z, int n){
int feld[][] = new int [s][z];
for(int i = 0; i < s; i++){
for(int j = 0; j < z; j++){
feld[i][j] = 0;
}
}
for(int i = 0; i < n; i++){
selectRandomPosition(s, z);
feld[randomHeight][randomWidth] = 1;
}
}
so it starts the selectRandomPosition code:
public static int[] selectRandomPosition(int maxWidth, int maxHeight) {
int randomHeight = StdRandom.uniform(0, maxHeight);
int randomWidth = StdRandom.uniform(0, maxWidth);
return new int[]{randomHeight, randomWidth};
}
Here I am not allowed to change anything, but it returns a new array. Now my question is how can I use the new array in makeRandomBoard?, since I do not know any name of the array. When I use feld[randomHeight][randomWidth] = 1; it says that it does not know these variables.
And he did get the answer:
Call the method, and assign its return value to a variable. Now you have a name for the array:
// Make a call
int[] randomArray = selectRandomPosition(maxW, maxH);
// Access the width
int randomW = randomArray[0];
// Access the height
int randomH = randomArray[1];
but what do I have to write now?
I tried it with:
feld[randomW][randomH] = 1;
but it seems like it doesn't work. I also need a return statement.
Can anyone help me?

I believe this is the solution you are looking for:
Solution
public class Minesweeper1 {
// Note:
// s == Height
// z == Width
public static int[][] makeRandomBoard(int s, int z, int n) {
// Note: Misspelling of "field"?
int feld[][] = new int [s][z];
// Initialize the game board with no mines (value of 0)
for(int i = 0; i < s; i++) {
for(int j = 0; j < z; j++) {
feld[i][j] = 0;
}
}
// Iterate through n times to place "mines" (value of 1)
for(int i = 0; i < n; i++){
// selectRandomPosition returns an array of length 2
// the first index (0) = randomHeight
// the second index (1) = randomWidth
// Notice that z and s is flipped
// because the first parameter is for width, which is z
// and the second parameter is for height, which is s
int[] position = selectRandomPosition(z, s);
int positionX = position[1];
int positionY = position[0];
// The order of positionY/positionX is key!
// If it's in the wrong order you will get an
// IndexOutOfBoundsException!
feld[positionY][positionX] = 1;
}
// Return the newly created array
return feld;
}
public static int[] selectRandomPosition(int maxWidth, int maxHeight) {
int randomHeight = StdRandom.uniform(0, maxHeight);
int randomWidth = StdRandom.uniform(0, maxWidth);
// Notice that this is returning a fixed array of two elements
// the first being the Y component, and the second being the X
// component.
return new int[]{randomHeight, randomWidth};
}
}
Problems
Passing the wrong values
You were calling selectRandomPosition wrong. Remember that s is the Height, and z is the Width. So you were passing into selectRandomPosition the Height for the first parameter, and the Width for the second parameter. Look at the method declaration:
public static int[] selectRandomPosition(int maxWidth, int maxHeight)
That meant you passed the Height into the maxWidth, and the Width into the maxHeight. My solution flips it for you. This can be confusing because s and z don't really give you hints to what they are (Height and Width) - consider renaming these variables to help you.
Accessing in the wrong order
You have in your question:
feld[randomW][randomH] = 1;
This is wrong, it should be:
feld[randomH][randomW] = 1;
This image shows a visual representaion of what a two dimensional array looks like:
So the access would be:
feld[0][0] == 1
feld[0][1] == 1
feld[0][2] == 1
feld[1][0] == 1
feld[1][1] == 2
feld[1][2] == 4
feld[2][0] == 1
feld[2][1] == 3
feld[2][2] == 9
Nit-Pick: Misspellings
Other than having weird variable names like s and z that do not help you at all in remembering what means what, your main variable that you will eventually return is misspelled. Did you mean "field"?
Variable naming is important and can help you, and other readers, to easily understand your code. Also, comments in places where you think you need them also help!

Related

Adding to 2D Array returning 'Index 0 out of bounds for length 0' error

I have a string currentBoard that is #######.x+.##..w.##....#######. I'm trying to add each character in the string to a 2D-array so it will look like this:
######
#.x+.#
#..w.#
#....#
######
I can't figure out why the out of bounds error keeps coming up. I've tested to check that the values I use to determine the array size are valid, I've tested adding a value manually, like gameboard[0][0] = '#'; which doesn't work. This is my first time working with multi-dimensional arrays so I must be doing something totally dumb. I just can't figure it out.
Here's the entire code block I'm working with:
static char[][] gameBoard = new char[currentWidth][currentHeight];
public static void generateBoard() {
int x = 0;
int y = 0;
for (int i = 0; i < currentBoard.length(); i++) {
char z = currentBoard.charAt(i);
gameBoard[x][y] = z;
if (y == currentHeight) {
y = 0;
}
if ((i + 1) % currentWidth == 0) {
x++;
}
y++;
}
}
currentHeight is 5, currentWidth is 6.
I believe you're trying to set static fields for your array parameters, but the array is already created at the point you're updating them. Take for example:
static int height; // == 0!
static int width; // == 0!
static char[][] gameBoard = new char[currentWidth][currentHeight];
public static void main(String... args) {
height = 5;
width = 6;
//but the gameboard is already made
generateBoard();
}
public static void generateBoard() {
//...
//gameboard is not valid,
}
In general, avoid misusing static for reasons like above. One solution to this problem would be to have a class which encapsulates your game board, and takes the width/height as arguments.
Your code can be greatly simplified by making the observation that the x-coordinate will be the remainder of dividing i by currentWidth and the y-coordinate will be the quotient of i divided by the currentWidth, rounded down.
public static void generateBoard() {
for (int i = 0, len = currentBoard.length(); i < len; i++) {
char z = currentBoard.charAt(i);
final int x = i % currentWidth;
final int y = i / currentWidth;
gameBoard[x][y] = z;
}
}
See the above code in action here.
It seems that the width and height in the declaration of the board have to be switched:
public static void main(String[] args) {
String currentBoard = "#######.x+.##..w.##....#######";
char[][] board = new char[5][6];
for (int i = 0, x = 0, y = 0; i < currentBoard.length(); i++) {
board[y][x] = currentBoard.charAt(i);
x++;
if (x == board[y].length) {
x = 0;
y++;
}
}
for (char[] row : board) {
System.out.println(new String(row));
}
}
prints as expected:
######
#.x+.#
#..w.#
#....#
######

return new int[]{randomHeight, randomWidth};

I want to code some basic stuff for a little minesweeper-game, that we do in university. Now I have the problem that my code .
public class Minesweeper1 {
public static int[][] makeRandomBoard(int s, int z, int n){
//creating the field and fill with 0
int feld[][] = new int [s][z];
for(int i = 0; i < s; i++){
for(int j = 0; j < z; j++){
feld[i][j] = 0;
}
}
//n-times to fill the field
for( int i = 0; i < n; i++){
selectRandomPosition(s, z);
//want to get them from selectRandomPosition
feld[randomHeight][randomWidth] = 1;
}
}
}
So it starts the selectRandomPosition code:
public static int[] selectRandomPosition(int maxWidth, int maxHeight) {
int randomHeight = StdRandom.uniform(0, maxHeight);
int randomWidth = StdRandom.uniform(0, maxWidth);
return new int[]{randomHeight, randomWidth};
}
Here I'm not allowed to change anything, but it returns a new array. Now is my question how can I use the new array in my makeRandomBoard method, since I do not know any name of the array. When I use feld[randomHeight][randomWidth] = 1;, it says that it doesn't know these variables.
how I can use the new array in my makeRandomBoard method, since I do not know any name of the array?
Call the method, and assign its return value to a variable. Now you have a name for the array:
// Make a call
int[] randomArray = selectRandomPosition(maxW, maxH);
// Access the width
int randomW = randomArray[0];
// Access the height
int randomH = randomArray[1];

Initializing 2d java array

I am working on an extremely basic game. However when I try to create the array i am running into errors. The error is index out of bounds. However I thought I fixed it by adding the -1 to make sure I don't go out of bounds. can someone tell me, or give me a clue as to what I did wrong?
package gameProject;
public class world {
int numEnemies, numBosses;
int [][] world = new int[10][10];
public world(){
int[][] world = createArray(10,10);
populateWorld(world);
}
private int[][] createArray(int inX, int inY){
//create the array that holds world values
int[][] world = new int[inX][inY];
//initialize the world array
for(int i = 0; i < world.length - 1; i ++){
for(int j = 0; j < world[0].length - 1; j++){
world[i][j] = 0;
}
}
return world;
}
private void populateWorld(int[][] world){
for(int i = 0; i < world.length - 1; i++){
for(int j = 0; j < world[0].length - 1; i++){
world[i][j] = 0;
}
}
}
}
In your populateWorld method, change
for(int j = 0; j < world[0].length - 1; i++)
to
for(int j = 0; j < world[0].length - 1; j++)
You keep incrementing the wrong counter, going eventually out of its bounds. (10)
(PS: you don't need the length - 1 in your loops' condition, just length would do)
The error is in
for (int j = 0; j < world[0].length - 1; i++)
you should write
for (int j = 0; j < world[0].length - 1; j++)
instead.
Note that you can reduce your code a little bit:
You create the array for member World.world twice. Also the elements of an int array are already initialized to 0 so you don't need to do this explicitly.
You should just do
private int[][] createArray(int inX, int inY) {
int[][] world = new int[inX][inY];
for (int i = 0; i < inX; i++)
for (int j = 0; j < inY; j++)
world[i][j] = 0;
return world;
}
You never actually need to check the length of the world array, because the length was already passed in as a parameter value.
And then also
private void populateWorld(int[][] world) {
for (int i = 0; i < world.length; i++)// v error 'i' should be 'j'
for (int j = 0; j < world[i].length; j++) // <- error on this line
world[i][j] = 0;
}
Your basic problem is that you're incrementing the wrong loop variable.
Why? Because you're far off from any clean code.
Lemme show you how clean coding is done:
class names start with a capital letter, method and variable name with lower case letters
you might prefix your variables with their scope ('m' for member, 'p' for parameter, nothing for local variables). Saves you the all-time-reference to 'this'. Strongly depends on your code style. I highly suggest doing it, keeps your code clean and really easy to debug.
use the final and private keywords where possible
use descriptive variable names. Here especially x and y for loop variables, as you're abstracting a 2d-plane
Some more considerations:
usually games grow more complex. Usually simple primitives (like your int-array) will not suffice for long to store all relevant information. Use classes like Cell
use enums so you can lose magic numbers => coding, reading and debugging made a lot easier
So - after a lot of talk - here's the final code:
package gameproject;
/**
* Use comments like this to describe what the classes purpose is.
* Class comment is the most important one. If you can't tell what a method/variable is doing by its name, you should also comment methods and/or variables!
* #author JayC667
*/
public class World {
/*
* STATIC part of the class - keep separated from object code
*/
// you could/should also put these static classes to their separate files and make em non-static
/**
* Denotes, what a {#linkplain Cell} is occupied with
*/
static public enum CellType {
EMPTY, //
BOSS, //
ENEMY
}
/**
* Represents a single cell within the world. Stores information about its coodrinates (redundant) and its occupator (see {#linkplain CellType})
* #author JayC667
*/
static private class Cell { // use cell to store data for you
public final int mX; // x and y are actually not useful at the moment, you could also remove them
public final int mY;
private CellType mCellType = CellType.EMPTY;
public Cell(final int pX, final int pY) {
mX = pX;
mY = pY;
}
public CellType getCellType() {
return mCellType;
}
public void setCellType(final CellType pCellType) {
mCellType = pCellType;
}
}
// when possible, make methods static, unless you unnecessarily blow up the parameter list
// this is a typical demo for a factory method
static private Cell[][] createWorld(final int pWidth, final int pHeight) {
final Cell[][] newWorld = new Cell[pWidth][pHeight];
for (int y = 0; y < pHeight - 1; y++) {
for (int x = 0; x < pWidth - 1; x++) {
newWorld[y][x] = new Cell(x, y);
}
}
return newWorld;
}
/*
* OBJECT part of the class - keep separated from static code
*/
private final Cell[][] mWorld;
private final int mWorldWidth;
private final int mWorldHeight;
private final int mNumberOfEnemies;
private final int mNumberOfBosses;
public World(final int pWidth, final int pHeight, final int pNumberOfEnemies, final int pNumberOfBosses) {
if (pWidth < 1 || pHeight < 1) throw new IllegalArgumentException("World width and height must be greater than 0!");
if (pNumberOfEnemies < 0 || pNumberOfBosses < 0) throw new IllegalArgumentException("Enemy and boss counts must not be negative!");
if (pWidth * pHeight < pNumberOfEnemies + pNumberOfBosses) throw new IllegalArgumentException("World is too small for all the bad guys!");
mWorldWidth = pWidth;
mWorldHeight = pHeight;
mNumberOfEnemies = pNumberOfEnemies;
mNumberOfBosses = pNumberOfBosses;
mWorld = createWorld(pWidth, pHeight);
populateWorld();
}
// refers to many member variables, so not static (would only blow up parameter list)
private void populateWorld() {
for (int i = 0; i < mNumberOfBosses; i++) {
final Cell c = getRandomCell(CellType.EMPTY);
mWorld[c.mY][c.mX].setCellType(CellType.BOSS);
}
for (int i = 0; i < mNumberOfEnemies; i++) {
final Cell c = getRandomCell(CellType.EMPTY);
mWorld[c.mY][c.mX].setCellType(CellType.ENEMY);
}
}
private Cell getRandomCell(final CellType pCellType) {
while (true) { // TODO not a good, but simple solution; might run infinite loops
final int randomX = (int) (mWorldWidth * Math.random());
final int randomY = (int) (mWorldHeight * Math.random());
if (mWorld[randomY][randomX].getCellType() == pCellType) return new Cell(randomX, randomY);
}
}
}

Strange unreachable yet compilable Code

Well I made this method Resize with in my Class Object2D, which is supposed to resize the two-dimensional Color-Array PointInformation of the Object2D, that it is called onto, by a certain Percentage. (I found that easier to do when convertig the 2D-Array into an 1D Array)
public class Object2D
{
int width;
int height;
int ResizePercentage = 100;
Color PointInformation[][];
public void Resize(int Percentage)
{
Color[]temp = Standart_Methods.Reduce2DArray(this.PointInformation);
int temp_width = this.width;
int temp_height = this.height;
double Faktor = (Percentage+100)/100;
this.width = (int) (this.width*Faktor);
this.height = (int) (this.height*Faktor);
this.ResetPointInformation();
Color[]temp2 = Standart_Methods.Reduce2DArray(this.PointInformation);
int SamePixelCount = 0;
Color LastColor = temp[0];
for (int i = 0; i < temp.length; i++)
{
if (temp[i] == LastColor )
{
SamePixelCount += 1;
}
else
{
for (int i2 = (int) (i*Faktor); i == 1; i-- )
//Method Resize will only be called when i*Faktor is going to be 100% = X.0 (An Integer)
{
temp2[i*2-i] = LastColor;
}
SamePixelCount = 0;
}
}
Standart_Methods.PrintArray(temp2);
int a = 10;
int b = 0;
System.out.print(a/b); //No Exeption, Code unreachable!?
}
}
It basically starts at temp[0] and adds 1 to the int SamePixelCount as long as it finds the same Color.
When a different Color is found, the method writes the Color of the former Pixels into the right Places in the temp2 Array.
for (int i = 0; i < temp.length; i++)
{
if (temp[i] == LastColor )
{
SamePixelCount += 1;
}
else
{
for (int i2 = (int) (i*Faktor); i == 1; i-- )
//Method Resize will only be called when i*Faktor is going to be 100% = X.0 (An Integer)
{
temp2[i*2-i] = LastColor;
}
SamePixelCount = 0;
}
}
The correct translation of the manipulated Array temp2 into the Object's PointInformation is still missing, because I wanted to test, if temp2 was correctly resized out of temp, so I did
Standart_Methods.PrintArray(temp2); //the Method works btw
but it just did nothing! And even bader! Everything I put at the place of that command, also didn't!
int a = 10;
int b = 0;
System.out.print(a/b); //No Exeption!
And what is even stranger is, that as soon as I call the Method Resize, somewhere, everything after the Call turns into the same strange unreachable Code!?
I am seriously totally clueless about what could have caused this problem.
Any help would be nice!
dividing by zero certainly will give you ArithmeticException:
public class Test {
public static void main(String[] args) {
int a = 10;
int b = 0;
System.out.println(a/b);
}
}
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Test.main(Test.java:14)
I suggest use eclipse and trace your code using the debugger. Inspect your variables per code line and I'm sure you can figure our what's wrong

StackOverflowError exception ruining interesting and complex program

So this problem is a little bit complicated to understand what I'm trying to do.
Basically, I am trying to randomly generate 3 vectors, all of size 11.
The first vector must have a 1 at position 0 with the next 5 positions being 0 (e.g. 100000) while the next five digits can be either 0 1 or 2, however there can only be one zero used in the last 5 digits, hence 10000012101 would be valid but 10000012001 wouldn't.
The same is applicable to the second and third vector however the first 1 will move a place for the second and the third (010000xxxxx for the second, and 001000xxxxx for the third).
There are more conditions that have to be satisfied. Each vector must differ from each other in at least 5 positions (10000011210 would differ from 01000022100 in 5 positions which would work).
However, there is also a final constraint which states that if you add the vectors modulo 3, then the result of adding these two must have at least 5 NON zero values in the vector.
I have went about this by using arraylists. As I know the first 6 elements of each arraylist for each vector I manually put these in, and for the next 5 elements I randomly assign these, if there is more than one 0 in the last five digits, i call the method again recursively.
The problem I have with this program is that when I try to run my code it comes up with a
Exception in thread "main" java.lang.StackOverflowError
at java.util.ArrayList.get(Unknown Source)
I think it's because it's continuously trying to loop and therefore crashing but I'm not sure. See below for the code.
import java.util.ArrayList;
/**
* The purpose of this class is to be able to capture different ways
* of generating six vectors that will produce a collection of 729
* vectors that guarantee 9 out of 11 correct.
*/
public class GenerateVectors {
static ArrayList<Integer> firstVector = new ArrayList<Integer>();
static ArrayList<Integer> secondVector = new ArrayList<Integer>();
static ArrayList<Integer> thirdVector = new ArrayList<Integer>();
static ArrayList<Integer> sumOfXandY = new ArrayList<Integer>();
//Creates the first vectors to ensure it starts with "1,0,0,0,0,0"
//and has at most one more zero in the last 5 digits
public void createFirstVector(){
int[] fir stVector1 = {1,0,0,0,0,0};
for (int i=0; i<firstVector1.length; i++) {
firstVector.add(firstVector1[i]);
}
for(int i = 0; i < 5; i++){
int x = (int) (Math.random()*3);
firstVector.add(x);
}
int j = 0;
for(int i = 6; i<firstVector.size(); i++){
if(firstVector.get(i).equals(0)){
j++;
}
}
if(j>1){
OneZeroInLastFive(firstVector);
}
int[] sum = {0,0,0,0,0,0,0,0,0,0,0};
for (int i=0; i<sum.length; i++) {
sumOfXandY.add(sum[i]);
}
}
//Edits the vector if there is more than 0 in the last five digits
public void OneZeroInLastFive(ArrayList<Integer> x){
int j = 0;
for(int i = 6; i<x.size(); i++){
if(x.get(i).equals(0)){
j++;
}
}
if(j>1){
x.set(6, (int) (Math.random()*3));
x.set(7, (int) (Math.random()*3));
x.set(8, (int) (Math.random()*3));
x.set(9, (int) (Math.random()*3));
x.set(10, (int) (Math.random()*3));
j = 0;
OneZeroInLastFive(x);
}
}
//Creates the second vector with the last 5 digits random
public void createSecondVector(){
int[] secondVector1 = {0,1,0,0,0,0};
for (int i=0; i<secondVector1.length; i++) {
secondVector.add(secondVector1[i]);
}
for(int i = 0; i < 5; i++){
int x = (int) (Math.random()*3);
secondVector.add(x);
}
}
//Creates the third vector with the last 5 digits random
public void createThirdVector(){
int[] thirdVector1 = {0,0,1,0,0,0};
for (int i=0; i<thirdVector1.length; i++) {
thirdVector.add(thirdVector1[i]);
}
for(int i = 0; i < 5; i++){
int x = (int) (Math.random()*3);
thirdVector.add(x);
}
}
/**
* Will edit the second vector to ensure the following conditions are satisfied
* - The sum of x and y modulo 3 has at least 5 NON zeros
* - x and y must DIFFER in at least 5 places
* - There is only one zero within the last 5 digits
*
*/
public void checkVectors(ArrayList<Integer> x, ArrayList<Integer> y){
int k = 0;
int m = 0;
for(int j = 0; j < x.size(); j++){
if(x.get(j).equals(y.get(j))){
;
}
else{
k++;
}
}
for(int i = 6; i<y.size(); i++){
if(y.get(i).equals(0)){
m++;
}
}
if((k>4 && m<1)&& checkNonZeros(x,y)){
System.out.println("Conditions met");
}
else{
y.set(6, (int) (Math.random()*3));
y.set(7, (int) (Math.random()*3));
y.set(8, (int) (Math.random()*3));
y.set(9, (int) (Math.random()*3));
y.set(10, (int) (Math.random()*3));
k = 0;
m = 0;
checkVectors(x,y);
}
}
public ArrayList<Integer> addTwoVectors(ArrayList<Integer> x, ArrayList<Integer> y, ArrayList<Integer> z){
for(int i = 0; i<x.size(); i++){
int j = x.get(i);
int k = y.get(i);
z.set(i, ((j+k)%3));
}
return z;
}
public boolean checkNonZeros(ArrayList<Integer> x, ArrayList<Integer> y){
addTwoVectors(x,y, sumOfXandY);
int j = 0;
for(int i = 0; i<firstVector.size(); i++){
if(sumOfXandY.get(i).equals(0)){
;
}
else{
j++;
}
}
if(j<5){
return false;
}
else {
return true;
}
}
public static void main(String[] args){
GenerateVectors g = new GenerateVectors();
g.createFirstVector();
g.createSecondVector();
g.createThirdVector();
g.checkVectors(firstVector,secondVector);
g.checkVectors(secondVector,thirdVector);
System.out.println(firstVector);
System.out.println(secondVector);
System.out.println(thirdVector + "\n");
System.out.println(g.checkNonZeros(firstVector, secondVector));
System.out.println(g.checkNonZeros(secondVector,thirdVector));
System.out.println(sumOfXandY);
}
}
Any help would be much appreciated!!!
The problem is that you have methods that recursively call themselves in order to 'redo', which may happen many times before you get a success. This is fine in languages like scheme or ml which do proper tail recursion, but java does not, so you get stack overflows.
In order to fix this you need to manually convert the recursive code into a loop. Code that looks like:
method(arg1, arg2) {
Code_block_1;
if (test) {
Code_block_2;
} else {
Code_block_3;
method(newarg1, newarg2);
}
}
needs to become something like:
method(arg1, arg2) {
Code_block_1;
while(!test) {
Code_block_3;
arg1 = newarg1;
arg2 = newarg2;
Code_block_1;
}
Code_block_2;
}
You can then refactor stuff to get rid of/merge the duplicated code if you wish.

Categories

Resources