Peg solitaire solution change destination - java
I wrote a program that solves a peg solitaire in java.
My program gets a starting board and a destination board and try to finish the game.
I have a sort of counter that count my turn because I have a destination with more the 1 peg rest and as assume that if I have to remove only 2 pegs so I can solve it in only 2 moves.
I have an board class that I create:
public class Board {
private int board[][] = new int[7][7];
public Board(String place)
{
board[0][0]=2;
board[1][0]=2;
board[5][0]=2;
board[6][0]=2;
board[0][1]=2;
board[1][1]=2;
board[5][1]=2;
board[6][1]=2;
board[0][5]=2;
board[1][5]=2;
board[5][5]=2;
board[6][5]=2;
board[0][6]=2;
board[1][6]=2;
board[5][6]=2;
board[6][6]=2;
int loca=0;//location on the string of place
for(int i=0;i<7;i++){
for(int j=0;j<7;j++){
if(board[i][j]!=2) {
if (place.charAt(loca) == 'O') {
loca++;
board[i][j] = 1;
} else if (place.charAt(loca) == '.') {
loca++;
board[i][j] = 0;
}
}
System.out.print(board[i][j]);//print for test
}
System.out.println();//print for test
}
System.out.println();
}
public Board(Board copy){
for(int i=0;i<7;i++)
{
for(int j=0;j<7;j++)
{
board[i][j]=copy.getValue(i,j);
}
}
}
public int getValue(int x, int y)
{
return board[x][y];
}
public boolean isFinished(Board destination)
{
for(int i=0;i<7;i++)
{
for(int j=0;j<7;j++)
{
if(this.getValue(i,j)!=destination.getValue(i,j))
{
return false;
}
}
}
return true;
}
public Board turn(Board board,String direction,int x,int y)
{
if(direction.equals("right"))
{
board.setValue(x,y,0);
board.setValue(x+1,y,0);
board.setValue(x+2,y,1);
return board;
}
else if(direction.equals("left"))
{
board.setValue(x,y,0);
board.setValue(x-1,y,0);
board.setValue(x-2,y,1);
return board;
}
else if(direction.equals("up"))
{
board.setValue(x,y,0);
board.setValue(x,y-1,0);
board.setValue(x,y-2,1);
return board;
}
else if(direction.equals("down"))
{
board.setValue(x,y,0);
board.setValue(x,y+1,0);
board.setValue(x,y+2,1);
return board;
}
else{
System.out.println("there is not such direction, method turn on board class");
return null;//just for caution
}
}
public boolean isLegal(int x, int y){
if(board[x][y]==2)
{
return false;
}
else{
return true;
}
}
public boolean canTurn(String direction,int x,int y){
if(direction.equals("right"))
{
if(x<5) {
if (board[x][y] == 1 && board[x + 1][y] == 1 && board[x + 2][y] == 0) {
return true;
}
}
}
else if(direction.equals("left"))
{
if(x>1) {
if (board[x][y] == 1 && board[x - 1][y] == 1 && board[x - 2][y] == 0) {
return true;
}
}
}
else if(direction.equals("up"))
{
if(y>1) {
if (board[x][y] == 1 && board[x][y - 1] == 1 && board[x][y - 2] == 0) {
return true;
}
}
}
else if(direction.equals("down"))
{
if(y<5) {
if (board[x][y] == 1 && board[x][y + 1] == 1 && board[x][y + 2] == 0) {
return true;
}
}
}
else{
System.out.println("there is not such direction, method canTurn on board class");
return false;//just for caution
}
return false;
}
public void setValue(int x, int y, int value)
{
board[x][y]=value;
}
}
and I wrote my "solver" class.
public class PegSolver {
public int peg =1;
Board destinationBoard = new Board("OOOOOOOOOOOOOOOOO..OOOOOOOOOOOOOO");
Board board = new Board("OOOOOOOOOOOOOOOO.OOOOOOOOOOOOOOOO");
public void start(){
solve(0,board);
}
public boolean solve(int turn, Board board){
Board temp = new Board(board);
if(turn>peg)
{
return false;
}
else if(turn==peg){
//todo:check if solve
if(temp.isFinished(destinationBoard))
{
System.out.println("solution");
return true;
}
else
{
return false;
}
}
else//lower then 8
{
for(int i=0;i<7;i++){
for (int j=0;j<7;j++)
{
if(board.isLegal(i,j)) {
if(board.canTurn("right",i,j) && solve(turn++, temp.turn(temp, "right", i, j)))
{
return true;
}
else if(board.canTurn("left",i,j) && solve(turn++, temp.turn(temp, "left", i, j)))
{
return true;
}
else if(board.canTurn("up",i,j) && solve(turn++, temp.turn(temp, "up", i, j)))
{
return true;
}
else if(board.canTurn("down",i,j) && solve(turn++, temp.turn(temp, "down", i, j)))
{
return true;
}
}
}
}
}
return false;
}
}
When the program finds a solution, it needs to print "solution" but for some reason my program can't find a solution even when it's a basic destination with one move.
Can someone help me please?
Please review the modified code.
Many of the changes are related to indices and directions inconsistency across the code: where x represents horizontal index and y represents vertical index: array index should be board[y][x] (and not board[x][y]).
Many "magic numbers" were changed to constants for better readability of the code.
A toString method was added to the Boardclass to print out a board state. It uses special characters to make a nice printout :
This is helpful when debugging.
public class PegSolver {
private final Board startBoard, destinationBoard;
public PegSolver(Board startBoard, Board destinationBoard) {
super();
this.startBoard = startBoard;
this.destinationBoard = destinationBoard;
}
public void start(){
solve(0,startBoard);
}
private boolean solve(int turn, Board board){
//check if solve
if(board.isFinished(destinationBoard))
{
System.out.println("solved after "+ turn +" turns");
return true;
}
for(int x=0;x<board.boardSize();x++){
for (int y=0;y<board.boardSize();y++)
{
if(board.isLegal(x,y)) {
if(board.canTurn("right",x,y)
//turn++ changed to turn+1 so turn is incremented before invoking next solve
//and avoid changing the value of turn
&& solve(turn+1, board.turn(new Board(board), "right", x, y)))
return true;
else if(board.canTurn("left",x,y)
&& solve(turn+1, board.turn(new Board(board), "left", x, y)))
return true;
else if(board.canTurn("up",x,y)
&& solve(turn+1, board.turn(new Board(board), "up", x, y)))
return true;
else if(board.canTurn("down",x,y)
&& solve(turn+1, board.turn(new Board(board), "down", x, y)))
return true;
}
}
}
return false;
}
public static void main(String[] args) {
Board[] destinationBoards = {
//by order of number of turns
new Board("OOOOOOOOOOOOOO..OOOOOOOOOOOOOOOOO"), //one right turn
new Board("OOO.OOOO.OOOOO.OOOOOOOOOOOOOOOOOO"), //right, down
new Board("OOO.OO..OOOOOO.OOOOOOOOOOOOOOOOOO"), //right, down,right
new Board("OOO.OOO.OOOOO..OOOOO.OOOOOOOOOOOO"), //right, down,right,up
new Board("OOOOOOO..OOOO...OOOO.OOOOOOOOOOOO"), //right, down,right,up,up
new Board(".OO.OOO.OOOOO...OOOO.OOOOOOOOOOOO"), //right, down,right,up,up,down
new Board(".OO.OOO.OOOOO...OOOOO..OOOOOOOOOO"), //right, down,right,up,up,down, left
new Board(".OO.OOO.OOOOO...OOOOO.OOOOO.OO.OO"), //right, down,right,up,up,down,left,up
new Board(".OO.OO..O.OOO...OOOOO.OOOOO.OO.OO"), //10 turns
new Board("..O..O.O..OOO...OOOO..OOOOO..O..O"), //15 turns
new Board(".........O................O......"), //30 turns
new Board("...................O............."), //31 turns
};
Board startBoard = new Board("OOOOOOOOOOOOOOOO.OOOOOOOOOOOOOOOO");
for(Board destinationBoard : destinationBoards ){
new PegSolver(startBoard, destinationBoard).start();
}
}
}
class Board {
//int representation of the three states of a board cell
private final static int EMPTY = 0, PEG = 1, BORDER = 2;
/*cahr representation of the three states of a board cell
special chars are used to get nice printout
todo: change board to char[][] to avoid the need for two
representations (int and char)
*/
private final static char[] CHAR_REPRESENTATION = {9898,9899,10062};
private final static char ERROR = '?';
private final int BOARD_SIZE=7, CORNER_SIZE=2;
private final int board[][] = new int[BOARD_SIZE][BOARD_SIZE];
public Board(String place) {
int loca=0;
for(int y=0;y<BOARD_SIZE;y++){
for(int x=0;x<BOARD_SIZE;x++){
if(isWithinBoard(x,y)) {
if (place.charAt(loca) == 'O') {
loca++;
board[y][x] = PEG;
} else if (place.charAt(loca) == '.') {
loca++;
board[y][x] = EMPTY;
}
}else{
board[y][x] = BORDER;
}
}
}
//for testing
//System.out.println(this);
}
//copy constructor
public Board(Board copy){
for(int x=0;x<BOARD_SIZE;x++)
{
for(int y=0;y<BOARD_SIZE;y++)
{
board[y][x]=copy.getValue(x,y);
}
}
}
public int getValue(int x, int y)
{
return board[y][x]; //and not return board[x][y];
}
public boolean isFinished(Board destination)
{
for(int i=0;i<BOARD_SIZE;i++)
{
for(int j=0;j<BOARD_SIZE;j++)
{
if(this.getValue(i,j)!=destination.getValue(i,j))
return false;
}
}
return true;
}
public Board turn(Board board,String direction,int x,int y)
{
if(direction.equals("right"))
{
board.setValue(x,y,EMPTY);
board.setValue(x+1,y,EMPTY);
board.setValue(x+2,y,PEG);
return board;
}
else if(direction.equals("left"))
{
board.setValue(x,y,EMPTY);
board.setValue(x-1,y,EMPTY);
board.setValue(x-2,y,PEG);
return board;
}
else if(direction.equals("up"))
{
board.setValue(x,y,EMPTY);
board.setValue(x,y-1,EMPTY);
board.setValue(x,y-2,PEG);
return board;
}
else if(direction.equals("down"))
{
board.setValue(x,y,EMPTY);
board.setValue(x,y+1,EMPTY);
board.setValue(x,y+2,PEG);
return board;
}
System.out.println("there is not such direction, method turn on startBoard class");
return null;
}
public boolean isLegal(int x, int y){
if(board[y][x]==BORDER) //and not if(board[x][y]==BORDER)
return false;
return true;
}
public boolean canTurn(String direction,int x,int y){
if(direction.equals("right") && x < BOARD_SIZE - 2)
{
if (board[y][x] == PEG && board[y][x + 1] == PEG && board[y][x + 2] == EMPTY)
return true;
}
else if(direction.equals("left") && x > 1)
{
if (board[y][x] == PEG && board[y][x - 1] == PEG && board[y][x - 2] == EMPTY)
return true;
}
else if(direction.equals("up") && y > 1)
{
if (board[y][x] == PEG && board[y - 1][x] == PEG && board[y - 2][x] == EMPTY)
return true;
}
else if(direction.equals("down") && y < BOARD_SIZE - 2)
{
if (board[y][x] == PEG && board[y + 1][x] == PEG && board[y + 2][x] == EMPTY)
return true;
}
return false;
}
public void setValue(int x, int y, int value)
{
board[y][x]=value; //and not board[x][y]=value;
}
//for square nxn board
public int boardSize(){
return board.length;
}
public boolean isWithinBoard(int x, int y){
//check bounds
if (x < 0 || y < 0 || x >= BOARD_SIZE || y >= BOARD_SIZE) return false;
//left top corner
if (x < CORNER_SIZE && y < CORNER_SIZE) return false;
//right top corner
if(x >= BOARD_SIZE - CORNER_SIZE && y < CORNER_SIZE) return false;
//left bottom corner
if(x < CORNER_SIZE && y >= BOARD_SIZE - CORNER_SIZE) return false;
//right bottom corner
if(x >= BOARD_SIZE - CORNER_SIZE && y >= BOARD_SIZE - CORNER_SIZE) return false;
return true;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (int[] row : board) {
for(int cell : row){
if(cell<CHAR_REPRESENTATION.length && cell >= 0) {
sb.append(CHAR_REPRESENTATION[cell]);
}else{
sb.append(ERROR);
}
}
sb.append("\n"); //new line
}
return sb.toString();
}
}
Todo:
The code is working but it needs further in-depth testing and debugging.
If something is not clear, don't hesitate to ask.
Related
A* Pathfinding really slow
I have an A* pathfinding algorithm that I've used for a Spigot plugin which worked fine. I then added a requirements system so it won't try and pathfind through places it shouldn't. Now it seems REALLY slow, and it looks like it has nothing to do with the requirements code itself, and more to do with the algorithm having many more incorrect paths when calculating. I seem to be getting 1500ms+ on this, which is definitely not good xD Here is the pathfinder code: public Path calculate(PathfinderGoal goal, PathScorer scorer, List<PathRequirement> requirements, int maxNodes) { PathNode start = toNode(npc.getLocation()); PathNode end = toNode(goal.getLocation()); List<PathNode> open = new ArrayList<>() {{ add(start); }}; List<PathNode> navigated = new ArrayList<>(); start.setF(scorer.computeCost(start, end)); Timer timer = new Timer().start(); while (!open.isEmpty()) { PathNode current = null; for (PathNode node : open) { if (current == null || node.getH() < current.getH()) { current = node; } } if (scorer.computeCost(current, end) < 1 || (navigated.size() >= maxNodes && maxNodes != -1)) { navigated.add(navigated.size() < maxNodes ? end : current); return reconstruct(navigated, navigated.size() - 1); } open.remove(current); current.close(); for (PathNode node : current.getNeighbors()) { if (node.isClosed()) { continue; } double tentG = current.getG() + scorer.computeCost(current, node); if (!open.contains(node) || tentG < node.getG()) { boolean requirementsMet = true; for (PathRequirement requirement : requirements) { requirement.setNavigated(navigated); if (!navigated.isEmpty() && !requirement.canMoveToNewNode(navigated.get(navigated.size() - 1), node)) { requirementsMet = false; break; } } if (!navigated.contains(current)) { navigated.add(current); } node.setG(tentG); node.setH(scorer.computeCost(node, end)); node.setF(tentG + node.getH()); if (!open.contains(node) && requirementsMet) { open.add(node); } } } Bukkit.broadcastMessage("Open Set Size: " + open.size()); Bukkit.broadcastMessage(timer.stop() + "ms"); } return null; } private Path reconstruct(List<PathNode> navigated, int index) { final PathNode current = navigated.get(index); Path withCurrent = new Path(new ArrayList<>() {{ add(current); }}); if (index > 0 && navigated.contains(current)) { return reconstruct(navigated, index - 1).append(withCurrent); } return withCurrent; } And here is the PathNode class: public PathNode(Pathfinder pathfinder, int x, int y, int z) { this.pathfinder = pathfinder; this.x = x; this.y = y; this.z = z; } #Override public boolean equals(Object other) { if (!(other instanceof PathNode otherNode)) { return false; } return otherNode.x == x && otherNode.y == y && otherNode.z == z; } public List<PathNode> getNeighbors() { return new ArrayList<>() { { for (int x = -1; x <= 1; x++) { for (int y = -1; y <= 1; y++) { for (int z = -1; z <= 1; z++) { add(new PathNode(pathfinder, PathNode.this.x + x, PathNode.this.y + y, PathNode.this.z + z)); } } } } }; } public Location getLocation() { return new Location(pathfinder.getNPC().getLocation().getWorld(), x, y, z); } public double getF() { return F; } public void setF(double f) { this.F = f; } public double getG() { return G; } public void setG(double g) { this.G = g; } public double getH() { return H; } public void setH(double h) { this.H = h; } public boolean isClosed() { return closed; } public void close() { this.closed = true; } Valid Requirements Class: public class ValidPathRequirement extends PathRequirement { #Override public boolean canMoveToNewNode(PathNode from, PathNode to) { Block fromBlock = from.getLocation().getBlock(); Block toBlock = to.getLocation().getBlock(); boolean validHeight = toBlock.getType().isAir() && toBlock.getRelative(BlockFace.UP).getType().isAir(); // checks if is player height boolean validGround = toBlock.getRelative(BlockFace.DOWN).getType().isSolid(); // is there a block underneath that they can stand on? boolean validFromPrev = toBlock.getLocation().subtract(fromBlock.getLocation()).getY() <= 1; // is it max one block higher than the last one? // is this one causing issues? Location fromLocDist = from.getLocation().clone(); Location toLocDist = to.getLocation().clone(); toLocDist.setY(fromLocDist.getY()); boolean validDistance = fromLocDist.distance(toLocDist) <= 1; return validHeight && validGround && validFromPrev; } }
Without looking at the rest of the algorithm, the first thing that stands out is that your data structures are incorrect. The "open" list needs to be a Priority Queue, and "closed" (or "navigated") should be a set.
Is there a solution to prevent this recursion?
In this program, a randomly generated 2D array is populated with 1's or 0's and I attempt to find a path of 1's (no diagonal movement). I have got the program to work for smaller dimensions of the 2D array, but when the dimensions are too large, the error Exception in thread "main" java.lang.StackOverflowError occurs. import java.util.Scanner; import java.util.Random; public class Daft { private int counter = 0; public static void main(String[] args) { Daft punk = new Daft(); punk.run(); } public void run() { int ans; int[][] array; int[][] solvedPath; do { counter = 1; array = populate(defineArray(firstDimension(),secondDimension())); solvedPath = findPath(array); System.out.println("Times before solvable: " + counter); print(solvedPath); ans = continuity(); }while(ans != 0); } public int[][] findPath(int[][] array) { int r = 0, c = 0; while(true) { array[0][0] = 7; if(c == 0 && r == array.length-1) { //reached the bottom left, checks right if(array[r][c+1] == 1) { array[r][c+1] = 7; c+=1; } else { array[r][c] = 7; break; } } else if(c == array[0].length-1 && r == array.length-1) { //reached the bottom right, checks left if(array[r][c-1] == 1) { array[r][c-1] = 7; } else { array[r][c] = 7; break; } } else if(r == array.length-1) { //reached the bottom, checks left/right if(array[r][c+1] == 1 && array[r][c-1] == 1) { counter++; newPath(array); break; } else if(array[r][c+1] == 1) { //checks right array[r][c+1] = 7; c+=1; } else if(array[r][c-1] == 1) { //checks left array[r][c-1] = 7; c-=1; } else { //end of path array[r][c] = 7; break; } } else if(c == 0) { //reached the left, checks right/bottom if(array[r][c+1] == 1 && array[r+1][c] == 1) { //checks if path is unique counter++; newPath(array); break; } else if(array[r][c+1] == 1) { array[r][c+1] = 7; c+=1; } else if(array[r+1][c] == 1) { array[r+1][c] = 7; r+=1; } else { counter++; //path has ended, not solvable newPath(array); break; } } else if(c == array[0].length-1) { //reached the right, checks left/bottom if(array[r+1][c] == 1 && array[r][c-1] == 1) { //checks if path is unique counter++; newPath(array); break; } else if(array[r+1][c] == 1) { array[r+1][c] = 7; r+=1; } else if(array[r][c-1] == 1) { array[r][c-1] = 7; c-=1; } else { counter++; //path has ended, not solvable newPath(array); break; } } else if(array[r][c+1] == 1 && array[r+1][c] == 1) { //checks if path is unique counter++; newPath(array); break; } else if(array[r][c-1] == 1 && array[r+1][c] == 1) { //checks if path is unique counter++; newPath(array); break; } else if(array[r][c+1] == 1) { //checks right array[r][c+1] = 7; c+=1; } else if(array[r+1][c] == 1) { //checks bottom array[r+1][c] = 7; r+=1; } else if(array[r][c-1] == 1) { //checks left array[r][c-1] = 7; c-=1; } else { counter++; newPath(array); break; } } return array; } public int firstDimension() { Scanner in = new Scanner(System.in); System.out.println("Size of the first dimension:"); return in.nextInt(); } public int secondDimension() { Scanner in = new Scanner(System.in); System.out.println("Size of the second dimension:"); return in.nextInt(); } public int[][] defineArray(int firstDimension, int secondDimension) { return new int[firstDimension][secondDimension]; } public int[][] populate(int[][] array) { Random rand = new Random(); for(int i = 0; i < array.length; i++) { for(int j = 0; j < array[i].length; j++) { array[i][j] = rand.nextInt(2); } } return array; } public int continuity() { Scanner in = new Scanner(System.in); System.out.println("Enter a number to continue (0 to quit):"); return in.nextInt(); } public void print(int[][] array) { for(int[] ints : array) { for(int anInt : ints) { System.out.print(anInt + " "); } System.out.println(); } System.out.println(); } public void newPath(int[][] array) { findPath(populate(array)); } }
How can I update my output on console in Java? (Right hand rule maze solver)
I'm trying to solve maze by using right hand rule, and my algorithm seems pretty good to me. I have a little problem with my codes though. I want to update my output on console, but I really don't know how to do it. I kind of got the sense that I have to use Thread.sleep, but I don't know where to put it so that it can update my console constantly without printing whole new maze each move. I want to make user can see the X's current position, and I want there's no trailing X. It's a bit hard to explain with just words, so I made an gif picture. And here are my codes. Thank you for anyone who will answer my question! Have a nice day y'all :D public class MazeTraversalGradedProgram { private static int row, column, count; private static String direction = "right"; private static char maze1 [] [] = { {'#','#','#','#','#','#','#','#','#','#','#','#'}, {'#','.','.','.','#','.','.','.','.','.','.','#'}, {'.','.','#','.','#','.','#','#','#','#','.','#'}, {'#','#','#','.','#','.','.','.','.','#','.','#'}, {'#','.','.','.','.','#','#','#','.','#','.','.'}, {'#','#','#','#','.','#','.','#','.','#','.','#'}, {'#','.','.','#','.','#','.','#','.','#','.','#'}, {'#','#','.','#','.','#','.','#','.','#','.','#'}, {'#','.','.','.','.','.','.','.','.','#','.','#'}, {'#','#','#','#','#','#','.','#','#','#','.','#'}, {'#','.','.','.','.','.','.','#','.','.','.','#'}, {'#','#','#','#','#','#','#','#','#','#','#','#'}}; private static char maze2 [] [] = { {'#','#','#','#','#','#','#','#','#','#','#','#'}, {'#','.','.','.','.','.','#','.','.','.','.','#'}, {'#','.','#','.','#','.','#','#','#','#','.','#'}, {'#','#','#','.','#','.','.','.','.','#','.','#'}, {'#','.','.','.','.','#','#','#','.','#','.','#'}, {'#','#','#','#','.','#','.','#','.','#','.','#'}, {'#','.','.','#','.','#','.','#','.','#','.','.'}, {'#','#','#','#','.','#','.','#','.','#','.','#'}, {'#','.','.','.','.','#','.','.','.','#','.','#'}, {'#','.','#','#','#','#','#','#','.','#','.','#'}, {'.','.','#','.','.','.','.','#','.','.','.','#'}, {'#','#','#','#','#','#','#','#','#','#','#','#'}}; private static void printMaze (char [] [] maze) { for (int i = 0; i<maze.length; i++) { for(int j = 0; j<maze[i].length; j++) { System.out.print(maze [i][j] + " "); } System.out.println(); } System.out.println(); System.out.println(); } private static void goForward (char [] [] maze){ if (direction == "right") { column++; maze[row][column] = 'X'; } else if (direction == "up") { // array[xnd row --- ][ynd column | ] row--; maze[row][column] = 'X'; } else if (direction == "left") { column--; maze[row][column] = 'X'; } else if (direction == "down") { row++; maze[row][column] = 'X'; } } private static boolean wallOnRight (char [] [] maze) { if (direction == "right" && maze[row+1][column] == '#') { return true; } else if (direction == "up" && maze[row][column+1] == '#') { return true; } else if (direction == "left" && maze[row-1][column] == '#') { return true; } else if (direction == "down" && maze[row][column-1] == '#') { return true; } return false; } private static boolean wallOnFront (char [] [] maze) { if (direction == "right" && maze[row][column+1] == '#') { return true; } else if (direction == "up" && maze[row-1][column] == '#') { return true; } else if (direction == "left" && maze[row][column-1] == '#') { return true; } else if (direction == "down" && maze[row+1][column] == '#') { return true; } return false; } private static void traverseMaze (char [] [] maze){ if (count == 0) { for (int i = 0; i < 12; i++) { if (maze[i][0] == '.'){ // array[xnd row --- ][ynd column | ] maze[i][0] = 'X'; row = i; column = 0; } } count++; } if (wallOnRight(maze) && !wallOnFront(maze)) { goForward(maze); } else if (wallOnRight(maze) && wallOnFront(maze)) { if (direction == "right") { direction = "up"; } else if (direction == "up") { direction = "left"; } else if (direction == "left") { direction = "down"; } else if (direction == "down") { direction = "right"; } } else if (!wallOnRight(maze)) { if (direction == "right") { direction = "down"; } else if (direction == "up") { direction = "right"; } else if (direction == "left") { direction = "up"; } else if (direction == "down") { direction = "left"; } goForward(maze); } if (column == 11) { count = 0 ; } else { traverseMaze(maze); } } public static void main (String [] args){ printMaze(maze1); traverseMaze(maze1); printMaze(maze2); traverseMaze(maze2); } }
Java game error
I'm programming a java game. It's almost done but it's giving me a error (and I don't understand why it happens, the code seems okay). Error. Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - Erroneous sym type: projetofinal.ProjetoFinalv2.movimento at projetofinal.ProjetoFinalv2.main(ProjetoFinalv2.java:26) C:\Users\Francisco\AppData\Local\NetBeans\Cache\8.2\executor-snippets\run.xml:53: Java returned: 1 BUILD FAILED (total time: 2 seconds) Here's the code: package projetofinal; import java.util.Scanner; import java.util.Random; public class ProjetoFinalv2 { static char[][] tabuleiro; static int x, y, jogadorX, jogadorY, pontos; static char direction; static boolean inGame = true; public static void main(String[] args) { x = 5; y = 5; tabuleiro = new char[x][y]; jogadorX = 0; jogadorY = 4; pontos = 7; quadro(); while(inGame == true) { customcreator(); Scanner scan = new Scanner(System.in); String resposta = scan.nextLine(); movimento(resposta.charAt(0)); } } public static void placePot() { boolean notDone = true; while(notDone) { int tabX = random(0, 4); int tabY = random(0, 4); if(tabuleiro[tabX][tabY] == '.') { tabuleiro[tabX][tabY] = 'P'; notDone = false; } } } public static boolean bomba(int x, int y) { if(tabuleiro[x][y] == 'B') { return true; } else { return false; } } public static boolean win() { if(tabuleiro[jogadorX][jogadorY] == 'F') { return true; } else { return false; } } public static boolean gameover() { if(pontos > 0) { return false; } else { return true; } } public static int potepoints(int x, int y) { if(tabuleiro[x][y] == 'P') { return random(3,5); } else { return -1; } } public static void quadro() { for(int linha = 0; linha < x; linha++) { for(int vertical = 0; vertical < y; vertical++) { tabuleiro[linha][vertical] = '.'; } } //Por as bombas na posição correta for(int i = quantos(); i>0; i--) { boolean tab = true; while(tab) { int tabX = random(1, 3); int tabY = random(1, 2); if(tabuleiro[tabX][tabY] != 'B') { tabuleiro[tabX][tabY] = 'B'; tab = false; } } } //Mete o pote que da pontos placePot(); } public static void tabuleirocreator() { playercreator(); for(int linha = 0; linha < y; linha++) { for(int vertical = 0; vertical < x; vertical++) { System.out.print(tabuleiro[vertical][linha]); } System.out.print("\n"); } } public static void playercreator() { tabuleiro[jogadorX][jogadorY] = 'J'; } public static void customcreator() { tabuleiro[0][4] = 'I'; tabuleiro[4][0] = 'F'; tabuleirocreator(); } public static int random(int min, int max) { Random generator = new Random(); int Num = generator.nextInt((max - min) + 1) + min; return Num; } public static int quantos() { return random(2, 3); } } //Ciclo do jogo public static void movimento(char newDirection) { if(newDirection == 'w' || newDirection == 'W') { if(jogadorY > 0) { tabuleiro[jogadorX][jogadorY] = '.'; jogadorY -= 1; pontos--; } } else { if(newDirection == 'a' || newDirection == 'A') { if(jogadorX > 0) { tabuleiro[jogadorX][jogadorY] = '.'; jogadorX -= 1; pontos--; } } else { if(newDirection == 's' || newDirection == 'S') { if(jogadorY < 4) { tabuleiro[jogadorX][jogadorY] = '.'; jogadorY += 1; pontos--; } } else { if(newDirection == 'd' || newDirection == 'D') { if(jogadorX < 4) { tabuleiro[jogadorX][jogadorY] = '.'; jogadorX += 1; pontos--; } } else { System.out.println("Wrong direction!"); } } } } if(bomba(jogadorX, jogadorY)) { pontos = 0; } int tab = potepoints(jogadorX, jogadorY); if(tab != -1) { pontos += tab; } if(win()) { System.out.println("You won"); inGame = false; } if(gameover()) { System.out.println("Game Over"); inGame = false; } } ////////////////////////////////////////////////////////////// I'm a quite noob in java (i started to learn recently) so, i'm sorry if the question is bad.
The message tells you that the compiler cannot find a definition for projetofinal.ProjetoFinalv2.movimento, a symbol on line 26: movimento(resposta.charAt(0));. But movimento is not defined inside the class. The class definition ends with the closing brace (}) just before the orphaned method definition for movimento. Not only does that make the method definition inaccessible to the caller, it is utterly illegal to define methods or variables outside of a class.
Returning moves with MiniMax
I've got my code working and the program running perfectly! Turns out the problem also involved the computer not returning a 0 when required. Thank you to everyone who helped. If anyone needs any help like I did check out the code below. import java.util.Scanner; public class TicTacToeSolver{ public static void main(String[] args){ Scanner input=new Scanner(System.in); char[] board={0,0,0,0,0,0,0,0,0}; int player=1,move; System.out.println("Tic-Tac-Toe:"); while (true){ PrintBoard(board); if (player==1){ System.out.print("Enter move: "); move=input.nextInt(); if (ValidMove(board,move)==true){ board[move-1]='X'; player=-1; } } else{ board[MiniMax(board,player,0,9)[1]]='O'; player=1; } if(CheckWin(board)!=0){ PrintBoard(board); System.out.println("You lost!"); System.exit(0); } else if (CheckDraw(board)==true){ PrintBoard(board); System.out.println("Draw!"); System.exit(0); } } } public static boolean ValidMove(char[]board,int move){ if(move>=1 && move<=9){ if (board[move-1]==0){ return true; } } return false; } public static int CheckWin(char[] board){ if (board[0]=='X' && board[1]=='X' && board[2]=='X'||//Horizontal. board[3]=='X' && board[4]=='X' && board[5]=='X' || board[6]=='X' && board[7]=='X' && board[8]=='X' || board[0]=='X' && board[4]=='X' && board[8]=='X' ||//Diagonal. board[2]=='X' && board[4]=='X' && board[6]=='X' || board[0]=='X' && board[3]=='X' && board[6]=='X' ||//Vertical. board[1]=='X' && board[4]=='X' && board[7]=='X' || board[2]=='X' && board[5]=='X' && board[8]=='X'){ return -1; } else if (board[0]=='O' && board[1]=='O' && board[2]=='O'||//Horizontal. board[3]=='O' && board[4]=='O' && board[5]=='O' || board[6]=='O' && board[7]=='O' && board[8]=='O' || board[0]=='O' && board[4]=='O' && board[8]=='O' ||//Diagonal. board[2]=='O' && board[4]=='O' && board[6]=='O' || board[0]=='O' && board[3]=='O' && board[6]=='O' ||//Vertical. board[1]=='O' && board[4]=='O' && board[7]=='O' || board[2]=='O' && board[5]=='O' && board[8]=='O'){ return 1; } return 0; } public static boolean CheckDraw(char[] board){ int total=0; for (int i=0;i<9;i++){ if (board[i]!=0){ total+=1; } } if (total==9){ return true; } return false; } public static void PrintBoard(char[] board){ System.out.println("------------------------------"); System.out.println(board[0]+"|"+board[1]+"|"+board[2]); System.out.println("-+-+-"); System.out.println(board[3]+"|"+board[4]+"|"+board[5]); System.out.println("-+-+-"); System.out.println(board[6]+"|"+board[7]+"|"+board[8]); System.out.println("\n"); } public static int[] MiniMax(char[] board,int player,int depth, int maxDepth){ int bestScore,bestMove=-1,score; if (CheckWin(board)!=0||depth==maxDepth){ return new int[] {CheckWin(board),bestMove}; } if (CheckDraw(board)==true){ return new int[] {0,bestMove}; } if (player==-1){ bestScore=-9999; } else{ bestScore=9999; } for (int i=0;i<9;i++){ if (board[i]==0){ if (player==-1){ board[i]='O'; score=MiniMax(board,player*-1,depth+1,maxDepth)[0]; board[i]=0; if (score>bestScore){ bestScore=score; bestMove=i; } } else{ board[i]='X'; score=MiniMax(board,player*-1,depth+1,maxDepth)[0]; board[i]=0; if(score<bestScore){ bestScore=score; bestMove=i; } } } } return new int[] {bestScore,bestMove}; } }
I think I've answered this elsewhere so there must be a few of you doing this assignment! Below the first level you should only be checking if the levels below return any winning moves or not. You don't need to use any of their values. Example code: public List<Location> bestMoves() { List<Location> winningMoves = possibleMoves().stream() .filter(move -> apply(move).isWinFor(nextPlayer)) .collect(Collectors.toList()); if (!winningMoves.isEmpty()) return winningMoves; else return possibleMoves().stream() .filter(move -> apply(move).bestMoves().isEmpty()) .collect(Collectors.toList()); }
You could return both the move and the score through an object that contains both. public class TicTacToeSolver{ private static class Move { int move; int score; Move( int m, int s ) { move = m; score = s; } } ... } You could return this object like this: return new Move( bestScore, bestMove ); Within minimax() itself, you could get the score like this: Move candidateMove = MiniMax(board,player*-1,depth+1,maxDepth); int score = candidateMove.score; At the top level, you could get the best move like this: Move bestMove = MiniMax(board,player,0,9); int move = bestMove.move;