I am currently trying to create an array of objects out of a char Array.
My problem is that somehow the for-loop seems to insert wrong values into the objects. And I just can't figure out what's going wrong. I was trying to fix it for hours but nothing worked.
For example: The if inside of the for loop detects it is at the right char '#' and j=6, k=5. (checked it with System.out.println().)
I tell it to create an object inside for the GameObject array and give it the appropriate coordinates (x=k, y=j). But for some reason the coordinates turn out to be (k=)x=5 and (j=)y=5 instead?!
Both values always seem to be identical for some reason. No matter what, it's always 1,1; 2,2; 3,3 etc... The number is basically k (=the intended y-coordinate) taken twice. It seems to not access the "j" correctly?
The object array itself is all right, just the values inside of the objects turn out wrong.
In code, the method looks like this:
public static GameObject[][] initGO(int x, int y) throws IOException {
GameObject[][] goMap = new GameObject[x][y];
LoadFile loader = new LoadFile();
char[] ch = loader.readChar("src\\control\\bla.txt");
int i = 0;
while (i < ch.length) {
for (int j = 0; j < y; j++) {
for (int k = 0; k < x; k++) {
if (ch[i] == '#') {
goMap[k][j] = new Player(k, j, "Player");
}
i++;
}
}
}
return goMap;
}
Player just looks like this:
public class Player extends GameObject {
public Player(int x, int y, String name) {
super(x, y, name);
this.x=y;
this.y=y;
this.name = name;
}
}
Thanks a lot for anyone trying to help!
You made a simple copy-paste-edit error when setting variables. Look at this part of the code:
public Player(int x, int y, String name) {
super(x, y, name);
this.x=y; // <-- This should be "this.x=x;"
this.y=y;
this.name = name;
}
Related
I have a matrix that represents a grid and would like to find out all possible places an object can move to.
An object can only move horizontally or vertically.
Let's assume that the example below is the grid I'm looking at, which is represented as a 2d matrix. The object is the *, the 0s are empty spaces that an object can move to, and the 1s are walls which the object cannot jump over or go on to.
What is the best way to find all possible movements of this object provided that it can only move horizontally or vertically?
I'd like to print a message saying: "There are 9 places the object can go to." The 9 is for the example below, but I would like it to work for any configuration of the below grid. So all I have to do is give the current coordinates of the * and it will give me the number of possible positions it can move to.
A thing to note is that the *'s original position is not considered in the calculations, which is why for the example below the message would print 9 and not 10.
I have a isaWall method that tells me if the cell is a wall or not. The isaWall method is in a Cell class. Each cell is represented by its coordinates. I looked into using Algorithms like BFS or DFS, but I didn't quite understand how to implement them in this case, as I am not too familiar with the algorithms. I thought of using the Cells as nodes of the graph, but wasn't too sure how to traverse the graph because from the examples I saw online of BFS and DFS, you would usually have a destination node and source node (the source being the position of the *), but I don't really have a destination node in this case. I would really appreciate some help.
00111110
01000010
100*1100
10001000
11111000
EDIT: I checked the website that was recommend in the comments and tried to implement my own version. It unfortunately didn't work. I understand that I have to expand the "frontier" and I basically just translated the expansion code to Java, but it still doesn't work. The website continues explaining the process, but in my case, there is no destination cell to go to. I'd really appreciate an example or a clearer explanation pertaining to my case.
EDIT2: I'm still quite confused by it, can someone please help?
While BFS/DFS are commonly used to find connections between a start and end point, that isn't really what they are. BFS/DFS are "graph traversal algorithms," which is a fancy way of saying that they find every point reachable from a start point. DFS (Depth First Search) is easier to implement, so we'll use that for your needs (note: BFS is used when you need to find how far away any point is from the start point, and DFS is used when you only need to go to every point).
I don't know exactly how your data is structured, but I'll assume your map is an array of integers and define some basic functionality (for simplicity's sake I made the start cell 2):
Map.java
import java.awt.*;
public class Map {
public final int width;
public final int height;
private final Cell[][] cells;
private final Move[] moves;
private Point startPoint;
public Map(int[][] mapData) {
this.width = mapData[0].length;
this.height = mapData.length;
cells = new Cell[height][width];
// define valid movements
moves = new Move[]{
new Move(1, 0),
new Move(-1, 0),
new Move(0, 1),
new Move(0, -1)
};
generateCells(mapData);
}
public Point getStartPoint() {
return startPoint;
}
public void setStartPoint(Point p) {
if (!isValidLocation(p)) throw new IllegalArgumentException("Invalid point");
startPoint.setLocation(p);
}
public Cell getStartCell() {
return getCellAtPoint(getStartPoint());
}
public Cell getCellAtPoint(Point p) {
if (!isValidLocation(p)) throw new IllegalArgumentException("Invalid point");
return cells[p.y][p.x];
}
private void generateCells(int[][] mapData) {
boolean foundStart = false;
for (int i = 0; i < mapData.length; i++) {
for (int j = 0; j < mapData[i].length; j++) {
/*
0 = empty space
1 = wall
2 = starting point
*/
if (mapData[i][j] == 2) {
if (foundStart) throw new IllegalArgumentException("Cannot have more than one start position");
foundStart = true;
startPoint = new Point(j, i);
} else if (mapData[i][j] != 0 && mapData[i][j] != 1) {
throw new IllegalArgumentException("Map input data must contain only 0, 1, 2");
}
cells[i][j] = new Cell(j, i, mapData[i][j] == 1);
}
}
if (!foundStart) throw new IllegalArgumentException("No start point in map data");
// Add all cells adjacencies based on up, down, left, right movement
generateAdj();
}
private void generateAdj() {
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j < cells[i].length; j++) {
for (Move move : moves) {
Point p2 = new Point(j + move.getX(), i + move.getY());
if (isValidLocation(p2)) {
cells[i][j].addAdjCell(cells[p2.y][p2.x]);
}
}
}
}
}
private boolean isValidLocation(Point p) {
if (p == null) throw new IllegalArgumentException("Point cannot be null");
return (p.x >= 0 && p.y >= 0) && (p.y < cells.length && p.x < cells[p.y].length);
}
private class Move {
private int x;
private int y;
public Move(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
}
Cell.java
import java.util.LinkedList;
public class Cell {
public final int x;
public final int y;
public final boolean isWall;
private final LinkedList<Cell> adjCells;
public Cell(int x, int y, boolean isWall) {
if (x < 0 || y < 0) throw new IllegalArgumentException("x, y must be greater than 0");
this.x = x;
this.y = y;
this.isWall = isWall;
adjCells = new LinkedList<>();
}
public void addAdjCell(Cell c) {
if (c == null) throw new IllegalArgumentException("Cell cannot be null");
adjCells.add(c);
}
public LinkedList<Cell> getAdjCells() {
return adjCells;
}
}
Now to write our DFS function. A DFS recursively touches every reachable cell once with the following steps:
Mark current cell as visited
Loop through each adjacent cell
If the cell has not already been visited, DFS that cell, and add the number of cells adjacent to that cell to the current tally
Return the number of cells adjacent to the current cell + 1
You can see a visualization of this here. With all the helper functionality we wrote already, this is pretty simple:
MapHelper.java
class MapHelper {
public static int countReachableCells(Map map) {
if (map == null) throw new IllegalArgumentException("Arguments cannot be null");
boolean[][] visited = new boolean[map.height][map.width];
// subtract one to exclude starting point
return dfs(map.getStartCell(), visited) - 1;
}
private static int dfs(Cell currentCell, boolean[][] visited) {
visited[currentCell.y][currentCell.x] = true;
int touchedCells = 0;
for (Cell adjCell : currentCell.getAdjCells()) {
if (!adjCell.isWall && !visited[adjCell.y][adjCell.x]) {
touchedCells += dfs(adjCell, visited);
}
}
return ++touchedCells;
}
}
And that's it! Let me know if you need any explanations about the code.
I need to write some methods for a game in java and one of them is int[] findStone. The method returns an array, which gives the coordinate of the element that I am searching.
The field looks like this and is defined like this: private static int[][] gamefield = new int[8][6];
So if I use the method: findStone(3)[0], it should return 0 for the x coordinate and for findStone(3)1, 2. This is the code that I wrote.
private static int[] findStone(int stone) {
int[] position = new int[2];
for(int x = 0; x < 8; x++ ){
for(int y = 0; y < 6; y++ ) {
int a = gamefield[x][y];
int i = x;
int j = y;
if(a == stone) {
position[0] = i;
position[1] = j;
}
break;
}
}
return position;
}
The problem is: The method only returns the x-coordinates for the first row corectly, for the other elements it shows me 0. Could someone explain me what I did wrong and what I should change? Please, only simple explanation. I am only at the beginning and I don't have experience in java.
Thank you :)
You probably intended to put your break clause inside the if block. The way you have it now, the break keyword has no effect. It just breaks the inner loop (with y variable), but since this block of code ends here anyway, it simply does nothing.
You're searching for a single point on your map, so when you find the stone position, you can immediately return it, as there's nothing more to do.
Moreover, you don't need additional variables, a, i and j. Using them is not wrong, but code looks clearer and is more concise without them. Have a look at this code:
private static int[] findStone(int stone) {
int[] position = new int[2];
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 6; y++) {
if (gamefield[x][y] == stone) {
position[0] = x;
position[1] = y;
return position;
}
}
}
return null; // if there's no given stone
}
In my program I have a class called Cell, defined like so:
public class Cell {
private int x;
private int y;
public Cell (int x, int y) {
this.x = x;
this.y = y;
}
#Override
public boolean equals (Object o) {
boolean result = false;
if (o instanceof Cell) {
Cell other = (Cell) o;
result = (this.x == other.x && this.y == other.y)
}
return result;
}
#Override
public int hashCode() {
int result = x;
result = 31 * result + y;
return result;
}
}
I have a Grid class, like so (many methods cut out and variable names simplified):
public class Grid {
private Set<Cell> cellArray;
public Grid() {
cellArray = new HashSet<Cell>();
}
public Set<Cell> getCellArray() {
return cellArray;
}
public void addCellArray(Cell cell) {
cellArray.add(cell)
}
}
In my main body of code, I take in a grid object, like so:
public class Controller {
private Grid grid;
public Controller (Grid grid) (
this.grid = grid;
Then, I have a series of loops that look like this:
private set<Cell> cellArray = grid.getCellArray();
boolean endLoop = false;
do {
x = randomGenerator.nextInt(10);
y = randomGenerator.nextInt(10);
for (int i = 0; i < length; i++) {
if (cellArray.contains(new Cell(x, y+i))) {
continue;
}
}
for (int j = 0; j < length; j++) {
cellArray.add(new Cell(x, y+i));
}
endLoop = true;
} while(!endLoop);
I'm aware it's a very messy, with too much instantiation going on (and if anyone has pointers to make it cleaner, feel free to point them out) - however, the main issue is the fact that the first for loop is meant to check if the cellArray contains the items - it doesn't seem to be doing this.
There's no error message, no null pointer or anything like that. I've tried debugging it and have seen it compare two cells with identical x and y values, without proceeding to the continue statement to start the do while loop again.
I am assuming this is because even though they have identical values, they are different 'objects' and so aren't coming back as equal.
How could I fix this and get them to equate to one another if their values are the same?
Your continue statement continues the inner for-loop (which is quite useless here). You probably want to continue the outer loop: continue outerLoop;, with the label outerLoop: put in front of do {.
As the Java API states, the contains method should rely on your equals method, so object equality should work as you expect it.
I am trying to implement an algorithm to clear dead stones in my Go game.
I hear that floodfill is the best to achieve this as using it recursively would be most effiecient and easier to implement.
I am having trouble using it within my code and was wondering how I should go about implementing it.
This is one of my classes, it is pretty self explanatory.
import java.io.*;
public class GoGame implements Serializable {
int size;
char[][] pos; // This is the array that stores whether a Black (B) or White (W) piece is stored, otherwise its an empty character.
public GoGame(int s){
size = s;
}
public void init() {
pos = new char[size][size];
for (int i=0;i<size;i++) {
for (int j=0;j<size;j++) {
pos[i][j] = ' ';
}
}
}
public void ClearAll() {
for (int i=0;i<size;i++) {
for (int j=0;j<size;j++) {
pos[i][j] = ' ';
}
}
}
public void clear(int x, int y) {
pos[x][y]=' ';
}
public void putB(int x, int y) { //places a black stone on the board+array
pos[x][y]='B';
floodfill(x,y,'B','W');
}
public void putW(int x, int y) { //places a white stone on the board+array
pos[x][y]='W';
floodfill(x,y,'W','B');
}
public char get(int x, int y) {
return pos[x][y];
}
public void floodfill(int x, int y, char placed, char liberty){
floodfill(x-1, y, placed, liberty);
floodfill(x+1, y, placed, liberty);
floodfill(x, y-1, placed, liberty);
floodfill(x, y+1, placed, liberty);
}
}
x and y are the coordinates of the square, placed is the character of the stone put down, liberty is the other character
Any help would be amazing!
while the other answers are technically correct, you are also missing a lot more logic related to go. what you need to do is, i think (on a B move):
for each W neighbour of the move:
check that W group to see if it has any liberties (spaces)
remove it if not
flood fill is useful for finding the extent of a group of stones, but your routine needs a lot more than that (i'm simplifying here, and also trying to guess what this routine is used for - see comments below this answer).
given the above, a flood fill that identifies all the stones in a group would be something like this (note that it uses a second array for the fill, because you don't want to be changing pos just to find a group):
public void findGroup(int x, int y, char colour, char[][] mask) {
// if this square is the colour expected and has not been visited before
if (pos[x][y] == colour && mask[x][y] == ' ') {
// save this group member
mask[x][y] = pos[x][y];
// look at the neighbours
findGroup(x+1, y, colour, mask);
findGroup(x-1, y, colour, mask);
findGroup(x, y+1, colour, mask);
findGroup(x, y-1, colour, mask);
}
}
you can call that to identify a single group (and copy it into mask), so it will help you identify the members of a W group that neighbour a B move (for example), but it is only a small part of the total logic you need.
finally, note that if you want to do something with every stone in a group you have two options. you can call a routine like the one above, and then loop over mask to find the group, or you can put the action you want to do directly inside the routine (in which case you still use mask to control the extent of the flood fill in the test && mask[x][y] == ' ' but you don't use it as a result - all the work is done by the time the routine returns).
(programming something to handle go correctly, following all the rules, is actually quite complex - you've got a lot of work ahead... :o)
I'd use false proof for that. Here is how I find captured stones:
private static final int SIZE = 8;
private static final int VACANT = 0; //empty point
private static final int MY_COLOR = 1; //Black
private static final int ENEMY_COLOR = 2; //White
private static final int CHECKED = 50; //Mark for processed points
private static final int OUT = 100; //points out of the board
private static boolean isCaptured(int col, int row, int[][] board) {
boolean result = !isNotCaptured(col, row, board);
cleanBoard(board);
return result;
}
private static boolean isNotCaptured(int col, int row, int[][] board) {
int value = board[col][row];
if (!(value == MY_COLOR || value == CHECKED))
return true;
int top = row < SIZE - 1 ? board[col][row + 1] : OUT;
int bottom = row > 0 - 1 ? board[col][row - 1] : OUT;
int left = col > 0 ? board[col - 1][row] : OUT;
int right = col < SIZE - 1 ? board[col + 1][row] : OUT;
if (top == VACANT || right == VACANT || left == VACANT || bottom == VACANT)
return true;
board[col][row] = CHECKED;
return (top == MY_COLOR && isNotCaptured(col, row + 1, board))
|| (bottom == MY_COLOR && isNotCaptured(col, row - 1, board))
|| (left == MY_COLOR && isNotCaptured(col - 1, row, board))
|| (right == MY_COLOR && isNotCaptured(col + 1, row, board));
}
private static void cleanBoard(int[][] board) {
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < SIZE; j++) {
if (board[i][j] == CHECKED)
board[i][j] = MY_COLOR;
}
}
}
Then you can call method like this:
isCaptured(5, 4, board)
I think that BFS will be better for this case because you need to explore the neighbors first, so that if any of them is captured then the point is captured.
As others pointed out, there is also a "ko rule" in Go which roughly means that you are not allowed to capture back immediately when a single stone is captured (simplified). In summary, you may want to use an existing library for this.
I recommend the brugo repository, which is available in maven.
<!-- https://mvnrepository.com/artifact/be.brugo/brugo -->
<dependency>
<groupId>be.brugo</groupId>
<artifactId>brugo</artifactId>
<version>0.1.0</version>
</dependency>
It roughly works like this.
(warning: code not tested)
// create a starting position
Position position = new Position(boardSize, komi);
// play a move
Intersection whereToPlay = Intersection.valueOf(4,4);
IntStatus colorToPlay = IntStatus.BLACK;
Position position2 = position.play(whereToPlay, colorToPlay);
// watch the result.
IntStatus[][] matrix = position2.getMatrix()
It also contains objects to export to Load/Save SGF. The loading of SGF files does not only support UTF-8 but also Asian encodings. Here is a screenshot that shows how difficult this is to implement yourself:
If you also plan to use javafx, then run this demo: brugo.go.ui.javafx.goban.GobanComponentDemo
Enough to get you started.
I am getting a NullPointerException when the getCave method is called when it tries to return the 2D array. I have not been able to find a solution online. I can get the program to run without the exception by replacing the return with a new Cave that is not an array but that would not fit my needs. Here is a simplified version of my code:
import java.util.Random;
public class Board {
public static final int DEFAULT_ROWS = 10;
public static final int DEFAULT_COLS = 10;
Cave[][] caveArray = new Cave[DEFAULT_ROWS+2][DEFAULT_COLS+2];
public Board(int rows, int cols){
Random rand = new Random();
for (int j = 1; j < (cols+1); j++) {
for (int i = 1; i < (rows+1); i++) {
Cave temp;
temp = new Cave(i, j);
int rnum = rand.nextInt(100)+1;
if (rnum > 50) {
caveArray[i][j]=temp;
caveArray[i][j].makeBlocked();
}
else if(rnum <=50) {
caveArray[i][j]=temp;
caveArray[i][j].makeOpen();
}
}
}
}
public Cave getCave(int r, int c){
return caveArray[r][c];
}
}
here is the caller:
private void newGame() {
// Set up the game board.
gameBoard = new Board(DEFAULT_ROWS, DEFAULT_COLS);
// Set up the 3 characters.
characters = new ArrayList<Character>();
// Add the adventurer (always in the top left).
characters.add(new Adventurer(gameBoard.getCave(0, 0)));
selected = 0; // Initially select the adventurer.
}
which calls:
public class Adventurer extends Character{
Adventurer(Cave initLoc) {
super(initLoc);
}
which calls:
public abstract class Character implements CaveWorker{
protected Cave location;
public Character(Cave initLoc){
location = initLoc;
location.setOccupied(true);
}
The only explanation that I can offer without observing a stack trace (those are really helpful, more times than not) is that if you attempt to index into caveArray[0][c], or even caveArray[r][0] there's not going to be anything there.
You have two options - either use the fact that arrays will start at index 0 (it's not so bad), or preemptively place a Cave object in row 0 and column 0 that serves no real purpose. Aligning with (0,0) would be the easier choice, though.