Need a push in the right direction for a class assignment. I've read other posts that mentioned creating a variable/method to store the path traveled, but not sure how to get about it...
Edited 9/28/16
was able to get to the end point of the maze but still haven't figured out
how to print only the path taken; I really need to
import java.io.*;
import java.util.*;
public class Maze
{
private static int rows, cols, startRow, startCol, nextRow, nextCol;
private static int endRow = 3;
private static int endCol = 34;
private static char[][] mazeBoard;
//private static char start = 'S';
private static char end = 'E';
//private boolean finish = false;
private char[][] explored = new char[rows][cols];
//construct the maze board
public Maze() throws FileNotFoundException
{
Scanner in = new Scanner(new File("maze.txt"));
rows = in.nextInt();
cols = in.nextInt();
startRow = in.nextInt();
startCol = in.nextInt();
//fill out the mazeBoard
mazeBoard = new char[rows][cols];
int i = 0;
while (in.hasNextLine())
{
String inLine = in.nextLine();
if (inLine.isEmpty())
{
continue;
}
for (int j = 0;j < cols; j++)
{
char nextChar = inLine.charAt(j);
mazeBoard[i][j] = nextChar;
System.out.print(nextChar);
}
System.out.println();
i++;
}
in.close();
}
//updated the move method from void to boolean
public boolean move(int row, int col, int prevRow, int prevCol)
{
boolean finish = false;
prevRow = row;
prevCol = col;
//show location
System.out.println("row: " + row + " col: " + col);
//base case1 to check for out of bounds and not the previous position
if (row < 0 || col < 0 || row >= rows || col >= cols || row != prevRow || col != prevCol)
{ return false; }
//base case2 to see if reached exit/end point
if (row == endRow && col == endCol)
{
System.out.println("Found the exit!");
return true;
}
//base case3 to check for wall
if (mazeBoard[row][col] == '+' || mazeBoard[row][col] == '*')
{ return false; }
mazeBoard[row][col] = '*';
//try to move down
if (move(row + 1, col, prevRow, prevCol))
{ return true; }
//try to move right
if (move(row, col + 1, prevRow, prevCol))
{ return true; }
//try to move up
if (move(row - 1, col, prevRow, prevCol))
{ return true; }
//try to move left
if (move(row, col - 1, prevRow, prevCol))
{ return true; }
row = prevRow;
col = prevCol;
return false;
}
public static void main(String[] args) throws FileNotFoundException
{
Maze maze = new Maze();
maze.move(startRow, startCol);
}
}
====
so I'm not sure how to implement a method to keep track of path traveled, any pointers will be greatly appreciated!
The easy way is to wait until you find the solution. Then simply record the successful moves as you crawl back up that branch of the call tree. Each winning call prepends its move to the front of the return value and passes that back up the stack. This would be something like
result = move(rowM + 1, colM);
if result != ""
return "D" + result; // "D" for a move right
else {
// Try a move right ...
You do have a couple of things to fix. Most of all, you have to block taking a step you've already taken. Right now, when your search hits a dead end, it keeps repeating the final step and backtrack in an infinite recursion.
Second, you'll need to implement logic to abort other searches once you've found one solution. Setting a finish doesn't help much; that's a local variable, and you need to communicate to the calling program that you've failed or succeeded.
Is that enough to move you to the next step?
Related
My approach seems to be correct , the issue is whether multiple trips are allowed.
My solution seems to exceed the correct answer.
The Question:
In a N x N grid representing a field of cherries, each cell is one of three possible integers.
0 means the cell is empty, so you can pass through;
1 means the cell contains a cherry, that you can pick up and pass through;
-1 means the cell contains a thorn that blocks your way.
Your task is to collect maximum number of cherries possible by following the rules below:
Starting at the position (0, 0) and reaching (N-1, N-1) by moving right or down through valid path cells (cells with value 0 or 1);
After reaching (N-1, N-1), returning to (0, 0) by moving left or up through valid path cells;
When passing through a path cell containing a cherry, you pick it up and the cell becomes an empty cell (0);
If there is no valid path between (0, 0) and (N-1, N-1), then no cherries can be collected.
My Solution:
class Solution {
public int cherryPickup(int[][] grid) {
int N = grid.length;
int[][] dp;
char[][] track;
boolean f = true;
int sum = 0;
int count = 0;
while(f)
{
dp = new int[N][N];
track = new char[N][N];
dp[0][0] = grid[0][0];
track[0][0] = 'a';
char c;
c='u';
for(int i=1;i<N;i++)
{
if(c=='r'||grid[i][0]==-1)
{
c='r';
dp[i][0]=-1;
}
else
dp[i][0] = dp[i-1][0] + grid[i][0];
track[i][0] = c;
}
c='s';
for(int j=1;j<N;j++)
{
if(c=='r'||grid[0][j]==-1)
{
c='r';
dp[0][j]=-1;
}
else
dp[0][j] = dp[0][j-1] + grid[0][j];
track[0][j] = c;
}
for(int i=1;i<N;i++)
for(int j=1;j<N;j++)
{
if(grid[i][j]==-1||(track[i-1][j]=='r' && track[i][j-1]=='r'))
{
track[i][j] = 'r';
dp[i][j] = -1;
}
else
{
if(dp[i-1][j]>=dp[i][j-1])
{
track[i][j] = 'u';
dp[i][j] = dp[i-1][j] + grid[i][j];
}
else
{
track[i][j] = 's';
dp[i][j] = dp[i][j-1] + grid[i][j];
}
}
}
if(dp[N-1][N-1]<=0)
break;
sum += dp[N-1][N-1];
int r = N-1 , cr = N-1;
while(r>0||cr>0)
{
grid[r][cr]=0;
if(track[r][cr]=='s')
cr--;
else
r--;
}
grid[0][0] = 0;
}
return sum;
}
}
Can someone help??
I have looked at this question here I tried most of the code samples from there but when i use it in my code it just skips the algorithm.
I have this DFS algorithm that uses stack, I am getting a EmptyStackException, I have debugged the algorithm and after first recursive search the stack is empty, the first search works but then the size of stack is set to 0, What am I missing here? github
How can I make sure that the stack is not empty after the first search?
The line that I get the exception on is while(true){AddBridges state = gameTree.peek(); ...
I am using a 2d Array to generate the nodes at random from 0 to 4 0 = null 1-4 = island The array generates Random Integers every time the user starts the game, could that cause the Algorithm to brake,
After a weekend of debugging I found that the algorithm sometimes brakes after 4-6 searches, and sometimes breaks after the first search.
public int[][] debug_board_state_easy = new int[4][4];
//This Generates random 2d array
private void InitializeEasy() {
Random rand = new Random();
setCurrentState(new State(WIDTH_EASY));
for (int row = 0; row < debug_board_state_easy.length; row++) {
for (int column = 0; column < debug_board_state_easy[row].length; column++) {
debug_board_state_easy[row][column] = Integer.valueOf(rand.nextInt(5));
}
}
for (int row = 0; row < debug_board_state_easy.length; row++) {
for (int column = 0; column < debug_board_state_easy[row].length; column++) {
System.out.print(debug_board_state_easy[row][column] + " ");
}
System.out.println(debug_board_state_easy);
}
//I am applying the search algorithm here...
this.search();
for (int row = 0; row < WIDTH_EASY; ++row) {
for (int column = 0; column < WIDTH_EASY; ++column) {
getCurrentState().board_elements[row][column] = new BoardElement();
getCurrentState().board_elements[row][column].max_connecting_bridges = Integer.valueOf(debug_board_state_easy[row][column]);
getCurrentState().board_elements[row][column].row = row;
getCurrentState().board_elements[row][column].col = column;
if (getCurrentState().board_elements[row][column].max_connecting_bridges > 0) {
getCurrentState().board_elements[row][column].is_island = true;
}
}
}
}
void search() {
Map<Point, List<Direction>> remainingOptions = new HashMap<>();
Stack<Land> gameTree = new Stack<>();
gameTree.push(new AddBridges(debug_board_state_easy));
while(true) {
AddBridges state = gameTree.peek();
int[] p = state.lowestTodo();
if (p == null)
System.out.println("solution found");
// move to next game state
int row = p[0];
int column = p[1];
System.out.println("expanding game state for node at (" + row + ", " + column + ")");
List<Direction> ds = null;
if(remainingOptions.containsKey(new Point(row,column)))
ds = remainingOptions.get(new Point(row,column));
else{
ds = new ArrayList<>();
for(Direction dir : Direction.values()) {
int[] tmp = state.nextIsland(row, column, dir);
if(tmp == null)
continue;
if(state.canBuildBridge(row,column,tmp[0], tmp[1]))
ds.add(dir);
}
remainingOptions.put(new Point(row,column), ds);
}
// if the node can no longer be expanded, and backtracking is not possible we quit
if(ds.isEmpty() && gameTree.isEmpty()){
System.out.println("no valid configuration found");
return;
}
// if the node can no longer be expanded, we need to backtrack
if(ds.isEmpty()){
gameTree.pop();
remainingOptions.remove(new Point(row,column));
System.out.println("going back to previous decision");
continue;
}
Direction dir = ds.remove(0);
System.out.println("connecting " + dir.name());
remainingOptions.put(new Point(row,column), ds);
AddBridgesnextState = new AddBridges(state);
int[] tmp = state.nextIsland(row,column,dir);
nextState.connect(row,column, tmp[0], tmp[1]);
gameTree.push(nextState);
}
}
}
Add bridges class
public class AddBridges {
private int[][] BRIDGES_TO_BUILD;
private boolean[][] IS_ISLAND;
private Direction[][] BRIDGES_ALREADY_BUILT;
public Land(int[][] bridgesToDo){
BRIDGES_TO_BUILD = copy(bridgesToDo);
int numberRows = bridgesToDo.length;
int numberColumns = bridgesToDo[0].length;
BRIDGES_ALREADY_BUILT = new Direction[numberRows][numberColumns];
IS_ISLAND = new boolean[numberRows][numberColumns];
for(int i=0;i<numberRows;i++) {
for (int j = 0; j < numberColumns; j++) {
BRIDGES_ALREADY_BUILT[i][j] = null;
IS_ISLAND[i][j] = bridgesToDo[i][j] > 0;
}
}
}
public AddBridges (AddBridges other){
BRIDGES_TO_BUILD = copy(other.BRIDGES_TO_BUILD);
int numberRows = BRIDGES_TO_BUILD.length;
int numberColumns = BRIDGES_TO_BUILD[0].length;
BRIDGES_ALREADY_BUILT = new Direction[numberRows][numberColumns];
IS_ISLAND = new boolean[numberRows][numberColumns];
for(int i=0;i<numberRows;i++) {
for (int j = 0; j < numberColumns; j++) {
BRIDGES_ALREADY_BUILT[i][j] = other.BRIDGES_ALREADY_BUILT[i][j];
IS_ISLAND[i][j] = other.IS_ISLAND[i][j];
}
}
}
public int[] next(int r, int c, Direction dir){
int numberRows = BRIDGES_TO_BUILD.length;
int numberColumns = BRIDGES_TO_BUILD[0].length;
// out of bounds
if(r < 0 || r >=numberRows || c < 0 || c >= numberColumns)
return null;
// motion vectors
int[][] motionVector = {{-1, 0},{0,1},{1,0},{0,-1}};
int i = Arrays.asList(Direction.values()).indexOf(dir);
// calculate next
int[] out = new int[]{r + motionVector[i][0], c + motionVector[i][1]};
r = out[0];
c = out[1];
// out of bounds
if(r < 0 || r >=numberRows || c < 0 || c >= numberColumns)
return null;
// return
return out;
}
public int[] nextIsland(int row, int column, Direction dir){
int[] tmp = next(row,column,dir);
if(tmp == null)
return null;
while(!IS_ISLAND[tmp[0]][tmp[1]]){
tmp = next(tmp[0], tmp[1], dir);
if(tmp == null)
return null;
}
return tmp;
}
public boolean canBuildBridge(int row0, int column0, int row1, int column1){
if(row0 == row1 && column0 > column1){
return canBuildBridge(row0, column1, row1, column0);
}
if(column0 == column1 && row0 > row1){
return canBuildBridge(row1, column0, row0, column1);
}
if(row0 == row1){
int[] tmp = nextIsland(row0, column0, Direction.EAST);
if(tmp == null)
return false;
if(tmp[0] != row1 || tmp[1] != column1)
return false;
if(BRIDGES_TO_BUILD[row0][column0] == 0)
return false;
if(BRIDGES_TO_BUILD[row1][column1] == 0)
return false;
for (int i = column0; i <= column1 ; i++) {
if(IS_ISLAND[row0][i])
continue;
if(BRIDGES_ALREADY_BUILT[row0][i] == Direction.NORTH)
return false;
}
}
if(column0 == column1){
int[] tmp = nextIsland(row0, column0, Direction.SOUTH);
if(tmp == null)
return false;
if(tmp[0] != row1 || tmp[1] != column1)
return false;
if(BRIDGES_TO_BUILD[row0][column0] == 0 || BRIDGES_TO_BUILD[row1][column1] == 0)
return false;
for (int i = row0; i <= row1 ; i++) {
if(IS_ISLAND[i][column0])
continue;
if(BRIDGES_ALREADY_BUILT[i][column0] == Direction.EAST)
return false;
}
}
// default
return true;
}
public int[] lowestTodo(){
int R = BRIDGES_TO_BUILD.length;
int C = BRIDGES_TO_BUILD[0].length;
int[] out = {0, 0};
for (int i=0;i<R;i++) {
for (int j = 0; j < C; j++) {
if(BRIDGES_TO_BUILD[i][j] == 0)
continue;
if (BRIDGES_TO_BUILD[out[0]][out[1]] == 0)
out = new int[]{i, j};
if (BRIDGES_TO_BUILD[i][j] < BRIDGES_TO_BUILD[out[0]][out[1]])
out = new int[]{i, j};
}
}
if (BRIDGES_TO_BUILD[out[0]][out[1]] == 0) {
return null;
}
return out;
}
#TargetApi(Build.VERSION_CODES.GINGERBREAD)
private int[][] copy(int[][] other){
int[][] out = new int[other.length][other.length == 0 ? 0 : other[0].length];
for(int r=0;r<other.length;r++)
out[r] = Arrays.copyOf(other[r], other[r].length);
return out;
}
public void connect(int r0, int c0, int r1, int c1){
if(r0 == r1 && c0 > c1){
connect(r0, c1, r1, c0);
return;
}
if(c0 == c1 && r0 > r1){
connect(r1, c0, r0, c1);
return;
}
if(!canBuildBridge(r0, c0, r1, c1))
return;
BRIDGES_TO_BUILD[r0][c0]--;
BRIDGES_TO_BUILD[r1][c1]--;
if(r0 == r1){
for (int i = c0; i <= c1 ; i++) {
if(IS_ISLAND[r0][i])
continue;
BRIDGES_ALREADY_BUILT[r0][i] = Direction.EAST;
}
}
if(c0 == c1){
for (int i = r0; i <= r1 ; i++) {
if(IS_ISLAND[i][c0])
continue;
BRIDGES_ALREADY_BUILT[i][c0] = Direction.NORTH;
}
}
}
}
One part of your question stood out to me as the root of the problem: "What am I missing here"? Unit tests, unless I just didn't see them in your project.
Questions like "the array generates Random Integers every time the user starts the game, could that cause the Algorithm to brake?", are the reason unit tests exist, along with the following:
In the course of writing tests on sections of code that don't end up
being the problem, you'll prove definitively that they aren't the
problem.
If the code you're working with can't be tested as-is, or
is "too complex" to test, re-writing it will make you a better
designer and will often lead to "I can't believe I didn't see that"
moments.
When you refactor this program (reduce complexity, rename variables to make them easier to understand, etc), you'll be notified immediately if something breaks
and you won't have to spend another weekend trying to figure it out.
As an example, instead of randomizing the board within the method that searches it, randomize it elsewhere and then drop it into that method as an argument (or into the class' constructor). That way, you can initialize your own test board(s) with your own supplied values and see if some boards work better than others and why. Split up larger methods into smaller methods, each with their own parameters and tests. Aim to make a program out of smaller confirmed-working pieces, instead of making a huge thing and then wondering if the problem is the small part you think it is or something else.
You'll save so much time and frustration in the long run, and you'll end up leagues ahead of those who code for hours and then debug for hours.
There's a lot going on in the code, but the first thing I notice might help:
// if the node can no longer be expanded, we need to backtrack
if(ds.isEmpty()){
gameTree.pop();
remainingOptions.remove(new Point(row,column));
System.out.println("going back to previous decision");
continue;
}
you pop from the stack, and continue onto the next while(true) iteration, at that point, there may be nothing on the stack since you have not added anything else.
I agree with #Rosa -
The EmptyStackException should occur when removing or looking up empty Stack-
======Iteration/State in code ======
**if(ds.isEmpty()){** //HashMap isEmpty = true and gameTree.size() = 1
gameTree.pop(); // After removing element gameTree.size() = 0 (no elements in stack to peek or pop)
remainingOptions.remove(new Point(row,column));
System.out.println("going back to previous decision");
continue; //Skip all the instruction below this, continue to next iteration
}
========Next iteration========
while(true){
AddBridges state = gameTree.peek(); // gameTree.size() = 0 and a peek
operation shall fail and program will return EmptyStackException.
Required isEmpty check -
if(gameTree.isEmpty()){
System.out.println("no valid configuration found");
return;
}
AddBridges state = gameTree.peek();
As, no actions have been performed by function but while loop. In case other instcutions to be processed , a "break" is required.
I am making a tic tac toe game for n number of players on a nxn board, but the winning condition is aways 3 on a row. My so far solution to the problem is: when a move is made the program will check the following square for 3 on a row.
(x-1,y+1) (x,y+1) (x+1,y+1)
(x-1,y) (x,y) (x+1,y)
(x-1,y-1) (x,y-1) (x+1,y-1)
It will check the top (x-1,y+1) (x,y+1) (x+1,y+1) bottom(x-1,y-1) (x,y-1) (x+1,y-1)
sides(x+1,y+1) (x+1,y) (x+1,y-1) , (x-1,y+1) (x-1,y) (x-1,y-1) , the diagonals and the ones going through the middle(x,y).
my code so far is:
public int checkWinning() {
for(int a = 1; a < size-1; a++){
for(int b = 1; b < size-1; b++){
if (board[a][b] == board[a+1][b] && board[a][b] == board[a-1][b]){
return board[a][b];
}else if(board[a][b] == board[a][b+1] && board[a][b] == board[a][b-1]){
return board[a][b];
}else if(board[a][b] == board[a+1][b-1] && board[a][b] == board[a-1][b+1]){
return board[a][b];
}else if(board[a][b] == board[a+1][b+1] && board[a][b] == board[a-1][b-1]){
return board[a][b];
}
}
}
for(int d = 1; d < size-1; d++){
if (board[0][d] == board[0][d-1] && board[0][d] == board[0][d+1]){
return board[0][d];
} else if (board[size-1][d] == board[size-1][d-1] && board[size-1][d] == board[size-1][d+1]){
return board[size-1][d];
}
}
for(int c = 1; c < size-1; c++){
if (board[c][0] == board[c-1][0] && board[c][0] == board[c+1][0]){
return board[c][0];
}else if(board[c][size-1] == board[c-1][size-1] && board[c][size-1] == board[c+1][size-1]){
return board[c][size-1];
}
}
return 0;
}
where the first section is where I check the ones through the middle and diagonals. the second section I check the top an bottom and the top and the thrid section checks the sides.
When it returns 0 is means that there are no winner yet.
#override
public void checkResult() {
int winner = this.board.checkWinning();
if (winner > 0) {
this.ui.showResult("Player "+winner+" wins!");
}
if (this.board.checkFull()) {
this.ui.showResult("This is a DRAW!");
}
}
Board[x][y] -> 2-dimensional array representing the board, The coordinates are counted from top-left (0,0) to bottom-right (size-1, size-1), board[x][y] == 0 signifies free at position (x,y), board[x][y] == i for i > 0 signifies that Player i made a move on (x,y), just so you know it.
my problem is that when i expands the board to a size larger than 3x3 the program somehow overwrites it self or a does not check every thing sides top and bottom every time, and I can't seem too se why.
EDIT:
played with the app for a few minutes... interesting results
java -jar tic-tac-toe.jar 5 20
It was a cats game!!
|1|1|5|5|1|3|5|3|1|5|2|5|1|1|2|
|2|3|2|3|1|5|3|5|3|2|3|1|5|2|2|
|5|4|5|4|1|5|5|4|2|1|4|5|4|2|2|
|3|2|1|5|5|5|2|4|5|3|4|1|2|4|2|
|3|4|1|2|5|4|1|1|4|5|1|3|3|4|1|
|1|5|4|4|3|2|5|1|3|5|1|3|5|3|4|
|2|5|1|4|3|3|3|5|3|1|1|4|3|4|4|
|1|4|5|1|1|5|4|5|2|4|1|1|5|4|3|
|1|3|2|1|4|2|4|3|3|4|5|2|4|3|3|
|5|1|1|3|3|4|4|4|2|2|1|4|3|2|5|
|2|2|3|1|5|5|4|1|3|5|3|2|3|3|2|
|2|4|2|4|4|1|3|1|1|3|1|2|1|2|2|
|2|5|5|1|4|3|4|5|5|4|5|3|3|5|2|
|4|5|2|1|5|3|2|1|3|2|2|2|2|4|4|
|4|1|1|4|5|4|5|4|2|2|3|3|2|2|3|
Played 100 games:
Number wins by Player1: 0
Number wins by Player2: 0
Number wins by Player3: 0
Number wins by Player4: 0
Number wins by Player5: 0
Number of ties: 100
didn't scroll through all 100 games to find the winning board, but I thought this was interesting:
java -jar tic-tac-toe.jar 2 10
Player2 won the game!
|1|1|2|1|2|2| |2|1|2|
|2|2|2|2|2|2|2|2|2|2|
|2|1|2|2|2|1|1|1|1|1|
|1|1|1|1|2|1|2|1|1|1|
|2|2| |1|2|1|1|1|1|2|
|2|2|2|1|1|1| |1|2|2|
|2|2|1|2|2|2|2|2|1|1|
| | |2|2|2|2| |1|1|1|
|1|1|2|2|2|1|1|1|1| |
| | |1|1|1|1|1|2|1| |
Played 100 games:
Number wins by Player1: 0
Number wins by Player2: 1
Number of ties: 99
This does answer your question... but I took it a bit far... decided to implement the solution.
Instead of counting matches... I just check from teh point the last player plays, if all marks in a row column and diagnal match the players, he wins.
package com.clinkworks.example;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class TicTacToe {
private static final String TIE = "TIE";
private static final Map<String, Integer> gamesToWinsMap = new HashMap<String, Integer>();
/**
* accepts input in the following format:
*
* playerCount rowCount columnCount (sets the game with the n players, n columns, and n rows)
* - java -jar tic-tac-toe.jar 2 3 3
* PlayerCount squareSize (defaults to a game with rows and cols the same as squareSize and the player count given)
* - java -jar tic-tac-toe.jar 2 3
* PlayerCount (defaults to a 3 by 3 game)
* - java -jar tic-tac-toe.jar 2
* no input (defaults to a 3 by 3 game with 2 players)
* - java -jar tic-tac-toe.jar
* #param args
*/
public static void main(String[] args) {
int playerCount = 2;
int rows = 3;
int cols = 3;
if(args.length == 3){
playerCount = Integer.valueOf(args[0]);
rows = Integer.valueOf(args[1]);
cols = Integer.valueOf(args[2]);
}
if(args.length == 2){
playerCount = Integer.valueOf(args[0]);
rows = Integer.valueOf(args[1]);
cols = rows;
}
if(args.length == 1){
playerCount = Integer.valueOf(args[0]);
}
for(int i = 1; i <= playerCount; i++){
gamesToWinsMap.put("Player" + i, 0);
}
//lets play 100 games and see the wins and ties
playGames(100, playerCount, rows, cols);
for(int i = 1; i <= playerCount; i++){
System.out.println("Number wins by Player" + i + ": " + gamesToWinsMap.get("Player" + i));
}
System.out.println("Number of ties: " + gamesToWinsMap.get(TIE));
}
public static void playGames(int gamesToPlay, int playerCount, int rows, int cols) {
//play a new game each iteration, in our example, count = 100;
for (int i = 0; i < gamesToPlay; i++) {
playGame(playerCount, rows, cols);
}
}
public static void playGame(int playerCount, int rows, int cols) {
//create a new game board. this initalizes our 2d array and lets the complexity of handling that
// array be deligated to the board object.
Board board = new Board(playerCount, rows, cols);
//we are going to generate a random list of moves. Heres where we are goign to store it
List<Move> moves = new ArrayList<Move>();
//we are creating moves for each space on the board.
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
moves.add(new Move(row, col));
}
}
//randomize the move list
Collections.shuffle(moves);
//do each move
for (Move move : moves) {
board.play(move);
if(gameOver(board)){
break;
}
}
}
public static boolean gameOver(Board board){
if (board.whoWon() != null) {
System.out.println(board.whoWon() + " won the game!");
System.out.println(board);
Integer winCount = gamesToWinsMap.get(board.whoWon());
winCount = winCount == null ? 1 : winCount + 1;
gamesToWinsMap.put(board.whoWon(), winCount);
return true;
} else if (board.movesLeft() == 0) {
System.out.println("It was a cats game!!");
System.out.println(board);
Integer tieCount = gamesToWinsMap.get(TIE);
tieCount = tieCount == null ? 1 : tieCount + 1;
gamesToWinsMap.put(TIE, tieCount);
return true;
}
return false;
}
public static class Move {
private int row;
private int column;
public Move(int row, int column) {
this.row = row;
this.column = column;
}
public int getRow() {
return row;
}
public int getColumn() {
return column;
}
}
public static class Board {
private final int rowSize;
private final int columnSize;
private final Integer[][] gameBoard;
private int playerCount;
private int currentPlayer;
private String winningPlayer;
public Board() {
gameBoard = new Integer[3][3];
currentPlayer = 1;
winningPlayer = null;
this.rowSize = 3;
this.columnSize = 3;
playerCount = 2;
}
public Board(int players) {
gameBoard = new Integer[3][3];
currentPlayer = 1;
winningPlayer = null;
this.rowSize = 3;
this.columnSize = 3;
playerCount = players;
}
public Board(int rowSize, int columnSize) {
gameBoard = new Integer[rowSize][columnSize];
currentPlayer = 1;
winningPlayer = null;
playerCount = 2;
this.rowSize = rowSize;
this.columnSize = columnSize;
}
public Board(int players, int rowSize, int columnSize) {
gameBoard = new Integer[rowSize][columnSize];
currentPlayer = 1;
winningPlayer = null;
playerCount = players;
this.rowSize = rowSize;
this.columnSize = columnSize;
}
/**
*
* #return the amount of empty spaces remaining on the game board, or if theres a winning player, zero.
*/
public int movesLeft() {
if(whoWon() != null){
return 0;
}
int moveCount = 0;
for (int x = 0; x < getRowSize(); x++) {
for (int y = 0; y < getColumnSize(); y++) {
moveCount += getMoveAt(x, y) == null ? 1 : 0;
}
}
return moveCount;
}
/**
* If someone won, this will return the winning player.
*
* #return the winning player
*/
public String whoWon() {
return winningPlayer;
}
/**
* This move allows the next player to choose where to place their mark.
*
* #param row
* #param column
* #return if the game is over, play will return true, otherwise false.
*/
public boolean play(Move move) {
if (!validMove(move)) {
// always fail early
throw new IllegalStateException("Player " + getCurrentPlayer() + " cannot play at " + move.getRow() + ", " + move.getColumn() + "\n" + toString());
}
doMove(move);
boolean playerWon = isWinningMove(move);
if (playerWon) {
winningPlayer = "Player" + getCurrentPlayer();
return true;
}
shiftPlayer();
boolean outOfMoves = movesLeft() <= 0;
return outOfMoves;
}
public int getRowSize() {
return rowSize;
}
public int getColumnSize() {
return columnSize;
}
public int getCurrentPlayer() {
return currentPlayer;
}
public Integer getMoveAt(int row, int column) {
return gameBoard[row][column];
}
private void doMove(Move move) {
gameBoard[move.getRow()][move.getColumn()] = getCurrentPlayer();
}
private void shiftPlayer() {
if(getCurrentPlayer() == getPlayerCount()){
currentPlayer = 1;
}else{
currentPlayer++;
}
}
private int getPlayerCount() {
return playerCount;
}
private boolean validMove(Move move) {
boolean noMoveAtIndex = false;
boolean indexesAreOk = move.getRow() >= 0 || move.getRow() < getRowSize();
indexesAreOk = indexesAreOk && move.getColumn() >= 0 || move.getColumn() < getColumnSize();
if (indexesAreOk) {
noMoveAtIndex = getMoveAt(move.getRow(), move.getColumn()) == null;
}
return indexesAreOk && noMoveAtIndex;
}
private boolean isWinningMove(Move move) {
// since we check to see if the player won on each move
// we are safe to simply check the last move
return winsDown(move) || winsAcross(move) || winsDiagnally(move);
}
private boolean winsDown(Move move) {
boolean matchesColumn = true;
for (int i = 0; i < getColumnSize(); i++) {
Integer moveOnCol = getMoveAt(move.getRow(), i);
if (moveOnCol == null || getCurrentPlayer() != moveOnCol) {
matchesColumn = false;
break;
}
}
return matchesColumn;
}
private boolean winsAcross(Move move) {
boolean matchesRow = true;
for (int i = 0; i < getRowSize(); i++) {
Integer moveOnRow = getMoveAt(i, move.getColumn());
if (moveOnRow == null || getCurrentPlayer() != moveOnRow) {
matchesRow = false;
break;
}
}
return matchesRow;
}
private boolean winsDiagnally(Move move) {
// diagnals we only care about x and y being teh same...
// only perfect squares can have diagnals
// so we check (0,0)(1,1)(2,2) .. etc
boolean matchesDiagnal = false;
if (isOnDiagnal(move.getRow(), move.getColumn())) {
matchesDiagnal = true;
for (int i = 0; i < getRowSize(); i++) {
Integer moveOnDiagnal = getMoveAt(i, i);
if (moveOnDiagnal == null || moveOnDiagnal != getCurrentPlayer()) {
matchesDiagnal = false;
break;
}
}
}
return matchesDiagnal;
}
private boolean isOnDiagnal(int x, int y) {
if (boardIsAMagicSquare()) {
return x == y;
} else {
return false;
}
}
private boolean boardIsAMagicSquare() {
return getRowSize() == getColumnSize();
}
public String toString() {
StringBuffer stringBuffer = new StringBuffer();
for(int y = 0; y < getColumnSize(); y++) {
for(int x = 0; x < getRowSize(); x++) {
Integer move = getMoveAt(x, y);
String moveToPrint = "";
if (move == null) {
moveToPrint = " ";
} else {
moveToPrint = move.toString();
}
stringBuffer.append("|").append(moveToPrint);
}
stringBuffer.append("|\n");
}
return stringBuffer.toString();
}
}
}
I have to revise my answer. If you want to have three in a row regardless of your board size, your loop code might be sufficient, but you are always checking whether the values of the fields are the same but never make a difference between empty and non-empty fields.
So “empty” can win too, which would effectively hide a possible win of a player. In other words, your code does not work correctly, even for a field size of three. You didn’t test it enough.
If I initialize the board as
int[][] board={
{ 1, 1, 1 },
{ 0, 0, 0 },
{ 0, 0, 0 },
};
your code returns 0 as the second row contains three zeros. I assumed that 0 represents the empty field but the actual value for “empty” doesn’t matter. You have to exclude empty fields from the three-in-a-row check.
You can simplify this a fair amount by breaking the logic up a bit.
First realize that you only need to check for a win around the piece you just placed.
Now we need a way to check whether that move is a winner.
First we need a simple function to check whether a cell matches a given value, returning true if its within bounds and matches.
private boolean cellMatches(int x, int y, int val) {
if (x<0||x>boardWidth)
return false;
if (y<0||y>boardHeight)
return false;
return board[x][y]==val;
}
Now a function that you give a starting position (x and y) and a delta (dx, dy) and it checks up to two cells in that direction returning a count of how many in a row matched value. The for loop may be overkill for two checks but it would easily allow you to expand up to longer lines being used.
private int countMatches(int x, int y, int dx, int dy, int val) {
int count = 0;
for (int step=1;step<=2;step++) {
if (cellMatches(x+dx*step, y+dy*step, val) {
count++;
} else {
return count;
}
}
return count;
}
Now we can use the previous method. When we place a new piece we can just count out in each matching pair of directions. The combined count is the total number in a row. (i.e. two in a row top + 1 bot = a total run length of 4). If any of those run lengths is three then it is a winning move.
private boolean makeMove(int x, int y, int val) {
board[x][y] = val;
int runlength=countMatches(x,y,0,1,val) + countMatches(x,y,0,-1,val);
if (runLength >= 2)
return true;
int runlength=countMatches(x,y,1,0,val) + countMatches(x,y,-1,0,val);
if (runLength >= 2)
return true;
int runlength=countMatches(x,y,1,1,val) + countMatches(x,y,-1,-1,val);
if (runLength >= 2)
return true;
int runlength=countMatches(x,y,1,-1,val) + countMatches(x,y,-1,1,val);
if (runLength >= 2)
return true;
return false;
}
Note that because we need to count the center piece that we placed we just need a run length of two or more.
I'm having trouble coding the 8 queens problem. I've coded a class to help me solve it, but for some reason, I'm doing something wrong. I kind of understand what's supposed to happen.
Also, we have to use recursion to solve it but I have no clue how to use the backtracking I've read about, so I just used it in the methods checking if a position is legitimate.
My board is String [] [] board = { { "O", "O"... etc etc with 8 rows and 8 columns.
If I'm getting anything wrong conceptually or making a grave Java mistake, please say so :D
Thanks!
public void solve () {
int Queens = NUM_Queens - 1;
while (Queens > 0) {
for (int col = 0; col < 8; col++) {
int row = -1;
boolean c = false;
while (c = false && row < 8) {
row ++;
c = checkPos (row, col);
}
if (c == true) {
board[row][col] = "Q";
Queens--;
}
else
System.out.println("Error");
}
}
printBoard ();
}
// printing the board
public void printBoard () {
String ret = "";
for (int i = 0; i < 8; i++) {
for (int a = 0; a < 8; a++)
ret += (board[i][a] + ", ");
ret += ("\n");
}
System.out.print (ret);
}
// checking if a position is a legitimate location to put a Queen
public boolean checkPos (int y, int x) {
boolean r = true, d = true, u = true, co = true;
r = checkPosR (y, 0);
co = checkPosC (0, x);
int col = x;
int row = y;
while (row != 0 && col != 0 ) { //setting up to check diagonally downwards
row--;
col--;
}
d = checkPosDD (row, col);
col = x;
row = y;
while (row != 7 && col != 0 ) { //setting up to check diagonally upwards
row++;
col--;
}
d = checkPosDU (row, col);
if (r = true && d = true && u = true && co = true)
return true;
else
return false;
}
// checking the row
public boolean checkPosR (int y, int x) {
if (board[y][x].contentEquals("Q"))
return false;
else if (board[y][x].contentEquals("O") && x == 7)
return true;
else //if (board[y][x].contentEquals("O"))
return checkPosR (y, x+1);
}
// checking the column
public boolean checkPosC (int y, int x) {
if (board[y][x].contentEquals("Q"))
return false;
else if (board[y][x].contentEquals("O") && y == 7)
return true;
else //if (board[y][x].contentEquals("O"))
return checkPosR (y+1, x);
}
// checking the diagonals from top left to bottom right
public boolean checkPosDD (int y, int x) {
if (board[y][x].contentEquals("Q"))
return false;
else if (board[y][x].contentEquals("O") && (x == 7 || y == 7))
return true;
else //if (board[y][x].contentEquals("O"))
return checkPosR (y+1, x+1);
}
// checking the diagonals from bottom left to up right
public boolean checkPosDU (int y, int x) {
if (board[y][x].contentEquals("Q"))
return false;
else if (board[y][x].contentEquals("O") && (x == 7 || y == 0))
return true;
else //if (board[y][x].contentEquals("O"))
return checkPosR (y-1, x+1);
}
}
As this is homework, the solution, but not in code.
Try to write a method that only handles what needs to happen on a single column; this is where you are supposed to use recursion. Do backtracking by checking if a solution exists, if not, undo your last change (i.e. change the queen position) and try again. If you only focus on one part of the problem (one column), this is much easier than thinking about all columns at the same time.
And as Quetzalcoatl points out, you are assigning false to your variable in the first loop. You probably do not want to do that. You should always enable all warnings in your compiler (run javac with -Xlint) and fix them.
You are trying some kind of brute-force, but, as you already mentioned, you have no recursion.
Your programs tries to put a queen on the first possible position. But at the end no solution is found. It follows that your first assumption (the position of your first queen) is invalid. You have to go back to this state. And have to assume that your checkPos(x,y) is false instead of true.
Now some hints:
As mentioned before by NPE int[N] queens is more suitable representation.
sum(queens) have to be 0+1+2+3+4+5+6+7=28, since a position has to be unique.
Instead of checking only the position of the new queen, you may check a whole situation. It is valid if for all (i,j) \in N^2 with queen(i) = j, there exists no (k,l) != (i,j) with abs(k-i) == abs(l-j)
So I've been writing a program for the game boggle. I create a little board for the user to use, but the problem is I don't know how to check if that word is on the board recursively. I want to be able to check if the word the entered is indeed on the board, and is valid. By valid I mean, the letters of the word must be adjacent to each other. For those who have played boggle you'll know what I mean. All I want to do is check if the word is on the board.
This is what I have so far ....
import java.io.*;
public class boggle {
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
private String s = "";
private int [][] lettersNum = new int [5][5];
private char [][] letters = new char [5][5];
private char [] word = new char [45]; // Size at 45, because the longest word in the dictionary is only 45 letters long
private char [] temp;
public void generateNum()
{
for (int row = 0; row < 5; row ++)
{
for (int col = 0; col < 5; col++)
{
lettersNum [row][col] = (int) (Math.random() * 26 + 65);
}
}
}
public void numToChar()
{
for (int row = 0; row < 5; row ++)
{
for (int col = 0; col < 5; col++)
{
letters [row][col] = (char)(lettersNum[row][col]);
}
}
}
public void display()
{
for (int row = 0; row < 5; row ++)
{
for (int col = 0; col < 5; col++)
{
System.out.print(letters[row][col]);
}
System.out.println("");
}
}
public void getInput() throws IOException
{
System.out.println("Please enter a word : ");
s=br.readLine();
s=s.toUpperCase();
word = s.toCharArray();
}
public int search(int row, int col)
{
if((row <0) || (row >= 5) || (col < 0) || (col >= 5))
{
return (0);
}
else
{
temp = word;
return (1+ search(row +1, col) +
search(row -1, col) +
search(row, col + 1) +
search(row, col-1) +
search(row +1, col +1)+
search(row +1, col -1)+
search(row -1, col +1)+
search(row -1, col -1));
}
}
}
The search was my searching algorithm to check if the word is on the board but I don't know if it is correct or if it will work. Furthermore, I don't know how to actually tell the user that the word is valid !
Thanks for all the help :)
SO I tried to use what you suggested below but I dont really understand the int [5][5] thing. So this is what I tried, but I keep getting out of bounds errors ! Here is the soruce ...
public void locate()
{
temp = word[0];
for (int row = 0; row <5; row++)
{
for (int col = 0; col <5; col++)
{
if(temp == letters[row][col])
{
search(row,col);
}
}
}
}
public int search(int row, int col)
{
if(letters[row][col-1]==word[count]) // Checks the letter to the left
{
count++;
letters[row][col-1] = '-'; // Just to make sure the program doesn't go back on itself
return search(row, col-1);
}
else if (letters[row][col+1] == word[count])// Checks the letter to the right
{
count++;
letters[row][col+1] = '-';// Just to make sure the program doesn't go back on itself
return search(row, col +1);
}
else if (letters[row+1][col]== word[count])// Checks the letter below
{
count++;
letters[row+1][col] = '-';// Just to make sure the program doesn't go back on itself
return search(row +1 , col);
}
else if (letters[row-1][col]== word[count])// Checks the letter above
{
count++;
letters[row-1][col] = '-';// Just to make sure the program doesn't go back on itself
return search(row -1 , col);
}
else if (letters[row-1][col-1]== word[count])// Checks the letter to the top left
{
count++;
letters[row-1][col-1] = '-';// Just to make sure the program doesn't go back on itself
return search(row -1 , col-1);
}
else if (letters[row-1][col+1]== word[count])// Checks the letter to the top right
{
count++;
letters[row-1][col+1] = '-';// Just to make sure the program doesn't go back on itself
return search(row -1 , col+1);
}
else if (letters[row+1][col-1]== word[count])// Checks the letter to the bottom left
{
count++;
letters[row+1][col-1] = '-';// Just to make sure the program doesn't go back on itself
return search(row +1 , col-1);
}
else if (letters[row+1][col+1]== word[count])// Checks the letter to the bottom right
{
count++;
letters[row+1][col+1] = '-';// Just to make sure the program doesn't go back on itself
return search(row +1 , col+1);
}
return 0;
}
private int count = 0; (was declared at the top of the class, in case you were wondering where I got the word[count] from
Your current search function doesn't actually do anything. I'm assuming this is homework so, no free lunch ;)
The simplest approach would be to have two recursive functions:
public boolean findStart(String word, int x, int y)
This will do a linear search of the board looking for the first character in word. If your current location doesn't match, you call yourself with the next set of coords. When it finds a match, it calls your second recursive function using word, the current location, and a new, empty 4x4 matrix:
public boolean findWord(String word, int x, int y, int[][] visited)
This function first checks to see if the current location matches the first letter in word. If it does, it marks the current location in visited and loops through all the adjoining squares except ones marked in visited by calling itself with word.substring(1) and those coords. If you run out of letters in word, you've found it and return true. Note that if you're returning false, you need to remove the current location from visited.
You can do this with one function, but by splitting out the logic I personally think it becomes easier to manage in your head. The one downside is that it does do an extra comparison for each first letter in a word. To use a single function you would need to keep track of what "mode" you were in either with a boolean or a depth counter.
Edit: Your longest word should only be 16. Boggle uses a 4x4 board and a word can't use the same location twice. Not that this really matters, but it might for the assignment. Also note that I just did this in my head and don't know that I got it 100% right - comments appreciated.
Edit in response to comments:
Here's what your iterative locate would look like using the method I outline above:
public boolean locate(String word)
{
for (int row = 0; row < 4; row++)
{
for (int col =0; col < 4; col++)
{
if (word.charAt(0) == letters[row][col])
{
boolean found = findWord(word, row, col, new boolean[4][4]);
if (found)
return true;
}
}
}
return false;
}
The same thing recursively looks like the following, which should help:
public boolean findStart(String word, int x, int y)
{
boolean found = false;
if (word.charAt(0) == letters[x][y])
{
found = findWord(word, x, y, new boolean[4][4]);
}
if (found)
return true;
else
{
y++;
if (y > 3)
{
y = 0;
x++;
}
if (x > 3)
return false;
}
return findStart(word, x, y);
}
So here's findWord() and a helper method getAdjoining() to show you how this all works. Note that I changed the visited array to boolean just because it made sense:
public boolean findWord(String word, int x, int y, boolean[][] visited)
{
if (letters[x][y] == word.charAt(0))
{
if (word.length() == 1) // this is the last character in the word
return true;
else
{
visited[x][y] = true;
List<Point> adjoining = getAdjoining(x,y,visited);
for (Point p : adjoining)
{
boolean found = findWord(word.substring(1), p.x, p.y, visited);
if (found)
return true;
}
visited[x][y] = false;
}
}
return false;
}
public List<Point> getAdjoining(int x, int y, boolean[][] visited)
{
List<Point> adjoining = new LinkedList<Point>();
for (int x2 = x-1; x2 <= x+1; x2++)
{
for (int y2 = y-1; y2 <= y+1; y2++)
{
if (x2 < 0 || x2 > 3 ||
y2 < 0 || y2 > 3 ||
(x2 == x && y2 == y) ||
visited[x2][y2])
{
continue;
}
adjoining.add(new Point(x2,y2));
}
}
return adjoining;
}
So now, after you get input from the user as a String (word), you would just call:
boolean isOnBoard = findStart(word,0,0);
I did this in my head originally, then just went down that path to try and show you how it works. If I were to actually implement this I would do some things differently (mainly eliminating the double comparison of the first letter in the word, probably by combining the two into one method though you can do it by rearranging the logic in the current methods), but the above code does function and should help you better understand recursive searching.