I'm trying to program Minesweeper in Java. I am currently trying to create an x amount of unique Mines, which positions ( as POINTS, where x corresponds to Row and y to column for JavaFX) are saved in a one dimensional Array. So that I can then return the list to the controller.
I could start and:
create all Points, add them to the array, test every Point with every other Point, overwrite the doubles with new Points, test again...
but that seems awfully inelegant.
My problem so far was, that when I test whether or not my just created point is .equal() to every Point in the Mines[] array, it throws an exception since the array is empty.
This new solution is the best I came up with so far, but still buggy. Either some pointers with the current code or a more elegant approach would be great!
Thanks for the help
MineNumber = mines;
Mheight = height;
Mwidth = width;
int row;
int column;
int counter = 0;
Point[] Mines = new Point[MineNumber]; //5
Random Rnd = new Random();
boolean create=true;
no clue why it only works with -1 there, but after some trying this way it at least runs
do {
if (counter < MineNumber - 1) {
row = Rnd.nextInt(Mwidth);
column = Rnd.nextInt(Mheight);
Point p = new Point(row, column);
System.out.println(p); //test
if (counter <= 0) {
Mines[0] = p;
counter++;
} else {
for (int i = 0;i < counter; i++) {
if (Mines[i].equals(p)) {
break;
} else {
Mines[counter] = p;
counter++;
}
}
}
} else {
create = false;
}
} while (create);
System.out.println(Mines[0] + " " + Mines[1] + " " + Mines[2] + " "
+ Mines[3] + " " + Mines[4]);
}
Output:
java.awt.Point[x=3,y=2]
java.awt.Point[x=1,y=8]
java.awt.Point[x=9,y=12]
java.awt.Point[x=3,y=2] java.awt.Point[x=1,y=8] java.awt.Point[x=9,y=12] java.awt.Point[x=9,y=12] null
Store each location of a placed mine in a set:
Set<Point> placedMines = new HashSet<>();
Then you can do your loop from 0 till mine number without the need to change the index and running into issues with accessing an element that was not yet set.
You can check easily:
Point p = Point(row, column);
while (placedMines.contains(p)) {
// there is already a mine at that location, select a different one.
p = Point(Rnd.nextInt(Mwidth), Rnd.nextInt(Mheight));
}
Related
I am teaching myself java using the cs106a course from Stanford.
Currently I am on chapter 10 of the book "The Art and Science of Java".
The problem is to write a 3x3 Magic Square.
The exercise:
You have to write a 3x3 array
Each side of the array(Magic Square) has to equal 15
The problem:
The program I wrote works, the assignment is complete, this question is for self learning. As a beginner I would like to improve the method SumOfSides() and make it smaller and more efficient. I tried iterating the array in this method but still have issues. Is there a way to make it more efficient?
public void run() {
//set the font
setFont("Helvetica-40");
//fill the array
fillArray();
//sum up all sides
SumOfSides();
//check if all of the sides in the magic square array equal 15:
checkSides(mSqr);
//I used this for debugging purposes only:
//showSides();
}
//for debugging purposes:
public void showSides() {
println(sumRight0);
println(sumRight1);
println(sumRight2);
println(sumBottom0);
println(sumBottom1);
println(sumBottom2);
println(sumDiagonalUp);
println(sumDiagonalDown);
}
public void SumOfSides() {
sumRight0 = mSqr[0][0] + mSqr[0][1] + mSqr[0][2];
sumRight1 = mSqr[1][0] + mSqr[1][1] + mSqr[1][2];
sumRight2 = mSqr[2][0] + mSqr[2][1] + mSqr[2][2];
sumBottom0 =mSqr[0][0] + mSqr[1][0] + mSqr[2][0];
sumBottom1 =mSqr[0][1] + mSqr[1][1] + mSqr[2][1];
sumBottom2 =mSqr[0][2] + mSqr[1][2] + mSqr[2][2];
sumDiagonalUp = mSqr[2][0] + mSqr[1][1]+ mSqr[0][2];
sumDiagonalDown = mSqr[0][0] + mSqr[1][1] + mSqr[2][2];
}
/*This predicate method checks if the sides
of the array add up to 15: */
public boolean checkSides(int[][] myArray) {
if (sumRight0 ==15 && sumRight1 ==15&& sumRight2==15 && sumBottom0==15&& sumBottom1==15&&
sumBottom2==15&& sumDiagonalUp==15&&sumDiagonalDown==15) {
println("True, this is a Magic Square");
return true;
} else {
println("False, the sides do not equal 15");
return false;
}
}
public void fillArray() {
int num =0;
for(int row=0; row <3; row++) {
for (int col=0; col<3; col++) {
num=readInt("");
mSqr[row][col]=num;
}
}
/*Test array values here to see
* if they were entered correctly.
*/
//println(mSqr[1][2]); //should be 6
//println(mSqr[2][0]); //should be 7
}
//instance variables:
int[][] mSqr= new int[3][3];
List<List<Integer>> new1 = new ArrayList<>();
private int sumRight0;
private int sumRight1;
private int sumRight2;
private int sumBottom0;
private int sumBottom1;
private int sumBottom2;
private int sumDiagonalUp;
private int sumDiagonalDown;
}
Perhaps the only thing is readability. You could take the values and move them into more readable variables:
int topLeft = mSqr[0][0];
int topMid = mSqr[0][1];
...
int sumLeft = topLeft + midLeft + bottomLeft;
int sumRight = topRight = midRight + bottomRight;
...
To address your concern of making it smaller, I would argue that converting the sums into loops, as you mentioned, is certainly not worth it in the case that you are doing 6 sums of 3 values each. Furthermore, each term of each sum is common to either one or two other sums, which does not provide much overlap. If you were performing larger sums (larger in number of terms in the sum, not the total value), then perhaps it would be worth it on a readability/SLOC argument.
Suppose you did want to do a loop still though, you could do something like
sumLeft = 0;
sumRight = 0;
sumTop = 0;
sumBottom = 0;
sumDiagonalUp = 0;
sumDiagonalDown = 0;
for(int i = 0; i < mSqr.length; i++) {
for(int j = 0; j < mSqr[i].length; j++) {
if (i == 0) {
sumLeft += mSqr[i][j];
}
if (i == mSqr.length - 1) {
sumRight += mSqr[i][j];
}
if (j == 0) {
sumTop += mSqr[i][j];
}
if (j == mSqr[i].length) {
sumBottom += mSqr[i][j];
}
if (i == j) {
sumDiagonalDown += mSqr[i][j];
}
if (i + j == mSqr.length - 1) {
sumDiagonalUp += mSqr[i][j];
}
}
}
The loops only provide benefit on large magic squares.
Also, I am confused by your description contrasted with your implementation. It seems you are summing each row and column, and the two diagonals of the square, as opposed to the 4 sides and the diagonals.
I've been working on a Tic-Tac-Toe artificial intelligence lately as a side project. I have thus far succeeded in creating a working prototype of the game that randomly generates the computer moves, making the user win around 90% of time. However, I am trying to make the computer unbeatable through the minimax algorithm. While using the minimax algorithm, I need to get successors for the board, this is what I am having trouble with
This is currently my function:
public static ArrayList<board> successors(board aBoard) {
board orig = aBoard;
ArrayList<board> succ = new ArrayList<board>();
for(int i = 0; i < 9; i++) {
int row = i / 3;
int col = i % 3;
if(!orig.gameBoard[row][col].filled) {
System.out.println(row);
System.out.println(col);
System.out.println("Row: " + row + " Column: " + col);
board newBoard = orig;
//newBoard.gameBoard[row][col].filled = true;
//newBoard.gameBoard[row][col].index = 2;
succ.add(newBoard);
}
}
System.out.println("Number of successors: " + succ.size());
int emptyIndex = 0;
for(int i = 0; i < succ.size(); i++) {
//find the empty index
// System.out.println(emptyIndex / 3);
// System.out.println(emptyIndex % 3);
// System.out.println(succ.get(i).gameBoard[emptyIndex / 3][emptyIndex % 3].index + "\n");
while(succ.get(i).gameBoard[emptyIndex / 3][emptyIndex % 3].index != 0) {
emptyIndex++;
//System.out.println(emptyIndex + " is a good index");
}
System.out.println("Empty Index " + emptyIndex);
System.out.println("i: " + i);
succ.get(i).gameBoard[emptyIndex / 3][emptyIndex % 3].index = 2;
succ.get(i).gameBoard[emptyIndex / 3][emptyIndex % 3].filled = true;
}
return succ;
}
It DOES initially get the number of successors correct, it's just that the outputs are off. For example I initially make the first move as follows:
https://imgur.com/a/T3lv0YZ
but the results should include all the possible moves the computer can make. Instead it outputs this:
https://imgur.com/a/EfEL5ll
What am I doing wrong? I have been trying to solve this problem for 2 days now.
board newBoard = orig;
newBoard will point to orig, so all changes made to newBoard will also be made to orig, and vice versa. when the AI makes it's move on newBoard, the move is made to the original board as well, since they both point to the same object.
you'll want to create a new board object identical to the original board, then make changes to that before adding it to the arraylist. when copying the board state over, take care not to copy references like classes and arrays, and instead use new instances.
I need some help making my Java method (getNumGroupsOfSize) work. It should tally how large an array "group" (consecutive elements that share the same value) is, and then print out how many other groups share that size. So for example, array [1,1,1,2,2,2,3,3,3,4,5,6,7] would print:
size 1=4
size 3=3
and then would stop running.
This is what I have so far:
import static java.lang.System.*;
import java.util.Arrays;
import java.util.Scanner;
public class ArrayStats {
int[] numArray;
int number;
public ArrayStats(int[] array) {
setArray(array);
}
public void setArray(int[] array) {
numArray = array;
}
public int getNumGroupsOfSize() {
int cnt = 0;
for (int x = 0; x < numArray.length - 1; x++) {
if (numArray[x] == numArray[x + 1]);
cnt++;
for (int y = 2; y <= 9; y++) {
if (cnt == y)
number = cnt;
else if (cnt == 1)
number = 1;
}
}
return number;
}
public String toString() {
return "size count" + " == " + getNumGroupsOfSize() + Arrays.toString(numArray);
}
}
I'm pretty sure my getNumGroupsOfSize is not coded correctly, but I'm not sure how to make it work. I would genuinely appreciate any help that can be offered. If you need any more information, don't hesitate to comment. Thank you!
Your method getNumGroupsSize() doesn't make much sense. For example how do you print out all the groups if you just store one number? I wrote the method new and it prints the numbers directly. You can also store them in an array if you want to.
public void getNumGroupsOfSize() {
int cnt = 1;
int currentNumber = numArray[0];
for (int x = 0; x < numArray.length - 1; x++) {
if (numArray[x] == numArray[x + 1]){
cnt++;
}
else{
System.out.println(currentNumber + ": " + cnt);
currentNumber=numArray[x+1];
cnt=1;
}
}
System.out.println(currentNumber + ": " + cnt);
}
For each encountered series, you have to count its size and update the information about how many series has this size.
So the int number field you are using is clearly not enough to achieve it as it persists only a very elementary information.
In your case, you need to have two associated information : for each series size, you want to know the number of series that have this size.
A Map object should do the job.
It would use as key the size of the series and as value the number of series that have this size.
Map<Integer, Integer> occurrenceBySeriesSize = new HashMap<>();
At each time an encountered series is finished, update the map with the new count :
int serieSize = ...;
Integer occurrences = occurrenceBySeriesSize.get(serieSize);
if (occurrences == null){
occurrences = 0;
}
occurrenceBySeriesSize.put(serieSize, ++occurrences);
I want to solve an DFS algorithm. It is about the game 8-puzzles or N x N puzzle. At the beginning i have two arrays like (the Zero represents an empty field):
int[][] start = {{0,1,2}, {4,5,3}, {7,8,6}};
int[][] target = {{1,2,3}, {1,5,6}, {7,8,0}};
This arrays goes into my generic DFS class, which works fine. I used it of other tasks correctly. But for the completeness here is the basic part of my DFS class:
private static boolean search(State node, State target) {
if (node.equals(target))
return true;
for (State neighbour : node.getNeighbours()) {
if (!visited.contains(neighbour)) {
predMap.put(neighbour,node);
visited.add(neighbour);
if (search(neighbour, target)){
return true;
}
}
}
return false;
}
So at first my start array will pass as the first parameter and my target array as the second.
In my Stateclass i want to implement the getNeighbours()method which should return all possibles states. In the first Round something like:
First:
|0|1|2|
|4|5|3|
|7|8|6|
Second (rotated zero):
|1|0|2|
|4|5|3|
|7|8|6|
etc...
And here is my problem. How can u do that? It works for the first 4 operations but then i get an exception (The zero or the empty field is not on the position as excepted or there are two zeros). What is wrong there?
#Override
public List<State> getNeighbours() {
List<State> neighbours = new LinkedList<>();
// possibles moves...
final int startX = (freeX - 1 < 0) ? freeX : freeX - 1;
final int startY = (freeY - 1 < 0) ? freeY : freeY - 1;
final int endX = (freeX + 1 > N - 1) ? freeX : freeX + 1;
final int endY = (freeY + 1 > N - 1) ? freeY : freeY + 1;
for (int row = startX; row <= endX; row++) {
for (int column = startY; column <= endY; column++) {
int tmp = board[row][column];
board[row][column] = board[freeX][freeY];
board[freeX][freeY] = tmp;
// Just show the table...
System.out.println("=== BEFORE ===");
for (int[] x : board) {
System.out.println(Arrays.toString(x));
}
neighbours.add(new State(board, freeX + row, freeY + column));
board[freeX][freeY] = board[row][column];
board[row][column] = tmp;
// Just show the table...
System.out.println("=== AFTER ===");
for (int[] x : board) {
System.out.println(Arrays.toString(x));
}
}
}
return neighbours;
}
complete code https://gist.github.com/T0bbes/66d36326aa8878d5961880ce370ba82d
I checked your code, the reason of get that exception is, the board array is shared by every state. You should make a deep copy of that array, and you can try this code:
public Board(int[][] board, int x, int y){
if (board[x][y]!=0)
throw new IllegalArgumentException("Field (" +x+","+y+") must be free (0).");
this.board = new int[board.length][board[0].length];
for (int i = 0; i < this.board.length; i++)
for (int j = 0; j < this.board[i].length; j++)
this.board[i][j] = board[i][j];
this.freeX = x;
this.freeY = y;
this.N = board.length;
}
But there are still some problems in your code:
DFS may recursion a lot and get a StackOverflow -- you should increase stack size(-Xss100m works for me). After increase stack size, your code can output a solution, but it takes 197144 steps...
Indeed, as you see, DFS output only a valid solution(if your code is correct), not optimal solution. You should try BFS.
I am creating a simple maze game in java. The code reads a data file and assigns it to a String array. The player inputs what direction he or she would like to go in and each position contains a certain number of points (0, 1, or 2) that corresponds to the obstacleNumber (0, 1, or 2). I want to keep track of the points as well as the number of times the player has moved but I cannot figure out where to call my methods to make sure that the counting is correct. I'm sorry if this is a really stupid question but I am new to java!
The array is being filled correctly but I cannot count the moves and points.
import java.util.*;
import java.io.File;
public class Program12
{
static public void main( String [ ] args ) throws Exception
{
if(args.length != 1) {
System.out.println("Error -- usage is: java Lab11 roomData.txt");
System.exit(0);
}
File newFile = new File(args[0]);
Scanner inputFile = new Scanner(newFile);
int numberOfRows = inputFile.nextInt();
int numberOfColumns = inputFile.nextInt();
Room[][] game;
game = new Room[numberOfRows][numberOfColumns];
int rowNumber = 0;
int columnNumber = 0;
int moves = 0;
int points = 0;
for(int i = 0; i < numberOfRows; i++)
{
for (int j = 0; j < numberOfColumns; j++)
{
String obstacle = inputFile.nextLine();
int obstacleNumber = inputFile.nextInt();
Room room = new Room(obstacle, obstacleNumber);
game[i][j] = room;
}
System.out.println();
countPoints(obstacleNumber, points);
}
while(true)
{
printPlayerLocation(numberOfRows, numberOfColumns, rowNumber, columnNumber);
System.out.println();
System.out.print("Enter up, down, left, or right to move: ");
Scanner userInput = new Scanner(System.in);
String in = userInput.nextLine();
if(in.equals("left") || in.equals("right") || in.equals("up") || in.equals("down"))
{
if (in.equalsIgnoreCase("up"))
{
rowNumber = rowNumber - 1;
}
if (in.equalsIgnoreCase("down"))
{
rowNumber = rowNumber + 1;
}
if (in.equalsIgnoreCase("left"))
{
columnNumber = columnNumber - 1;
}
if (in.equalsIgnoreCase("right"))
{
columnNumber = columnNumber + 1;
}
}
else
{
System.out.println("Input invalid! Please enter up, down, left, or right.");
}
try
{
System.out.println(game[columnNumber][rowNumber].toString());
}
catch (ArrayIndexOutOfBoundsException e)
{
System.out.println("You cannot leave the boardwalk during the hunt! Please start over.");
System.exit(0);
}
countMoves(in, moves);
//countPoints(obstacleNumber, points);
}
}
public static void printPlayerLocation(int numberOfRows, int numberOfColumns, int rowNumber, int columnNumber)
{
System.out.println();
System.out.print("***** PLAYER LOCATION *****");
String[][] game = new String[numberOfRows][numberOfColumns];
for (int i = 0; i < numberOfRows; i++)
{
for (int j = 0; j < numberOfColumns; j++)
{
game[i][j] = "*";
}
}
game[rowNumber][columnNumber] = "P";
for (int i = 0; i < numberOfRows; i++)
{
System.out.println();
for (int j = 0; j < numberOfColumns; j++)
{
System.out.printf("%-5s", game[i][j]);
}
}
System.out.println();
}
//doesn't correctly count the moves
public static void countMoves(String in, int moves)
{
if(in.equals("left") || in.equals("right") || in.equals("up") || in.equals("down"))
{
moves++;
}
System.out.println("You have used " + moves + " moves.");
}
//doesn't correctly count the points
public static void countPoints(int obstacleNumber, int points)
{
if(obstacleNumber == 0)
{
points = points;
}
if(obstacleNumber == 1)
{
points++;
}
if(obstacleNumber == 2)
{
points = points + 2;
}
System.out.println("You have obtained " + points + " points so far. Keep hunting!");
}
The data file has the size of the array (4 4) and an obstacleNumber and obstacle
0 this obstacleNumber would award 0 points
1 this obstacleNumber would award 1 point
2 this obstacleNumber would award 2 points
16 times to fill the array.
I would like the sample output to print the player location (which it does correctly), ask the user to input a direction (which it does correctly), print the text in the data file (again already done) and then print the number of moves already used and the amount of points the player has gained so far.
How do you correctly calculate the number of times the user typed "up, down, right, or left" and how many points does the user have so far? Thank you in advance for your help I sincerely appreciate your time.
The moves arent count right, because countMoves doesnt increment the Variable moves from the main function.
If you do :
System.out.println(moves);
countMoves(in, moves);
System.out.println(moves);
You will see that the value didnt changed.
So you could add a return value to countMoves and assingn moves with it :
moves = countMoves(in,moves);
Or you could increment the moves here :
if(in.equals("left") || in.equals("right") || in.equals("up") || in.equals("down"))
{
moves++;
if (in.equalsIgnoreCase("up"))
{
rowNumber = rowNumber - 1;
}
if (in.equalsIgnoreCase("down"))
{
rowNumber = rowNumber + 1;
}
if (in.equalsIgnoreCase("left"))
{ columnNumber = columnNumber - 1;
}
if (in.equalsIgnoreCase("right"))
{ columnNumber = columnNumber + 1;
}
}
The same with Points i think.
The line
points = points;
Would only make sense if you have a classvariable that would get the point value but assign a variable with its own value doenst make sense .
So maybe add a return to the countPoints and assign points with it :
points = countPoints(obstacleNumber, points);
In Java, arguments to methods are always passed by value. It can get confusing with objects though. But with primitive types like int it's very simple. To the functions countMoves and countPoints you are only giving the value of the moves and points, respectively, but not their reference. That is, the methods are working in fact with another variable. This variable is initialized to the value you give in and you can change it as you want, but the changes made to this variable are only visible to the method. Therefore in order to make the changes visibile to the outer variables you must reset their values. For instance you could do this:
public static int countMoves(String in, int moves) {
//... change the value of moves as you want
return moves; //return the new value
}
And then use the method like:
moves = countMoves(in, moves);
Where the set variable is the one you define in main. Analogously for countPoints. Another possibility would be to define moves and points in the class Program12 and make the methods count methods modify these variables directly without passing them, like:
public static void countMoves(String in) {
moves = ...
}
In this case the moves moves defined in Program12 is visible to the countMoves and so you are changing directly the variable you want; there is no need to reset it.
--
But big but. The code you have is rather spaghetti. You should think how to better structure and compartmentalize the code into closely-related logical units. In object-oriented programming you do it with classes. For example, you could define a class called GameState that keeps the variables moves and points or anything else shall you need it, and define there the count methods or other methods to modify the statistics of the game. Don't make the main method define the logic of the program. It should merely be used to read the input to initialize some sort of class Game and write to output the results of the Game.
I might be wrong here (early in the morning...) but I'm guessing you always get the same moves and points value? This is because you are not increasing the values of the actual moves and points. When you send an Int as a parameter to a method you are not sending a pointer to the Int but a copy of it which will be used by the method and then removed when leaving it. You need to either return moves and points after increasing the values or put them as static attributes. Try doing it this way instead:
...
moves = countMoves(String in, int moves);
...
public static int countMoves(String in, int moves) {
if(in.equals("left") || in.equals("right") || in.equals("up") || in.equals("down")) {
moves++;
}
System.out.println("You have used " + moves + " moves.");
return moves;
}
Or you could increase them when identifying the moving direction (which is more efficient since you don't have to redo the check if the move was valid):
if (in.equalsIgnoreCase("up")) {
rowNumber = rowNumber - 1;
moves++;
}
...
EDIT
Points Problem:
Since you didn't post how Room is implemented I just improvise, but I figure it should look something like this:
...
points = countPoints(game[rowNumber][columnNumber].getObstacleNumber(), points);
...
and change countPoints() to:
public static int countPoints(int obstacleNumber, int points) {
if(obstacleNumber == 0) points = points;
if(obstacleNumber == 1) points++;
if(obstacleNumber == 2) points += 2;
System.out.println("You have obtained " + points + " points so far. Keep hunting!");
return points;
}
or just (provided you know that the input is correct):
public static int countPoints(int obstacleNumber, int points) {
points += obstableNumber;
System.out.println("You have obtained " + points + " points so far. Keep hunting!");
return points;
}